10. Compare revisions

What actually changed between rev A and rev B, structurally rather than textually.

After the first review, the question becomes “what changed since the one we already reviewed, and do I need to look at all of it again”.

A text diff of two schematic files cannot answer that. Export the same unmodified design twice and the files usually differ, because coordinates shift, identifiers get reassigned, and ordering is not stable. Everything is a change, so nothing is.

agni diff compares the designs rather than the files.

Two revisions

The Jetson board upstream is a single snapshot, so the project makes its second revision itself, by a documented edit. tools/make_rev_b.py copies rev A and changes two things. It fits R357 and R358, two I2C pull-ups that the schematic marked do-not-populate. It also renames the two interrupt nets spelled with a trailing n to KiCad’s overbar. A reviewer would plausibly ask for both after the first review. Rev B is a design folder of its own, designs/jetson-rev-b, with a descriptor matching rev A’s, so the two read the same way and differ only by the edit.

make rev-b

Then compare them:

$ make rev-b
$ agni diff designs/jetson designs/jetson-rev-b
diff designs/jetson -> designs/jetson-rev-b

Components: +0  -0  ~2
Nets:       new 0  deleted 0  renamed 2  hard 0  soft 0

Components changed (2):
  R357 dnp: "yes" -> "no"
  R358 dnp: "yes" -> "no"

Nets changed (2):
  [renamed] /USB Debug, PD/PDC_I2C1_IRQn -> /USB Debug, PD/~{PDC_I2C1_IRQ_R}
  [renamed] /USB Debug, PD/PDC_I2C2_IRQn -> /USB Debug, PD/~{PDC_I2C2_IRQ_R}

Two parts changed and two nets were renamed, which accounts for the whole edit. A text diff of these two folders would be short too, because a script made the change. A revision KiCad saved after a day of real work moves coordinates, reassigns identifiers and reorders the file, and this diff reads the same either way.

Renamed is not deleted plus added

PDC_I2C1_IRQn -> ~{PDC_I2C1_IRQ_R} is the interesting classification. Textually that is one net vanishing and another appearing. Structurally it is the same net with a new name, and the tool says so because the set of pins on it did not change.

Two revisions side by side. A net called SIG in rev A and a net called DATA in rev B hold the same three pin connections, so the diff reports one renamed net instead of one deletion and one addition. rev A rev B SIG DATA U1.4 R3.1 J2.7 U1.4 R3.1 J2.7 identical pin set agni diff: [renamed] SIG -> DATA matching on names alone would report one net deleted and one net appeared

That distinction is most of the value. A rename touching forty nets is a naming sweep and needs skimming. Forty nets genuinely deleted and forty added is a redesign and needs reviewing. They look identical in a text diff.

The new name carries a lesson of its own. The obvious spelling, ~{PDC_I2C1_IRQ}, already names the net on the far side of the series resistor R110, so a label spelled that way would have JOINED the two nets, and the diff would have shown a hard change where a rename was meant. The script refuses a name that is already in use. The board’s own convention names the near side of a series resistor with an _R suffix, as in ~{USBC2_INT_R}.

Hard and soft

A hard change alters what is connected, by joining or removing a pin. A soft change alters something recorded about the net without changing connectivity.

Hard changes are where electrical risk lives. When a diff is large, read the hard changes first and treat the soft ones as background. This edit has none. Fitting a part changes what is BUILT rather than what is drawn, so it shows as a component change, dnp: "yes" -> "no".

The review delta

The structural diff says what moved. Running the checklist on both says whether it helped:

$ agni review designs/jetson
**6 pass, 7 fail, 1 n/a, 1 not-automated (of 15)**
| H1 | active-low signals use the overbar | fail | jetson/active-low-overbar: /USB Debug, PD/PDC_I2C1_IRQn (net name matches no allowed naming pattern); jetson/active-low-overbar: /USB Debug, PD/PDC_I2C2_IRQn (net name matches no allowed naming pattern) |
$ agni review designs/jetson-rev-b
**7 pass, 6 fail, 1 n/a, 1 not-automated (of 15)**
| H1 | active-low signals use the overbar | pass |  |

One failure became a pass. H1 passes because both trailing-n names are gone. I4, every I2C bus has pull-ups, still fails, because the board has other undriven buses, but it fails on two nets fewer:

$ python3 tools/make_rev_b.py designs/jetson designs/jetson-rev-b
$ agni check --verdicts --rule i2c-pull-up designs/jetson-rev-b 2>/dev/null | grep -E '^i2c-pull-up|I2C0_SCL_1V8 |I2C3_SDA_1V8 '
i2c-pull-up  26 fail, 28 pass

Read the subjects. The two fitted resistors pull up I2C0_SCL_1V8 and I2C3_SDA_1V8, the clock of one bus and the data line of another, which their neighbouring reference designators would not suggest. The diff told you which parts changed. The verdicts told you which buses that helped. On a real revision, check that half. A fix can go onto a different net than the one intended, and then the fix causes a regression.

Comparing across formats

The diff runs over the internal representation rather than the file, so the two sides do not have to be the same format. A design exported as EDIF last quarter and as KiCad this quarter compares cleanly. If the diff comes back empty, the two describe the same netlist. The same diff verifies that a CAD migration did not quietly change the design.

Next

Archive and gate, which is about keeping a result and making it block a merge.