Replace Faradworks Inc. TOS/privacy/contact/metadata with Michele Bigi. Dual-read pinscope_* keys; write periscope_* only. AGPL LICENSE and GitHub fork parent unchanged. validate.py not edited.
18 KiB
Piano — indipendenza architettonica e di licenza da PinScope
Stato: solo piano. Nessuna modifica a source di prodotto, remotes, LICENSE, né git history.
Base: PINSCOPE_AUDIT.md (snapshot prodotto facbaa2 / cursor/pcb-review-plan-44dd).
Intento di Michele: lasciare il codice PinScope e le sue licenze; isolare l’albero ereditato; disegnare dipendenze; marcare cosa deve essere riscritto. Non cancellare ogni riga ereditata.
Questo piano non stacca il fork GitHub (manvalan/periscope ← Faradworks/Pinscope). Lo stacco è un passo legale successivo, fuori da queste fasi di lavoro, salvo decisione esplicita.
1. Obiettivo
Due indipendenze distinte, nello stesso prodotto:
| Asse | Cosa significa | Cosa non significa |
|---|---|---|
| Architetturale | Periscope evolve identity, auth, LLM, contratto finding, job PCB/placement senza fingere di essere Faradworks/Pinscope e senza che il nuovo codice importi il loop PinScope come se fosse “nostro” | Cancellare graph.py, i parser, o il 79% di linee lineage |
| Licenza / identità | Operatore, TOS, privacy, metadata, vendor terzi con licenza nota; AGPL del fork resta visibile e attribuita | Relicenziare l’albero PinScope, togliere AGPL, o chiedere a Faradworks una licenza commerciale come se fossimo noi l’upstream |
Criterio di fatto: un modulo è “nativo Periscope” se può cambiare contratto (finding, PCB, auth locale, DeepSeek) senza patchare il recinto PinScope. Un modulo è “ereditato” se un git blame/Jaccard da audit lo lega a pinscopex / UI OSS Faradworks.
L’audit già dice: l’indipendenza non è bloccata dalle stringhe pinscope; è bloccata da pipeline, identità legale, main stantio, seam Clerk/Anthropic, ImpedenceFinder senza licenza.
2. Confine di isolamento (fence)
2.1 Recinto — albero ereditato (resta, non si “ripulisce”)
Trattare come una dipendenza in-tree, non come prodotto Periscope:
| Pacchetto logico | Path odierni | Licenza da audit |
|---|---|---|
| Core schematico PinScope | backend/periscopex/{graph,models,parsers,parsers_edif,validate,validation_tools,resolve_passives,derating,bom_summary,taxonomy,pin_mux_check,led_current_check,pin_function_tokens}.py |
AGPL-3.0 del fork (blob LICENSE identico a upstream) |
| Orchestrazione review | backend/services/pipeline.py, pipeline_worker.py, services/validation.py, services/extraction.py (parte DIRECT) |
stessa |
| Skills Anthropic/Console | skills/extract-pattern, skills/extract-specs, skills/extract-pintable/{schema.json,validate.py}, scripts/upload_skills.py, backend/skills_manifest.json |
stessa + contratto Claude |
| UI OSS / marketing shell | gran parte di frontend/src UPSTREAM/DERIVED, frontend/public, frontend/content/terms.md + privacy.md (testo Faradworks) |
AGPL + TOS Faradworks nel contenuto |
| Gateway seams | billing_hook.py, proxy.ts, clerk-theme-provider.tsx, use-optional-auth.ts, analytics, CSP hosts |
stub open-core PinScope |
| Fixture upstream | simple_project/ (asc/csv/pdf/design_graph.json), docs/how-it-works.svg |
AGPL / contenuto upstream |
Regola del recinto (quando si implementerà, non ora):
- Import solo da una facciata stretta (es.
build_graph,parse_bom,parse_netlist_any,FindingPydantic,validate_design_async). - Nessun nuovo check PCB/schema scrive dentro
validate.py. - Nessun file nativo assume Clerk, Anthropic Console,
pinscope.ai, Faradworks Inc. - Il recinto conserva
LICENSEAGPL e l’attribuzione “derived from Faradworks/Pinscope”.
Implementazione fisica futura (non in fase identità): directory tipo vendor/pinscope/ oppure package backend/pinscope_legacy/ con shim periscopex — solo dopo che i consumer nativi non importano più path sparsi. Non è un rename cosmetico (pinscopex → periscopex è già successo e non è un recinto).
2.2 Nativo Periscope (fuori recinto)
| Area | Path | Perché è nativo |
|---|---|---|
| Contratto finding | finding_engine.py, docs/motore-finding.md |
NEW; clamp FACT/REQUIREMENT/INFERENCE |
| PCB exam | pcb_pipeline.py, pcb_*.py, parsers_kicad_pcb.py, UI pcb/ |
NEW; INDIRECT sul grafo |
| Placement F2 | placement_pipeline.py, placement_pack.py, functional_groups.py |
NEW |
| RF / antenna | antenna_*.py, parte Impedance UI |
NEW |
| Facade Z0 | periscopex/impedance.py |
NEW; il solver è terzi |
| Auth self-host | local_jwt.py, local_users.py, routers/auth.py |
REPLACEMENT |
| LLM DeepSeek | deepseek_provider.py, local_skill.py, pdf_ingest.py |
NEW |
| Deploy | scripts/update-periscope.sh, docker-compose.yml |
NEW (nomi pinscope_* ancora WEAK) |
| Plugin KiCad | plugins/kicad/ |
NEW |
| Check deterministici fork | dnp_check, sequencing_check, layout_rules, … |
NEW ma INDIRECT: usano models / graph |
2.3 Terzi (né PinScope né “nostro motore”)
vendor/impedancefinder/ — commit a0c8d0ec, licenza UNKNOWN (audit §6.4). Resta dietro impedance.py + vendor_path.py. Non mescolare con AGPL PinScope né con il finding engine.
3. Albero delle dipendenze
Forza: DIRECT = stesso control flow / blob lineage PinScope; INDIRECT = codice nativo che importa DIRECT; WEAK = alias, brand, reti Docker.
Faradworks/Pinscope (AGPL-3.0)
│
├─ DIRECT periscopex.graph / parsers* / taxonomy / models
│ ├─ INDIRECT pipeline MODE=run (Parse → extract → build_graph → review)
│ ├─ INDIRECT pcb_pipeline.ensure_graph + pintable cache
│ ├─ INDIRECT placement / functional_groups
│ └─ INDIRECT cad_bridge, parsers_kicad*, pcb_inventory
│
├─ DIRECT validate.py + validation_tools + extraction skills
│ ├─ INDIRECT finding_engine.complete_findings (graft, non sostituisce il loop)
│ ├─ INDIRECT pcb AI (_parse_review)
│ └─ WEAK anthropic SDK, upload_skills.py, CLAUDE.md Console
│
├─ DIRECT models.Finding + normalize_findings + dedupe_findings
│ └─ INDIRECT finding_engine (PE-*, provenance clamp) + FindingCard
│
├─ DIRECT Next.js app (wizard, report, admin, legal pages)
│ ├─ INDIRECT pcb-exam-section, impedance-panel, topology-panel, local sign-in
│ └─ WEAK Faradworks metadata, pinscopex localStorage, ClerkThemeProvider
│
├─ DIRECT Clerk / billing_hook seams
│ └─ INDIRECT local JWT (parallel stack, non ha spento Clerk)
│
└─ (non PinScope) vendor/impedancefinder
└─ INDIRECT periscopex.impedance → tab RF
3.1 Consumer Periscope × sottosistema PinScope
| Sottosistema PinScope | Consumer Periscope | Forza | Se si riscrive il PinScope… |
|---|---|---|---|
| Graph + parsers BOM/netlist | pipeline.py, PCB, placement, tutti i check |
DIRECT / INDIRECT | Cade tutto il prodotto |
validate.py review loop |
report schema, PCB AI | DIRECT | Serve un reviewer nativo prima di spegnere PinScope |
Finding Pydantic |
finding_engine, UI card, cad-bridge |
DIRECT | Mappare al contratto motore-finding.md |
| Skills pintable/pattern/specs | extraction, library | DIRECT | Già in parte sostituiti da local_skill.py |
| UI shell | ogni pagina | DIRECT | Identità e finding card prima; wizard dopo |
| Clerk/billing | main.py, admin, email |
DIRECT + WEAK | Auth locale già c’è |
| Legal Faradworks | /terms /privacy layout |
DIRECT contenuto | Non è codice motore |
Cosa deve essere riscritto (per indipendenza vera, fasi tarde — non per “pulizia”):
- Identità legale/UI — obbligatorio e primo; non è il motore.
- Seam Clerk + Anthropic — obbligatorio per non dipendere dal cloud Faradworks.
- Loop
validate.py/_parse_review/ tool graph — obbligatorio per un motore Periscope, dopo identità; oggifinding_engineè solo un clamp. - IR
Finding— allineare il tipo Pydantic al contratto FACT/REQUIREMENT/INFERENCE (oggi campi doppifinding/why). - UI report/wizard — quando il contratto finding è nativo; non nella fase identità.
- Parsers/graph — non obbligatori per identità; rewrite solo se si vuole un CAD layer Periscope senza AGPL PinScope (programma XL, ultimo).
4. Mappa licenze — cosa blocca una licenza Periscope “pulita”
“Pulita” = Periscope come opera dell’operatore Michele, con dipendenze dichiarate, non “Periscope senza AGPL”. L’albero PinScope resta AGPL; toglierlo richiederebbe rewrite totale del recinto (fase ultima) e comunque rispetto dei diritti sul codice già pubblicato.
| Pezzo | Evidenza audit | Blocca identità Periscope? | Blocca relicenza non-AGPL del binario combinato? |
|---|---|---|---|
LICENSE AGPL-3.0 identico a upstream |
KEEP | No, se attribuito | Sì, finché il recinto è nel tree/servizio |
TOS/privacy Faradworks, Inc. + dev@faradworks.com |
REPLACE | Sì (operatore sbagliato) | No (non è la GPL) |
Metadata layout.tsx authors/publisher Faradworks, @getFaradWorks |
REPLACE | Sì | No |
| README “commercial licensing of the original → Faradworks” | tenere come attribuzione upstream, non come offerta nostra | Parziale | No |
Fork GitHub ancora parent: Faradworks/Pinscope |
non staccare in questo piano | No (fatto) | No |
anthropic in requirements.txt + upload_skills.py |
ISOLATE | Policy prodotto / ToS Anthropic vs DeepSeek | No |
| Clerk JWKS / API | ISOLATE | ToS Clerk se usato in prod | No |
ImpedenceFinder license: null, no LICENSE file |
INVESTIGATE | Distribuzione RF tab | Sì per quel vendor (sconosciuta) |
| PyMuPDF dual AGPL or Artifex commercial | INVESTIGATE | Quale grant in VPS | AGPL già dal root; commerciale Artifex è altro contratto |
| Transitive Python | no lockfile | Audit incompleto | Possibile gap |
| npm MPL/LGPL (lightningcss, sharp-libvips) | lock fields | Attribuzione frontend | Copyleft diverso, non Faradworks |
xlsx@0.18.5 Apache-2.0 nel lock |
OK dichiarato | No | No |
Bloccanti identità (fase A): testi Faradworks nel prodotto.
Bloccanti “SaaS Periscope senza AGPL”: l’intero recinto PinScope + PyMuPDF se si usa il grant AGPL. Questo piano non promette relicenza.
Bloccante vendor: ImpedenceFinder senza licenza — non distribuire come “Periscope MIT/Apache”.
5. KEEP / ISOLATE / REWRITE / REMOVE
Sforzo: S (file/config), M (un sottosistema, test esistenti), L (contratto + UI + pipeline), XL (nuovo CAD/IR). Non è calendario.
| Area | Azione | Sforzo | Fase |
|---|---|---|---|
Blob LICENSE AGPL + attribuzione PinScope |
KEEP | — | tutte |
| Graph, parsers, taxonomy, BOM, derating, EDIF | KEEP nel recinto | — | A–C; REWRITE solo E (XL) |
simple_project, how-it-works.svg |
KEEP | — | |
Changelog storico Pinscope/PS-* |
KEEP | — | |
PCB, placement, antenna, plugin, finding_engine come clamp |
KEEP nativo | — | non toccare in A |
TOS, privacy, contact, footer ©, layout.tsx authors, Twitter |
REWRITE (identità) | S–M | A |
storage-keys.ts write pinscopex: |
REWRITE write path; dual-read | S | A |
Alias pinscope_version, JWT pinscope-local, CORS host, Docker pinscope_* |
ISOLATE poi scadere | S | A |
| Clerk stack | ISOLATE; REMOVE quando JWT locale è l’unico modo | M | B |
anthropic, upload_skills.py, CLAUDE.md Console |
ISOLATE; REMOVE se DeepSeek-only | M | B |
billing_hook / proxy stubs |
ISOLATE (firme); non Faradworks in copy | S | B |
validate.py + validation_tools + _parse_review |
KEEP in A–B; REWRITE reviewer nativo | L | C |
models.Finding vs motore-finding.md |
REWRITE IR (compat shim) | M–L | C |
normalize_findings / dedupe_findings |
KEEP o reimplementare sul nuovo IR | M | C |
| Skills extraction (schema) | ISOLATE; prompt già in parte REPLACEMENT | M | C |
| FindingCard / report UI | REWRITE quando IR nativo | M–L | D |
| Wizard upload / admin Clerkisms | REWRITE / pulizia | M | D |
vendor/impedancefinder |
ISOLATE + licenza esplicita | S legale + M se drop | B (licenza), non engine |
| Parsers/graph nativi Periscope | REWRITE solo se si esce da AGPL PinScope | XL | E |
| Stacco fork GitHub | non in questo piano | legale | dopo E o mai |
REMOVE in A: niente codice motore. Solo copy Faradworks dopo TOS Periscope pronti.
6. Sequenza per fasi
Fase A — Identità e recinto documentale (non rewriting del finding engine)
Allineato all’audit §11 punti 1–4: finding_engine / validate.py non si riscrivono qui.
- Pubblicare audit + questo piano (solo docs).
- Decidere
origin/mainvscursor/pcb-review-plan-44ddsenza staccare il fork (merge prodotto sumainoppuremaindichiarato archivio). - TOS/privacy/contact/metadata/Twitter/footer operatore Periscope; una riga di attribuzione AGPL PinScope/Faradworks (non “siamo Faradworks”).
- Compatibility fence: un modulo/doc per chiavi
pinscope_*; smettere di scriverepinscopex:inlocalStorage. - Dichiarare a codice (commento/ADR) il recinto §2 — ancora senza muovere file.
Done quando: UI e legal non dicono Faradworks Inc.; AGPL e fork parent invariati; PCB/schema invariati.
Fase B — Seam runtime (Clerk, Anthropic, vendor license)
Audit §11 punti 5–6, 8–9.
- JWT locale default documentato; Clerk dietro seam nominato (
use_clerk). - DeepSeek unico provider supportato; Anthropic + Console skills = optional/legacy; CLAUDE.md = README.
- Licenza scritta per ImpedenceFinder o non distribuire
vendor/. - Lockfile Python per transitive.
Done quando: boot produzione non richiede Clerk; nessun path “devi uploadare skill Anthropic”; vendor RF ha SPDX o è fuori tree.
Fase C — Motore review PinScope-derived (rewrite map, dopo A–B)
Qui sì si riscrive l’engine ereditato. Ordine interno:
| Step | Oggetto | Perché |
|---|---|---|
| C0 | Spec freeze motore-finding.md = unico IR |
Già nativo; non diluire in validate.py |
| C1 | Adapter: validate.py emette solo Finding grezzi → complete_finding |
Già parziale; chiudere i campi doppi |
| C2 | REWRITE loop per-IC: tool find_connected_components / get_pintable / excerpt su provider DeepSeek senza copiare validation_tools.py |
Cuore DIRECT da sostituire |
| C3 | Extraction: local_skill.py + schemi JSON (KEEP schema se identici; REWRITE orchestrazione Anthropic) |
|
| C4 | Spegnere import da validate.py nel PCB (_parse_review → parser finding nativo) |
Toglie INDIRECT PCB→PinScope reviewer |
| C5 | Test golden simple_project + Emmaforo: parity FACT/REQUIREMENT, non parity prose |
Non in C: riscrivere graph.py / parser KiCad.
Done quando: validate.py PinScope può restare nel recinto non chiamato dal job schema/PCB, oppure ridotto a wrapper deprecato.
Fase D — UI
FindingCard, filtri Layout, wizard, admin senza Clerk copy, package-lock version drift. Dopo C1 almeno (stesso oggetto finding).
Fase E — Parsers / graph (opzionale, XL)
Solo se l’obiettivo diventa opera senza codice AGPL PinScope. Sostituire BOM/netlist/graph/taxonomy è un secondo prodotto. PCB nativo resta INDIRECT finché ensure_graph chiama PinScope.
Stacco fork GitHub: solo dopo consiglio legale, non in A–D.
7. Rischi e sconosciuti
| Rischio | Impatto |
|---|---|
Clone di default main ≠ prodotto 2.32.1 |
Ogni PR “solo docs” su main descrive un altro tree |
Rewrite validate.py in A |
Rompe schema+PCB; l’audit lo vieta come primo passo |
| Recinto solo rename di cartella | Falso recinto (già successo con periscopex) |
| TOS Periscope scritti male | Resta il testo Faradworks o si perde AGPL attribution |
| ImpedenceFinder | Distribuzione RF senza grant |
| PyMuPDF grant in VPS | Dual license; non verificato a runtime |
Clerk rimasto in ENVIRONMENT=production |
Deploy script vs JWT locale |
| Anthropic ancora importabile se c’è la key | README ≠ runtime |
| Trademark Pinscope/Periscope/Faradworks | Audit: solo use, nessuna registrazione |
| Relicenza “Periscope MIT” | Impossibile finché il recinto è servito (AGPL §13 network) |
| Gateway privato Faradworks | Non è nel repo; non auditabile |
8. Non-obiettivi (espliciti)
- Non modificare source prodotto, remotes,
LICENSE, git history in questa consegna (piano only). - Non staccare il fork GitHub in queste fasi (passo legale successivo, se mai).
- Non cancellare il codice PinScope “perché è PinScope”.
- Non riscrivere
finding_engine/validate.py/ PCB nella fase A. - Non auto-placer, non write-back pcbnew (già fuori da
piano-pcb-review.md). - Non promettere una licenza Periscope non-AGPL.
- Non mescolare mbparks/pinscope (Arduino) — progetto altro.
- Non usare questo piano come licenza a refactor su
cursor/pcb-review-plan-44ddoltre un eventuale solo file docs su nuovo branch.
9. Priorità di rewrite (lista operativa)
- Identità — TOS, privacy, contact,
layout.tsx,site.tsTwitter, footer © - Fence compat — stop write
pinscopex:; isolare alias versione/JWT/CORS/Docker mainvs product branch — topologia git, fork attaccato- Clerk seam — default JWT locale
- Anthropic/Console seam — DeepSeek-only di fatto
- Licenza ImpedenceFinder — grant o drop vendor
- Lockfile Python — transitive
- IR finding —
Finding≡motore-finding.md(fase C, non A) - Loop
validate.py/validation_tools— reviewer nativo (C) - PCB/schema smettono di chiamare
_parse_reviewPinScope (C4) - UI FindingCard/wizard (D)
- Parsers/graph solo se si vuole uscire da AGPL PinScope (E)
- Stacco fork — legale, fuori piano
10. Riferimenti
- Audit: PINSCOPE_AUDIT.md
- Contratto finding nativo:
docs/motore-finding.md(store) /docs/motore-finding.mdnel repo prodotto - Job PCB:
docs/piano-pcb-review.md