← Commit history

Initial commit: app/adom-concur

John Lauer ·5262522fea ·4mo ago
2 files changed +227
README.mdadded+198
@@ -0,0 +1,198 @@+# adom-concur++**Cross-source consensus check for chip libraries.**++A small Rust CLI that runs downstream of `adom-ds2sf` and `adom-chip-fetcher`: it loads every available source-of-truth for a chip's symbol and footprint (datasheet-extracted, KiCad UL bundle, Fusion 360 EAGLE `.lbr`, Altium binary), compares them across seven axes, and emits a result.json with `status: golden | divergent | unrecoverable` plus tagged `hints[]` so the upstream caller can either re-fetch a suspect library or escalate to a human.++The pipeline:++```+adom-chip-fetcher  →  adom-ds2sf (status: ok)  →  adom-concur (status: golden)  →  downstream is happy+                                            ↓ divergent+                                       adom-chip-fetcher refetches a lib+                                       OR human reviews+```++## Why this matters++Concur is **opinionated** about whether a divergence requires upstream work or is safe to ship. Many "disagreements" between sources are known-benign patterns (exposed-pad counted as pin N+1 in one source but not the other, JEDEC-outline-name vs marketing-name, alt-function pin labels, pad-array span misread as body dim). Concur classifies these as **variants** and ships the dataset with `status: golden_with_variants` (exit 0) so the upstream caller can move forward and just remember the variants downstream. Real disagreements stay `divergent` (exit 2).++Real example from this release's smoke tests:++```+$ adom-concur check ~/project/adom-chip-fetcher/library/ADS1115IDGSR+  adom-ds2sf       — 10 pins, 10 pads, package "VSSOP-10"+  kicad       — 10 pins, 10 pads, footprint "SOT_ADS1115IDYNR_TEX"+  eagle (.lbr) — 10 pins, 10 pads, package "DGS0010A_N"++OK: ADS1115IDGSR — GOLDEN with variants [variants: label_only, stub_pin_names, body_dim_artifact]+```++What adom-concur figured out:++- `label_only_mismatch` — KiCad's footprint name starts with `SOT_` because that's TI's UL library prefix convention, but the geometry (pad count, pad layout, pitch) all agrees with EAGLE's `DGS0010A_N` and adom-ds2sf's `VSSOP-10`. The package family really is VSSOP. Cosmetic only.+- `stub_symbol_pin_names` — the KiCad UL symbol has pin "names" of "1", "2", "3"… instead of real labels. Downstream can use adom-ds2sf's or EAGLE's pin labels.+- `body_dim_measurement_artifact` — adom-ds2sf and EAGLE report different body dimensions (5.05×3.10 vs 4.45×2.00). Body dim is courtyard-only, doesn't affect placement; the diff is a measurement-method artifact (lead-tip span vs pad-array span vs body D dim).++All three are flagged but explained, exit 0, adom-chip-fetcher moves forward.++## Outputs++`<chip-dir>/<MPN>-concur.result.json` — the audit + agent contract:++```json+{+  "schema_version": "1",+  "status": "golden_with_variants",+  "exit_code": 0,+  "mpn": "ADS1115IDGSR",+  "summary": "ADS1115IDGSR — GOLDEN with variants [variants: label_only,stub_pin_names,body_dim_artifact]",+  "sources_compared": ["adom-ds2sf","kicad","eagle"],+  "sources_missing":  ["altium"],+  "variants": [+    { "kind": "label_only_mismatch",+      "notes": "adom-ds2sf: VSSOP-10 → family=VSSOP | eagle: DGS0010A_N → family=VSSOP | kicad: SOT_ADS1115IDYNR_TEX → family=SOT" },+    { "kind": "stub_symbol_pin_names",+      "stub_sources": ["kicad"],+      "canonical_sources": ["adom-ds2sf","eagle"] },+    { "kind": "body_dim_measurement_artifact",+      "notes": "adom-ds2sf: 5.05×3.10 mm | eagle: 4.45×2.00 mm" }+  ],+  "axes": [+    { "axis": "pad_count",     "verdict": "agree" },+    { "axis": "pin_names",     "verdict": "disagree",+      "conflicts": ["kicad has stub-only pin names …"] },+    { "axis": "package_family","verdict": "disagree",+      "conflicts": ["Package families disagree across sources: adom-ds2sf=VSSOP, kicad=SOT, eagle=VSSOP"] }+  ],+  "hints": [+    { "action": "ul_symbol_has_stub_names", "source": "kicad", "pin_count": 10,+      "suggestion": "Use ds2sf-extracted symbol JSON or refetch the .kicad_sym from a manufacturer-direct source" }+  ]+}+```++### Status ladder++| Status | Exit | Caller action |+|---|---|---|+| `golden` | 0 | Ship it, no caveats. |+| `golden_with_variants` | 0 | **Ship it.** Every disagreement is explained by `variants[]`. Downstream tools can use the variant list to decide which source to prefer (adom-ds2sf for pin labels when the KiCad symbol has stubs, etc). |+| `divergent` | 2 | Real disagreement. Refetch a library or escalate to a human. |+| `unrecoverable` | 3 | Couldn't parse ≥2 sources. |++### Variant kinds (v0.3)++| Kind | When | What it means |+|---|---|---|+| `exposed_pad_variant` | Pad count diff is exactly 1 | One source counts the EP/thermal pad as pin N+1; the other rolls it into the body. EE practice varies; both are correct. |+| `module_extra_pads` | Pad count diff > 1 (one source has more) | KiCad/EAGLE footprint includes mounting/shield/test pads beyond the module datasheet's user-facing pinout. |+| `label_only_mismatch` | Package family names differ but geometry agrees | Naming-convention artifact (e.g. TI's `SOT_` prefix on a VSSOP footprint, JEDEC outline `DGS0010A` → VSSOP, IPC-7351 generic name `SOP65P640X120-20N` → TSSOP). Cosmetic only. |+| `stub_symbol_pin_names` | One source's pin names are pin numbers ("1","2"…) | UL stub case. Downstream should use a richer source (adom-ds2sf or EAGLE) for labels. |+| `body_dim_measurement_artifact` | Body dim disagrees but pad geometry agrees | Different sources measured "body" differently (lead-tip span vs body D-dim vs pad-array span). Body dim is courtyard-only; doesn't affect placement. |+| `naming_convention_mismatch` | Pin names differ but every disagreement is a benign convention swap | Channel-digit position (`OUT1` ↔ `1OUT` for op-amps and multi-channel parts) or power-pin alias (`V+` ↔ `VCC`, `V-` ↔ `GND`). |++## Comparison axes++| Axis | What it checks |+|---|---|+| `pad_count` | Number of pads in the footprint |+| `pad_numbers` | Set of pad numbers/labels (1..N or A1, A4, B7…) |+| `symbol_pin_count` | Number of pins in the symbol |+| `pin_names` | Per-pin name across sources (slash → underscore, case-insensitive). Sources that emit stub names ("1","2"…) are flagged as `ul_symbol_has_stub_names` hint. |+| `pin_to_pad_map` | Does pin VDD map to the same pad number across sources? |+| `package_family` | SOIC / VSSOP / QFN / SOT / etc., with JEDEC outline aliases (DGS0010A → VSSOP, RGE → QFN, RUG → VQFN, …) |+| `body_dims` | Body x/y in mm, ±0.5 mm tolerance |++## Agent-to-agent contract++`hints[]` is a tagged-union list (separate from `variants[]` — variants explain *why* a disagreement is benign; hints tell the caller *what action to take*). v0.3 enriches refetch hints with concrete `suggested_sources` (priority-ordered) and `expected_resolution` so adom-chip-fetcher knows where to refetch from AND how to verify the refetch worked.++| Action | Carries | When |+|---|---|---|+| `refetch_library_source` | `{format, suspect, notes}` | A specific lib looks wrong; adom-chip-fetcher should try a different upstream. |+| `ul_symbol_has_stub_names` | `{source, pin_count, suggestion}` | KiCad UL stub case (pin "names" are pin numbers). |+| `accept_with_caveats` | `{caveats}` | Soft diffs within tolerance. |+| `human_review` | `{reason, notes}` | No automated repair safe. |+| `source_parse_failed` | `{format, path, error}` | A file couldn't be parsed at all. |++## Calling recipe++```rust+let r = run_concur(chip_dir);+match r.status.as_str() {+    "golden" => mark_chip_dir_clean(),+    "divergent" => {+        for h in &r.hints {+            match h {+                Hint::RefetchLibrarySource { format, .. } => {+                    refetch_lib_from_alternate_source(format);+                    return run_concur(chip_dir); // re-call after refetch+                }+                Hint::UlSymbolHasStubNames { .. } => {+                    // Replace .kicad_sym from adom-ds2sf JSON via downstream sym_create.+                }+                _ => {}+            }+        }+    }+    "unrecoverable" => log_for_human(&r),+    _ => unreachable!(),+}+```++## CLI++```+adom-concur check <CHIP-DIR>     # run cross-source check+adom-concur inspect <CHIP-DIR>   # print summary of an existing adom-concur.result.json+adom-concur health               # parser readiness check+adom-concur install              # drop SKILL.md+```++`check` flags: `--ds2sf-symbol`, `--ds2sf-footprint`, `--kicad-sym`, `--kicad-mod`, `--eagle`, `--mpn`, `--out-dir`, `--force`, `--json-only`.++## Validated chips (v0.3 release — 9-chip suite)++| MPN | Pkg | Status | Variants caught | Notes |+|---|---|---|---|---|+| ADS1115IDGSR | VSSOP-10 | golden_with_variants | label_only, stub_pin_names, body_dim_artifact | TI's `SOT_` prefix on VSSOP footprint; UL symbol stubs; adom-ds2sf body-dim picked up the lead-tip span |+| DRV8316RRGFR | VQFN-40 | golden_with_variants | ep | EP counted as pin 41 by KiCad/EAGLE, omitted by adom-ds2sf |+| VL53L8CX | OLGA-16 | golden_with_variants | ep, label_only, body_dim_artifact | Custom optical LGA; thermal pad EP variant |+| ESP32-S3-WROOM-1-N4 | SMD module | golden_with_variants | module_extras, body_dim_artifact | KiCad has 8 extra shield/test pads beyond the module's 41 castellations |+| LM358D | SOIC-8 | golden_with_variants | naming_convention | `OUT1`↔`1OUT` channel-digit + `V+`↔`VCC`, `V-`↔`GND` power-pin aliases |+| TPS62840YBGR | DSBGA-8 | golden_with_variants | body_dim_artifact | Cleanest of the suite; only courtyard body-dim diff |+| BMI270 | LGA-14 | golden_with_variants | label_only, body_dim_artifact | Bosch IMU; EAGLE 7.x .lbr now parses (DTD support) |+| **MSP430G2553IPW20** | TSSOP-20 | **divergent** | — | **Real bug.** KiCad symbol shifts pin functions: adom-ds2sf says pin 14=NC, KiCad says pin 14=P1.6 with 8 alt-functions. Likely wrong sub-variant in UL bundle. |+| **R7FA4M1AB3CFP** | LQFP-100 | **divergent** | — | **Real bug.** Pin 1: adom-ds2sf=`P108_TMS_SWDIO`, KiCad=`P400`. AVCC0 lands on pad 90 vs pad 88. **Wrong sub-variant of the Renesas RA4M1 family.** |++7/9 pass cleanly (`golden_with_variants` exit 0). 2/9 are real wrong-variant findings the upstream caller should refetch. **Zero false positives** in v0.3.++## Out of scope (current)++- **Altium .SchLib (symbol-side) parsing.** v0.6 added .PcbLib (pads) via the sister `altium-pcblib` crate; .SchLib pin labels are still pending.+- **Body-thickness comparison** (z-dim). Sources don't reliably report this.+- **Tolerance-aware lead/pad-pitch checks** beyond raw body dims.++## Altium multi-variant selection (v0.7)++Many vendor `.PcbLib`s ship multiple footprint variants in the same file — for example DRV8316RRGFR carries `RGF0040E-IPC_A` (41-pad IPC standard) AND `RGF0040E-MFG` (57-pad manufacturing layout with extra fiducials and test points). The upstream `altium-pcblib` crate picks one as "primary" by stream order.++If adom-concur naively trusts the primary, it can disagree with kicad+eagle 100% of the time. v0.7 computes the pad-count consensus from already-parsed sources (adom-ds2sf / kicad / eagle) and asks `altium-pcblib` for the variant whose pad count is closest to the median. Names containing `-MFG` / `_MFG` / `DEBUG` / `FIDUCIAL` / `TEST` get a tiebreak penalty so the IPC-standard variant wins when in doubt.++Effect on the benchmark: DRV8316RRGFR was reporting `divergent` with altium engaged (57 vs 41) → now reports `golden_with_variants` (41 across all four sources, only EP-counting differs).++## Build++```bash+cargo build --release+sudo cp target/release/adom-concur /usr/local/bin/+adom-concur install+```++Or just `./build.sh`.++## Related++- [`adom-ds2sf`](https://github.com/adom-inc/adom-ds2sf) — datasheet → symbol + footprint + provenance JSON. Upstream of adom-concur.+- adom-chip-fetcher — pulls the libraries that adom-concur cross-checks.
page.jsonadded+29
@@ -0,0 +1,29 @@+{+  "slug": "adom-concur",+  "version": "1.0.0",+  "type": "app",+  "description": "Cross-source consensus check for chip libraries — compares adom-ds2sf-extracted symbol+footprint against adom-chip-fetcher's KiCad/EAGLE/Altium libraries and emits agent-to-agent hints.",+  "dependencies": {},+  "tags": [+    "eda",+    "validation",+    "kicad",+    "cli"+  ],+  "scripts": {+    "install": "./install.sh",+    "uninstall": "./uninstall.sh"+  },+  "install": {+    "binary_name": "adom-concur"+  },+  "needs_sudo": true,+  "hero": {+    "type": "image",+    "path": "adom-concur.png"+  },+  "author": {+    "name": "John Lauer",+    "email": "[email protected]"+  }+}\ No newline at end of file