Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
7315b96d0This file is pinned to the selected release. Download the original to open it in your design tool.
# AUDIT.md — pcbflow read-only audit (Phase 1)
**Scope:** the entire pcbflow repo at `/home/nijo/axon`, read-only. Ground truth was
established by reading the source (not the docs about the source) and by running the suite.
**Measured facts (this run, 2026-07-14):**
- Test suite: **38 passed, 0 failed** (`tests/` 12 suites + 7 co-located). Fast (0.22 s), fully offline.
- Coverage on the `pcbflow/` package: **71 % overall**. Pure analyzers are strong
(`dfm` 100 %, `geometry` 100 %, `ipc` 100 %, `congestion` 100 %, `phases` 100 %,
`project` 98 %, `erc` 97 %, `routing` 93 %, `design_index` 92 %, `enet` 89 %).
Weak/absent: `cli.py` **47 %**, `mcp_server.py` **0 %**, `munch_server.py` **0 %**.
- No CI (`.github/workflows/` absent). No coverage gate. No known-bad fixtures.
- No Light-Dome fingerprints (one template placeholder `BAT+` in `templates/net_connection.template.md`, correct).
---
## 1. Claims-vs-evidence table
Every substantive README claim, marked **PROVEN** / **PARTIAL** / **UNPROVEN**, with evidence.
| # | Claim (README §) | Verdict | Evidence |
|---|---|---|---|
| C1 | §1 "a workspace and a method, not a program you run" | **PROVEN** | Markdown method + helper scripts; `workflow/`, `agents/`, `pcbflow/`. |
| C2 | §2 "never sizes a power path below its limit, never signs off a DRC, never orders a board" | **PROVEN (as policy)** | No auto-signoff / auto-order code exists anywhere; `pcbflow/ipc.py`+`routing.py` size to IPC-2221. It's a design stance, not an enforced interlock — nothing *could* order a board, which is the point. |
| C3 | §3 "Twelve phases, each with a checkpoint… you never start a phase until the previous is confirmed correct" | **PROVEN (mechanism)** | `pcbflow/phases.py` (12 phases) ↔ `workflow/` (12 files) ↔ `pcbflow/project.py:63-79` `can_advance()`/`advance()` **hard-refuses** advance without a recorded `PASS`. ⚠️ Caveat (see §3 gap): the verdict is **human/agent-asserted** (`record_verdict`), **not machine-computed** from the checks — the guard is enforced, the *judgment* is not automated. |
| C4 | §4 repository-overview folder table | **PROVEN** | Every listed folder exists. |
| C5 | §5 "AI-model-agnostic… Claude Code, Codex, OpenCode, Cursor, Gemini CLI… instructions live in plain Markdown" | **PARTIAL** | `CLAUDE.md`+`AGENTS.md` are model-neutral markdown, so *any* agent can read them — true in principle. But there are **no per-agent adapters/manifests** (`.claude-plugin/`, `.codex-plugin/`, `.cursor/rules/`, `GEMINI.md`, `action.yml`). "Works with X" is aspirational beyond "reads markdown". |
| C6 | §6 "official Bridge (run-api-gateway)… raw Chrome-DevTools fallback" | **PARTIAL** | Both paths are real code: `automation/easyeda/bridge.py`+`session.py` (Bridge) and `automation/browser/cdp.py` (CDP). **Neither is validated end-to-end** — `bridge.py:27-28` self-documents "unit-tested against a stdlib mock… needs a live EasyEDA session to validate". Minor drift: §6 names the fallback "`tools/launch_easyeda.py`" but that only launches Chrome; the CDP driver is `automation/browser/cdp.py`. |
| C7 | §7 "run `python3 tools/doctor.py`… lists each tool ✅/⚠️/❌" | **PROVEN** | `tools/doctor.py` implements it; checks OS/Python/Git/Node/Chrome/rsync/KiCad. |
| C8 | §7 "`projects/example-usb-c-3v3/` is **a complete, real reference board**" | **UNPROVEN / OVERSTATED** | Only **5 of 12 phases** have artifacts (brief, feasibility, bom, net_connection, netlist.enet, design_rules.json). **No placement, no KiCad board, no routed board, no DRC report, no gerbers, no findings report.** The example's *own* README correctly disclaims this ("geometry… this text repo intentionally doesn't vendor"); the top-level README does not. `ROADMAP.md` marks it 🚧 in-progress — a status conflict with §7. |
| C9 | §7 "Its netlist is machine-checkable: `python3 -m pcbflow.enet …`" | **PROVEN** | Runs; `pcbflow/enet.py` `verify()` returns clean on the shipped `.enet` (89 % covered). |
| C10 | §8 "Built now: 12-phase workflow" | **PROVEN** | `phases.py` + `workflow/`. |
| C11 | §8 "Built now: AI agent roster" | **PROVEN** | `agents/*.md` — one per phase-owner. |
| C12 | §8 "Built now: EasyEDA + KiCad automation" | **PARTIAL** | Exists but live-untested + brittle (see §2 tech-debt). KiCad side is `kicad-cli` shell (`automation/kicad/drc.sh` + `tools/drc.py`), tested for the guard logic only. |
| C13 | §8 "Built now: engineering knowledge base" | **PROVEN** | `knowledge/` is real, substantive content: `learning-db.md` (8 seed lessons L1–L8 with heuristic/why/instance/validation/prevention), `design-standards.md` (concrete IPC/DFM numbers), `knowledge-graph.md`, `knowledge-inheritance.md`, `principles.md`. Not templates. |
| C14 | §8 "Built now: a **complete self-healing reliability layer** (environment check, logging, auto-diagnosis, retry, recovery, resume, cross-platform tools)" | **PARTIAL / OVERSTATED** | Component reality: env-check ✅ (`doctor.py`, tested); auto-diagnosis ✅ (`diagnose.py`, tested); retry ✅ (`recover.py` backoff, tested); resume ✅ logic (`state.py`, **untested**); cross-platform ⚠️ (`platform_utils.py` path-logic tested, **not** live-validated on macOS/Windows); **logging ⚠️ unwired** (`pcbflow_log.py` `PhaseLogger` **not called by any workflow/agent** — grep-confirmed); **recovery ⚠️** (`recovery.py` browser strategies are correct *logic* but self-flagged "must be validated against a real session"; `heal.py` engine **not wired into any workflow**). "Complete" and "self-healing" overstate a reliability **library that is largely not wired in**. |
| C15 | §9 "The AI stops for approval before drawing copper; leaves safety/DRC/fab-order to you" | **PROVEN (as policy)** | Consistent with C2; human-in-the-loop by construction. |
| C16 | §9 "The AI's reliability layer **auto-recovers** common failures" | **PARTIAL** | `heal.py`/`recovery.py` implement the loop but nothing invokes them in a real path (C14). Auto-recovery is *available*, not *active*. |
| C17 | §9 "developed and validated on Linux; cross-platform tooling… **still needs real-world validation** on macOS/Windows" | **PROVEN (honest disclaimer)** | This one is correctly hedged and matches reality — a model for how the other claims should read. |
| C18 | Provenance: "extracted from a real ESP32 robotics board, including the honest record of what went wrong" | **PROVEN** | `knowledge/learning-db.md` + `docs/13_LESSONS_LEARNED.md`. |
**Headline:** the *architecture* is honest and internally consistent (phases ↔ workflow ↔ code
gate ↔ knowledge all harmonize). The two material honesty defects are **C8** ("complete
reference board" — it's front-half only) and **C14** ("complete self-healing reliability
layer" — it's a partly-wired library). Both are fixable by *either* completing the thing *or*
truthing the sentence; DoD-5 requires one of the two.
---
## 2. Tech-debt inventory
### 2a. Untested / weakly-tested code
| Item | Evidence | Severity |
|---|---|---|
| `pcbflow/mcp_server.py` — **0 % coverage** | no `tests/test_mcp_server.py`; entire MCP surface unexercised | HIGH |
| `pcbflow/munch_server.py` — **0 % coverage** | no test; `pcbmunch` entry point unexercised | HIGH |
| `pcbflow/cli.py` — **47 % coverage** | pass-through/arg-wiring branches untested | MED |
| `tools/state.py` (resume) — no test file | resume logic unvalidated | MED |
| Live-session code cannot run in CI | `cdp.py` `_eval`/`_shot`, `dump_schematic.js`, `section_generator.template.js`, `api_probe.js`, `launch_easyeda.py` actual-launch | MED (inherent; needs mock/NEEDS-LIVE-VALIDATION log) |
| Bridge + CDP end-to-end untested | `bridge.py:27-28`, `test_bridge.py` mock-only | HIGH (this is the EasyEDA transport) |
### 2b. Unwired / dead-on-arrival code (exists, nothing calls it)
| Item | Evidence | Severity |
|---|---|---|
| `PhaseLogger` never instantiated in any workflow/agent | grep: only `tools/heal.py` docstring + tests | HIGH (contradicts C14 "logging") |
| `heal.py` engine not invoked from any real path | no import outside tests | HIGH (contradicts C16 "auto-recovers") |
| `recovery.py` browser strategies untested vs live | `recovery.py:14-15` self-flag | MED |
### 2c. Brittle automation selectors / assumptions (will break on EasyEDA change)
| Assumption | Location | Severity |
|---|---|---|
| `window._EXTAPI_ROOT_` root object | `dump_schematic.js:17` | HIGH |
| Field-name fallback chains (`designator\|\|name`, `p.num\|\|p.number\|\|p.name`) silently pick wrong field | `dump_schematic.js:13,30` | HIGH |
| library-search method probed among 6 candidates | `section_generator.template.js` / `api_probe.js` | HIGH (needs manual probe per EasyEDA build) |
| Bridge port range 49620-49629; CDP port 9222 | `bridge.py:37-38`, `cdp.py` | LOW (env-overridable) |
| `session._detect()` swallows *all* bridge exceptions → silent CDP fallback, no reason logged | `session.py` | MED |
| `recon.py` rounds wire coords to int — 0.5-unit segments could miss a junction | `recon.py:30,43` | MED |
### 2d. Platform assumptions
| Item | Evidence | Severity |
|---|---|---|
| rsync-based profile clone marked N/A on Windows | `doctor.py` rsync check; `launch_easyeda.py` "best effort" on locked Windows profile | MED |
| Bash `automation/kicad/drc.sh` vs `tools/drc.py` — cross-platform story only partially unified | drc via `.sh`; README says use `.py` on Windows | LOW |
### 2e. Doc/code drift
| Drift | Evidence | Severity |
|---|---|---|
| README §7 "complete reference board" vs example README "intentionally doesn't vendor geometry" vs ROADMAP "🚧 in progress" | three docs, three scopes | HIGH |
| README §6 names CDP fallback as `tools/launch_easyeda.py` (actually launches Chrome; driver is `automation/browser/cdp.py`) | §6 line ~140 | LOW |
| `automation/easyeda/README.md` implies `session.py` is used in "phases 3,4,9"; it's only in tests/examples | README vs grep | LOW |
| Example project dir missing 7 of 12 phase subdirs that `_template/` has | `projects/example-usb-c-3v3/` | MED |
### 2f. Dead files
**None found.** Every `cli.py` pass-through target and README-referenced file exists. (This is a genuine positive — no orphaned modules.)
---
## 3. Gap analysis vs. the target improvement patterns
| Improvement pattern | pcbflow today | Gap |
|---|---|---|
| **H1** harmonized findings schema (detector/rule_id/severity/confidence/evidence_source/recommendation/provenance/stable-id) | `erc.py` emits `{rule,severity,where,reason}`; `dfm.py` emits `{rule,severity,value,limit,where,reason}` — **two ad-hoc shapes, no confidence/evidence/provenance/id** | **FULL GAP** — foundational; blocks trust rollup + diffable reports |
| **H2** offline pure-Python S-expr reader for `.kicad_sch`/`.kicad_pcb` | none — KiCad only via `kicad-cli`; EasyEDA only via live browser | **FULL GAP** — blocks the import-diff (DoD-3) and offline KiCad tests |
| **H3** committed example reports (real output) | none vendored | **FULL GAP** — DoD-1 |
| **H6** agent-facing install-guidance (per-platform quirks) | human platform docs exist; no agent-facing quirks file | **PARTIAL GAP** |
| **H9** deterministic finding IDs + ordering | none | **FULL GAP** (follows H1) |
| **P1** machine-**computed** gates (run the checks → verdict) | advance-guard enforced (`can_advance`), but verdict is **asserted, not computed**; no `compute_gate()` running ERC/DFM | **PARTIAL GAP** — the guard exists; the automated judgment does not |
| **P2** hard-blocked `export_manufacturing_package` (gates PASS + human approval evidence) | none | **FULL GAP** — DoD-3, phase-12 |
| **P3** known-good **and** known-bad fixture corpus | 1 good example only | **FULL GAP** — DoD-4 (can't prove gates *block*) |
| **P6** single env/config table + honest limitation notes | §9 has honest notes; env vars (`EDA_BRIDGE_PORT_*`, `CDP_PORT`, `EDA_BACKEND`) scattered, no table | **PARTIAL GAP** |
| **H4** VALIDATION.md (what was tested, baselines, ledger) | `docs/09_VALIDATION.md` is a methodology *narrative*; no root VALIDATION.md with a tested corpus + NEEDS-LIVE-VALIDATION log | **PARTIAL GAP** — DoD-2 |
| **P7** packaging (lockfile/PyPI/uvx/CI/version-consistency) | `pyproject` (setuptools) + 3 entry points; **no lockfile, no PyPI, no CI, no release automation** | **PARTIAL GAP** — DoD-6 |
| **H5** multi-agent manifests (thin shim over one core) | agent job-description markdown only | **FULL GAP** (do last) |
---
## 4. Risk-ranked top-10 highest-impact fixes
Sequenced by the prompt's risk order (proof → machine gates → robustness/file-parsing → CI →
fixtures+tests → packaging → docs-truthing → agent packaging), with effort S/M/L.
| # | Fix | Why (DoD / risk) | Effort |
|---|---|---|---|
| 1 | **Truth the two overstated claims now** (C8 "complete reference board" → "front-half worked example"; C14 "complete self-healing reliability layer" → "reliability *library*, partly wired"), and reconcile README §7 ↔ example README ↔ ROADMAP. | DoD-5 honesty. A known-false claim is a bug; this is the cheapest possible fix and unblocks trust. | **S** |
| 2 | **Complete the worked example end-to-end** — add placement + KiCad export + routed board + DRC report + gerbers + a committed example *findings report*, with **one documented command** to re-verify, ending DRC-clean. Where a step needs a live tool this env lacks, ship the artifact + log it NEEDS-LIVE-VALIDATION with exact manual steps. | DoD-1 (proof) + H3. The single biggest credibility lever; a stranger must reproduce in <1 h. | **L** |
| 3 | **Harmonized findings schema [H1] + stable IDs [H9]** — one `finding()` factory (detector, rule_id, severity, confidence, evidence_source, components, nets, recommendation, provenance, stable id); migrate `erc.py`+`dfm.py`+`verify` onto it; add a trust rollup. | Foundation for every traceable output; DoD-5. | **M** |
| 4 | **Machine-computed gates + hard-blocked export [P1/P2]** — `compute_gate(phase)` that *runs* ERC/DFM/spacing and returns a `GateOutcome` feeding `record_verdict`; a phase-12 `export` verb that **refuses** unless all gates PASS **and** a human approval-evidence file exists. Never auto-sign-off. | DoD-3 + realizes the stated safety model in code. | **M** |
| 5 | **Offline KiCad S-expr reader [H2] + EasyEDA→KiCad import-diff** that fails loudly on net/component mismatch. | DoD-3 robustness; also unlocks offline KiCad tests in CI. | **M/L** |
| 6 | **Fixture corpus [P3]** — ≥1 known-BAD project per gate (floating pin, no-ground, sub-min track, hole-to-hole, edge clearance) that must stay blocked + the clean example that must pass; assert both in tests. | DoD-4 (prove gates block, not just pass). | **M** |
| 7 | **CI on GitHub Actions (ubuntu + macos + windows)** running the suite + coverage gate (≥80 % on pure logic) + README badges; a root **VALIDATION.md [H4]** documenting what's tested vs NEEDS-LIVE-VALIDATION. | DoD-2 (trust). Closes the biggest single credibility gap. | **M** |
| 8 | **Resolve the reliability-layer honesty gap** — either wire `PhaseLogger` + `heal()` into ≥1 automation path (prove the loop), or de-scope C14/C16 to "opt-in library"; add a live-session smoke test logged NEEDS-LIVE-VALIDATION. | DoD-5; removes "aspirational" from a headline claim. | **M** |
| 9 | **Cover the 0 %/47 % modules** — test or mark-experimental `mcp_server.py`+`munch_server.py`; raise `cli.py` coverage; add `session._detect` logging + `recon.py` float-match note. | DoD-4 quality; kills the largest untested surfaces. | **M** |
| 10 | **Packaging + config discipline [P7/P6/H6]** — pinned/locked deps, `pip`/`uvx`-installable, single env/config table, agent-facing install-guidance; **defer** multi-agent manifests [H5] to the very end. | DoD-6 (DX). | **M** |
---
**STOP — Phase 1 (audit) complete. Awaiting your review before Phase 2 (IMPROVEMENT_PLAN.md).**