Altium - the Altium Bridge
Public Made by Adomby adom
Adom Bridge for Altium Designer: a resident DelphiScript agent gives the AI eval, the 1,100-command process launcher, all 8 EDA surfaces with screenshots, compile/ERC, DRC, OutJob outputs, native SchLib/PcbLib authoring with STEP 3D bodies, and dialog handling by PID.
main
0be1503
1mo ago
Adom Altium-Bridge Phase-2 Design-Lint Catalog
| Field | Value |
|---|---|
| Title | Adom altium-bridge Phase-2 DESIGN-LINT CATALOG |
| Document id | ALTIUM-LINT-SPEC-001 |
| Status | SPEC ONLY — no implementation, no scripts to ship |
| Modeled on | eda-agent design_lint_report (31 checks) plus 4 Adom-specific checks |
| Check count | 35 |
| Date | 2026-08-31 |
Purpose
This catalog is the Phase-2 read-only design-lint specification for Adom's altium-bridge. It lists every check an agent is expected to run against an open Altium Designer project, including:
- What each check detects
- Severity (
error/warning/info) - Surface (
schematic sheet/PCB board/library/project) - Altium DelphiScript objects and properties to read (no mutating APIs except read-side rebuilds such as
Polygon.Rebuildused only to inspect pour state) - Detection logic in plain steps
- An example good finding message
The catalog maps 1:1 onto eda-agent's 31-check design_lint_report sweep (schematic hygiene, connectivity, PCB geometry, variant DNP, polygon validity) and adds four Adom extras:
mouser_digikey_lcsc_params— all three supplier PNs requiredpin1_symbol_footprint— pin-1 / pad-1 disagreementunused_mechanical_layers— mechanical layers with leftover contentmissing_power_testpoints— power rails without a test point
Severity mapping vs eda-agent: eda-agent uses critical / warning / info. This catalog uses error / warning / info (error ≡ eda-agent critical).
Out of scope
- No implementation. This file is not Pascal, Python, or MCP tool code.
- Do not launch Altium. Do not open
.PcbDoc/.SchDoc/.PrjPcb. - Do not touch any altium-bridge repo, Adom Bridge folders, or Altium install.
- Do not run adom-bridge /
altium_evalagainst a live designer in this phase. - Do not write exploits, DRC mutators, or auto-fix scripts. Lint is read-only.
pcb.run_drc(if ever invoked later) mutates the.DRCreport file and is optional, off by default. - Library authoring (creating symbols/footprints) is out of scope; library reads (models, pin-1, 3D bodies) are in scope.
How an AI would run these checks later (via altium_eval)
This is documentation of the intended execution model. It is not permission to run it now.
- Ensure Altium Designer has the target
.PrjPcbfocused and compiled (IProject.DM_Compile/ workspaceGetWorkspace). Prefer SmartCompile; force recompile only if the netlist is stale. - For each check, emit a read-only DelphiScript snippet (no
AddPCBObject, noSchObjectFactorycreate, no file writes except returning JSON through the bridge stdout/IPC channel). - Send the snippet through the existing altium-bridge
altium_eval(or equivalentaudit.*IPC command) againstSchServer/PCBServer. - Typical entry points:
- Schematic:
SchServer.GetCurrentSchDocument→ISch_Document/ISch_Sheet;SchIterator_Create;AddFilter_ObjectSet(MkSet(eSchPort, eNetLabel, ePowerPort, eSchComponent, …)). - PCB:
Board := PCBServer.GetCurrentPCBBoard;Board.BoardIterator_Create;Iterator.AddFilter_ObjectSet(MkSet(eViaObject, ePadObject, eTrackObject, …));Iterator.AddFilter_LayerSet(AllLayers);Iterator.AddFilter_Method(eProcessAll). - Project / nets:
GetWorkspace→IWorkspace→IProject→IDocument/ flattenedDM_DocumentFlattened;INet.DM_PinCount,IComponent.
- Schematic:
- Destroy iterators (
SchIterator_Destroy,BoardIterator_Destroy) after each walk. - Aggregate
{checked, violations, items[]}per check into adesign_lint_report-shaped payload:summary,sections,totals,_failed. - Never highlight/select on canvas as the primary result; return structured findings with designator, net, sheet/board, and coordinates in mils.
Shared API conventions (verified unless marked)
| Server | Object | Notes |
|---|---|---|
SchServer |
ISch_Sheet / ISch_Document |
Current schematic |
SchServer |
ISch_Iterator |
SchIterator_Create / FirstSchObject / NextSchObject |
| Object ids | eSchPort, eNetLabel, ePowerPort / ePowerObject, eSchComponent, ePin, eWire, eBus, eSheetEntry, eImage |
|
| Interfaces | ISch_Port, ISch_NetLabel, ISch_PowerPort / ISch_PowerObject, ISch_Component, ISch_Pin, ISch_Parameter, ISch_Wire |
|
PCBServer |
IPCB_Board |
PCBServer.GetCurrentPCBBoard |
| Iterators | BoardIterator_Create, spatial iterator, group iterator |
|
| Objects | IPCB_Component, IPCB_Via, IPCB_Pad, IPCB_Track, IPCB_Arc, IPCB_Polygon, IPCB_BoardOutline, IPCB_LayerObject, IPCB_Text, IPCB_ComponentBody, IPCB_Net, IPCB_Region |
|
| Stack | ILayerStack |
|
| Workspace | IWorkspace, IProject, IDocument, IComponent, INet |
Flattened netlist after compile |
| Units | TCoord; MilsToCoord / CoordToMils |
1 mil = 10000 internal units |
ResetParameters is a parametric-process helper (Client API), not an object walker; lint scripts should not need it unless invoking a process.
Check catalog
Each check uses snake_case id. eda-agent names are noted where they differ.
1. floating_ports
- name: Floating / unconnected schematic ports
- what it detects: Ports whose electrical hotspot is not on a wire, pin, or sheet entry, or whose net does not appear on any pin / sheet entry on the same sheet.
- severity: warning
- surface: schematic sheet
- eda-agent analog:
find_floating_ports - API to read:
ISch_Sheet+ISch_Iteratorfiltered toeSchPort→ISch_PortISch_Port.Name/Text(net name),Location/Location.X/Location.YUNVERIFIED exact location property name (ISch_GraphicalObject.Locationis typical)- Spatial / small-area iterator at the port hotspot for
eWire,ePin,eSheetEntry - Flattened
INetmembership as a second signal
- detection logic:
- Compile the project.
- For every schematic sheet, iterate
eSchPort. - A port is floating if no
eWire/ pin / sheet entry occupies its hotspot or the flattened net for that port name has zero pins and zero sheet entries on that sheet. - Report net, sheet filename, location in mils.
- example good finding message:
Port "SPI_CLK" on sheet MCU.SchDoc at (1250, 800) mils is floating: hotspot is not on a wire, pin, or sheet entry.
2. unmatched_ports
- name: Multi-driver and no-driver nets (port direction)
- what it detects: Flattened nets with more than one Output port (multi-driver), or Input ports with zero Output/Bidirectional ports (no driver).
- severity: error
- surface: project
- eda-agent analog:
find_unmatched_ports(multi_output/no_driver) - API to read:
ISch_Portdirection:ISch_Port.IOTypeUNVERIFIED exact enum (ePortIOInput/ePortIOOutput/ePortIOBidirectionaltypical in Schematic API)- Flattened
INet.DM_NetName, group ports by net
- detection logic:
- Compile; walk all ports on all compiled documents.
- Bucket by flattened net name; count Input / Output / Bidirectional.
- Flag
output_count > 1as multi-driver; flaginput_count > 0andoutput_count + bidir_count = 0as no-driver.
- example good finding message:
Net "UART_TX" has 2 Output ports (multi-driver) across MCU.SchDoc and IO.SchDoc.
3. orphan_net_labels
- name: Unconnected / orphan net labels
- what it detects:
ISch_NetLabelobjects whose location is not on a wire or bus (phantom nets). - severity: error
- surface: schematic sheet
- eda-agent analog:
find_orphan_net_labels - API to read:
ISch_NetLabel, object ideNetLabelISch_NetLabel.Text(label string)- Location X/Y; spatial iterate 1-mil square for
eWire/eBus
- detection logic:
- Iterate every
eNetLabelon every sheet. - If no wire/bus intersects the label location, flag as orphan.
- Iterate every
- example good finding message:
Net label "nRESET" on PWR.SchDoc at (420, 210) mils is not on any wire or bus.
4. orphan_power_objects
- name: Unconnected / orphan power ports
- what it detects: Power-port markers sitting off-wire (phantom GND/VCC).
- severity: error
- surface: schematic sheet
- eda-agent analog:
find_orphan_power_objects - API to read:
ISch_PowerPort/ISch_PowerObject; object idePowerPort/ePowerObject(UNVERIFIED which id the running AD version exposes; both appear in docs)Text/ net name;Style(ePowerGndPower,ePowerGndSignal,ePowerGndEarth,ePowerBar, …)- Spatial 1-mil test for
eWire
- detection logic:
- Iterate power objects.
- If no wire at the electrical hotspot, flag orphan.
- example good finding message:
Power port "GND" on MCU.SchDoc at (100, 50) mils is not on a wire.
5. single_pin_nets
- name: Single-pin named nets
- what it detects: Flattened nets with exactly one pin and at least one net-label / port / power-object (broken named connection, not a silent NC).
- severity: warning
- surface: project
- eda-agent analog:
find_single_pin_nets - API to read:
INet.DM_PinCount(workspace) — also cited asNet.PinCountin some PCB-sideIPCB_NetsamplesINet.DM_NetName; first pin designator + pin number- Presence of net identifiers on that net (UNVERIFIED exact
INetchild enumeration:DM_NetItemCount/ schematic objects sharing the name)
- detection logic:
- Compile; use
DM_DocumentFlattened. - For each net with
DM_PinCount = 1, check that a net label, port, or power object names that net. - Skip unnamed default nets and intentional NC pins if the lone pin name matches NC/DNC/RSVD.
- Compile; use
- example good finding message:
Net "I2C_SDA" has exactly 1 pin (U3-12) plus a net label; the other end is missing.
6. power_port_orientation
- name: Power-port orientation convention
- what it detects: Ground symbols not facing down; power bars not facing up.
- severity: warning
- surface: schematic sheet
- eda-agent analog:
power_port_orientation - API to read:
ISch_PowerPort.Style:ePowerGndPower,ePowerGndSignal,ePowerGndEarth,ePowerBarISch_PowerPort.Orientation/GetState_Orientation— 0 / 90 / 180 / 270 degrees
- detection logic:
- Iterate power ports.
- Ground styles must be 270° (down). Bar style must be 90° (up).
- Other styles (circle, arrow, wave) are info-only / skip unless project standard says otherwise.
- example good finding message:
Ground power port "GND" on PWR.SchDoc has Orientation=90 (expected 270 / down).
7. duplicate_designators
- name: Duplicate schematic designators
- what it detects: Two or more source-sheet components sharing the same designator (pre-flatten).
- severity: error
- surface: project
- eda-agent analog:
find_designator_collisions - API to read:
ISch_Component.Designator/Designator.TextISch_Component.UniqueId- Walk source sheets, not compiled flattened docs (flattening hides collisions with channel suffixes)
- detection logic:
- Collect designator → list of (sheet, unique id).
- Flag any designator with count > 1.
- example good finding message:
Designator R12 occurs 2 times (MCU.SchDoc, ANALOG.SchDoc).
8. component_param_visibility
- name: Per-class visible component parameters
- what it detects: Caps without visible value+voltage, resistors without visible value, inductors without L+Isat, ICs without visible MPN.
- severity: info
- surface: schematic sheet
- eda-agent analog:
component_param_visibility/audit.validate_component_params - API to read:
ISch_Component.Designator,Comment- Child iterator
eParameter→ISch_Parameter.Name,Text,IsHidden
- detection logic:
- Classify by designator prefix (C/R/L/U).
- Required visible (
IsHidden=False) fields: C → value endingFand voltage endingV; R → value endingR|k|M|m; L →Hand currentA; U → parameter name startingManufacturer Part Number. - Comment field may satisfy a requirement if visible and matching the pattern.
- example good finding message:
C17 (class capacitor) is missing visible voltage rating (need a parameter or Comment ending in V).
9. missing_datasheets
- name: ICs missing datasheet URL
- what it detects: U* components with no
http(s)://in HelpURL / Datasheet / DatasheetURL / ComponentLink1URL…ComponentLink4URL. - severity: info
- surface: schematic sheet / library
- eda-agent analog:
find_missing_datasheets - API to read:
ISch_Parameter.NameandTextonISch_Component - detection logic: Scan U* parameters; if none contain
http://orhttps://in those slots, flag. - example good finding message:
U4 (lib_ref STM32G031K8Tx, comment STM32G031K8T6) has no http(s) datasheet URL in HelpURL/Datasheet/ComponentLink*URL.
10. mpn_inconsistencies
- name: Conflicting manufacturer part numbers
- what it detects: Same
(lib_ref, comment)group of ICs with different MPNs. - severity: warning
- surface: project
- eda-agent analog:
find_mpn_inconsistencies - API to read:
ISch_Component.LibReferenceUNVERIFIED (LibraryPath/SymbolReferencealso exist);Comment; parameterManufacturer Part Number - detection logic: Group U* by (lib_ref, comment); if unique MPN set size > 1, flag the group.
- example good finding message:
lib_ref=AP2112K-3.3TRG1 comment=3.3V LDO has MPNs AP2112K-3.3TRG1 and AP2112K-3.3TRG1-ND across U10,U11.
11. placeholder_values
- name: Placeholder parameter strings
- what it detects: Component parameters equal to TBD/TBA/TODO/FIXME/XXX/?/??/???/PLACEHOLDER/FILLER/ASK/UNKNOWN/N/A/NA (trim, case-insensitive).
- severity: error
- surface: schematic sheet
- eda-agent analog:
find_placeholder_values - API to read: All
ISch_Parameter.TextplusComment - detection logic: Whole-string match after trim; skip empty (other checks cover empty).
- example good finding message:
R9 parameter Comment="TBD" looks like a leftover placeholder.
12. visible_supplier_pn
- name: Visible supplier part numbers on schematic
- what it detects: Parameters whose name starts with
supplierandIsHidden=False(eda-agent BOM-hygiene: supplier SKUs should not appear on SCH PDF). Note: Adom extramouser_digikey_lcsc_paramsrequires those parameters to exist; this check only requires they are hidden on the canvas. - severity: info
- surface: schematic sheet
- eda-agent analog:
find_visible_supplier_pn - API to read:
ISch_Parameter.Name,Text,IsHidden - detection logic: Name prefix
supplier(case-insensitive) AND not hidden → violation. - example good finding message:
U2 parameter "Supplier Part Number 1"="296-1234-1-ND" is visible on the schematic; hide it (keep MPN visible).
13. off_grid_components
- name: Schematic components off snap grid
- what it detects: Placed symbols whose origin is not on the project grid (default 100 mil).
- severity: info
- surface: schematic sheet
- eda-agent analog:
find_off_grid_components - API to read:
ISch_Component.Location.X/Y(TCoord); compareAbs(CoordToMils(X)) mod grid_mils - detection logic: Default
grid_mils=100. Flag if remainder ≠ 0. Report dx/dy. - example good finding message:
U7 on MCU.SchDoc is 4 mil off the 100-mil grid at (1254, 800).
14. unconnected_ic_pins
- name: Unconnected IC pins (excluding NC)
- what it detects: U* pins with empty /
?net, skipping names matching NC / N.C. / DNC / N/C / NO CONNECT / RSVD / RESERVED. - severity: warning
- surface: project
- eda-agent analog:
find_unconnected_ic_pins(BOM / flattened pins) - API to read: Workspace
IComponentpins + net name; orISch_Pin+ compiled net.ISch_Pin.Designator,Name, electrical type UNVERIFIED (ISch_Pin.Electrical/eElectricInput…) - detection logic: For each U* pin, if net is nil/empty/
?and name is not NC-like, flag. - example good finding message:
U3 pin 12 (PA8) has no net (not named NC/DNC/RSVD).
15. pin_net_name_mismatches
- name: Power/ground pin name vs net name
- what it detects: IC pins named VCC/VDD/GND/VSS (etc.) attached to a net that is not a power/ground rail.
- severity: warning
- surface: project
- eda-agent analog:
find_pin_net_name_mismatches - API to read: Pin
Name+ connectedINet.DM_NetName - detection logic: Regex power pin names vs
_net_is_power; ground pin names vs_net_is_ground. Flag mismatches. - example good finding message:
U5 pin 8 name="VCC" is on net "GPIO_PA0" (power_pin_on_non_power_net).
16. missing_decoupling
- name: IC power pins without a capacitor on the net
- what it detects: ICs whose recognised power/ground pins do not share a net with any C* component (
missingorpartial). - severity: warning
- surface: project
- eda-agent analog:
find_missing_decoupling - API to read: Flattened pin nets; designators starting with C
- detection logic: Build net → capacitors. For each U* power pin, require ≥1 C* on that net. Skip ICs with no recognised power pins.
- example good finding message:
U3 status=partial: pin 21 VDDA on net +3V3_A has no capacitor; other power pins are covered.
17. unplaced_components
- name: Schematic components with no PCB placement
- what it detects: Fitted schematic components that have no corresponding
IPCB_Componenton the board (ECO not pushed, or component deleted from PCB). - severity: error
- surface: project
- eda-agent analog: none (Adom/Phase-2; closest is design-difference snapshot)
- API to read:
- Schematic:
ISch_Component.Designator.Text - PCB:
IPCB_Component.Name(refdes);Board.GetPcbComponentByRefDesdocumented onIPCB_BoardasPcbComponentByRefDes/ similar — UNVERIFIED exact method spelling (GetPcbComponentByRefDesvsPcbComponentByRefDes) - Skip DNP / not-fitted in current variant (see
variant_dnp_mismatch)
- Schematic:
- detection logic:
- Collect fitted schematic designators.
- Collect PCB
Component.Nameset. - SCH minus PCB → unplaced.
- example good finding message:
C42 is on the schematic (fitted) but has no IPCB_Component on the board.
18. components_outside_board_outline
- name: Components off the board outline
- what it detects: Placed footprints whose origin (or body) sits outside
IPCB_BoardOutline. - severity: error
- surface: PCB board
- eda-agent analog:
find_components_outside_board_outline - API to read:
Board.BoardOutline/Board.GetState_BoardOutline→IPCB_BoardOutlineIPCB_BoardOutline.PrimitiveInsidePoly(used by eda-agent / SelectCMPInOutSideBOL.pas)IPCB_Component.X,Y,Layer,Name
- detection logic: For each component, if outline
PrimitiveInsidePolyis false for the origin (and optionally bounding box), flag. - example good finding message:
J1 origin at (3200, -50) mils is outside the board outline (top layer).
19. pads_near_board_edge
- name: Board-edge clearance violations
- what it detects: Pads/vias closer than clearance (default 25 mil) to the outline — depaneling damage.
- severity: warning
- surface: PCB board
- eda-agent analog:
find_pads_near_board_edge - API to read:
Board.PrimPrimDistance(Board.BoardOutline, Prim)— documented in eda-agent; UNVERIFIED against current AD if method isPrimPrimDistancevsBoard.PrimPrimDistanceIPCB_Pad,IPCB_Via
- detection logic: For each pad/via, if distance <
clearance_mils(default 25), flag kind, designator, distance, XY. - example good finding message:
Pad U3-1 is 12 mil from board outline (min 25 mil) at (40, 800).
20. via_antennas
- name: Via antennas / dangling vias
- what it detects: Vias electrically connected on only one layer (open stub).
- severity: warning
- surface: PCB board
- eda-agent analog:
find_via_antennas - API to read:
IPCB_Via.X,Y,LowLayer,HighLayer,Net,HoleSize,SizeVia.IsConnected— UNVERIFIED (may not exist as a boolean; eda-agent counts layers viaBoard.PrimPrimDistance = 0to track/arc/pad/fill/region, plusVia.IsConnectedToPlaneon plane layers)ILayerStackto enumerate signal vs plane layers between Low and High
- detection logic:
- Iterate
eViaObject. - Count layers where a same-net primitive touches the via, or plane connection is true.
- If connected-layer count = 1, flag antenna. If count = 0, flag dangling via (orphan).
- Iterate
- example good finding message:
Via on net "SPI_CLK" at (1250, 900) mils is connected on only 1 layer (antenna).
21. unrouted_connections
- name: Unrouted net connections
- what it detects: Ratsnest / incomplete routing: nets with pads not fully connected by tracks/arcs/vias.
- severity: warning
- surface: PCB board
- eda-agent analog:
pcb.get_unrouted_nets(review snapshot, not a numbered audit) — included here so the 31-check lint covers routing completeness - API to read:
IPCB_Net;Board.ConnectivelyValidateNetsdocumented onIPCB_Board— UNVERIFIED return shape- From-to / connection object id UNVERIFIED (
eConnectionObject/ ratsnest primitives) - Pad count vs connected copper graph
- detection logic:
- Optional:
Board.ConnectivelyValidateNets. - For each net with
PinCount/PadCount≥ 2, if any from-to remains or pads are in disjoint copper islands, flag net + incomplete node count. - Skip nets that are intentionally unrouted only if a rule/class says so (UNVERIFIED class name).
- Optional:
- example good finding message:
Net "+3V3" has 4 unrouted connections (14 pads, 2 copper islands).
22. polygon_validity
- name: Polygon validity / islands
- what it detects: Polygons/regions with zero area, failed pour, or orphan copper islands disconnected from the assigned net.
- severity: error
- surface: PCB board
- eda-agent analog:
find_invalid_regions(zero-area regions); Adom extends to pour islands - API to read:
IPCB_Polygon.Rebuild(read-side rebuild to inspect pour; treat as inspection, not an ECO)IPCB_Polygon.Net,Layer,Name/PolygonOutline- Region area;
IPCB_Regionnot owned by component/dimension - Island enumeration UNVERIFIED (
GetState_Island, pour result island count — mark unverified; fallback: after Rebuild, spatial-split regions whose net copper does not touch a same-net pad)
- detection logic:
- Iterate polygons and free regions.
- Flag area = 0 / unset.
- After Rebuild, flag islands that do not touch any pad/via of the polygon net.
- example good finding message:
Polygon "GND_Top" on Top Layer has 2 islands; island at (1800, 400) mils touches no GND pad.
23. variant_dnp_mismatch
- name: DNP / variant not-fitted mismatches
- what it detects: Components Not Fitted in the current variant that still look fitted on PCB (paste, no DNP marking), or fitted SCH parts marked DNP inconsistently.
- severity: warning
- surface: project
- eda-agent analog:
variant_not_fitted - API to read:
- Project current variant description
- Flattened component fitted flag — UNVERIFIED exact property (
IComponent.DM_Fitted/DM_NotFitted/ variantGetState_Fitted). eda-agent returns{designator, comment, unique_id}for NotFitted. - PCB:
IPCB_Componentstill present (Altium keeps DNP footprints); paste-mask expansion / locked primitives as secondary signals UNVERIFIED
- detection logic:
- If no variant selected, report info and skip mismatch logic.
- List NotFitted designators.
- Cross-check SCH parameters (
DNP,Fitted) vs variant table; flag disagreement.
- example good finding message:
Variant "Build-A": R99 is Not Fitted in the variant table but schematic parameter Fitted=True.
24. missing_footprint_models
- name: Missing footprint / PCB model on schematic component
- what it detects: Schematic components with empty
Footprint/ noISch_Implementationof type PCB, or PCB components with emptyPattern/SourceFootprintLibrary. - severity: error
- surface: library / schematic sheet / PCB board
- eda-agent analog: none (library hygiene)
- API to read:
ISch_Componentimplementations:ISch_Implementation(ModelName,ModelType=PCBLIB/PCB)- PCB:
IPCB_Component.Pattern,SourceFootprintLibrary,SourceLibReference
- detection logic: Flag if no PCB implementation, or
Patternis empty, or source library path is empty and footprint cannot be resolved. - example good finding message:
U12 has no PCB footprint implementation (Pattern empty; SourceFootprintLibrary blank).
25. missing_3d_bodies
- name: Missing 3D bodies on footprints
- what it detects: Placed PCB components with no
IPCB_ComponentBodychild (STEP/extruded body). - severity: info
- surface: library / PCB board
- eda-agent analog: none
- API to read:
IPCB_Componentgroup iterator,eComponentBodyObject→IPCB_ComponentBodyIPCB_Component.DefaultPCB3DModeldocumented- Mechanical layer extruded bodies as fallback
- detection logic: Skip fiducials, mounting holes, logos (designator prefixes FID/MH/HOLE or
ComponentKindmechanical UNVERIFIED enum). Flag electrical parts with zero bodies and emptyDefaultPCB3DModel. - example good finding message:
U3 (Pattern=QFN-48) has no IPCB_ComponentBody and DefaultPCB3DModel is empty.
26. silkscreen_over_pad
- name: Silkscreen overlapping pads
- what it detects: Overlay text/tracks/arcs overlapping SMD/through-hole copper pads (fab ink on paste).
- severity: warning
- surface: PCB board
- eda-agent analog: none (DRC silk-to-solder-mask sometimes covers this)
- API to read:
IPCB_Text,IPCB_Track,IPCB_ArconeTopOverlay/eBottomOverlayIPCB_Padon top/bottom signal layers- Overlap helper UNVERIFIED:
Board.PrimPrimDistance(silk, pad) = 0or bounding-rect intersect then exact outline. No dedicatedSilkscreenOverPadAPI documented.
- detection logic:
- For each overlay primitive (including component silk children if primitive lock allows iteration), measure distance to pads on the same side.
- Distance ≤ 0 (or < silk-to-pad rule clearance) → violation.
- Ignore courtyard-only mechanical layers.
- example good finding message:
Silkscreen text "U3" on Top Overlay overlaps pad U3-1 (PrimPrimDistance=0 at (1010, 540) mils).
27. tented_via_ratio
- name: Tented vs untented via surfaces
- what it detects: Fraction of outer via surfaces that are tented; reports ratio (consumer boards typically want ~1.0).
- severity: warning (if untented ratio exceeds project threshold; default report-only with warning when any outer surface is untented on a production board)
- surface: PCB board
- eda-agent analog:
tented_via_ratio - API to read:
IPCB_Viatenting:GetState_IsTenting_Top/GetState_IsTenting_Bottom(NEXUS/AD docs)- Query-language equivalents
SolderMaskTentingTop/SolderMaskTentingBottom SolderMaskExpansionon pad cache
- detection logic: Count top/bottom surfaces that actually reach outer layers. Buried/blind inner-only ignored. Emit
tented,untented,ratio. - example good finding message:
Via tenting ratio=0.72 (48 untented outer surfaces / 172); example untented via on net GND at (200, 200).
28. bad_connections
- name: Near-miss track / arc endpoints
- what it detects: Track/arc endpoints within
tolerance_mils(default 1.0) of another same-net primitive but not actually touching (photoplot open). - severity: warning
- surface: PCB board
- eda-agent analog:
find_bad_connections - API to read:
IPCB_Track(X1,Y1,X2,Y2,Layer,Net),IPCB_Arc; spatial iterator; skip teardrops, in-component prims, no-net, full-circle arcs - detection logic: For each signal-layer endpoint, if no same-net pad/via/track/arc at exact coord but one exists within tolerance, flag dangling/near-miss.
- example good finding message:
Track on net "nCS" layer TopLayer endpoint (812.4, 400.0) mils is 0.6 mil from via copper (tolerance 1.0); photoplot will not bridge.
29. signal_vias_without_return
- name: Signal vias without nearby return via
- what it detects: Non-power/ground vias with no GND/power via within
radius_mils(default 50). - severity: warning
- surface: PCB board
- eda-agent analog:
find_signal_vias_without_return - API to read:
IPCB_Via.Net.Name; heuristic prefixes GND / V / + / − - detection logic: For each signal via, spatial-search power/ground vias within radius. None → violation. Simplified proximity, not stackup-aware.
- example good finding message:
Signal via on net "USB_DP" at (1500, 700) mils has no GND/power via within 50 mils.
30. removed_pad_shapes
- name: Removed unused pad / via copper
- what it detects: Pads/vias with annular ring stripped on layers that still need copper (
Tools → Remove Unused Pad Shapesover-applied). - severity: warning
- surface: PCB board
- eda-agent analog:
find_removed_pad_shapes - API to read:
Via.SizeOnLayer(L) <= Via.HoleSizePad.IsPadRemoved(L)— used by community PadShapeRemoved.pas
- detection logic: For each layer in the via/pad stack, flag removed copper. Count per layer-instance.
- example good finding message:
Via on net "+3V3" at (600, 600) has SizeOnLayer(Mid1)=HoleSize (annular ring removed on Mid1).
31. unlocked_component_primitives
- name: Unlocked footprint primitives
- what it detects: Placed components with primitive lock off (pads can be dragged off-center).
- severity: warning
- surface: PCB board
- eda-agent analog:
find_unlocked_component_primitives - API to read:
IPCB_Componentprimitive lock — UNVERIFIED exact name (PrimitiveLock/GetState_PrimitiveLock). Community and eda-agent treat it as a boolean on the component. - detection logic: Iterate components; flag unlocked. Skip if intentionally exploded for documentation.
- example good finding message:
Q2 has PrimitiveLock=False; a pad can be dragged off the footprint without warning.
32. mouser_digikey_lcsc_params (Adom extra)
- name: Mouser, Digi-Key, and LCSC part-number parameters required
- what it detects: Every procurable (fitted, non-mechanical) schematic component missing any of the three required supplier parameters. Adom rule: all three are required, even if an MPN already exists.
- severity: error
- surface: schematic sheet / project
- eda-agent analog: none (opposite emphasis of
find_visible_supplier_pn, which only hides them) - API to read:
ISch_Componentparameter iterator →ISch_Parameter.Name,Text- Accepted names (normalize case/spaces/underscores):
- Mouser:
Mouser,Mouser Part Number,Mouser PN,Supplier Part Number nwhere supplier name is Mouser - Digi-Key:
DigiKey,Digi-Key,DigiKey Part Number,DK PN - LCSC:
LCSC,LCSC Part Number,LCSC PN,JLCPCB
- Mouser:
- Altium Supplier link slots
Supplier n+Supplier Part Number n— UNVERIFIED whether Adom libraries use native supplier links vs free parameters
- detection logic:
- Skip logos, fiducials, mechanical-only, and current-variant DNP parts.
- For each remaining component, require non-empty Text for all three families.
- Missing one, two, or three all fail; list which keys are empty.
- Do not require the parameters to be visible (
IsHiddenmay be True). Existence is the Adom rule; visibility is check 12.
- example good finding message:
R4 is missing required supplier parameters: Mouser=ok, DigiKey=empty, LCSC=empty (Adom rule: all three required).
33. pin1_symbol_footprint (Adom extra)
- name: Pin-1 disagreement between symbol and footprint
- what it detects: Symbol pin whose designator is
1does not correspond to footprint padName = '1'in electrical mapping (wrong pin-swap, rotated QFN, pin-1 dot vs pad 1). - severity: error
- surface: library / schematic sheet / PCB board
- eda-agent analog: none
- API to read:
- SCH:
ISch_Pin.Designator(pin number),ISch_Pin.Name, orientation / location relative to symbol - PCB:
IPCB_Pad.Name = '1'(user requirement);IPCB_Pad.Layer; componentRotation - Pin-to-pad map:
ISch_Implementation/ pin mapping model — UNVERIFIED (ISch_ModelDatafileLink,MappedPin/PinMapping) - PCB
IPCB_Component.Getstate_PadByName('1')documented asGetstate_PadByName
- SCH:
- detection logic:
- For each component with a PCB implementation, fetch symbol pin
Designator='1'and footprint padName='1'. - If either side is missing, flag.
- If a pin-map exists and pin 1 is mapped to a pad whose name is not
'1', flag disagreement. - Optional geometric heuristic (UNVERIFIED): symbol pin-1 in the "upper-left" of unrotated symbol vs footprint pad-1 in the courtyard pin-1 marker; report as info only, not error.
- For each component with a PCB implementation, fetch symbol pin
- example good finding message:
U6 symbol pin Designator=1 (name=VSS) maps to footprint pad Name=12; footprint pad Name=1 is mapped to symbol pin 12 (QFN rotation/pin-1 mismatch).
34. unused_mechanical_layers (Adom extra)
- name: Unused mechanical layers that still have content
- what it detects: Mechanical layers that are not part of the active layer stack / fabrication output set, yet still contain tracks, arcs, text, fills, or component bodies (leftover courtyard, fab notes on Mechanical 13–16, etc.).
- severity: info
- surface: PCB board
- eda-agent analog: none
- API to read:
ILayerStack/Board.LayerStack— UNVERIFIED exact property (IPCB_MasterLayerStack)IPCB_LayerObject; mechanical layer idseMechanical1…eMechanical16(AD extends beyond 16 in later versions — UNVERIFIED max)Board.LayerIsUsed/Board.MechanicalLayerEnabled— UNVERIFIED names; fallback: iterate all primitives and bucket byPrim.Layer- Pairing: courtyard often Mechanical 15, 3D on Mechanical 13 — project convention, not API
- detection logic:
- Build the set of mechanical layers that appear in the stack or are enabled for Gerber/ODB output (UNVERIFIED output-job API).
- Iterate primitives (
eTrackObject,eArcObject,eTextObject,eFillObject,eRegionObject,eComponentBodyObject) on mechanical layers. - If a mechanical layer has content but is disabled / not in stack / not in the fab output set, flag layer id + primitive count + sample coordinates.
- Do not flag empty disabled layers.
- example good finding message:
Mechanical 14 is not in the active layer stack but contains 11 primitives (example text "OLD COURTYARD" at (0, 0) mils).
35. missing_power_testpoints (Adom extra)
- name: Missing test points on power rails
- what it detects: Power/ground nets (VCC/VDD/+3V3/+5V/GND/…) with no dedicated test-point pad or test-point component (
TP*/ pad with testpoint property). - severity: warning
- surface: PCB board / project
- eda-agent analog: none (DRC has
IPCB_TestPointUsage/IPCB_TestPointStyleRulebut that is rule-engine, not this lint) - API to read:
IPCB_Padtestpoint flags — UNVERIFIED (IsTestPoint/GetState_IsTestpointTop/TestpointTop/TestpointBottom; query language has test-point fields)IPCB_Component.NamematchingTP*or comment/type Test PointIPCB_Net.Namepower heuristic (same as decoupling check)- Design rules
IPCB_TestPointUsageonly as optional cross-check, not required
- detection logic:
- Identify power nets from names:
GND*,VCC*,VDD*,VSS*, leading+,VBAT,VBUS,VREF, … - A net has a test point if any pad has the testpoint property or any
TP*component pad is on that net. - Flag power nets with ≥1 connected pad and zero test points.
- Optionally require both top-accessible TP for rails brought to connectors (UNVERIFIED policy).
- Identify power nets from names:
- example good finding message:
Power net "+3V3" has 22 pads and 0 test points (no TP* component and no pad TestpointTop/Bottom).
Mapping: eda-agent 31 → this catalog
eda-agent LINT_AUDIT_LIST + BOM-side audits are covered as follows. Some eda-agent checks are folded or omitted to keep the catalog at 35 while absorbing Adom MUST items (unplaced, footprints, 3D, silk-over-pad, unrouted).
| eda-agent section | This catalog id | Notes |
|---|---|---|
component_param_visibility |
component_param_visibility |
|
power_port_orientation |
power_port_orientation |
|
find_floating_ports |
floating_ports |
|
find_unmatched_ports |
unmatched_ports |
multi-driver / no-driver |
find_designator_collisions |
duplicate_designators |
|
find_missing_datasheets |
missing_datasheets |
|
find_mpn_inconsistencies |
mpn_inconsistencies |
|
find_single_pin_nets |
single_pin_nets |
|
find_non_embedded_images |
(omitted from 35; style) | Re-add as 36 if needed |
find_visible_supplier_pn |
visible_supplier_pn |
Complementary to Adom extra 32 |
find_orphan_net_labels |
orphan_net_labels |
|
find_orphan_power_objects |
orphan_power_objects |
|
find_placeholder_values |
placeholder_values |
|
find_off_grid_components |
off_grid_components |
|
find_components_outside_board_outline |
components_outside_board_outline |
|
find_pads_near_board_edge |
pads_near_board_edge |
|
variant_not_fitted |
variant_dnp_mismatch |
|
tented_via_ratio |
tented_via_ratio |
|
find_bad_connections |
bad_connections |
|
find_signal_vias_without_return |
signal_vias_without_return |
|
find_via_antennas |
via_antennas |
|
find_removed_pad_shapes |
removed_pad_shapes |
|
find_pads_center_not_connected |
(folded into unrouted_connections / via antennas) |
UNVERIFIED pad-center API |
find_invalid_regions |
polygon_validity |
Extended with islands |
find_mixed_designator_rotation |
(omitted from 35; silk style) | |
find_unlocked_component_primitives |
unlocked_component_primitives |
|
find_mirrored_pcb_text |
(omitted from 35; silk style) | |
find_acute_angles |
(omitted from 35; DFM) | |
find_inconsistent_track_widths |
(omitted from 35; DFM) | |
find_unconnected_ic_pins |
unconnected_ic_pins |
BOM-side |
find_pin_net_name_mismatches |
pin_net_name_mismatches |
BOM-side |
find_missing_decoupling |
missing_decoupling |
BOM-side |
| — | unplaced_components |
MUST |
| — | missing_footprint_models |
MUST |
| — | missing_3d_bodies |
MUST |
| — | silkscreen_over_pad |
MUST |
| — | unrouted_connections |
MUST |
| — | mouser_digikey_lcsc_params |
Adom extra |
| — | pin1_symbol_footprint |
Adom extra |
| — | unused_mechanical_layers |
Adom extra |
| — | missing_power_testpoints |
Adom extra |
Omitted eda-agent style/DFM checks may be reintroduced later as ids 36+ without changing 1–35.
Finding message quality
A good finding (aligned with eda-agent review discipline, adapted for lint):
- Names the exact designator, pin, net, sheet or board coordinates in mils
- States the observed API fact (not a guess about device function)
- Is actionable (what is missing or wrong)
- Does not say “verify X” or relay a raw ERC category
Lint is allowed to list many similar items; the later review agent triages them.
Summary table
| id | severity | surface |
|---|---|---|
| floating_ports | warning | schematic sheet |
| unmatched_ports | error | project |
| orphan_net_labels | error | schematic sheet |
| orphan_power_objects | error | schematic sheet |
| single_pin_nets | warning | project |
| power_port_orientation | warning | schematic sheet |
| duplicate_designators | error | project |
| component_param_visibility | info | schematic sheet |
| missing_datasheets | info | schematic sheet / library |
| mpn_inconsistencies | warning | project |
| placeholder_values | error | schematic sheet |
| visible_supplier_pn | info | schematic sheet |
| off_grid_components | info | schematic sheet |
| unconnected_ic_pins | warning | project |
| pin_net_name_mismatches | warning | project |
| missing_decoupling | warning | project |
| unplaced_components | error | project |
| components_outside_board_outline | error | PCB board |
| pads_near_board_edge | warning | PCB board |
| via_antennas | warning | PCB board |
| unrouted_connections | warning | PCB board |
| polygon_validity | error | PCB board |
| variant_dnp_mismatch | warning | project |
| missing_footprint_models | error | library / schematic sheet / PCB board |
| missing_3d_bodies | info | library / PCB board |
| silkscreen_over_pad | warning | PCB board |
| tented_via_ratio | warning | PCB board |
| bad_connections | warning | PCB board |
| signal_vias_without_return | warning | PCB board |
| removed_pad_shapes | warning | PCB board |
| unlocked_component_primitives | warning | PCB board |
| mouser_digikey_lcsc_params | error | schematic sheet / project |
| pin1_symbol_footprint | error | library / schematic sheet / PCB board |
| unused_mechanical_layers | info | PCB board |
| missing_power_testpoints | warning | PCB board / project |
Document control
- Nonce:
ALTIUM-LINT-SPEC-001 - Artifact path (box):
/workspace/altium-lint-spec.md - Intended later copy:
C:\Users\john\adom\altium-lint-spec.md - This phase: spec only; no Altium launch; no altium-bridge tree edits
<!-- Phase 2 design-lint catalog. Drafted 2026-08-31 from eda-agent's 31 checks + 4 Adom checks; API references marked UNVERIFIED must be eval-probed before implementation. -->
# Adom Altium-Bridge Phase-2 Design-Lint Catalog
| Field | Value |
| --- | --- |
| Title | Adom altium-bridge Phase-2 DESIGN-LINT CATALOG |
| Document id | ALTIUM-LINT-SPEC-001 |
| Status | SPEC ONLY — no implementation, no scripts to ship |
| Modeled on | eda-agent `design_lint_report` (31 checks) plus 4 Adom-specific checks |
| Check count | 35 |
| Date | 2026-08-31 |
## Purpose
This catalog is the Phase-2 **read-only design-lint specification** for Adom's altium-bridge. It lists every check an agent is expected to run against an open Altium Designer project, including:
- What each check detects
- Severity (`error` / `warning` / `info`)
- Surface (`schematic sheet` / `PCB board` / `library` / `project`)
- Altium DelphiScript objects and properties to **read** (no mutating APIs except read-side rebuilds such as `Polygon.Rebuild` used only to inspect pour state)
- Detection logic in plain steps
- An example good finding message
The catalog maps 1:1 onto eda-agent's 31-check `design_lint_report` sweep (schematic hygiene, connectivity, PCB geometry, variant DNP, polygon validity) and adds **four Adom extras**:
1. `mouser_digikey_lcsc_params` — all three supplier PNs required
2. `pin1_symbol_footprint` — pin-1 / pad-1 disagreement
3. `unused_mechanical_layers` — mechanical layers with leftover content
4. `missing_power_testpoints` — power rails without a test point
Severity mapping vs eda-agent: eda-agent uses `critical` / `warning` / `info`. This catalog uses `error` / `warning` / `info` (`error` ≡ eda-agent `critical`).
## Out of scope
- **No implementation.** This file is not Pascal, Python, or MCP tool code.
- **Do not launch Altium.** Do not open `.PcbDoc` / `.SchDoc` / `.PrjPcb`.
- **Do not touch** any altium-bridge repo, Adom Bridge folders, or Altium install.
- **Do not run** adom-bridge / `altium_eval` against a live designer in this phase.
- **Do not write exploits, DRC mutators, or auto-fix scripts.** Lint is read-only. `pcb.run_drc` (if ever invoked later) mutates the `.DRC` report file and is optional, off by default.
- Library *authoring* (creating symbols/footprints) is out of scope; library *reads* (models, pin-1, 3D bodies) are in scope.
## How an AI would run these checks later (via `altium_eval`)
This is documentation of the **intended** execution model. It is not permission to run it now.
1. Ensure Altium Designer has the target `.PrjPcb` focused and compiled (`IProject.DM_Compile` / workspace `GetWorkspace`). Prefer SmartCompile; force recompile only if the netlist is stale.
2. For each check, emit a **read-only DelphiScript** snippet (no `AddPCBObject`, no `SchObjectFactory` create, no file writes except returning JSON through the bridge stdout/IPC channel).
3. Send the snippet through the existing altium-bridge `altium_eval` (or equivalent `audit.*` IPC command) against `SchServer` / `PCBServer`.
4. Typical entry points:
- Schematic: `SchServer.GetCurrentSchDocument` → `ISch_Document` / `ISch_Sheet`; `SchIterator_Create`; `AddFilter_ObjectSet(MkSet(eSchPort, eNetLabel, ePowerPort, eSchComponent, …))`.
- PCB: `Board := PCBServer.GetCurrentPCBBoard`; `Board.BoardIterator_Create`; `Iterator.AddFilter_ObjectSet(MkSet(eViaObject, ePadObject, eTrackObject, …))`; `Iterator.AddFilter_LayerSet(AllLayers)`; `Iterator.AddFilter_Method(eProcessAll)`.
- Project / nets: `GetWorkspace` → `IWorkspace` → `IProject` → `IDocument` / flattened `DM_DocumentFlattened`; `INet.DM_PinCount`, `IComponent`.
5. Destroy iterators (`SchIterator_Destroy`, `BoardIterator_Destroy`) after each walk.
6. Aggregate `{checked, violations, items[]}` per check into a `design_lint_report`-shaped payload: `summary`, `sections`, `totals`, `_failed`.
7. Never highlight/select on canvas as the primary result; return structured findings with designator, net, sheet/board, and coordinates in mils.
### Shared API conventions (verified unless marked)
| Server | Object | Notes |
| --- | --- | --- |
| `SchServer` | `ISch_Sheet` / `ISch_Document` | Current schematic |
| `SchServer` | `ISch_Iterator` | `SchIterator_Create` / `FirstSchObject` / `NextSchObject` |
| | Object ids | `eSchPort`, `eNetLabel`, `ePowerPort` / `ePowerObject`, `eSchComponent`, `ePin`, `eWire`, `eBus`, `eSheetEntry`, `eImage` |
| | Interfaces | `ISch_Port`, `ISch_NetLabel`, `ISch_PowerPort` / `ISch_PowerObject`, `ISch_Component`, `ISch_Pin`, `ISch_Parameter`, `ISch_Wire` |
| `PCBServer` | `IPCB_Board` | `PCBServer.GetCurrentPCBBoard` |
| | Iterators | `BoardIterator_Create`, spatial iterator, group iterator |
| | Objects | `IPCB_Component`, `IPCB_Via`, `IPCB_Pad`, `IPCB_Track`, `IPCB_Arc`, `IPCB_Polygon`, `IPCB_BoardOutline`, `IPCB_LayerObject`, `IPCB_Text`, `IPCB_ComponentBody`, `IPCB_Net`, `IPCB_Region` |
| | Stack | `ILayerStack` |
| Workspace | `IWorkspace`, `IProject`, `IDocument`, `IComponent`, `INet` | Flattened netlist after compile |
| Units | `TCoord`; `MilsToCoord` / `CoordToMils` | 1 mil = 10000 internal units |
`ResetParameters` is a parametric-process helper (Client API), not an object walker; lint scripts should not need it unless invoking a process.
---
## Check catalog
Each check uses snake_case `id`. eda-agent names are noted where they differ.
---
### 1. `floating_ports`
- **name:** Floating / unconnected schematic ports
- **what it detects:** Ports whose electrical hotspot is not on a wire, pin, or sheet entry, or whose net does not appear on any pin / sheet entry on the same sheet.
- **severity:** warning
- **surface:** schematic sheet
- **eda-agent analog:** `find_floating_ports`
- **API to read:**
- `ISch_Sheet` + `ISch_Iterator` filtered to `eSchPort` → `ISch_Port`
- `ISch_Port.Name` / `Text` (net name), `Location` / `Location.X` / `Location.Y` **UNVERIFIED** exact location property name (`ISch_GraphicalObject.Location` is typical)
- Spatial / small-area iterator at the port hotspot for `eWire`, `ePin`, `eSheetEntry`
- Flattened `INet` membership as a second signal
- **detection logic:**
1. Compile the project.
2. For every schematic sheet, iterate `eSchPort`.
3. A port is floating if no `eWire` / pin / sheet entry occupies its hotspot **or** the flattened net for that port name has zero pins and zero sheet entries on that sheet.
4. Report net, sheet filename, location in mils.
- **example good finding message:** `Port "SPI_CLK" on sheet MCU.SchDoc at (1250, 800) mils is floating: hotspot is not on a wire, pin, or sheet entry.`
---
### 2. `unmatched_ports`
- **name:** Multi-driver and no-driver nets (port direction)
- **what it detects:** Flattened nets with more than one Output port (multi-driver), or Input ports with zero Output/Bidirectional ports (no driver).
- **severity:** error
- **surface:** project
- **eda-agent analog:** `find_unmatched_ports` (`multi_output` / `no_driver`)
- **API to read:**
- `ISch_Port` direction: `ISch_Port.IOType` **UNVERIFIED** exact enum (`ePortIOInput` / `ePortIOOutput` / `ePortIOBidirectional` typical in Schematic API)
- Flattened `INet.DM_NetName`, group ports by net
- **detection logic:**
1. Compile; walk all ports on all compiled documents.
2. Bucket by flattened net name; count Input / Output / Bidirectional.
3. Flag `output_count > 1` as multi-driver; flag `input_count > 0` and `output_count + bidir_count = 0` as no-driver.
- **example good finding message:** `Net "UART_TX" has 2 Output ports (multi-driver) across MCU.SchDoc and IO.SchDoc.`
---
### 3. `orphan_net_labels`
- **name:** Unconnected / orphan net labels
- **what it detects:** `ISch_NetLabel` objects whose location is not on a wire or bus (phantom nets).
- **severity:** error
- **surface:** schematic sheet
- **eda-agent analog:** `find_orphan_net_labels`
- **API to read:**
- `ISch_NetLabel`, object id `eNetLabel`
- `ISch_NetLabel.Text` (label string)
- Location X/Y; spatial iterate 1-mil square for `eWire` / `eBus`
- **detection logic:**
1. Iterate every `eNetLabel` on every sheet.
2. If no wire/bus intersects the label location, flag as orphan.
- **example good finding message:** `Net label "nRESET" on PWR.SchDoc at (420, 210) mils is not on any wire or bus.`
---
### 4. `orphan_power_objects`
- **name:** Unconnected / orphan power ports
- **what it detects:** Power-port markers sitting off-wire (phantom GND/VCC).
- **severity:** error
- **surface:** schematic sheet
- **eda-agent analog:** `find_orphan_power_objects`
- **API to read:**
- `ISch_PowerPort` / `ISch_PowerObject`; object id `ePowerPort` / `ePowerObject` (**UNVERIFIED** which id the running AD version exposes; both appear in docs)
- `Text` / net name; `Style` (`ePowerGndPower`, `ePowerGndSignal`, `ePowerGndEarth`, `ePowerBar`, …)
- Spatial 1-mil test for `eWire`
- **detection logic:**
1. Iterate power objects.
2. If no wire at the electrical hotspot, flag orphan.
- **example good finding message:** `Power port "GND" on MCU.SchDoc at (100, 50) mils is not on a wire.`
---
### 5. `single_pin_nets`
- **name:** Single-pin named nets
- **what it detects:** Flattened nets with exactly one pin **and** at least one net-label / port / power-object (broken named connection, not a silent NC).
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `find_single_pin_nets`
- **API to read:**
- `INet.DM_PinCount` (workspace) — also cited as `Net.PinCount` in some PCB-side `IPCB_Net` samples
- `INet.DM_NetName`; first pin designator + pin number
- Presence of net identifiers on that net (**UNVERIFIED** exact `INet` child enumeration: `DM_NetItemCount` / schematic objects sharing the name)
- **detection logic:**
1. Compile; use `DM_DocumentFlattened`.
2. For each net with `DM_PinCount = 1`, check that a net label, port, or power object names that net.
3. Skip unnamed default nets and intentional NC pins if the lone pin name matches NC/DNC/RSVD.
- **example good finding message:** `Net "I2C_SDA" has exactly 1 pin (U3-12) plus a net label; the other end is missing.`
---
### 6. `power_port_orientation`
- **name:** Power-port orientation convention
- **what it detects:** Ground symbols not facing down; power bars not facing up.
- **severity:** warning
- **surface:** schematic sheet
- **eda-agent analog:** `power_port_orientation`
- **API to read:**
- `ISch_PowerPort.Style`: `ePowerGndPower`, `ePowerGndSignal`, `ePowerGndEarth`, `ePowerBar`
- `ISch_PowerPort.Orientation` / `GetState_Orientation` — 0 / 90 / 180 / 270 degrees
- **detection logic:**
1. Iterate power ports.
2. Ground styles must be 270° (down). Bar style must be 90° (up).
3. Other styles (circle, arrow, wave) are info-only / skip unless project standard says otherwise.
- **example good finding message:** `Ground power port "GND" on PWR.SchDoc has Orientation=90 (expected 270 / down).`
---
### 7. `duplicate_designators`
- **name:** Duplicate schematic designators
- **what it detects:** Two or more source-sheet components sharing the same designator (pre-flatten).
- **severity:** error
- **surface:** project
- **eda-agent analog:** `find_designator_collisions`
- **API to read:**
- `ISch_Component.Designator` / `Designator.Text`
- `ISch_Component.UniqueId`
- Walk **source** sheets, not compiled flattened docs (flattening hides collisions with channel suffixes)
- **detection logic:**
1. Collect designator → list of (sheet, unique id).
2. Flag any designator with count > 1.
- **example good finding message:** `Designator R12 occurs 2 times (MCU.SchDoc, ANALOG.SchDoc).`
---
### 8. `component_param_visibility`
- **name:** Per-class visible component parameters
- **what it detects:** Caps without visible value+voltage, resistors without visible value, inductors without L+Isat, ICs without visible MPN.
- **severity:** info
- **surface:** schematic sheet
- **eda-agent analog:** `component_param_visibility` / `audit.validate_component_params`
- **API to read:**
- `ISch_Component.Designator`, `Comment`
- Child iterator `eParameter` → `ISch_Parameter.Name`, `Text`, `IsHidden`
- **detection logic:**
1. Classify by designator prefix (C/R/L/U).
2. Required visible (`IsHidden=False`) fields: C → value ending `F` and voltage ending `V`; R → value ending `R|k|M|m`; L → `H` and current `A`; U → parameter name starting `Manufacturer Part Number`.
3. Comment field may satisfy a requirement if visible and matching the pattern.
- **example good finding message:** `C17 (class capacitor) is missing visible voltage rating (need a parameter or Comment ending in V).`
---
### 9. `missing_datasheets`
- **name:** ICs missing datasheet URL
- **what it detects:** U* components with no `http(s)://` in HelpURL / Datasheet / DatasheetURL / ComponentLink1URL…ComponentLink4URL.
- **severity:** info
- **surface:** schematic sheet / library
- **eda-agent analog:** `find_missing_datasheets`
- **API to read:** `ISch_Parameter.Name` and `Text` on `ISch_Component`
- **detection logic:** Scan U* parameters; if none contain `http://` or `https://` in those slots, flag.
- **example good finding message:** `U4 (lib_ref STM32G031K8Tx, comment STM32G031K8T6) has no http(s) datasheet URL in HelpURL/Datasheet/ComponentLink*URL.`
---
### 10. `mpn_inconsistencies`
- **name:** Conflicting manufacturer part numbers
- **what it detects:** Same `(lib_ref, comment)` group of ICs with different MPNs.
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `find_mpn_inconsistencies`
- **API to read:** `ISch_Component.LibReference` **UNVERIFIED** (`LibraryPath` / `SymbolReference` also exist); `Comment`; parameter `Manufacturer Part Number`
- **detection logic:** Group U* by (lib_ref, comment); if unique MPN set size > 1, flag the group.
- **example good finding message:** `lib_ref=AP2112K-3.3TRG1 comment=3.3V LDO has MPNs AP2112K-3.3TRG1 and AP2112K-3.3TRG1-ND across U10,U11.`
---
### 11. `placeholder_values`
- **name:** Placeholder parameter strings
- **what it detects:** Component parameters equal to TBD/TBA/TODO/FIXME/XXX/?/??/???/PLACEHOLDER/FILLER/ASK/UNKNOWN/N/A/NA (trim, case-insensitive).
- **severity:** error
- **surface:** schematic sheet
- **eda-agent analog:** `find_placeholder_values`
- **API to read:** All `ISch_Parameter.Text` plus `Comment`
- **detection logic:** Whole-string match after trim; skip empty (other checks cover empty).
- **example good finding message:** `R9 parameter Comment="TBD" looks like a leftover placeholder.`
---
### 12. `visible_supplier_pn`
- **name:** Visible supplier part numbers on schematic
- **what it detects:** Parameters whose name starts with `supplier` and `IsHidden=False` (eda-agent BOM-hygiene: supplier SKUs should not appear on SCH PDF). **Note:** Adom extra `mouser_digikey_lcsc_params` *requires* those parameters to **exist**; this check only requires they are **hidden** on the canvas.
- **severity:** info
- **surface:** schematic sheet
- **eda-agent analog:** `find_visible_supplier_pn`
- **API to read:** `ISch_Parameter.Name`, `Text`, `IsHidden`
- **detection logic:** Name prefix `supplier` (case-insensitive) AND not hidden → violation.
- **example good finding message:** `U2 parameter "Supplier Part Number 1"="296-1234-1-ND" is visible on the schematic; hide it (keep MPN visible).`
---
### 13. `off_grid_components`
- **name:** Schematic components off snap grid
- **what it detects:** Placed symbols whose origin is not on the project grid (default 100 mil).
- **severity:** info
- **surface:** schematic sheet
- **eda-agent analog:** `find_off_grid_components`
- **API to read:** `ISch_Component.Location.X` / `Y` (TCoord); compare `Abs(CoordToMils(X)) mod grid_mils`
- **detection logic:** Default `grid_mils=100`. Flag if remainder ≠ 0. Report dx/dy.
- **example good finding message:** `U7 on MCU.SchDoc is 4 mil off the 100-mil grid at (1254, 800).`
---
### 14. `unconnected_ic_pins`
- **name:** Unconnected IC pins (excluding NC)
- **what it detects:** U* pins with empty / `?` net, skipping names matching NC / N.C. / DNC / N/C / NO CONNECT / RSVD / RESERVED.
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `find_unconnected_ic_pins` (BOM / flattened pins)
- **API to read:** Workspace `IComponent` pins + net name; or `ISch_Pin` + compiled net. `ISch_Pin.Designator`, `Name`, electrical type **UNVERIFIED** (`ISch_Pin.Electrical` / `eElectricInput` …)
- **detection logic:** For each U* pin, if net is nil/empty/`?` and name is not NC-like, flag.
- **example good finding message:** `U3 pin 12 (PA8) has no net (not named NC/DNC/RSVD).`
---
### 15. `pin_net_name_mismatches`
- **name:** Power/ground pin name vs net name
- **what it detects:** IC pins named VCC/VDD/GND/VSS (etc.) attached to a net that is not a power/ground rail.
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `find_pin_net_name_mismatches`
- **API to read:** Pin `Name` + connected `INet.DM_NetName`
- **detection logic:** Regex power pin names vs `_net_is_power`; ground pin names vs `_net_is_ground`. Flag mismatches.
- **example good finding message:** `U5 pin 8 name="VCC" is on net "GPIO_PA0" (power_pin_on_non_power_net).`
---
### 16. `missing_decoupling`
- **name:** IC power pins without a capacitor on the net
- **what it detects:** ICs whose recognised power/ground pins do not share a net with any C* component (`missing` or `partial`).
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `find_missing_decoupling`
- **API to read:** Flattened pin nets; designators starting with C
- **detection logic:** Build net → capacitors. For each U* power pin, require ≥1 C* on that net. Skip ICs with no recognised power pins.
- **example good finding message:** `U3 status=partial: pin 21 VDDA on net +3V3_A has no capacitor; other power pins are covered.`
---
### 17. `unplaced_components`
- **name:** Schematic components with no PCB placement
- **what it detects:** Fitted schematic components that have no corresponding `IPCB_Component` on the board (ECO not pushed, or component deleted from PCB).
- **severity:** error
- **surface:** project
- **eda-agent analog:** none (Adom/Phase-2; closest is design-difference snapshot)
- **API to read:**
- Schematic: `ISch_Component.Designator.Text`
- PCB: `IPCB_Component.Name` (refdes); `Board.GetPcbComponentByRefDes` **documented** on `IPCB_Board` as `PcbComponentByRefDes` / similar — **UNVERIFIED** exact method spelling (`GetPcbComponentByRefDes` vs `PcbComponentByRefDes`)
- Skip DNP / not-fitted in current variant (see `variant_dnp_mismatch`)
- **detection logic:**
1. Collect fitted schematic designators.
2. Collect PCB `Component.Name` set.
3. SCH minus PCB → unplaced.
- **example good finding message:** `C42 is on the schematic (fitted) but has no IPCB_Component on the board.`
---
### 18. `components_outside_board_outline`
- **name:** Components off the board outline
- **what it detects:** Placed footprints whose origin (or body) sits outside `IPCB_BoardOutline`.
- **severity:** error
- **surface:** PCB board
- **eda-agent analog:** `find_components_outside_board_outline`
- **API to read:**
- `Board.BoardOutline` / `Board.GetState_BoardOutline` → `IPCB_BoardOutline`
- `IPCB_BoardOutline.PrimitiveInsidePoly` (used by eda-agent / SelectCMPInOutSideBOL.pas)
- `IPCB_Component.X`, `Y`, `Layer`, `Name`
- **detection logic:** For each component, if outline `PrimitiveInsidePoly` is false for the origin (and optionally bounding box), flag.
- **example good finding message:** `J1 origin at (3200, -50) mils is outside the board outline (top layer).`
---
### 19. `pads_near_board_edge`
- **name:** Board-edge clearance violations
- **what it detects:** Pads/vias closer than clearance (default 25 mil) to the outline — depaneling damage.
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_pads_near_board_edge`
- **API to read:**
- `Board.PrimPrimDistance(Board.BoardOutline, Prim)` — documented in eda-agent; **UNVERIFIED** against current AD if method is `PrimPrimDistance` vs `Board.PrimPrimDistance`
- `IPCB_Pad`, `IPCB_Via`
- **detection logic:** For each pad/via, if distance < `clearance_mils` (default 25), flag kind, designator, distance, XY.
- **example good finding message:** `Pad U3-1 is 12 mil from board outline (min 25 mil) at (40, 800).`
---
### 20. `via_antennas`
- **name:** Via antennas / dangling vias
- **what it detects:** Vias electrically connected on only one layer (open stub).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_via_antennas`
- **API to read:**
- `IPCB_Via.X`, `Y`, `LowLayer`, `HighLayer`, `Net`, `HoleSize`, `Size`
- `Via.IsConnected` — **UNVERIFIED** (may not exist as a boolean; eda-agent counts layers via `Board.PrimPrimDistance = 0` to track/arc/pad/fill/region, plus `Via.IsConnectedToPlane` on plane layers)
- `ILayerStack` to enumerate signal vs plane layers between Low and High
- **detection logic:**
1. Iterate `eViaObject`.
2. Count layers where a same-net primitive touches the via, or plane connection is true.
3. If connected-layer count = 1, flag antenna. If count = 0, flag dangling via (orphan).
- **example good finding message:** `Via on net "SPI_CLK" at (1250, 900) mils is connected on only 1 layer (antenna).`
---
### 21. `unrouted_connections`
- **name:** Unrouted net connections
- **what it detects:** Ratsnest / incomplete routing: nets with pads not fully connected by tracks/arcs/vias.
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `pcb.get_unrouted_nets` (review snapshot, not a numbered audit) — included here so the 31-check lint covers routing completeness
- **API to read:**
- `IPCB_Net`; `Board.ConnectivelyValidateNets` **documented** on `IPCB_Board` — **UNVERIFIED** return shape
- From-to / connection object id **UNVERIFIED** (`eConnectionObject` / ratsnest primitives)
- Pad count vs connected copper graph
- **detection logic:**
1. Optional: `Board.ConnectivelyValidateNets`.
2. For each net with `PinCount`/`PadCount` ≥ 2, if any from-to remains or pads are in disjoint copper islands, flag net + incomplete node count.
3. Skip nets that are intentionally unrouted only if a rule/class says so (**UNVERIFIED** class name).
- **example good finding message:** `Net "+3V3" has 4 unrouted connections (14 pads, 2 copper islands).`
---
### 22. `polygon_validity`
- **name:** Polygon validity / islands
- **what it detects:** Polygons/regions with zero area, failed pour, or orphan copper islands disconnected from the assigned net.
- **severity:** error
- **surface:** PCB board
- **eda-agent analog:** `find_invalid_regions` (zero-area regions); Adom extends to pour islands
- **API to read:**
- `IPCB_Polygon.Rebuild` (read-side rebuild to inspect pour; treat as inspection, not an ECO)
- `IPCB_Polygon.Net`, `Layer`, `Name` / `PolygonOutline`
- Region area; `IPCB_Region` not owned by component/dimension
- Island enumeration **UNVERIFIED** (`GetState_Island`, pour result island count — mark unverified; fallback: after Rebuild, spatial-split regions whose net copper does not touch a same-net pad)
- **detection logic:**
1. Iterate polygons and free regions.
2. Flag area = 0 / unset.
3. After Rebuild, flag islands that do not touch any pad/via of the polygon net.
- **example good finding message:** `Polygon "GND_Top" on Top Layer has 2 islands; island at (1800, 400) mils touches no GND pad.`
---
### 23. `variant_dnp_mismatch`
- **name:** DNP / variant not-fitted mismatches
- **what it detects:** Components Not Fitted in the current variant that still look fitted on PCB (paste, no DNP marking), or fitted SCH parts marked DNP inconsistently.
- **severity:** warning
- **surface:** project
- **eda-agent analog:** `variant_not_fitted`
- **API to read:**
- Project current variant description
- Flattened component fitted flag — **UNVERIFIED** exact property (`IComponent.DM_Fitted` / `DM_NotFitted` / variant `GetState_Fitted`). eda-agent returns `{designator, comment, unique_id}` for NotFitted.
- PCB: `IPCB_Component` still present (Altium keeps DNP footprints); paste-mask expansion / locked primitives as secondary signals **UNVERIFIED**
- **detection logic:**
1. If no variant selected, report info and skip mismatch logic.
2. List NotFitted designators.
3. Cross-check SCH parameters (`DNP`, `Fitted`) vs variant table; flag disagreement.
- **example good finding message:** `Variant "Build-A": R99 is Not Fitted in the variant table but schematic parameter Fitted=True.`
---
### 24. `missing_footprint_models`
- **name:** Missing footprint / PCB model on schematic component
- **what it detects:** Schematic components with empty `Footprint` / no `ISch_Implementation` of type PCB, or PCB components with empty `Pattern` / `SourceFootprintLibrary`.
- **severity:** error
- **surface:** library / schematic sheet / PCB board
- **eda-agent analog:** none (library hygiene)
- **API to read:**
- `ISch_Component` implementations: `ISch_Implementation` (`ModelName`, `ModelType` = `PCBLIB` / `PCB`)
- PCB: `IPCB_Component.Pattern`, `SourceFootprintLibrary`, `SourceLibReference`
- **detection logic:** Flag if no PCB implementation, or `Pattern` is empty, or source library path is empty and footprint cannot be resolved.
- **example good finding message:** `U12 has no PCB footprint implementation (Pattern empty; SourceFootprintLibrary blank).`
---
### 25. `missing_3d_bodies`
- **name:** Missing 3D bodies on footprints
- **what it detects:** Placed PCB components with no `IPCB_ComponentBody` child (STEP/extruded body).
- **severity:** info
- **surface:** library / PCB board
- **eda-agent analog:** none
- **API to read:**
- `IPCB_Component` group iterator, `eComponentBodyObject` → `IPCB_ComponentBody`
- `IPCB_Component.DefaultPCB3DModel` **documented**
- Mechanical layer extruded bodies as fallback
- **detection logic:** Skip fiducials, mounting holes, logos (designator prefixes FID/MH/HOLE or `ComponentKind` mechanical **UNVERIFIED** enum). Flag electrical parts with zero bodies and empty `DefaultPCB3DModel`.
- **example good finding message:** `U3 (Pattern=QFN-48) has no IPCB_ComponentBody and DefaultPCB3DModel is empty.`
---
### 26. `silkscreen_over_pad`
- **name:** Silkscreen overlapping pads
- **what it detects:** Overlay text/tracks/arcs overlapping SMD/through-hole copper pads (fab ink on paste).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** none (DRC silk-to-solder-mask sometimes covers this)
- **API to read:**
- `IPCB_Text`, `IPCB_Track`, `IPCB_Arc` on `eTopOverlay` / `eBottomOverlay`
- `IPCB_Pad` on top/bottom signal layers
- Overlap helper **UNVERIFIED**: `Board.PrimPrimDistance(silk, pad) = 0` or bounding-rect intersect then exact outline. No dedicated `SilkscreenOverPad` API documented.
- **detection logic:**
1. For each overlay primitive (including component silk children if primitive lock allows iteration), measure distance to pads on the same side.
2. Distance ≤ 0 (or < silk-to-pad rule clearance) → violation.
3. Ignore courtyard-only mechanical layers.
- **example good finding message:** `Silkscreen text "U3" on Top Overlay overlaps pad U3-1 (PrimPrimDistance=0 at (1010, 540) mils).`
---
### 27. `tented_via_ratio`
- **name:** Tented vs untented via surfaces
- **what it detects:** Fraction of outer via surfaces that are tented; reports ratio (consumer boards typically want ~1.0).
- **severity:** warning (if untented ratio exceeds project threshold; default report-only with warning when any outer surface is untented on a production board)
- **surface:** PCB board
- **eda-agent analog:** `tented_via_ratio`
- **API to read:**
- `IPCB_Via` tenting: `GetState_IsTenting_Top` / `GetState_IsTenting_Bottom` (NEXUS/AD docs)
- Query-language equivalents `SolderMaskTentingTop` / `SolderMaskTentingBottom`
- `SolderMaskExpansion` on pad cache
- **detection logic:** Count top/bottom surfaces that actually reach outer layers. Buried/blind inner-only ignored. Emit `tented`, `untented`, `ratio`.
- **example good finding message:** `Via tenting ratio=0.72 (48 untented outer surfaces / 172); example untented via on net GND at (200, 200).`
---
### 28. `bad_connections`
- **name:** Near-miss track / arc endpoints
- **what it detects:** Track/arc endpoints within `tolerance_mils` (default 1.0) of another same-net primitive but not actually touching (photoplot open).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_bad_connections`
- **API to read:** `IPCB_Track` (`X1,Y1,X2,Y2`, `Layer`, `Net`), `IPCB_Arc`; spatial iterator; skip teardrops, in-component prims, no-net, full-circle arcs
- **detection logic:** For each signal-layer endpoint, if no same-net pad/via/track/arc at exact coord but one exists within tolerance, flag dangling/near-miss.
- **example good finding message:** `Track on net "nCS" layer TopLayer endpoint (812.4, 400.0) mils is 0.6 mil from via copper (tolerance 1.0); photoplot will not bridge.`
---
### 29. `signal_vias_without_return`
- **name:** Signal vias without nearby return via
- **what it detects:** Non-power/ground vias with no GND/power via within `radius_mils` (default 50).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_signal_vias_without_return`
- **API to read:** `IPCB_Via.Net.Name`; heuristic prefixes GND / V / + / −
- **detection logic:** For each signal via, spatial-search power/ground vias within radius. None → violation. Simplified proximity, not stackup-aware.
- **example good finding message:** `Signal via on net "USB_DP" at (1500, 700) mils has no GND/power via within 50 mils.`
---
### 30. `removed_pad_shapes`
- **name:** Removed unused pad / via copper
- **what it detects:** Pads/vias with annular ring stripped on layers that still need copper (`Tools → Remove Unused Pad Shapes` over-applied).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_removed_pad_shapes`
- **API to read:**
- `Via.SizeOnLayer(L) <= Via.HoleSize`
- `Pad.IsPadRemoved(L)` — used by community PadShapeRemoved.pas
- **detection logic:** For each layer in the via/pad stack, flag removed copper. Count per layer-instance.
- **example good finding message:** `Via on net "+3V3" at (600, 600) has SizeOnLayer(Mid1)=HoleSize (annular ring removed on Mid1).`
---
### 31. `unlocked_component_primitives`
- **name:** Unlocked footprint primitives
- **what it detects:** Placed components with primitive lock off (pads can be dragged off-center).
- **severity:** warning
- **surface:** PCB board
- **eda-agent analog:** `find_unlocked_component_primitives`
- **API to read:** `IPCB_Component` primitive lock — **UNVERIFIED** exact name (`PrimitiveLock` / `GetState_PrimitiveLock`). Community and eda-agent treat it as a boolean on the component.
- **detection logic:** Iterate components; flag unlocked. Skip if intentionally exploded for documentation.
- **example good finding message:** `Q2 has PrimitiveLock=False; a pad can be dragged off the footprint without warning.`
---
### 32. `mouser_digikey_lcsc_params` (Adom extra)
- **name:** Mouser, Digi-Key, and LCSC part-number parameters required
- **what it detects:** Every procurable (fitted, non-mechanical) schematic component missing **any** of the three required supplier parameters. **Adom rule: all three are required**, even if an MPN already exists.
- **severity:** error
- **surface:** schematic sheet / project
- **eda-agent analog:** none (opposite emphasis of `find_visible_supplier_pn`, which only hides them)
- **API to read:**
- `ISch_Component` parameter iterator → `ISch_Parameter.Name`, `Text`
- Accepted names (**normalize case/spaces/underscores**):
- Mouser: `Mouser`, `Mouser Part Number`, `Mouser PN`, `Supplier Part Number n` where supplier name is Mouser
- Digi-Key: `DigiKey`, `Digi-Key`, `DigiKey Part Number`, `DK PN`
- LCSC: `LCSC`, `LCSC Part Number`, `LCSC PN`, `JLCPCB`
- Altium Supplier link slots `Supplier n` + `Supplier Part Number n` — **UNVERIFIED** whether Adom libraries use native supplier links vs free parameters
- **detection logic:**
1. Skip logos, fiducials, mechanical-only, and current-variant DNP parts.
2. For each remaining component, require non-empty Text for all three families.
3. Missing one, two, or three all fail; list which keys are empty.
4. Do **not** require the parameters to be visible (`IsHidden` may be True). Existence is the Adom rule; visibility is check 12.
- **example good finding message:** `R4 is missing required supplier parameters: Mouser=ok, DigiKey=empty, LCSC=empty (Adom rule: all three required).`
---
### 33. `pin1_symbol_footprint` (Adom extra)
- **name:** Pin-1 disagreement between symbol and footprint
- **what it detects:** Symbol pin whose designator is `1` does not correspond to footprint pad `Name = '1'` in electrical mapping (wrong pin-swap, rotated QFN, pin-1 dot vs pad 1).
- **severity:** error
- **surface:** library / schematic sheet / PCB board
- **eda-agent analog:** none
- **API to read:**
- SCH: `ISch_Pin.Designator` (pin number), `ISch_Pin.Name`, orientation / location relative to symbol
- PCB: `IPCB_Pad.Name = '1'` (user requirement); `IPCB_Pad.Layer`; component `Rotation`
- Pin-to-pad map: `ISch_Implementation` / pin mapping model — **UNVERIFIED** (`ISch_ModelDatafileLink`, `MappedPin` / `PinMapping`)
- PCB `IPCB_Component.Getstate_PadByName('1')` **documented** as `Getstate_PadByName`
- **detection logic:**
1. For each component with a PCB implementation, fetch symbol pin `Designator='1'` and footprint pad `Name='1'`.
2. If either side is missing, flag.
3. If a pin-map exists and pin 1 is mapped to a pad whose name is not `'1'`, flag disagreement.
4. Optional geometric heuristic (**UNVERIFIED**): symbol pin-1 in the "upper-left" of unrotated symbol vs footprint pad-1 in the courtyard pin-1 marker; report as info only, not error.
- **example good finding message:** `U6 symbol pin Designator=1 (name=VSS) maps to footprint pad Name=12; footprint pad Name=1 is mapped to symbol pin 12 (QFN rotation/pin-1 mismatch).`
---
### 34. `unused_mechanical_layers` (Adom extra)
- **name:** Unused mechanical layers that still have content
- **what it detects:** Mechanical layers that are not part of the active layer stack / fabrication output set, yet still contain tracks, arcs, text, fills, or component bodies (leftover courtyard, fab notes on Mechanical 13–16, etc.).
- **severity:** info
- **surface:** PCB board
- **eda-agent analog:** none
- **API to read:**
- `ILayerStack` / `Board.LayerStack` — **UNVERIFIED** exact property (`IPCB_MasterLayerStack`)
- `IPCB_LayerObject`; mechanical layer ids `eMechanical1` … `eMechanical16` (AD extends beyond 16 in later versions — **UNVERIFIED** max)
- `Board.LayerIsUsed` / `Board.MechanicalLayerEnabled` — **UNVERIFIED** names; fallback: iterate all primitives and bucket by `Prim.Layer`
- Pairing: courtyard often Mechanical 15, 3D on Mechanical 13 — project convention, not API
- **detection logic:**
1. Build the set of mechanical layers that appear in the stack or are enabled for Gerber/ODB output (**UNVERIFIED** output-job API).
2. Iterate primitives (`eTrackObject`, `eArcObject`, `eTextObject`, `eFillObject`, `eRegionObject`, `eComponentBodyObject`) on mechanical layers.
3. If a mechanical layer has content but is disabled / not in stack / not in the fab output set, flag layer id + primitive count + sample coordinates.
4. Do not flag empty disabled layers.
- **example good finding message:** `Mechanical 14 is not in the active layer stack but contains 11 primitives (example text "OLD COURTYARD" at (0, 0) mils).`
---
### 35. `missing_power_testpoints` (Adom extra)
- **name:** Missing test points on power rails
- **what it detects:** Power/ground nets (VCC/VDD/+3V3/+5V/GND/…) with no dedicated test-point pad or test-point component (`TP*` / pad with testpoint property).
- **severity:** warning
- **surface:** PCB board / project
- **eda-agent analog:** none (DRC has `IPCB_TestPointUsage` / `IPCB_TestPointStyleRule` but that is rule-engine, not this lint)
- **API to read:**
- `IPCB_Pad` testpoint flags — **UNVERIFIED** (`IsTestPoint` / `GetState_IsTestpointTop` / `TestpointTop` / `TestpointBottom`; query language has test-point fields)
- `IPCB_Component.Name` matching `TP*` or comment/type Test Point
- `IPCB_Net.Name` power heuristic (same as decoupling check)
- Design rules `IPCB_TestPointUsage` only as optional cross-check, not required
- **detection logic:**
1. Identify power nets from names: `GND*`, `VCC*`, `VDD*`, `VSS*`, leading `+`, `VBAT`, `VBUS`, `VREF`, …
2. A net has a test point if any pad has the testpoint property or any `TP*` component pad is on that net.
3. Flag power nets with ≥1 connected pad and zero test points.
4. Optionally require both top-accessible TP for rails brought to connectors (**UNVERIFIED** policy).
- **example good finding message:** `Power net "+3V3" has 22 pads and 0 test points (no TP* component and no pad TestpointTop/Bottom).`
---
## Mapping: eda-agent 31 → this catalog
eda-agent `LINT_AUDIT_LIST` + BOM-side audits are covered as follows. Some eda-agent checks are folded or omitted to keep the catalog at 35 while absorbing Adom MUST items (unplaced, footprints, 3D, silk-over-pad, unrouted).
| eda-agent section | This catalog id | Notes |
| --- | --- | --- |
| `component_param_visibility` | `component_param_visibility` | |
| `power_port_orientation` | `power_port_orientation` | |
| `find_floating_ports` | `floating_ports` | |
| `find_unmatched_ports` | `unmatched_ports` | multi-driver / no-driver |
| `find_designator_collisions` | `duplicate_designators` | |
| `find_missing_datasheets` | `missing_datasheets` | |
| `find_mpn_inconsistencies` | `mpn_inconsistencies` | |
| `find_single_pin_nets` | `single_pin_nets` | |
| `find_non_embedded_images` | *(omitted from 35; style)* | Re-add as 36 if needed |
| `find_visible_supplier_pn` | `visible_supplier_pn` | Complementary to Adom extra 32 |
| `find_orphan_net_labels` | `orphan_net_labels` | |
| `find_orphan_power_objects` | `orphan_power_objects` | |
| `find_placeholder_values` | `placeholder_values` | |
| `find_off_grid_components` | `off_grid_components` | |
| `find_components_outside_board_outline` | `components_outside_board_outline` | |
| `find_pads_near_board_edge` | `pads_near_board_edge` | |
| `variant_not_fitted` | `variant_dnp_mismatch` | |
| `tented_via_ratio` | `tented_via_ratio` | |
| `find_bad_connections` | `bad_connections` | |
| `find_signal_vias_without_return` | `signal_vias_without_return` | |
| `find_via_antennas` | `via_antennas` | |
| `find_removed_pad_shapes` | `removed_pad_shapes` | |
| `find_pads_center_not_connected` | *(folded into `unrouted_connections` / via antennas)* | **UNVERIFIED** pad-center API |
| `find_invalid_regions` | `polygon_validity` | Extended with islands |
| `find_mixed_designator_rotation` | *(omitted from 35; silk style)* | |
| `find_unlocked_component_primitives` | `unlocked_component_primitives` | |
| `find_mirrored_pcb_text` | *(omitted from 35; silk style)* | |
| `find_acute_angles` | *(omitted from 35; DFM)* | |
| `find_inconsistent_track_widths` | *(omitted from 35; DFM)* | |
| `find_unconnected_ic_pins` | `unconnected_ic_pins` | BOM-side |
| `find_pin_net_name_mismatches` | `pin_net_name_mismatches` | BOM-side |
| `find_missing_decoupling` | `missing_decoupling` | BOM-side |
| — | `unplaced_components` | MUST |
| — | `missing_footprint_models` | MUST |
| — | `missing_3d_bodies` | MUST |
| — | `silkscreen_over_pad` | MUST |
| — | `unrouted_connections` | MUST |
| — | `mouser_digikey_lcsc_params` | Adom extra |
| — | `pin1_symbol_footprint` | Adom extra |
| — | `unused_mechanical_layers` | Adom extra |
| — | `missing_power_testpoints` | Adom extra |
Omitted eda-agent style/DFM checks may be reintroduced later as ids 36+ without changing 1–35.
---
## Finding message quality
A good finding (aligned with eda-agent review discipline, adapted for lint):
- Names the **exact** designator, pin, net, sheet or board coordinates in mils
- States the **observed API fact** (not a guess about device function)
- Is **actionable** (what is missing or wrong)
- Does **not** say “verify X” or relay a raw ERC category
Lint is allowed to list many similar items; the later review agent triages them.
---
## Summary table
| id | severity | surface |
| --- | --- | --- |
| floating_ports | warning | schematic sheet |
| unmatched_ports | error | project |
| orphan_net_labels | error | schematic sheet |
| orphan_power_objects | error | schematic sheet |
| single_pin_nets | warning | project |
| power_port_orientation | warning | schematic sheet |
| duplicate_designators | error | project |
| component_param_visibility | info | schematic sheet |
| missing_datasheets | info | schematic sheet / library |
| mpn_inconsistencies | warning | project |
| placeholder_values | error | schematic sheet |
| visible_supplier_pn | info | schematic sheet |
| off_grid_components | info | schematic sheet |
| unconnected_ic_pins | warning | project |
| pin_net_name_mismatches | warning | project |
| missing_decoupling | warning | project |
| unplaced_components | error | project |
| components_outside_board_outline | error | PCB board |
| pads_near_board_edge | warning | PCB board |
| via_antennas | warning | PCB board |
| unrouted_connections | warning | PCB board |
| polygon_validity | error | PCB board |
| variant_dnp_mismatch | warning | project |
| missing_footprint_models | error | library / schematic sheet / PCB board |
| missing_3d_bodies | info | library / PCB board |
| silkscreen_over_pad | warning | PCB board |
| tented_via_ratio | warning | PCB board |
| bad_connections | warning | PCB board |
| signal_vias_without_return | warning | PCB board |
| removed_pad_shapes | warning | PCB board |
| unlocked_component_primitives | warning | PCB board |
| mouser_digikey_lcsc_params | error | schematic sheet / project |
| pin1_symbol_footprint | error | library / schematic sheet / PCB board |
| unused_mechanical_layers | info | PCB board |
| missing_power_testpoints | warning | PCB board / project |
---
## Document control
- Nonce: `ALTIUM-LINT-SPEC-001`
- Artifact path (box): `/workspace/altium-lint-spec.md`
- Intended later copy: `C:\Users\john\adom\altium-lint-spec.md`
- This phase: spec only; no Altium launch; no altium-bridge tree edits