Files
periscope/docs/development/PINSCOPE_INDEPENDENCE_PLAN.md
T
michele a63e5bd7ab Fase A identity on PCB HEAD: operator fence, keep BOM/SPOF/EMI.
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.
2026-09-20 12:41:17 +02:00

18 KiB
Raw Blame History

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 lalbero ereditato; disegnare dipendenze; marcare cosa deve essere riscritto. Non cancellare ogni riga ereditata.

Questo piano non stacca il fork GitHub (manvalan/periscopeFaradworks/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 lalbero PinScope, togliere AGPL, o chiedere a Faradworks una licenza commerciale come se fossimo noi lupstream

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.

Laudit già dice: lindipendenza 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, Finding Pydantic, 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 LICENSE AGPL e lattribuzione “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 (pinscopexperiscopex è 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”):

  1. Identità legale/UI — obbligatorio e primo; non è il motore.
  2. Seam Clerk + Anthropic — obbligatorio per non dipendere dal cloud Faradworks.
  3. Loop validate.py / _parse_review / tool graph — obbligatorio per un motore Periscope, dopo identità; oggi finding_engine è solo un clamp.
  4. IR Finding — allineare il tipo Pydantic al contratto FACT/REQUIREMENT/INFERENCE (oggi campi doppi finding/why).
  5. UI report/wizard — quando il contratto finding è nativo; non nella fase identità.
  6. Parsers/graphnon 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 delloperatore Michele, con dipendenze dichiarate, non “Periscope senza AGPL”. Lalbero 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 , finché il recinto è nel tree/servizio
TOS/privacy Faradworks, Inc. + dev@faradworks.com REPLACE (operatore sbagliato) No (non è la GPL)
Metadata layout.tsx authors/publisher Faradworks, @getFaradWorks REPLACE 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 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”: lintero 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 AC; 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à) SM 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 è lunico 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 AB; REWRITE reviewer nativo L C
models.Finding vs motore-finding.md REWRITE IR (compat shim) ML 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 ML 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 allaudit §11 punti 14: finding_engine / validate.py non si riscrivono qui.

  1. Pubblicare audit + questo piano (solo docs).
  2. Decidere origin/main vs cursor/pcb-review-plan-44dd senza staccare il fork (merge prodotto su main oppure main dichiarato archivio).
  3. TOS/privacy/contact/metadata/Twitter/footer operatore Periscope; una riga di attribuzione AGPL PinScope/Faradworks (non “siamo Faradworks”).
  4. Compatibility fence: un modulo/doc per chiavi pinscope_*; smettere di scrivere pinscopex: in localStorage.
  5. 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 56, 89.

  • 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 AB)

Qui sì si riscrive lengine 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 lobiettivo 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 AD.


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; laudit 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-44dd oltre un eventuale solo file docs su nuovo branch.

9. Priorità di rewrite (lista operativa)

  1. Identità — TOS, privacy, contact, layout.tsx, site.ts Twitter, footer ©
  2. Fence compat — stop write pinscopex:; isolare alias versione/JWT/CORS/Docker
  3. main vs product branch — topologia git, fork attaccato
  4. Clerk seam — default JWT locale
  5. Anthropic/Console seam — DeepSeek-only di fatto
  6. Licenza ImpedenceFinder — grant o drop vendor
  7. Lockfile Python — transitive
  8. IR findingFindingmotore-finding.md (fase C, non A)
  9. Loop validate.py / validation_tools — reviewer nativo (C)
  10. PCB/schema smettono di chiamare _parse_review PinScope (C4)
  11. UI FindingCard/wizard (D)
  12. Parsers/graph solo se si vuole uscire da AGPL PinScope (E)
  13. Stacco fork — legale, fuori piano

10. Riferimenti