7. Your architecture
Declare what the board is supposed to be, and detect when it stops being that.
The three tiers so far describe your team. Naming, buses, and parts are the same across every board you build. This one describes one board. No other tier can catch a design drifting from what it was meant to be.
The engine has no built-in opinion about your architecture. It cannot know that a rail was supposed to be 1.8 V, because a netlist records what is connected and never records what anyone intended. So you declare it, and the declaration becomes checkable.
The declaration lives in the design’s own descriptor, under intent:, rather than at the project
root.
The declaration ¶
The intent: section of designs/jetson/design.yaml says two things about this board.
intent:
components:
J1: {exposure: internal} # Jetson AGX Thor module, board-to-board
J8: {exposure: internal} # FMC+ expansion power, mates with J18's accessory
J18: {exposure: internal} # FMC+ expansion mezzanine
J13: {exposure: internal} # M.2 key-M, NVMe card
J14: {exposure: internal} # M.2 key-E, wireless card
J10: {exposure: internal} # CSI camera FFC, cabled to a camera inside the product
J11: {exposure: internal} # CSI camera FFC
J15: {exposure: internal} # fan
J4: {exposure: internal} # Tag-Connect debug pads, used in manufacturing
J20: {exposure: internal} # Tag-Connect debug pads
nets:
+5V: {nominal: 5.0, domain: main}
+3V3: {nominal: 3.3, domain: io}
+1V8: {nominal: 1.8, domain: logic}
+5V_SOM: {nominal: 5.0, domain: module}
+5V_AON: {nominal: 5.0, domain: standby}
+3V3_AON: {nominal: 3.3, domain: standby-io}
Read it as you would describe the board to a colleague. These ten connectors join this board to other parts of the same product, and every other connector takes a cable from the outside world. These are the supplies, at these voltages, each in a named domain.
Which connectors face the field ¶
The first half matters more than it looks. Every rule about protection asks whether a net reaches the outside world, and a netlist cannot answer that. A module socket and a USB-C receptacle are both connectors, and the same part number can be the cable entry on one carrier and the socket for a daughterboard on another. So every connector counts as exposed until the design says otherwise.
Without the section:
$ sed -i.orig '/^intent:/,$d' designs/jetson/design.yaml
$ agni check designs/jetson
findings by rule:
bulk-cap 1
esd-protection 394
floating-input 3
i2c-pull-up 28
i2c-redundant-pull-up 4
input-protection 3
jetson-profiles/pcie-esd-missing 48
jetson/active-low-overbar 2
reverse-blocking-absent 8
single-pin-net 2
test-point-coverage 36
529 finding(s) total
26059 subject(s) considered by 41 rule(s), 1041 not considered (--verdicts for the detail)
With it:
$ agni check designs/jetson
findings by rule:
bulk-cap 1
esd-protection 10
floating-input 3
i2c-pull-up 28
i2c-redundant-pull-up 4
jetson/active-low-overbar 2
reverse-blocking-absent 1
single-pin-net 2
test-point-coverage 36
87 finding(s) total
25616 subject(s) considered by 42 rule(s), 647 not considered (--verdicts for the detail)
Hundreds of findings disappear. Nearly all of them were esd-protection. They sat on nets reaching
the module socket J1, the FMC+ header J18, and behind those the M.2 sockets and the two camera
connectors. J1’s pins carry most of the board’s signals. Rung 5’s PCIe profile
loses its esd findings for the same reason. None of those findings was wrong about the netlist, and
all of them were wrong about the board. Ten lines of intent turned a protection report nobody would
read into one worth reading. The findings that remain are on connectors where a user really can plug
in a cable, and a reviewer wants to see exactly those.
Rails and their domains ¶
The second half declares each supply’s voltage and the domain it belongs to. A domain carries one voltage, so two rails in it must agree, and each rail’s name must agree with what was declared:
$ agni check --verdicts --rule intent/voltage-domain-mismatch designs/jetson
intent/voltage-domain-mismatch 6 pass
pass +1V8 the rail's name declares 1.8V, matching voltage domain "logic"
pass +3V3 the rail's name declares 3.3V, matching voltage domain "io"
pass +3V3_AON the rail's name declares 3.3V, matching voltage domain "standby-io"
pass +5V the rail's name declares 5V, matching voltage domain "main"
pass +5V_AON the rail's name declares 5V, matching voltage domain "standby"
pass +5V_SOM the rail's name declares 5V, matching voltage domain "module"
6 verdicts across 1 rule(s), 6 pass
Today the board and the plan agree, and each pass says what was compared. The tier becomes useful on the day they stop agreeing. Here is the plan edited, on a scratch copy, to say the logic domain runs at 3.3 V while the board still runs it at 1.8 V:
$ sed -i.orig 's/+1V8: {nominal: 1.8, domain: logic}/+1V8: {nominal: 3.3, domain: logic}/' designs/jetson/design.yaml
$ agni check designs/jetson --rule intent/voltage-domain-mismatch
findings by rule:
intent/voltage-domain-mismatch 1
first 1:
[warning] intent/voltage-domain-mismatch: +1V8 (rail "+1V8" is declared in voltage domain "logic" (3.3V) but its name declares 1.8V)
1 finding(s) total
6 subject(s) considered by 1 rule(s) (--verdicts for the detail)
Nothing structural is wrong with the board, and no rule from any other tier has anything to say. The engine can catch this only because somebody wrote down what was intended, and the two disagree.
This tier does not find defects in the usual sense. It finds divergence between the board and the description of the board. That divergence creeps in over months, as people who did not write the original plan edit the design.
A tier can depend on another tier ¶
A declaration can say a third thing, under modules. It can say the board has two regulators, or a
CAN block made of these nets. A module can name its parts by device class (class: regulator), and
then it is only as good as the classification underneath it. On this board nothing classifies as a
regulator. The fact “this is a regulator” comes off a part’s datasheet, and the project seeds one
part. So a module declared by class would report every regulator missing. If you plan to declare
modules by class, seed those parts in params/ first, or the intent tier reports absences that are
really gaps in a different tier.
Without the declaration ¶
Some checklist questions are about intent, such as “each rail sits at its declared voltage”. A
design that never stated its intent cannot answer one. The question reads needs-design-intent, not
pass, and the reason names the intent: section it needs. A checklist that reported pass there
instead could not be trusted.
All four tiers ¶
That is the last of them. Names, interfaces, part limits and intent are each a file or a section, and each changed what the catalog could see as well as adding checks of its own. The next rungs bind your team’s review questions to all of it.
Next ¶
Write your checklist, which binds the team’s review questions to the engine so the mechanical ones answer themselves.