name: concur
description: Cross-source consensus check for chip libraries. Compares ds2sf-extracted symbol+footprint against chip-fetcher's KiCad/EAGLE/Altium libraries and emits a result.json with status (golden/divergent/unrecoverable), exit codes (0/2/3), and tagged hints[] so chip-fetcher can autonomously re-fetch a suspect library or escalate to a human. Trigger words — concur, golden dataset, cross-source check, kicad eagle altium agreement, lib agreement, library mismatch, ds2sf vs kicad, ul stub symbol, refetch library, chip lib consensus.

concur — cross-source consensus check

Pipeline position: chip-fetcherds2sf (status: ok) → concur (status: golden) → safe for downstream.

When the four sources of truth for a chip's symbol+footprint (ds2sf-extracted from the datasheet, KiCad UL bundle, EAGLE/Fusion 360 .lbr, Altium binary) all agree, you have a golden dataset. When they diverge, somebody's wrong — concur tells the upstream caller which source is suspect and what to do.

Outputs

<chip-dir>/<MPN>-concur.result.json — the audit + agent-to-agent contract:

{
  "schema_version": "1",
  "status": "golden | divergent | unrecoverable",
  "exit_code": 0 | 2 | 3,
  "mpn": "ADS1115IDGSR",
  "summary": "ADS1115IDGSR — DIVERGENT. Sources: [ds2sf,kicad,eagle]. Axes: 5 agree, 2 disagree, 0 source-missing.",
  "sources_compared": ["ds2sf","kicad","eagle"],
  "sources_missing": ["altium"],
  "axes": [
    { "axis": "pad_count",      "verdict": "agree", … },
    { "axis": "pin_names",      "verdict": "disagree",
      "conflicts": ["kicad has stub-only pin names (UL bundle did not carry the part's real pin labels)"] }
  ],
  "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" }
  ]
}

Commands

concur check <CHIP-DIR>     # run the cross-source check
concur inspect <CHIP-DIR>   # print summary of an existing concur.result.json
concur health               # readiness check
concur install              # drop SKILL.md

check flags: --ds2sf-symbol, --ds2sf-footprint, --kicad-sym, --kicad-mod, --eagle, --mpn, --out-dir, --force, --json-only.

Status ladder (agent-to-agent contract)

Exit status Meaning Caller action
0 golden All sources agree exactly. Accept.
0 golden_with_variants Disagreements exist but every one is explained by a variants[] entry (EP-only, module-extras, label-only, stub pin names, body-dim measurement artifact). Accept. Downstream tools use the variant list to decide which source to prefer.
2 divergent At least one disagreement is not covered by a variant. Walk hints[]; refetch a library or escalate.
3 unrecoverable Couldn't parse ≥2 sources. Surface to human.

variants[].kind enum

Variants explain why a disagreement is benign, separate from hints[] which tell the caller what to do.

Kind When Meaning
exposed_pad_variant Pad count diff is exactly 1 EP/thermal pad counted as pin N+1 by some sources, omitted by others.
module_extra_pads Pad count diff > 1 KiCad/EAGLE footprint includes mounting/shield/test pads beyond module datasheet pinout.
label_only_mismatch Package family names differ but geometry agrees TI's SOT_ prefix on VSSOP footprints, DGS0010A JEDEC outline → VSSOP, IPC-7351 generic names like SOP65P640X120-20N, etc. Cosmetic.
stub_symbol_pin_names One source's pin names are numeric ("1","2"…) UL bundle stub case. Use ds2sf or EAGLE for real names.
body_dim_measurement_artifact Body dim disagrees but pad geometry agrees Different "body" measurement methods. Doesn't affect placement.
naming_convention_mismatch Pin names differ but every disagreement is a benign convention swap Channel-digit position (OUT11OUT) for op-amps and multi-channel parts; power-pin aliases (V+VCC, V-GND) for chip-vendor-vs-library naming.

Comparison axes (what gets cross-checked)

  • pad_count — number of pads in the footprint
  • pad_numbers — set of pad numbers / labels
  • symbol_pin_count — number of pins in the symbol
  • pin_names — per-pin name across sources (slash-normalized, case-insensitive). Stub-only sources (UL bundles where pin "name" is the pin number) are flagged as ul_symbol_has_stub_names rather than failing the axis.
  • pin_to_pad_map — does pin VDD map to the same pad number across sources?
  • package_family — SOIC/QFN/SOT/VSSOP/etc., with JEDEC outline aliases (DGS0010A → VSSOP)
  • body_dims — body x/y in mm, ±0.5 mm tolerance

