Apply the finding engine to schematic and PCB reviews.
FACT, REQUIREMENT, and INFERENCE are separate fields; datasheet provenance lives in the rule DB so Recommended cannot stay ERROR; LLM output is REVIEW. Designer decisions persist across rescans. Schematic and PCB share one library and the same finding object in the report UI.
This commit is contained in:
+48
-207
@@ -1,238 +1,79 @@
|
||||
# Piano — PCB review (esame AI + check deterministici)
|
||||
# Piano — PCB review (esame geometria + stesso motore finding)
|
||||
|
||||
Fonte di verità per **Periscope Layout review**. Non è un auto-placer.
|
||||
Specifica finding: [`motore-finding.md`](motore-finding.md). Schema e PCB usano **lo stesso oggetto**. Questo file è il job layout.
|
||||
|
||||
**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**.
|
||||
**Non** è un auto-placer. PCB-only = geometria (mm, width, copper, via, pour, return stitch, pad-net). Validazione netlist / mux / LED resta schema.
|
||||
|
||||
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:
|
||||
|
||||
Contratto rispetto a [`docs/piano-implementazione.md`](piano-implementazione.md):
|
||||
|
||||
| | Schema (già in produzione) | PCB review (questo piano) | Placement F2 pack (fuori) |
|
||||
| | Schema | PCB review | Placement F2 (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`) |
|
||||
| Promessa | Netlist vs libreria datasheet | Layout vs libreria + geometria | xy nuovi |
|
||||
| Motore finding | FACT / REQUIREMENT / INFERENCE | uguale | — |
|
||||
| Deep exam PDF | **Una volta** → `library/extracted` | Consuma cache, `pdf_path=None` | — |
|
||||
| Job | `MODE=run` | `MODE=pcb` | `MODE=placement` |
|
||||
| Output | `report.json` | `pcb_report.json` (merge in GET /report) | pack json |
|
||||
|
||||
Senza `.kicad_pcb` il progetto resta uno schema completo. Il report schema **non** si riempie di finding layout.
|
||||
Senza `.kicad_pcb` il progetto è schema-completo. Il report schema non si riempie di PE-PLC/PE-SI.
|
||||
|
||||
---
|
||||
|
||||
## 0. Postura: esame AI, non progettazione
|
||||
## Motore (schema + PCB)
|
||||
|
||||
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.
|
||||
Vedi `motore-finding.md`. Invarianti:
|
||||
|
||||
### Domains e functional Groups
|
||||
1. Non mescolare FACT / REQUIREMENT / INFERENCE.
|
||||
2. Provenance **MANDATORY | RECOMMENDED | TYPICAL | EXAMPLE** nel rule DB. **Recommended ≠ ERROR**.
|
||||
3. Classi **RULE | RISK | REVIEW | INFO**. LLM = REVIEW, mai RULE.
|
||||
4. `decisions.json` + fingerprint: rescan non ri-naga (PSEL low intenzionale, ecc.).
|
||||
5. `status`, `confidence`, `evidence_status` indipendenti.
|
||||
6. Evidenza insufficiente → lo si dice, niente 1 oz / 10 °C / 50 Ω / IEC inventati.
|
||||
7. Oggetto riproducibile: facts, requirement, source, calculation, assumptions, confidence, severity, action.
|
||||
|
||||
Obbligatori come contesto dell’esame (non come packing):
|
||||
UI report (schema e layout): stessa `FindingCard` — Fact / Requirement / Inference, badge classe e provenance.
|
||||
|
||||
- **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**.
|
||||
Libreria: `library/extracted/{safe_mpn}.json` ∪ extracted/ progetto. PDF in `library/datasheets/blobs/`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Job parallelo (riuso stack)
|
||||
## Job PCB (invariato nello stack)
|
||||
|
||||
```
|
||||
┌─ MODE=run → status → report.json (schema)
|
||||
Project files ───┼─ MODE=placement → placement_status → placement_plan.json
|
||||
└─ MODE=pcb → pcb_status → pcb_report.json
|
||||
┌─ MODE=run → status → report.json
|
||||
Project files ───┼─ MODE=placement → placement_status → placement_plan.json
|
||||
└─ MODE=pcb → pcb_status → pcb_report.json
|
||||
```
|
||||
|
||||
### Riuso
|
||||
Stages: `ensure_graph` → `parse_pcb` → `classify` → `inventory` → `checks` → `ai_review` (layout vs library, no PDF) → `write_report`.
|
||||
|
||||
| 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 |
|
||||
Mutex vs analisi e vs placement. SSE `pcb_*`. IDs `PCB-{ref}-{001}`. KiCad `/net` vs net schema: **PE-LAY-003** una volta, non per-pad (`kicad_nets_match`).
|
||||
|
||||
### Contratto job
|
||||
### Check PCB (geometria) — gated
|
||||
|
||||
- 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 |
|
||||
| ID | Gate |
|
||||
| --- | --- |
|
||||
| `.kicad_pcb` (`has_pcb`) | Sì |
|
||||
| `design_graph.json` | Sì |
|
||||
| `extracted/` + `layout_rules` / pintable | Per check numerici e AI |
|
||||
| **Shared library** `library/extracted/{safe_mpn}.json` | **Unico** store schema+PCB. Deep exam PDF una volta (pipeline schema). |
|
||||
| PDF datasheet | Solo per estrazione / review **schema**. PCB **non** riattacca il PDF. |
|
||||
| Stackup nel PCB | Per Z0 e ampacity; skip se assente |
|
||||
| PE-LAY-001…003 | pad/ref/hierarchy nets |
|
||||
| PE-PLC-001…004 | `layout_rules` numerici |
|
||||
| PE-SI-001 | `length_match` mm |
|
||||
| PE-DRT-001 | Vop e Vrated |
|
||||
| PE-PWR-001 | I_load + width; IPC solo con thickness e Tjmax |
|
||||
| PE-VIA-001 | via count + I_load (INFO, no tabella inventata) |
|
||||
| PE-THM-001 | P=I_load×drop, courtyard senza pour/via |
|
||||
| PE-KEL-001 | sense/Kelvin pintable + ≥2 altri sul net |
|
||||
| PE-STCH-001 | pour GND + segnale senza via GND nel bbox |
|
||||
| Creepage | **skip** senza numero datasheet/IEC |
|
||||
| Crystal keepout | PE-PLC-004 se kind=keepout |
|
||||
|
||||
AI PCB: skip IC senza pintable (`run schematic review first`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Check (deterministici) + AI
|
||||
## Fasi
|
||||
|
||||
### 3.1 Inventario (non finding)
|
||||
**A — shipped (questa slice):** oggetto finding condiviso, clamp provenance/class, decisions, UI, libreria unica, geometria gated, net-slash.
|
||||
|
||||
Net con rame: lunghezza, layer, width min/max, via, coppia, bus, Z0 se stackup. Domains/groups elencati.
|
||||
**B — pianificata (non finta):** gerarchia component→system; timing; energy/thermal solo con parametri; ratings; derating PASS/MARGIN/RISK; PI; SI oltre skew; return path oltre stitch INFO; ESD/EMI; thermal FEM; BOM↔PCB↔datasheet; SPOF come REVIEW.
|
||||
|
||||
### 3.2 Deterministici
|
||||
**C — fuori:** auto-place, write-back pcbnew, unire i job, sshd/keys.
|
||||
|
||||
| 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 |
|
||||
| `PE-PWR-001` | Larghezza × spessore rame vs I_load | I_load + width; IPC-2221 solo con `copper_thickness_mm` e Tjmax (ΔT=Tjmax−25 °C) |
|
||||
| `PE-VIA-001` | I_load / N via | geometria via + I_load; INFO (niente tabella via inventata) |
|
||||
| `PE-THM-001` | P=I_load×(Vin−Vout) senza pour/via courtyard | I_load, Vin/Vout, courtyard |
|
||||
| `PE-KEL-001` | Pin sense/Kelvin su net di carico | nome pintable + ≥2 altri sul net |
|
||||
| `PE-STCH-001` | Segnale sopra pour GND senza via GND nel bbox | zone GND + segmenti; INFO |
|
||||
| Creepage | — | **skip** senza numero datasheet/IEC |
|
||||
| Crystal keepout | `PE-PLC-004` | `layout_rules` kind=keepout |
|
||||
|
||||
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 (layout-only, shared library)
|
||||
|
||||
Per ogni IC con **pintable in `library/extracted` o extracted/ di progetto** (stesso JSON):
|
||||
|
||||
- **Non** si ri-legge il PDF. L’esame datasheet profondo è quello della pipeline schema.
|
||||
- System prompt **PCB**: layout vs JSON di libreria.
|
||||
- User: `format_library_extraction` + `build_pcb_layout_context`.
|
||||
- `review_ic_async(..., pdf_path=None)` — niente attach, niente quote-verify PDF.
|
||||
- Skip: `no library extraction — run schematic review first`.
|
||||
- Recommendation obbligatoria; isolation per-IC.
|
||||
|
||||
UI: sezione report **PCB exam** (`pcb-exam-section.tsx`) — findings `source=pcb_review` e PE-PWR/THM/VIA/KEL/STCH. Nascosta con `?domain=schema`.
|
||||
|
||||
### 3.4 Skip (no folklore)
|
||||
|
||||
3W, creepage IEC senza numero, CPWG, HV isolation, length-match USB spec, confronto foto TI vs gerber, 1 oz / 10 °C / 50 Ω di default.
|
||||
|
||||
---
|
||||
|
||||
## 4. UI
|
||||
|
||||
| Superficie | Comportamento |
|
||||
| --- | --- |
|
||||
| Hub | **Run PCB review** se `hasPcb` |
|
||||
| `/project/[id]/pcb` | Stepper SSE (include `ai_review`) |
|
||||
| Sidebar | **Layout** → `/pcb` |
|
||||
| Report | Merge + sezione **PCB exam**; `?domain=layout`; badge Layout; 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 libreria 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.
|
||||
|
||||
### Fase 4 — Libreria unica + sezione PCB exam (macro operativa)
|
||||
|
||||
Un store `library/extracted` (più extracted/ di progetto). PCB non duplica l’esame PDF. Sezione report PCB exam + PE-PWR/THM/VIA/KEL/STCH.
|
||||
|
||||
**Done when:** IC senza pintable skipped; con libreria, AI layout-only; check IPC solo con stackup+Tjmax. Deploy.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
Deploy: `ssh periscope` + `/root/periscope/scripts/update-periscope.sh`.
|
||||
|
||||
Reference in New Issue
Block a user