# Piano — PCB review (esame AI + check deterministici) Fonte di verità per **Periscope Layout review**. Non è un auto-placer. **Delta vs revisione precedente:** l’esame del board è **agentico come la pipeline schema** (datasheet + neighborhood + tool, findings ERROR/WARNING/INFO con **sempre** una `recommendation`). Restano i check numerici gated. Auto-placement / pack / write-back pcbnew restano **fuori**. Prodotto: esaminare un `.kicad_pcb` già (parzialmente) sbrogliato — placement, routing, impedenze, lunghezze, decoupling, filtri, derating, compliance datasheet — e dire *cosa è sbagliato e come sistemarlo*. Non si spostano footprint e non si scrive rame. Contratto rispetto a [`docs/piano-implementazione.md`](piano-implementazione.md): | | Schema (già in produzione) | PCB review (questo piano) | Placement F2 pack (fuori) | | --- | --- | --- | --- | | Promessa | Lo schema rispetta il datasheet | Il **layout esistente** rispetta datasheet + geometria | Proporre xy nuovi | | Metodo | Check deterministici + **review LLM per-IC** | Stesso spirito: check + **review LLM per-IC sul PCB** | Skeleton `placement_pack.json` | | Trigger | BOM + netlist / `.kicad_sch` | + `.kicad_pcb` | PCB + `layout_rules` numerici | | Output | Finding pin/net, derating, review | Finding mm / net / Z0 / skew / via EP / layout AI; `PE-PLC*` `PE-SI*` `PE-LAY*` `PE-Z0*` | Proposte xy | | Job | `MODE=run` (`status`) | `MODE=pcb` (`pcb_status`) | `MODE=placement` (`placement_status`) | Senza `.kicad_pcb` il progetto resta uno schema completo. Il report schema **non** si riempie di finding layout. --- ## 0. Postura: esame AI, non progettazione Stesso spirito della Direct Datasheet Review: il modello legge datasheet + contesto del circuito **e** geometria del footprint/net, usa tool sul grafo, sottomette finding. Non progetta il board. ### Domains e functional Groups Obbligatori come contesto dell’esame (non come packing): - **Domains** = isole sulle power net (`functional_groups.py` / `placement_plan.json`). - **Groups** = IC + satelliti con `role_hint` (`decoupling`, `bulk`, `filter`, `crystal`, …). Il job PCB **classifica** (riusa `build_placement_plan`) e passa domains/groups al reviewer e all’inventory. Non propone coordinate. La pipeline Placement (`POST …/placement/start`) resta topologia routing-first. F2 pack/export **parcheggiati**. ### Placement = verifica (deterministico + AI) Misura ciò che è **già** sul board: distanza pad-cap, layer, via EP, keepout, crystal load caps. `placement_check` (`PE-PLC-001`…`004`) è il nucleo numerico. L’AI copre note di layout del datasheet **senza mm strutturato** (citazione + `Unverified:` se la quote non verifica), sempre con recommendation. ### Routing = la stessa postura Lunghezze, coppie, bus, Z0, pad-net vs schema. `si_check` (`PE-SI-001`) solo con `length_match` mm. L’AI può flaggare crossing/loop evidenti **solo** se il contesto geometria lo mostra; niente 3W/IEC inventati. ### Findings (come parte 1 / schema) Ogni finding PCB: - `status`: **ERROR** | **WARNING** | **INFO** - `recommendation` **obbligatoria** anche per INFO (cosa fare: spostare, allungare/accorciare, cambiare rating, verificare stackup, …) - `rule_id` sui check automatici; review AI: `source=pcb_review` - IDs `PCB-{designator}-{001}` per non collidere con lo schema Normalization resta **downgrade-only**. --- ## 1. Job parallelo (riuso stack) ``` ┌─ MODE=run → status → report.json (schema) Project files ───┼─ MODE=placement → placement_status → placement_plan.json └─ MODE=pcb → pcb_status → pcb_report.json ``` ### Riuso | Pezzo | Path | Ruolo PCB | | --- | --- | --- | | Workspace / SSE | `pipeline.py` | `PipelineWorkspace`, broker | | Dispatch | `job_runner.py`, `pipeline_worker.py` | `MODE=pcb` | | API | `routers/pipeline.py` | `pcb/start`, `cancel`, `events`, inventory | | Meta | `projects.py` | `pcb_status`, `pcb_state`, `pcb_execution_name`, `pcb_cancel_requested` | | Parser | `parsers_kicad_pcb.py` | `LayoutGraph` | | Groups | `functional_groups.py` | domains + groups | | Placement | `placement_check.py` | PE-PLC-* | | SI | `si_check.py` | PE-SI-001 | | Filtri | `filter_check.py` | contesto; proximity solo con mm | | Derating | `derating.py` | Vop vs Vrated se entrambi noti | | Impedenza | `impedance_traces.py` | inventory Z0; finding se target numerico | | Review LLM | `services/validation.py` + prompt PCB | per-IC, stesso loop tool/`submit_review` | | Cad bridge | `cad_bridge.py` | `target: pcb` | | UI | report `finding-card`, sidebar, `types.ts`, `api.ts` | tab Layout, merge findings | ### Contratto job - Non tocca `status` schema. - Soft-cancel `pcb_cancel_requested`. - Mutex vs analisi e vs placement (event log condiviso). - SSE `pcb_step_update` / `pcb_complete` / `pcb_error` / `pcb_cancelled`. - Locale: `local/pcb/{id}`. - Heal zombie come placement. - LLM: stesso provider DeepSeek della review schema; `ApiLogger` stage `pcb_review`; billing via `get_billing()` (NullBilling in OSS). - Senza API key in test: skip AI, check deterministici restano. ### Stages 1. `ensure_graph` — `design_graph.json` o graph_build. 2. `parse_pcb` — `layout_graph.json` / `parse_kicad_pcb`. Fail → error. 3. `classify` — domains + groups (`build_placement_plan`); scrive `functional_groups.json` se manca. 4. `inventory` — tracce, bus, lunghezze, Z0 → `pcb_inventory.json`. 5. `checks` — deterministici fail-soft (`run_pcb_checks`). 6. `ai_review` — per-IC come schema, contesto layout + group/domain + inventory del vicinato. 7. `write_report` — `pcb_report.json`, cad-bridge, IDs `PCB-*`. --- ## 2. Ingressi | Ingresso | Obbligatorio v1 | | --- | --- | | `.kicad_pcb` (`has_pcb`) | Sì | | `design_graph.json` | Sì | | `extracted/` + `layout_rules` / pintable | Per check numerici e AI | | PDF datasheet | Per AI (skip IC senza PDF, come schema) | | Stackup nel PCB | Per Z0; skip se assente | --- ## 3. Check (deterministici) + AI ### 3.1 Inventario (non finding) Net con rame: lunghezza, layer, width min/max, via, coppia, bus, Z0 se stackup. Domains/groups elencati. ### 3.2 Deterministici | ID | Cosa | Gate | | --- | --- | --- | | `PE-LAY-001` | Pad net ≠ pin net schema | entrambi noti | | `PE-LAY-002` | Ref schema senza footprint (skip `#PWR`) | graph + PCB | | `PE-PLC-001`…`004` | decoupling / via / same_layer / keepout | `layout_rules` numerici | | `PE-SI-001` | skew coppia | `length_match` mm | | `PE-DRT-001` | Vop > Vrated sul cap (derating.py) | entrambe le tensioni | | `PE-Z0-001` | Z0 fuori target | target in regola o netclass; mai 50 Ω default | Filtri: `check_filters` **non** duplicato nel report PCB (resta schema). L’AI e i groups usano `role_hint=filter` per proximity se c’è mm. ### 3.3 AI exam (schema-like) Per ogni IC con PDF: - System prompt **PCB** (placement, routing, decoupling, filtri, lunghezze, Z0, compliance layout). - User: `build_component_context` + blocco layout (xy, satelliti del group, lunghezze net, domains). - Stessi graph tools + `submit_review`. - Quote verify. Recommendation obbligatoria su ogni finding. - Isolamento per-IC; skip senza PDF. ### 3.4 Skip (no folklore) 3W, creepage IEC, CPWG, HV isolation, length-match USB spec, confronto foto TI vs gerber. --- ## 4. UI | Superficie | Comportamento | | --- | --- | | Hub | **Run PCB review** se `hasPcb` | | `/project/[id]/pcb` | Stepper SSE (include `ai_review`) | | Sidebar | **Layout** → `/pcb` | | Report | Merge `report.json` + `pcb_report.json`; `?domain=layout`; badge Layout + `rule_id`; recommendation sempre visibile | | Inventory | Traces/buses/Z0 + domains/groups | --- ## 5. Fasi di implementazione Dopo **ogni** fase: test delle funzioni toccate, commit, push. Dopo ogni macro-fase operativa: deploy `ssh periscope` + `scripts/update-periscope.sh` (niente chiavi/sshd). ### Fase 0 — Split schema / layout Togliere `placement_check` / `si_check` da `_run_deterministic_checks` schema. Eval schema: `layout=None` resta no-op. **Done when:** schema senza PCB = zero `PE-PLC`/`PE-SI`. ### Fase 1 — Job + deterministici + UI (macro operativa) Meta `pcb_*`, worker, router, `run_pcb_checks`, inventory, report merge, UI start/progress/filtro. **Done when:** upload PCB → start → finding nel report. Deploy. ### Fase 2 — AI exam + domains/groups (macro operativa) `classify` + `ai_review` per-IC, prompt PCB, recommendation obbligatoria, changelog Layout. **Done when:** con API key, IC con PDF producono finding `source=pcb_review` o coverage vuota; senza key, skip loggato. Deploy. ### Fase 3 — Plugin + eval PCB Cad-bridge pcbnew; golden fixture. Packing resta fuori. --- ## 6. Fuori scope - Auto-placement, packing mm, write-back pcbnew. - Autore di sbroglio / change width. - SPICE / IBIS / EM. - Inventare mm, Ω, V/mm. - EasyEDA, Gerber come ingresso, PADS layout. - Unire il job PCB nella run schema. - Toccare ssh keys / `sshd`. --- ## 7. Done (fixture) 1. Decoupling 15 mm vs regola 2 mm → `PE-PLC-001` + recommendation. 2. 1 mm → niente proximity. 3. Skew coppia > `length_match` → `PE-SI-001`. 4. Pad net mismatch → `PE-LAY-001`. 5. Senza PCB → 400 sul start. 6. AI: contesto contiene domain/group; finding senza recommendation rifiutati/completati dal parser. --- ## 8. Relazione Wave G di `piano-implementazione.md` = questo job di **esame** (ora anche LLM). F2 pack non entra.