hints[].action enum

Action Carries When
refetch_library_source {format, suspect, notes} A specific lib looks wrong; 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 (e.g. Altium parser not yet implemented).
source_parse_failed {format, path, error} A file couldn't be parsed at all.

hints[].action enum

Every hint tells the caller exactly what to do. v0.3 enriches the previously-skinny refetch hints with suggested_sources (priority-ordered list of where to refetch from) and expected_resolution (how the caller verifies the refetch worked).

Action Carries What chip-fetcher should do
refetch_library_source {format, suspect, notes, suggested_sources, expected_resolution} Walk suggested_sources in order. After each refetch, re-run concur check. The expected_resolution field tells you the specific axis that should change verdict on a successful refetch. Stop when status flips to golden / golden_with_variants.
ul_symbol_has_stub_names {source, pin_count, suggestion, chip_fetcher_action} Don't refetch the .kicad_sym — UL stub-naming is a UL property, not a chip-fetcher choice. Instead mark the chip dir's symbol source as ds2sf-preferred so downstream sym_create authors a fresh symbol with real labels from ds2sf's JSON.
rerun_ds2sf_with_stronger_model {reason, suspect_field, suggested_model} Re-run ds2sf extract --force --model claude-opus-4-7. ds2sf likely misread a small dimension or pin field with Haiku. Verify by re-running concur.
accept_with_caveats {caveats} Soft diffs within tolerance — accept the dataset, just remember the caveats for UI display.
human_review {reason, notes} Surface to a human; no automated repair safe.
source_parse_failed {format, path, error} A source file couldn't be parsed. If format == altium and concur version < 1.0, this is expected (Altium binary parser isn't implemented yet).

Agent-to-agent calling recipe

// (Pseudo-Rust for chip-fetcher's caller side.)

// Step 1: ds2sf
let ds2sf = run_ds2sf(chip_dir);
if ds2sf.status != "ok" {
    // Handle ds2sf needs_better_pdf path — see ds2sf SKILL.md.
}

// Step 2: concur
let mut tried_refetches: HashSet<String> = HashSet::new();
loop {
    let r = run_concur(chip_dir);
    match r.status.as_str() {
        "golden" | "golden_with_variants" => {
            // Apply ul_symbol_has_stub_names by marking the chip dir's
            // symbol source as ds2sf-preferred for downstream sym_create.
            for h in &r.hints {
                if let Hint::UlSymbolHasStubNames { .. } = h {
                    mark_chip_dir_symbol_source(chip_dir, "ds2sf-preferred");
                }
            }
            mark_chip_dir_clean(chip_dir, &r.variants);
            break;
        }
        "divergent" => {
            // Walk hints in order. First action that's not yet been tried wins.
            let mut acted = false;
            for h in &r.hints {
                match h {
                    Hint::RerunDs2sfWithStrongerModel { suggested_model, .. } => {
                        run_ds2sf(chip_dir, &["--force", "--model", suggested_model]);
                        acted = true; break;
                    }
                    Hint::RefetchLibrarySource { format, suggested_sources, .. } => {
                        for src in suggested_sources {
                            let key = format!("{format}|{src}");
                            if tried_refetches.insert(key) {
                                refetch_library(chip_dir, format, src);
                                acted = true; break;
                            }
                        }
                        if acted { break; }
                    }
                    _ => {}
                }
            }
            if !acted {
                // Out of automated options.
                log_for_human(&r);
                break;
            }
        }
        "unrecoverable" => { log_for_human(&r); break; }
        _ => unreachable!(),
    }
}

Out of scope for v0.1

  • Altium binary parsing (.SchLib / .PcbLib are OLE-compound). Surfaces as human_review with reason altium_parser_not_implemented.
  • Body-thickness comparison (z-dim). Sources don't reliably report this.
  • Automatic pin-name slash-normalization beyond /_ (e.g. fully-qualified mux paths).

Related

  • ds2sf (skill at ~/.claude/skills/ds2sf/SKILL.md) — upstream: extracts symbol+footprint+provenance from the datasheet PDF.
  • chip-fetcher (skill at ~/.claude/skills/chip-fetcher/SKILL.md) — primary consumer; pulls the libraries that concur cross-checks.