As-built completion record for v1 of the KB wiring-diagram extraction pipeline: scanned car-manual
wiring diagrams — until now invisible raster JPEGs with no extracted text — get a searchable text
sidecar (labels, components, decoded wire colors) that the vectorizer indexes, plus a best-effort,
confidence-flagged netlist built by a hybrid classical-CV + vision pipeline. Proven end-to-end on
1 pilot page (suzuki-vitara/wiring-diagrams/019-light-head-…), which went from 0 extracted text
(unfindable) to #1 within its manual for “fuel cut controller” / “IC regulator”.
Scaled 2026-07-29 — real content + a graphical render layer
Since v1 the pipeline has been scaled to real content (full
5door-supplementmanual: 55/55 diagram pages processed + vectorized), a per-page on-page render hook and a Mermaid graphical circuit renderer were added, and a folder/manual-root 404 was fixed. See v1.1 (2026-07-29) — scaled to real content + graphical render layer below. The v1 sections that follow are the original completion record and hard-won knowledge; they remain accurate for the pipeline internals.
Design in 2026-07-29-kb-wiring-extraction-design, task-by-task plan in 2026-07-29-kb-wiring-extraction-plan — this note is the completion record and the hard-won knowledge, not a restatement of either.
For Agents
Code:
/home/levander/wiring-extract/on telep-mainframe (house-rules-clean, no comments). Modules:
legend.py+legend.json— 13 Suzuki wire colors (B=Black …V=Violet) transcribed from the scan image_page_8_Picture_7.jpeg, plus symbols, connector rules, abbreviations.decode_color("B/Y") -> "Black/Yellow". Runs under any venv (pure stdlib).diagram_index.py—list_diagram_pages(); 10 of 21 Vitara wiring pages are diagram pages (38 images).cvtrace.py— the connectivity engine. Runs under/home/levander/ocr/venv(cv2 4.11 + scikit-image 0.26 [installed this session] + numpy + PIL + surya).trace(image, suppress_boxes, crop, debug).emit.py— writes the.wiring.jsonrecord +<page>.wires.txtsearchable sidecar +.linesnetlist.run.py—status/reindex/search/run_pageorchestrator.fuse_pilot.py— the vision-extraction+fusion template used per page. Vectorizer patch:/home/levander/kb-vectors/chunker.pyPATCHED (backupchunker.py.bak-wiring) — merges a page’s<page>.wires.txtonto that page’s chunks (samepage_url); the.wires.txtnever becomes its own page. 51 kb-vectors tests pass. Box constraints: CV/reindex thread-capped (OMP_NUM_THREADS=4+nice), one heavy job at a time (PSU brown-out limit). Vision is Claude Code subagent-driven (session model) — NOT boxclaude -p(weekly-limited), NOT a local VLM (GPU contention). Batch, no always-on service. State: v1 complete + proven on 1 pilot page; 1/10 Vitara diagram pages covered; source md / scans /clusters.jsonmd5-unchanged (non-destructive).
What was built
| Module | Role | Venv |
|---|---|---|
legend.py + legend.json | 13 Suzuki wire colors + symbols + connector rules + abbreviations; decode_color() | any |
diagram_index.py | list_diagram_pages() — 10/21 Vitara wiring pages are diagrams (38 images) | any |
cvtrace.py | classical-CV connectivity engine (trace()) | ocr/venv |
emit.py | writes .wiring.json + <page>.wires.txt + .lines netlist | — |
run.py | status/reindex/search/run_page orchestrator | — |
fuse_pilot.py | vision extraction + fusion template (per page) | subagent |
chunker.py (kb-vectors, patched) | merges .wires.txt onto the page’s chunks | kb-vectors/venv |
cvtrace.py pipeline (the connectivity engine)
Otsu binarize → despeckle → TEXT mask via surya DetectionPredictor (auto, ~35 boxes) → SYMBOL
mask (vision-supplied component boxes, centroid node kept) → skeletonize → graph build →
dot-vs-crossing classifier (distance-transform blob vs median wire half-width) → union-find nets.
bridge=1 default gap-bridge. Signature: trace(image, suppress_boxes, crop, debug).
Key findings / hard-won knowledge
Naive CV path-tracing is a NO-GO on these 1632px scans
Skeletonizing the raw binary produced 161 false junctions / 502 segments — because TEXT (the “VITARA” title, labels, fuse ratings) and COMPONENT SYMBOLS (fuse coils, switch boxes) skeletonize into dense false-junction clusters. Line-following itself worked; connectivity did not.
Masked CV is a GO — mask text + symbols BEFORE skeletonizing
Mask out text (surya auto-detect, ~35 boxes) + component symbols (vision-supplied boxes) first → junctions 161 → 37 (-77%), conductors intact, junctions land at real wire meets. Symbols were the bigger contaminant (161 → 106 text-only → 37 with symbols added). This is the “hybrid CV + vision” the roadmap predicted.
Clean division of labor (the architecture that works)
- Vision locates components / terminals / labels and reads wire colors.
- Those component boxes are passed to
cvtraceassuppress_boxes. - cvtrace returns the nets (deterministic conductor geometry — no hallucination).
- Vision then fuses semantics onto the nets and reconnects sub-pixel gaps (e.g. the battery → 30A ~6px break) — never fabricating untraceable connections.
- Confidence = f(CV edge confidence, vision endpoint confidence, color confidence).
Crossing vs junction
Solder-dot detection (a local blob thicker than the wire half-width) distinguishes real connections (merge nets) from hop-over crossings (don’t merge). Proven on synthetic and real (3 hops vs 5 dots on the pilot crop).
Scan resolution is the ceiling, not the model
1632×808 with ~9 systems/page = few pixels per label; wire-color stripe letters (
B/RvsB/Bl) are the failure point (~60% correct). 300–600 DPI rescans or single-circuit pages would push connections to ~90%+ — a documented future accuracy lever, not built in v1.
The search win is real but scoped
The pilot diagram page (019-light-head-…) went from unfindable (0 extracted text) to #1 within its
manual for “fuel cut controller” / “IC regulator” via the indexed sidecar. It is NOT global top-50 —
a terse structured list can’t out-rank prose service pages. Framing matters: the goal (diagram pages
become retrievable) is met.
Vision + fusion is token-heavy — this is the binding scale constraint
Vision + fusion runs via Claude Code subagents (session model), NOT box
claude -p(weekly-limited) and NOT a local VLM (GPU contention). It costs ~13 min + ~110k tokens PER PAGE. Scaling to all pages is the token-heavy remaining step.
v1.1 (2026-07-29) — scaled to real content + graphical render layer
Verified on telep-mainframe today. Four things landed: real-content scale-out, an on-page render hook, a Mermaid graphical circuit renderer, and a folder/manual-root 404 fix.
Scaled to real content — 5door-supplement 55/55
Beyond the thin suzuki-vitara/wiring-diagrams booklet (10/10 earlier), the full
suzuki-vitara/5door-supplement manual is now 55/55 diagram pages processed — extracted, rendered
on-page, and vectorized/searchable. Qdrant manuals carries ~377 points for this manual; 55 pages
carry the “Diagram data (extracted)” marker.
Key finding CONFIRMED at scale — clean single-system circuits clearly beat the dense-booklet ceiling
- Clean single-system circuits (stop/tail/interior lights, wipers, defogger, washers, DTC sensor circuits 037–043) trace well with decoded wire colors at high/med confidence — clearly beating the ~60% dense-booklet ceiling.
- Bundled harness / operation diagrams (central-locking, power-window, the 060 body-electrical multi-market page) stay honestly conservative (med/low, power-path + representative edges only).
- Routing / flowchart / block / mechanical figures correctly come out labels-only — NO fabrication.
- Honest gap: page 044’s crank-angle-sensor “circuit” is only a flowchart + pinout in the scan (not actually drawn), so it is left labels-only — the pipeline did not invent a schematic.
Empty pages are OCR artifacts, not bugs
Divider / cover / TOC pages (e.g.
017-wiring-diagram= heading only; the geo-tracker cover) render fine but are thin by nature. The real schematics in the thin booklet were concentrated on page 019 (the marker grouped 6 figures there) — so a page rendering “empty” is expected content, not a failure.
On-page render hook (hooks.py on_page_markdown)
Extended the existing on_page_markdown hook (merged with the kickfix deeplink rewriter + lazy-image) to
append a per-page ”## Kinyert huzalozási adatok (AI)” section, built from the per-page JSON
(/home/levander/wiring-extract/out/<folder>__<manual>__<page>.wiring.json):
- an HTML connections table (Honnan | Huzalszín | Hová | Bizt.),
- components + systems lists,
- an AI-provenance note.
Non-destructive — source md is untouched; the hook reads the <page>.wires.txt sidecar / JSON at
render time.
Mermaid graphical circuit renderer (NEW)
Enabled pymdownx.superfences + a mermaid custom fence in mkdocs.yml (mkdocs-material 9.7.7 renders
client-side). The render hook now ALSO emits a per-page ”### Áramköri gráf (AI)” mermaid graph LR:
- nodes = components,
- edges labeled with the decoded wire color,
- LOW-confidence edges dashed (
-.->), - grouped into a
subgraphper subsystem, - readability cap (~30 edges/subgraph) with the dashed/subgraph logic.
Applies to all 62+ processed pages (pure render-layer — no re-extraction).
Mermaid render is markup-verified but NOT live-browser-confirmed yet
Verified the emitted markup + that Material’s mermaid loader bundle is present, but NOT a live browser render (the Claude Chrome extension was not connected this session). Material lazy-loads mermaid from the CDN, so a live render needs browser internet. A live-browser confirm is an open follow-up.
Manual/folder-root 404 fix (gen_index.py)
With use_directory_urls, folder + manual directories 404’d (e.g. /suzuki-vitara/5door-supplement/).
Extended gen_index.py to generate a landing index.md for every folder + manual dir (idempotent
<!-- generated-index --> marker) so those roots now list their pages. Backup gen_index.py.bak-404.
Box tooling in /home/levander/wiring-extract/ (reusable)
For Agents
cvtrace.py— masked-CV path-tracing (surya text-mask + vision-supplied symbolsuppress_boxes→ skeletonize → dot-vs-crossing classifier → union-find nets).legend.py/legend.json— 13 Suzuki wire colors.diagram_index.py— diagram-page enumeration.emit.py— writes.wiring.json+<page>.wires.txt+.lines.run.py—status/reindex/searchorchestrator.- per-page spec drivers:
emit_driver.py/mech_emit.py/build_page.py+specs/.- Vision + fusion is subagent-driven (session model; box
claudeis weekly-limited).- Naive CV was NO-GO (text/symbol contamination → 161 false junctions); masked CV was GO (→ 37).
Status
- v1 complete + scaled (v1.1):
wiring-diagrams10/10 and5door-supplement55/55 diagram pages processed, rendered on-page (table + Mermaid graph), and vectorized/searchable (62+ pages total). - Clean single-system circuits trace high/med confidence; bundled/operation diagrams stay conservative; routing/flowchart/block/mechanical are labels-only — no fabrication.
- Non-destructive: source md / scans /
clusters.jsonunchanged; render layer + sidecars only. - Next targets: the workshop-manual electrical sections and Sidekick
wiring-1996. - Open follow-up: a live-browser confirm of the Mermaid render once the Chrome extension is connected.
To scale (the commands)
Per page:
- Vision extraction + fusion using the template
/home/levander/wiring-extract/fuse_pilot.py(subagent). emit.write→ produces<page>.wires.txt(+.wiring.json+.lines).- Reindex that manual/section:
OMP_NUM_THREADS=4 nice /home/levander/kb-vectors/venv/bin/python run.py reindex suzuki-vitara wiring-diagramsRelated
- 2026-07-29-kb-wiring-extraction-design — the design this implements (hybrid CV + vision, trust guards)
- 2026-07-29-kb-wiring-extraction-plan — the task-by-task implementation plan (Task 0 GO/NO-GO spike)
- 2026-07-24-kb-vectorize-complete — the vectorizer whose
chunker.pythis patches; Qdrantmanuals - 2026-07-24-knowledgebase — the source library whose wiring pages are now searchable
- 2026-07-25-kb-consolidated-gen-phase3-complete — the KB generation phase this extends the coverage of
- telep-mainframe — the host (RTX 3080 + 12900K);
ocr/venvhas cv2/skimage/surya - SESSION-HANDOVER
- homelab
- LOG
- TOPICS