# Criteri Rust — Periscope Percorso locale: `/Users/michelebigi/Development/periscope/docs/rust-criteri.md`. Costituzione: Python è il default. Rust **non** è un default. Questo documento dice *quando* un pezzo può entrare in Rust. Non sceglie ancora un pezzo. **Niente `rustup`, crate, né FFI finché una riga sotto non è scelta *e* misurata.** FEM / OpenEMS / field solver: fuori dal prodotto. Non sono candidati Rust. DRC: KiCad. Non è un candidato Rust in Periscope. ## Non solo velocità Un bottleneck di CPU non basta. Un pezzo va in Rust solo se **tutti** i punti seguenti sono veri. 1. **Correttezza geometrica** — pad ≠ via ≠ traccia ≠ zona deve sopravvivere al confine. Se Rust collassa oggetti per “è più facile in un AABB”, il pezzo è rifiutato anche se è più veloce. 2. **Memoria / ownership** — pressione reale (PCB grandi, segmenti, zone) o lifetime che Python non può possedere senza copie cieche. Non “magari un giorno”. 3. **Parser o hot path** — il costo sta in un ciclo stretto (parse `.kicad_pcb`, walk segmenti, predicate geometriche) dopo profiling. Non nell’orchestrazione, non nell’I/O HTTP, non nell’LLM. 4. **Determinismo** — stessa input + config → stesso modello e stessi numeri. Niente hash random, niente ordine di hash map visibile nei finding, niente dipendenza dall’LLM. 5. **Confine Python grosso** — una chiamata: struct in → struct out. Vietato un round-trip per pad, per via, per “is_point_in_poly” dal loop Python. Se manca anche uno solo di questi, il pezzo resta in Python. ## Sequenza obbligatoria (costituzione §§33–36) ```text implementazione corretta in Python ↓ misura (wall + allocazioni, board reale: HubAudio / Emmaforo) ↓ profiling (il hot path ha un nome di funzione) ↓ scelta esplicita del pezzo in questo file ↓ Rust con confine grosso ↓ benchmark sulla stessa board ↓ accetta / rifiuta sui numeri e sulla semantica (via resta via) ``` Finché la riga “Pezzo scelto” sotto è vuota: **nessun rustup**. ## Cosa non va in Rust | Area | Perché | | --- | --- | | Pipeline, job, SSE, FastAPI | orchestrazione | | Estrazione datasheet, skills, LLM | I/O + modello | | Review AI, normalize, dedup | non deterministico in autorità | | Project CRUD, storage, report JSON | I/O | | Frontend | altro runtime | | Auth / JWT / users | fuori perimetro; non toccare | | FEM, OpenEMS, ampacity IPC via, DRC | non è Periscope | | ImpedenceFinder venduto | già un core chiuso; non riscrivere “per Rust” | | Un check `PE-*` isolato | il check è regola + evidenza; il costo è il parser/geometria a monte | ## Candidati *solo dopo misura* (nessuno scelto) Questi sono i posti dove un profilo *potrebbe* mostrare un hot path. Non sono un piano di porting. - Parser `.kicad_pcb` (`parsers_kicad_pcb.py`) se il wall su HubAudio è il parse, non i check. - Predicate geometriche usate da stub / zone / courtyard (track graph, point-in-poly) se il walk segmenti domina. - Walk grafo net→pin su BOM grandi, se misurato. Non candidati: `run_pcb_checks` come god-object Rust; “tutto il core”; Z inventata più veloce. ## Pezzo scelto Nessuno. Nessuna misura registrata in questo file. Quindi: niente toolchain Rust in questa macro-fase. ## Come registrare una scelta (futuro) Quando una misura esiste, aggiungere qui: ```text Pezzo: Board: Python wall: alloc: Hot path: Ipotesi Rust: correttezza geometrica | memoria | parser | determinismo | confine Benchmark dopo: e test via≠pad ancora verdi Decisione: accetta | rifiuta ```