Update PCB review plan: AI exam like schematic, no auto-place.
Adds per-IC LLM review, domains/groups as exam context, required recommendations, and phased job MODE=pcb. Packing stays parked.
This commit is contained in:
+128
-191
@@ -1,72 +1,62 @@
|
||||
# Piano — PCB review (controllo placement + routing)
|
||||
# Piano — PCB review (esame AI + check deterministici)
|
||||
|
||||
Documento **solo di piano**. Non è un implementazione sprint e **non** è un auto-placer.
|
||||
Fonte di verità per **Periscope Layout review**. Non è un auto-placer.
|
||||
|
||||
Prodotto: **Periscope Layout review** — esaminare un board KiCad già sbrogliato (o parzialmente sbrogliato) e dire *dove* placement e routing violano geometria + datasheet.
|
||||
**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 da questo piano) |
|
||||
| | Schema (già in produzione) | PCB review (questo piano) | Placement F2 pack (fuori) |
|
||||
| --- | --- | --- | --- |
|
||||
| Promessa | Lo schema rispetta il datasheet | Il rame e le posizioni **esistenti** rispettano datasheet + geometria | Proporre xy nuovi |
|
||||
| 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 LLM | Finding mm / net / Z0 / skew / via EP, `rule_id` `PE-PLC*` / `PE-SI*` / `PE-LAY*` | `placement_pack.json` proposte |
|
||||
| Job | `MODE=run` (`status`) | Job parallelo `MODE=pcb` (`pcb_status`) | già `MODE=placement` (`placement_status`) |
|
||||
| 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 un Periscope schema **completo**. Il report schema **non** si riempie di `PE-PLC` / `PE-SI`.
|
||||
Senza `.kicad_pcb` il progetto resta uno schema completo. Il report schema **non** si riempie di finding layout.
|
||||
|
||||
---
|
||||
|
||||
## 0. Postura: esame, non progettazione
|
||||
## 0. Postura: esame AI, non progettazione
|
||||
|
||||
### Placement = verifica
|
||||
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.
|
||||
|
||||
Si misura ciò che è **già** sul board:
|
||||
### Domains e functional Groups
|
||||
|
||||
- distanza footprint/pad (euclidea e shortest-path sui segmenti);
|
||||
- layer (F.Cu vs B.Cu) vs `same_layer`;
|
||||
- via nel courtyard del pad termico vs `min_via_count`;
|
||||
- keepout: net estraneo nel courtyard;
|
||||
- crystal: load cap vs pin XIN/XOUT con la stessa metrica.
|
||||
Obbligatori come contesto dell’esame (non come packing):
|
||||
|
||||
Non si spostano footprint. Non si scrive `.kicad_pcb`. Non si usa `placement_pack` / `build_placement_pack` come obiettivo di questo piano.
|
||||
- **Domains** = isole sulle power net (`functional_groups.py` / `placement_plan.json`).
|
||||
- **Groups** = IC + satelliti con `role_hint` (`decoupling`, `bulk`, `filter`, `crystal`, …).
|
||||
|
||||
`placement_check` (`backend/periscopex/placement_check.py`, `PE-PLC-001`…`004`) è già questa postura. Resta il nucleo placement del job PCB.
|
||||
Il job PCB **classifica** (riusa `build_placement_plan`) e passa domains/groups al reviewer e all’inventory. Non propone coordinate.
|
||||
|
||||
La pipeline Placement esistente (`POST …/placement/start`, `placement_plan.json`) è **topologia routing-first** (domini, satelliti, `role_hint`). Utile come contesto (“questo C è decoupling di U1”) ma **non** è auto-placement. F2 packing (`placement_pack.json`, collisioni, export pcbnew) resta **parcheggiato**.
|
||||
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
|
||||
|
||||
Si misura ciò che è **già** in rame:
|
||||
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.
|
||||
|
||||
- lunghezza net / coppia / bus (somma segmenti, non folklore USB);
|
||||
- intra-pair skew vs `layout_rules.kind=length_match` **solo se** c’è un mm nel datasheet (`si_check`, `PE-SI-001`);
|
||||
- Z0 sulle tracce dove stackup + larghezza esistono (`impedance_traces.py` + ImpedanceFinder);
|
||||
- mismatch pad PCB vs pin schema (net name su pad vs `DesignGraph.pin_net`);
|
||||
- elenco tracce / bus per il report (inventario, poi check).
|
||||
### Findings (come parte 1 / schema)
|
||||
|
||||
Non si sbroglia. Non si cambia larghezza. Non si inventano 3W, creepage IEC, o target 50 Ω se il datasheet/stackup non li danno.
|
||||
Ogni finding PCB:
|
||||
|
||||
### Datasheet compliance (layout)
|
||||
- `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
|
||||
|
||||
Solo vincoli **strutturati** già estratti in `ComponentConstraints.layout_rules` (skill C4, `layout_rules.py`):
|
||||
|
||||
| `kind` | Check PCB | Skip se |
|
||||
| --- | --- | --- |
|
||||
| `decoupling_proximity` | distanza / path vs `max_distance_mm`; crystal stesso | `max_distance_mm` null |
|
||||
| `thermal_via` | via in courtyard vs `min_via_count` | courtyard o count assenti |
|
||||
| `keepout` | endpoint net estraneo in courtyard | courtyard assente |
|
||||
| `length_match` | skew coppia vs `max_distance_mm` | mm assente |
|
||||
|
||||
Niente default 3 mm. Niente “foto del layout TI vs gerber”. Citazione: `source_page` sul finding, come oggi.
|
||||
Normalization resta **downgrade-only**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Come sta in parallelo alla pipeline schema
|
||||
|
||||
Oggi i check layout (`placement_check`, `si_check`) girano **dentro** la review schema (`backend/services/validation.py` → `_run_deterministic_checks`) se esiste `layout_graph.json`. Funziona, ma mescola due prodotti nello stesso `report.json` e nello stesso `status`.
|
||||
|
||||
Target:
|
||||
## 1. Job parallelo (riuso stack)
|
||||
|
||||
```
|
||||
┌─ MODE=run → status → report.json (schema)
|
||||
@@ -74,211 +64,158 @@ Target:
|
||||
└─ MODE=pcb → pcb_status → pcb_report.json
|
||||
```
|
||||
|
||||
Stesso pattern job/stage/findings della Placement sibling, **non** un secondo auto-placer.
|
||||
### Riuso
|
||||
|
||||
### Riuso obbligatorio (non reinventare)
|
||||
|
||||
| Pezzo | Path | Ruolo nel job PCB |
|
||||
| Pezzo | Path | Ruolo PCB |
|
||||
| --- | --- | --- |
|
||||
| Workspace / SSE broker | `backend/services/pipeline.py` (`PipelineWorkspace`, `broker`) | Download upload, `layout_graph.json`, eventi |
|
||||
| Job dispatch | `backend/services/job_runner.py`, `backend/pipeline_worker.py` | Nuovo `MODE=pcb` accanto a `run` / `regen` / `placement` |
|
||||
| API sibling | `backend/routers/pipeline.py` (`placement/start|cancel|events`) | `pcb/start`, `pcb/cancel`, `pcb/events` |
|
||||
| Meta progetto | `backend/services/projects.py` (`placement_status*`) | `pcb_status`, `pcb_state`, `pcb_execution_name`, `pcb_cancel_requested` |
|
||||
| Parser board | `backend/periscopex/parsers_kicad_pcb.py` | `LayoutGraph` (footprint, pad net, segmenti, via, zone, stackup) |
|
||||
| Grafo schema | `design_graph.json` / `build_graph(..., pcb_path=)` | Pin↔net; `capacitors_on_net`; CAD index |
|
||||
| Placement verify | `placement_check.py` | PE-PLC-* |
|
||||
| SI verify | `si_check.py` | PE-SI-001 |
|
||||
| BOM/schema | `bom_match_check.py` | Resta **schema**. Sul PCB: analogo **pad-net match** (nuovo check piccolo, stesso schema `Finding`) |
|
||||
| Cad bridge | `cad_bridge.py` (`target: pcb` per `PE-PLC`/`PE-SI`/`PE-LAY`) | Plugin pcbnew focus |
|
||||
| Validation helpers | `assign_finding_ids`, fail-soft per check, `annotate_findings_cad` | IDs + CAD |
|
||||
| Impedenza tracce | `impedance_traces.py`, `routers/impedance.py`, `impedance_nets.json` | Inventario Z0; finding solo se target numerico esiste |
|
||||
| UI | `finding-card`, report filters, `types.ts` / `api.ts`, `pcb-upload.tsx`, pagine/hooks placement come stampo | Tab Layout + findings nel report |
|
||||
| Test | `tests/test_kicad_pcb.py`, `test_placement_check.py`, `test_si_check.py`, `test_placement_pipeline.py` | Fixtures + job smoke |
|
||||
| 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 (come Placement)
|
||||
### Contratto job
|
||||
|
||||
- **Non** tocca `ProjectMeta.status` dell’analisi schema.
|
||||
- Soft-cancel: flag `pcb_cancel_requested` (come `placement_cancel_requested`).
|
||||
- Mutex: non partire se analisi `queued|running` **o** placement `queued|running` **o** pcb già attivo (l’event log è condiviso e Placement fa `clear_history`).
|
||||
- SSE: eventi `pcb_step_update` / `pcb_complete` / `pcb_error` / `pcb_cancelled`. Lo stream schema ignora `pcb_*` (come già ignora `placement_*`).
|
||||
- Locale: `enqueue` con `proc_key=pcb:{id}`, `execution_name=local/pcb/{id}` (stesso trick di `local/placement/`).
|
||||
- Heal zombie: `heal_if_pcb_stuck` speculare a `heal_if_placement_stuck` (evento terminale, o artefatto `pcb_report.json` se il worker è morto dopo la scrittura).
|
||||
- Billing: job **free** (come placement). Nessun LLM in v1.
|
||||
- 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 del job PCB (v1)
|
||||
### Stages
|
||||
|
||||
1. **`ensure_graph`** — riusa `design_graph.json`; se manca, `graph_build` da BOM+netlist (stesso helper Placement). Senza grafo: 400, non inventare connettività dal solo PCB.
|
||||
2. **`parse_pcb`** — riusa `layout_graph.json` o `parse_kicad_pcb(uploads/pcb.kicad_pcb)` e upload. Fail → `pcb_status=error` (a differenza dello schema, qui il PCB è l’ingresso).
|
||||
3. **`inventory`** — lista net con rame, lunghezze, coppie `_DP/_DM` `_P/_N`, bus omonimi, Z0 dove stackup+width ci sono. Artefatto `pcb_inventory.json` (leggibile in UI). Nessun finding da soli numeri.
|
||||
4. **`checks`** — funzioni pure in `periscopex/` (fail-soft per check). Vedi §3.
|
||||
5. **`write_report`** — `pcb_report.json` (`ValidationReport`), cad-bridge merge, IDs `PCB-{designator}-{001}` per non collidere con lo schema.
|
||||
|
||||
Senza datasheet / `layout_rules`: l’inventory c’è comunque; i finding datasheet-gated sono lista vuota, non errore.
|
||||
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 | Dove | Obbligatorio v1 |
|
||||
| --- | --- | --- |
|
||||
| `.kicad_pcb` | `uploads/pcb.kicad_pcb`, `has_pcb` | Sì |
|
||||
| Design graph | `design_graph.json` (da BOM+netlist / KiCad sch flatten) | Sì (per pin↔net e MPN) |
|
||||
| Estrazioni IC | `extracted/` + library | Per `layout_rules` / pintable pin names |
|
||||
| Datasheet PDF | library blobs | Solo per `source_page` in UI; i check v1 sono deterministici |
|
||||
| Stackup nel PCB | `LayoutGraph.stackup` (εr, h, t, layer names) | Per Z0; skip se assente |
|
||||
| `layout_rules` | JSON MPN, `KNOWN_KINDS` | Per PE-PLC / PE-SI; skip se mm/count null |
|
||||
|
||||
Non in v1: Gerber come ingresso, EasyEDA JSON, PADS dump come layout, zip gerarchico PCB (il board non è gerarchico).
|
||||
|
||||
Allineamento net: i nomi net del PCB devono combaciare con lo schema **dopo** flatten gerarchico (`U1.4` ↔ pad). Un mismatch è un finding (`PE-LAY-001`), non un crash.
|
||||
| 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. Cosa elenca e cosa controlla questa stage
|
||||
## 3. Check (deterministici) + AI
|
||||
|
||||
Due uscite distinte: **inventario** (sempre, se il parse riesce) e **findings** (solo regola + numero).
|
||||
### 3.1 Inventario (non finding)
|
||||
|
||||
### 3.1 Inventario (report Layout, non finding)
|
||||
Net con rame: lunghezza, layer, width min/max, via, coppia, bus, Z0 se stackup. Domains/groups elencati.
|
||||
|
||||
Per ogni net con rame:
|
||||
### 3.2 Deterministici
|
||||
|
||||
- nome, `NetType` dallo schema se noto;
|
||||
- lunghezza mm (somma segmenti, come `si_check.net_length_mm`);
|
||||
- layer usati, min/max width, n. via;
|
||||
- coppia differenziale se suffisso noto;
|
||||
- Z0 stimata se stackup+width (riuso `impedance_traces.analyze_where_needed` / `impedance_nets.json`);
|
||||
- appartenenza a bus (prefisso comune: `D[0-7]`, `A[0-15]`, `USB_DP/DM`) — lunghezze affiancate, **senza** soglia inventata.
|
||||
| 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 |
|
||||
|
||||
UI: tabella “Traces / buses” sulla pagina PCB o tab Layout. Serve a *vedere* il board prima dei finding.
|
||||
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.2 Check deterministici (findings, stesso modello `Finding`)
|
||||
### 3.3 AI exam (schema-like)
|
||||
|
||||
Registrati in un unico `run_pcb_checks(graph, constraints_map, layout)` (nuovo wrapper sottile; **non** SDK LLM in `periscopex/`).
|
||||
Per ogni IC con PDF:
|
||||
|
||||
| ID | Source | Cosa | Gate |
|
||||
| --- | --- | --- | --- |
|
||||
| `PE-LAY-001` | nuovo `pcb_net_match` (specchio di `bom_match_check`) | Pad net ≠ pin net schema, stesso ref+pin | Pad ha `net` e lo schema ha `pin_net` |
|
||||
| `PE-LAY-002` | stesso modulo | Ref in schema senza footprint PCB (o viceversa, skip `#PWR`) | Graph + footprints |
|
||||
| `PE-PLC-001` | `placement_check` | Decoupling / crystal oltre `max_distance_mm` (path se esiste, senno euclidea) | regola + mm |
|
||||
| `PE-PLC-002` | idem | Via termiche < `min_via_count` | courtyard + count |
|
||||
| `PE-PLC-003` | idem | `same_layer: true` e cap sull’altro lato senza via sotto il pin | boolean regola + layer footprint |
|
||||
| `PE-PLC-004` | idem | Keepout: net estraneo in courtyard | courtyard |
|
||||
| `PE-SI-001` | `si_check` | Intra-pair skew > `length_match` mm | coppia nominale **e** mm datasheet |
|
||||
| `PE-Z0-001` (fase 2) | da `impedance_traces` | Z0 fuori target | target in `layout_rules` **o** netclass KiCad esplicita; mai 50 Ω di default |
|
||||
- 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.
|
||||
|
||||
Campi finding (già sul modello): `rule_id`, `net`, `pins[]`, `source`, `cad_sheet` / `cad_uuid` se in `cad_index`, `status` ERROR/WARNING, `source_page` dalla regola.
|
||||
### 3.4 Skip (no folklore)
|
||||
|
||||
Normalization: **downgrade-only** se un giorno si aggiunge un pass; v1 non alza severità.
|
||||
|
||||
### 3.3 Fuori dai finding (skip esplicito, log)
|
||||
|
||||
- 3W / crosstalk senza distanza datasheet o calcolatore.
|
||||
- Creepage/clearance IEC 62368 senza V/mm nel datasheet.
|
||||
- Isolation barrier / HV courtyard senza keepout HV.
|
||||
- CPWG se il vendor ImpedanceFinder non lo dà.
|
||||
- Length-match “USB spec” / 150 mil folklore.
|
||||
- Confronto visivo application-circuit vs PCB.
|
||||
|
||||
Queste restano Wave G residue in `piano-implementazione.md`, non questo job.
|
||||
3W, creepage IEC, CPWG, HV isolation, length-match USB spec, confronto foto TI vs gerber.
|
||||
|
||||
---
|
||||
|
||||
## 4. UI
|
||||
|
||||
Gating: `hasPcb`. Senza PCB, nessun bottone “Run PCB review”, nessun finding layout nel report schema.
|
||||
|
||||
| Superficie | Comportamento |
|
||||
| --- | --- |
|
||||
| Project hub | Accanto a “Build placement plan”: **Run PCB review** (verify). Upload già `PcbUploadButton`. |
|
||||
| `/project/[id]/pcb` | Stampo di `/placement`: stepper SSE (`ensure_graph` → `parse_pcb` → `inventory` → `checks` → `write_report`), cancel, errore, link al report. |
|
||||
| Sidebar | Voce **Layout** (`/pcb` o `report?domain=layout`). Nested route = `forceDocument` come placement. |
|
||||
| Report | `GET /report/{id}` **merge** `report.json` + `pcb_report.json`. Filtro URL `?domain=schema\|layout\|all`. Finding card: badge “Layout” + `rule_id` (`PE-PLC-001`) oltre “Automated check”. |
|
||||
| Inventory | Tabella tracce/bus/Z0 sulla pagina PCB (dati `pcb_inventory.json` / `impedance_nets.json`). |
|
||||
| Plugin | `periscope-findings.json` include finding `target: pcb` dopo il job PCB (cad-bridge già distingue prefissi). |
|
||||
|
||||
Commenti / review_states restano keyed by `finding_id` su `report.json` (o dict parallelo); il merge in GET non deve perdere commenti schema. IDs prefissati `PCB-` evitano collisioni `U3-001`.
|
||||
|
||||
Re-run schema **non** cancella `pcb_report.json`. Re-run PCB **non** tocca findings LLM.
|
||||
| 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
|
||||
## 5. Fasi di implementazione
|
||||
|
||||
Ordine: non parallelizzare con auto-pack. Non mischiare changelog Core vs Layout.
|
||||
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 — Confine (doc + split)
|
||||
### Fase 0 — Split schema / layout
|
||||
|
||||
- Questo documento = contratto.
|
||||
- Togliere `placement_check` / `si_check` da `_run_deterministic_checks` della review schema (restano no-op senza layout; lo split evita PE-PLC nello schema).
|
||||
- Eval harness schema (`eval_report.py`) continua a chiamarli con `layout=None` (no-op) **oppure** li sposta in eval PCB dedicato.
|
||||
Togliere `placement_check` / `si_check` da `_run_deterministic_checks` schema. Eval schema: `layout=None` resta no-op.
|
||||
|
||||
**Done when:** run schema senza PCB = zero `PE-PLC`/`PE-SI` nel report.
|
||||
**Done when:** schema senza PCB = zero `PE-PLC`/`PE-SI`.
|
||||
|
||||
### Fase 1 — Job parallelo + inventory + check già esistenti (slice usabile)
|
||||
### Fase 1 — Job + deterministici + UI (macro operativa)
|
||||
|
||||
- Meta `pcb_*`, `enqueue` `MODE=pcb`, router start/cancel/events, worker.
|
||||
- Stages §1; artefatti `layout_graph.json`, `pcb_inventory.json`, `pcb_report.json`.
|
||||
- Check: `pcb_net_match` + `check_placement` + `check_si`.
|
||||
- UI: start, progress, merge findings nel report, filtro Layout, `rule_id` sulla card.
|
||||
- Test: wrapper `run_pcb_checks` su fixture (decoupling 15 mm → `PE-PLC-001`; 1 mm → niente); pad net mismatch → `PE-LAY-001`; job busy helpers come `test_placement_pipeline.py`; pytest API start 400 senza PCB.
|
||||
Meta `pcb_*`, worker, router, `run_pcb_checks`, inventory, report merge, UI start/progress/filtro.
|
||||
|
||||
**Done when:** upload `.kicad_pcb` → start PCB → finding visibili nel report; schema invariato.
|
||||
**Done when:** upload PCB → start → finding nel report. Deploy.
|
||||
|
||||
### Fase 2 — Inventario ricco (tracce, bus, Z0)
|
||||
### Fase 2 — AI exam + domains/groups (macro operativa)
|
||||
|
||||
- Tabella lunghezze + coppie + bus.
|
||||
- Z0 per net signal con stackup (già `impedance_traces`); finding `PE-Z0-001` **solo** con target numerico (regola o netclass).
|
||||
- Collegare `impedance_nets.json` al job PCB (oggi è side-effect dello schema `graph_build`).
|
||||
`classify` + `ai_review` per-IC, prompt PCB, recommendation obbligatoria, changelog Layout.
|
||||
|
||||
**Done when:** board con stackup mostra Z0 in UI; senza stackup, skip loggato, zero finding inventati.
|
||||
**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 dopo `write_report`; click finding centra footprint in pcbnew (`plugins/kicad/periscope_plugin.py`).
|
||||
- Golden keys su fixture (USB skew voluta → `PE-SI-001`; simple_project senza PCB → vuoto).
|
||||
- Changelog Layout (voce distinta, non “un po’ di Periscope in più”).
|
||||
|
||||
### Fase 4 — Non fare (parcheggio)
|
||||
|
||||
- `placement_pack` / collisioni courtyard / export xy / muovere rame.
|
||||
- Auto-place antenna in `.kicad_pcb`.
|
||||
- 3W, creepage IEC, CPWG, isolation HV senza numero.
|
||||
- LLM che “legge” il layout come review schema.
|
||||
- Secondo ingresso Gerber/EasyEDA.
|
||||
Cad-bridge pcbnew; golden fixture. Packing resta fuori.
|
||||
|
||||
---
|
||||
|
||||
## 6. Fuori scope (esplicito)
|
||||
## 6. Fuori scope
|
||||
|
||||
- Auto-placement, packing mm, write-back pcbnew, “migliora il floorplan”.
|
||||
- Autore di sbroglio / change width / length-tune.
|
||||
- Simulazione SPICE / IBIS / EM / VSWR.
|
||||
- Inventare millimetri, Ω, o V/mm.
|
||||
- Plugin EasyEDA; parser JSON EasyEDA.
|
||||
- Layout da `!PADS-POWERPCB`.
|
||||
- Unire forzatamente job PCB nella run schema.
|
||||
- Toccare ssh / keys / `sshd` (irrilevante a questo piano).
|
||||
- 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. Come si misura il “done”
|
||||
## 7. Done (fixture)
|
||||
|
||||
Fixture minima (non un USB inventato in produzione, ma un `.kicad_pcb` di test in `tests/`):
|
||||
|
||||
1. C di decoupling a 15 mm da VDD con regola 2 mm → `PE-PLC-001`.
|
||||
2. Stesso C a 1 mm → nessun finding proximity.
|
||||
3. Coppia `USB_DP`/`USB_DM` con skew > `length_match` → `PE-SI-001`.
|
||||
4. Pad `U1.1` net `+3V3` vs schema `GND` → `PE-LAY-001`.
|
||||
5. Progetto senza PCB: job PCB rifiutato; report schema pulito.
|
||||
|
||||
Niente LLM. Niente coordinate proposte.
|
||||
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 col piano esistente
|
||||
## 8. Relazione
|
||||
|
||||
`piano-implementazione.md` Wave G (G0 ingest, G1 SI gated, G2 placement vs datasheet) è **questo** prodotto, riletto come job parallelo di **esame**.
|
||||
|
||||
La roadmap Placement F2 (pack v1/v2/export) **non** entra in queste fasi. `placement_check` resta verifica; `placement_pack` resta skeleton gated e non si estende qui.
|
||||
|
||||
Chats Cursor precedenti: nessuna decisione di “PCB error pipeline” come job; solo note RF (“auto-place rame nel PCB = dopo”). Questo piano è la decisione: **review**, non place.
|
||||
Wave G di `piano-implementazione.md` = questo job di **esame** (ora anche LLM). F2 pack non entra.
|
||||
|
||||
Reference in New Issue
Block a user