diff --git a/docs/plans/2026-08-10-rimozione-schema-v1-v2.md b/docs/plans/2026-08-10-rimozione-schema-v1-v2.md new file mode 100644 index 00000000..81ffa54d --- /dev/null +++ b/docs/plans/2026-08-10-rimozione-schema-v1-v2.md @@ -0,0 +1,447 @@ +# Piano di implementazione: workspace descriptor esclusivamente schema v3 + +> **Per gli agenti esecutori:** SUB-SKILL OBBLIGATORIA: usare `superpowers:subagent-driven-development` (raccomandata) oppure `superpowers:executing-plans`, procedendo task per task con TDD e review tra i task. + +**Obiettivo:** rimuovere dal prodotto ogni capacità di leggere, migrare, rendere operativo o presentare workspace descriptor schema v1/v2. Il solo descriptor accettato diventa schema v3. Restano intatti i formati versionati non correlati e gli state file del registry già prodotti da versioni recenti con revisioni v3. + +**Architettura:** parser, registry, renderer, diagnostica, route e frontend convergono su un solo tipo `WorkspaceV3`. Il campo pubblico `WorkspaceRevision.state` scompare. Un decoder privato normalizza in memoria gli state file già scritti con `state: "operational"`, elimina quel campo prima di qualsiasi uso/API e rifiuta ogni combinazione non-v3 o incoerente. I build backend diventano clean-first, così la cancellazione dei migratori sorgente implica anche la loro assenza da `dist` e dall'immagine core. + +**Tech stack:** TypeScript 5, Zod 4, Fastify 5, React 18, Vitest, Node.js 22, Bash/PowerShell, Git e Docker Compose. + +**Stato:** piano revisionato dopo review indipendente. La sua approvazione non autorizza l'implementazione; attendere un esplicito ordine separato. + +--- + +## Decisioni confermate + +1. Nessun workspace v1/v2 reale deve essere preservato o migrato. +2. Eliminare `migrate-legacy.ts`, `migrate-v2-qdrant.ts` e le relative interfacce CLI. +3. Eliminare il campo `state` dal tipo/API `WorkspaceRevision` e da tutti i nuovi state/manifest del registry. +4. Descriptor v1/v2 presenti in Git o negli snapshot vengono rifiutati, senza conversione automatica. +5. Non toccare i documenti storici sotto `docs/superpowers/` e i vecchi piani; possono descrivere decisioni passate. +6. Non iniziare P2 finché P1 non dispone di nuova evidenza automatica e di una nuova decisione manuale esplicita. + +## Confini da non oltrepassare + +Questa rimozione riguarda soltanto il **workspace descriptor**. Non eliminare o rinominare: + +- `schemaVersion`/`schema_version` di bundle ZIP, report, job, ledger, manifest di sessione o artifact di fase; +- `RevisionLeaseRecord.state` (`creating`/`persisted`), maintenance state, process state o UI state non collegati a `WorkspaceRevision`; +- `migration_required` usato nei futuri piani P3–P6 per ownership DWH, punti semantici revisionless o altre migrazioni non-descriptor; +- `allowLegacy` del frontend sessioni, che significa “sessione senza revisione workspace” e non descriptor v1/v2; +- documenti storici o report conservati. + +L'unica compatibilità legacy mantenuta nel codice è il decoder privato degli state file già scritti con il campo revisionale `state: "operational"`. Non costituisce supporto a descriptor v1/v2. + +## Contratto v3-only + +- `WorkspaceDescriptor`, `CanonicalWorkspace` e `WorkspaceV3` rappresentano la stessa forma v3; mantenere gli alias soltanto quando migliorano la semantica dei confini. +- `parseWorkspaceYaml` e `validateWorkspaceDescriptor` accettano esclusivamente `workspace.schema_version === 3`. +- v1/v2 generano l'errore pubblico già sanitizzato `workspace_invalid`; non usare più il messaggio o lo stato `migration_required` per i descriptor. +- Un'attivazione Git contenente anche un solo descriptor non-v3 fallisce interamente e conserva il precedente active state. +- Le revisioni restituite dalle API contengono esattamente `id`, `commit`, `blob`, `snapshotPath`, senza `state`. +- Nuovi `active.json` e `snapshot.json` non contengono `state` nelle revisioni. + +## Compatibilità degli state file esistenti + +Definire due decoder stretti e distinti: + +```ts +interface StoredWorkspaceRevision { + id: string; + commit: string; + blob: string; + snapshotPath: string; + state?: "operational"; // solo input compatibile; mai restituito +} + +interface WorkspaceRevision { + id: string; + commit: string; + blob: string; + snapshotPath: string; +} +``` + +Regole: + +1. `active.json` accetta soltanto `{head,revisions}`; `snapshot.json` soltanto `{head,revisions,files}`. +2. Ogni revision object accetta soltanto i quattro campi correnti più l'opzionale vecchio `state: "operational"`. +3. `state: "migration_required"`, qualsiasi altro valore o campo sconosciuto è rifiutato. +4. Il decoder ricostruisce un nuovo oggetto `WorkspaceRevision`; non restituisce mai l'oggetto JSON originale. +5. Active state e snapshot manifest vengono confrontati dopo la normalizzazione. +6. L'integrità continua a validare path, commit, blob, digest, descriptor v3 e Evidence context. +7. La lettura non modifica snapshot storici. La successiva attivazione riscrive `active.json` nel formato corrente; tutti i nuovi snapshot sono state-free. +8. Un vecchio file già privo di `state` è naturalmente il formato corrente, ma il relativo descriptor deve comunque essere v3. + +## Mappa completa dei file + +### Backend produttivo + +- `backend/src/workspaces/schema.ts` +- `backend/src/workspaces/types.ts` +- `backend/src/workspaces/runtime-renderer.ts` +- `backend/src/workspaces/contracts.ts` +- `backend/src/workspaces/diagnostics.ts` +- `backend/src/workspaces/bindings.ts` +- `backend/src/workspaces/registry.ts` +- `backend/src/routes/workspaces.ts` +- `backend/src/routes/sessions.ts` +- `backend/src/routes/sql.ts` +- Eliminare `backend/src/workspaces/migrate-legacy.ts` +- Eliminare `backend/src/workspaces/migrate-v2-qdrant.ts` + +### Build e tooling P1 + +- `backend/package.json` +- Creare `backend/scripts/clean-dist.mjs` +- Creare un test Node per il clean build +- `backend/scripts/p1-manual-acceptance.mjs` +- `backend/scripts/p1-manual-acceptance.test.mjs` +- `backend/scripts/p1-render-snapshot.test.mjs` + +### Frontend + +- `frontend/src/api/workspaces.ts` +- `frontend/src/api/sessions.ts` +- `frontend/src/shell/SteerInput.tsx` +- `frontend/src/shell/WorkspaceManager.tsx` +- Test/fixture in `api`, `SteerInput`, `WorkspaceManager`, `NewSessionDialog`, `WorkspacePublishDialog` e `drafts`. + +### Deploy, fixture e verificatori + +- `scripts/workspace-registry-smoke.sh` +- Creare `scripts/fixtures/workspace-registry-smoke.yaml` +- `scripts/test-no-deployment-coupling-scope.sh` +- `scripts/test-windows-clone-contract.ps1` +- `scripts/verify-workspace-install-docs.sh` +- `scripts/test-verify-workspace-install-docs.sh` + +### Documentazione corrente + +- `README.md` +- sezione corrente di `PROJECT_STATE.md`, prima di `## Historical snapshots` +- `docs/workspace-diagnostic-protocol.md` +- `docs/install/local-workspace-registry.md` +- `docs/install/server-workspace-registry.md` + +--- + +### Task 0: Congelare scope e baseline prima delle modifiche + +**File:** nessuna modifica produttiva. + +- [ ] Registrare `BASE_SHA=$(git rev-parse HEAD)` e verificare che gli altri piani non vengano inclusi nei commit di implementazione. +- [ ] Salvare l'inventario iniziale dei simboli descriptor-legacy: + +```bash +git grep -nE 'WorkspaceV1|WorkspaceV2|LegacyWorkspace|migration_required|migrate-legacy|migrateWorkspaceV1ToV2|migrateWorkspaceV2ToV3' -- \ + backend/src backend/test backend/scripts frontend/src scripts README.md PROJECT_STATE.md docs/install docs/workspace-diagnostic-protocol.md +``` + +- [ ] Classificare ogni risultato come descriptor legacy, compatibility decoder previsto, contratto diverso o documento storico. +- [ ] Verificare nei registry/installazioni disponibili che i descriptor attivi siano v3; questa è una precondizione di deploy, non un migratore. +- [ ] Non procedere se il worktree contiene modifiche applicative non attribuibili a questo piano. + +### Task 1: Scrivere i test RED del contratto v3-only + +**File:** +- `backend/test/workspaces-schema.test.ts` +- `backend/test/workspace-registry.test.ts` +- `backend/test/routes-workspaces.test.ts` + +- [ ] Aggiungere test che `parseWorkspaceYaml`, `validateWorkspaceDescriptor` e le route validate/publish rifiutino esplicitamente v1 e v2. +- [ ] Aggiungere test registry per: + - bootstrap pulito con solo v1/v2: fallimento, nessun `active.json` pubblicato; + - repository misto v3+v2: attivazione atomica rifiutata; + - pull che introduce v1/v2: precedente active state ancora leggibile; + - retained snapshot contenente descriptor non-v3: rifiuto fail-closed; + - risposta API state-free. +- [ ] Eseguire: + +```bash +cd backend +npx vitest run test/workspaces-schema.test.ts test/workspace-registry.test.ts test/routes-workspaces.test.ts +``` + +Atteso: RED per i nuovi requisiti, non errori di fixture casuali. + +### Task 2: Rendere lo schema backend esclusivamente v3 + +**File:** +- `backend/src/workspaces/schema.ts` +- `backend/src/workspaces/types.ts` +- test del Task 1 + +- [ ] Eliminare `WorkspaceV1`, `WorkspaceV2`, `LegacyWorkspace`, relativi Zod schema e `migrateWorkspaceV1ToV2`. +- [ ] Rendere `WorkspaceDescriptorSchema = WorkspaceV3Schema`. +- [ ] Eliminare `validateCanonicalWorkspace`, aggiornando **tutti** i chiamanti in `routes/workspaces.ts`, incluso il chiamante attualmente oltre quelli elencati nel vecchio piano. +- [ ] Eliminare `isCanonicalWorkspace`/`isOperationalWorkspace` dopo aver sostituito i rami condizionali con validazione v3 diretta. +- [ ] Conservare test negativi v1/v2; non cancellare le sole prove che impediscono una regressione futura. +- [ ] Eseguire test focalizzati e typecheck. +- [ ] Commit: `refactor: make workspace descriptors schema v3 only`. + +### Task 3: Normalizzare in sicurezza active state e snapshot manifest + +**File:** +- `backend/src/workspaces/registry.ts` +- `backend/test/workspace-registry.test.ts` + +- [ ] Scrivere RED per state/manifest con: + - campo assente; + - vecchio `state: "operational"`; + - `state: "migration_required"`; + - valore sconosciuto; + - campo extra; + - active state e manifest con formati misti; + - snapshot attivo, storico e fallback offline. +- [ ] Rimuovere `state` da `WorkspaceRevision` e da tutti i nuovi writer. +- [ ] Sostituire cast e vecchie migrazioni con decoder stretti che restituiscono oggetti normalizzati state-free. +- [ ] Rimuovere `LegacyWorkspaceRevision`, `LegacyActiveState`, `LegacySnapshotManifest`, `deriveStateFromLegacyRevisions`, `migrateLegacyActiveState`, `migrateLegacySnapshotManifest`, `sameLegacyRevisions` e le condizioni operative basate su `state`. +- [ ] Mantenere tutti i controlli di integrità e far validare ogni YAML come v3. +- [ ] Provare che list/read/API non riemettono il vecchio campo anche immediatamente dopo un restart, prima di una nuova attivazione. +- [ ] Commit: `refactor: remove workspace revision state`. + +### Task 4: Eliminare i rami v1/v2 da renderer, contracts, bindings e diagnostica + +**File:** +- `backend/src/workspaces/runtime-renderer.ts` +- `backend/src/workspaces/contracts.ts` +- `backend/src/workspaces/diagnostics.ts` +- `backend/src/workspaces/bindings.ts` +- relativi test + +- [ ] Scrivere/aggiornare test RED che accettano v3 e rifiutano input non-v3 al confine, senza renderer/diagnoser legacy. +- [ ] Eliminare il renderer v2/pgvector e i rami v1. +- [ ] Eliminare variabili contract e diagnostica solamente v2. +- [ ] Semplificare bindings dopo la validazione v3, senza indebolire validazione secrets/trasporti. +- [ ] Eseguire i test focalizzati: + +```bash +cd backend +npx vitest run \ + test/workspace-runtime-renderer.test.ts \ + test/workspaces-contracts.test.ts \ + test/workspaces-diagnostics.test.ts \ + test/workspaces-bindings.test.ts \ + test/workspace-runtime-handoff.test.ts +``` + +- [ ] Commit: `refactor: remove legacy workspace runtime branches`. + +### Task 5: Rimuovere migratori senza perdere test di deployment non correlati + +**File:** +- Eliminare i due migratori e i test esclusivamente di migrazione. +- Creare/spostare in un test dedicato le prove deployment presenti in `workspaces-migrate-legacy.test.ts:81-114`. + +- [ ] Prima di eliminare `workspaces-migrate-legacy.test.ts`, spostare in un file con nome coerente: + - volume registry durevole e mount Git read-only; + - contratto Dockerfile; + - fallback offline smoke; + - self-test di cleanup dell'immagine per-run. +- [ ] Eliminare `migrate-legacy.ts`, `migrate-v2-qdrant.ts` e i test di trasformazione. +- [ ] Conservare un fixture v2 soltanto nei test negativi di rifiuto. +- [ ] Eseguire i nuovi test deployment e il typecheck. +- [ ] Commit: `refactor: remove workspace migration utilities`. + +### Task 6: Aggiornare tutte le route backend e il tooling P1 + +**File:** +- `backend/src/routes/workspaces.ts` +- `backend/src/routes/sessions.ts` +- `backend/src/routes/sql.ts` +- test route inclusi `routes-sql-meta.test.ts` +- `backend/scripts/p1-manual-acceptance.mjs` +- test manual/render P1 + +- [ ] Rimuovere filtri/gate `revision.state` da tutte le route. La garanzia deriva dal registry v3-only. +- [ ] Aggiornare mock/fixture `WorkspaceRevision` in tutti i test backend. +- [ ] Aggiornare il validatore del manifest P1 manuale affinché richieda esattamente la revisione state-free. +- [ ] Aggiornare i fixture `p1-manual-acceptance.test.mjs` e `p1-render-snapshot.test.mjs`. +- [ ] Aggiungere un test JS specifico che rifiuti manifest con revisioni malformate senza reintrodurre `migration_required`. +- [ ] Eseguire: + +```bash +cd backend +npx vitest run test/routes-workspaces.test.ts test/routes-sessions.test.ts test/routes-sql-meta.test.ts +cd .. +node --test --test-concurrency=1 \ + backend/scripts/p1-manual-acceptance.test.mjs \ + backend/scripts/p1-render-snapshot.test.mjs +``` + +- [ ] Commit: `refactor: remove workspace revision state consumers`. + +### Task 7: Rendere il build backend clean-first + +**File:** +- `backend/package.json` +- Creare `backend/scripts/clean-dist.mjs` +- Creare test Node del clean build + +- [ ] Scrivere RED: creare un file sentinella in `backend/dist/workspaces/`, eseguire il clean/build e verificare che non sopravviva. +- [ ] Implementare la pulizia con API Node multipiattaforma, non con `rm -rf` nella npm script. +- [ ] Fare eseguire il clean prima di `tsc` da `npm run build`. +- [ ] Verificare dopo il build: + +```bash +test ! -e backend/dist/workspaces/migrate-legacy.js +test ! -e backend/dist/workspaces/migrate-v2-qdrant.js +``` + +- [ ] Costruire l'immagine core in un contesto pulito e verificare che i due moduli non esistano nell'immagine. +- [ ] Verificare che i manifest di integrità P1 continuino a legare l'intero nuovo `dist`. +- [ ] Commit: `build: remove stale backend distribution files`. + +### Task 8: Aggiornare frontend e contratto API state-free + +**File:** +- `frontend/src/api/workspaces.ts` +- `frontend/src/api/sessions.ts` +- `frontend/src/shell/SteerInput.tsx` +- `frontend/src/shell/WorkspaceManager.tsx` +- test/fixture frontend correlati + +- [ ] Scrivere/aggiornare test per revisioni senza `state` e risposta non-v3 rifiutata al confine workspace. +- [ ] Eliminare `state` dal tipo e dal parser revisionale. +- [ ] Rimuovere gate/banner/filtro `migration_required` e anche la visualizzazione `record.revision.state`. +- [ ] Mantenere `allowLegacy` per sessioni senza revisione. +- [ ] Aggiornare fixture in: + - `api/workspaces.test.ts`, `api/sessions.test.ts`; + - `SteerInput.test.tsx`, `WorkspaceManager.test.tsx`; + - `NewSessionDialog.test.tsx`, `WorkspacePublishDialog.test.tsx`; + - `drafts.test.ts`, mantenendo il test negativo di schema non-3. +- [ ] Documentare che core e frontend devono essere aggiornati insieme; il parser nuovo non usa più `state`. +- [ ] Eseguire typecheck e suite frontend. +- [ ] Commit: `refactor: remove legacy workspace UI state`. + +### Task 9: Sostituire fixture e smoke con descriptor v3 completi + +**File:** +- `scripts/workspace-registry-smoke.sh` +- Creare `scripts/fixtures/workspace-registry-smoke.yaml` +- `scripts/test-no-deployment-coupling-scope.sh` +- `scripts/test-windows-clone-contract.ps1` +- test deployment spostati nel Task 5 + +- [ ] Creare un descriptor v3 completo `id: local`, collection `local`, embedding interno 1024/cosine, LLM policy e diagnostica DWH; omettere Evidence per non richiedere un tree Git nello smoke registry. +- [ ] Validare il fixture con il parser produttivo in un test backend. +- [ ] Copiare il fixture nello seed repository e rimuovere sia l'invocazione del migratore sia il build backend ormai inutile allo smoke. +- [ ] Nel test Windows non cambiare soltanto il numero di versione: fornire il contratto v3 completo mantenendo lo scopo path-with-spaces/clone. +- [ ] Aggiornare il fixture dello scope coupling senza indebolire l'assenza-gate. +- [ ] Eseguire test shell focalizzati e, con Docker disponibile, lo smoke reale senza retry. +- [ ] Commit: `test: replace legacy workspace deployment fixtures`. + +### Task 10: Aggiornare documentazione corrente e relativi verifier + +**File:** +- documenti/verifier indicati nella mappa + +- [ ] Aggiornare README e soltanto la sezione corrente di `PROJECT_STATE.md`; non riscrivere gli snapshot storici. +- [ ] Eliminare procedure di migrazione v1/v2 dai manuali local/server e dal protocollo diagnostico. +- [ ] Modificare `verify-workspace-install-docs.sh` perché richieda “schema v3 only” e l'assenza di `migration_required` nella documentazione corrente. +- [ ] Aggiornare i fixture negativi del test del verifier. +- [ ] Non cambiare gli usi di `migration_required` nei piani P3–P6 relativi a ownership/artifact diversi. +- [ ] Eseguire: + +```bash +bash scripts/test-verify-workspace-install-docs.sh +bash scripts/verify-workspace-install-docs.sh --fixtures-only +``` + +- [ ] Commit: `docs: make schema v3 the only workspace contract`. + +### Task 11: Eseguire absence gate e suite complete + +- [ ] Eseguire backend clean build, typecheck e test: + +```bash +cd backend +npm run build +npx tsc --noEmit -p . +npx vitest run +``` + +- [ ] Eseguire frontend: + +```bash +cd frontend +npx tsc -b +npx vitest run +npm run build +``` + +- [ ] Eseguire script/verifier interessati, incluso lo smoke Docker obbligatorio se l'ambiente dispone di Docker. Non lasciarlo “opzionale” in una consegna che modifica lo smoke. +- [ ] Eseguire `git diff --check`. +- [ ] Eseguire l'absence gate ristretto: + +```bash +git grep -nE 'WorkspaceV1|WorkspaceV2|LegacyWorkspace|migrateWorkspaceV1ToV2|migrateWorkspaceV2ToV3' -- \ + backend/src frontend/src scripts && exit 1 || true + +git grep -nE 'migration_required|migrate-legacy|migrate-v2-qdrant' -- \ + backend/src backend/scripts frontend/src scripts README.md docs/install docs/workspace-diagnostic-protocol.md && exit 1 || true + +test ! -e backend/dist/workspaces/migrate-legacy.js +test ! -e backend/dist/workspaces/migrate-v2-qdrant.js +``` + +Nota: trasformare questi esempi in uno script con allowlist esplicita; non affidarsi a `&& exit 1 || true`, che può mascherare errori di esecuzione. Lo script deve distinguere “nessun match” da errore Git/I/O. + +- [ ] Ispezionare il diff per assicurarsi che nessun formato non-descriptor sia stato modificato. + +### Task 12: Rigenerare l'evidenza automatica P1 + +- [ ] Partire dal commit sorgente finale pulito. +- [ ] Eseguire una sola integrazione completa, senza retry automatico: + +```bash +./scripts/p1-acceptance.sh integration --keep +``` + +- [ ] Verificare report JSON/Markdown, hash dichiarati, manifest sorgente/dist, secret scan, ownership cleanup e porte chiuse. +- [ ] Aggiornare `PROJECT_STATE.md` con il nuovo commit/tree/report e con stati distinti: + +```text +automated integration: PASS +manual acceptance: PENDING +``` + +- [ ] Committare soltanto lo stato tracciato, mai `.artifacts`. +- [ ] Non riusare l'evidenza precedente legata a `c733896`. + +### Task 13: Riaprire e chiudere il gate manuale P1 + +- [ ] Preparare un ambiente manuale nuovo: + +```bash +./scripts/p1-manual-acceptance.sh prepare +./scripts/p1-manual-acceptance.sh serve +``` + +- [ ] Il reviewer segue integralmente il nuovo `GUIDE.md`, verificando anche che revisioni/API/manifest siano state-free e che v1/v2 siano rifiutati senza mutazione. +- [ ] Arrestare il server e verificare porte/processi: + +```bash +./scripts/p1-manual-acceptance.sh stop +``` + +- [ ] Solo il reviewer crea `VERDICT.md` e decide PASS/FAIL. +- [ ] Se PASS, aggiornare `PROJECT_STATE.md` e committare `docs: record schema-v3-only P1 acceptance`. +- [ ] Pulire il lab soltanto dopo conferma del reviewer. +- [ ] **STOP:** non iniziare P2 finché il reviewer non approva esplicitamente il nuovo P1. + +--- + +## Criteri finali di accettazione + +1. Nessun descriptor v1/v2 viene parsato, pubblicato, attivato, renderizzato, diagnosticato o mostrato. +2. I vecchi state file di revisioni v3 con `state: "operational"` continuano a caricarsi, ma API e nuovi file sono state-free. +3. Descriptor non-v3 o state incoerenti falliscono senza sostituire il precedente active state. +4. Nessun migratore sopravvive in sorgenti, `dist`, immagine core, script o documentazione corrente. +5. I formati versionati non collegati ai workspace descriptor sono invariati. +6. Backend, frontend, verifier, smoke e build interessati sono verdi. +7. Una nuova integrazione P1 è PASS al commit finale. +8. La nuova acceptance manuale P1 è decisa esplicitamente dal reviewer. +9. P2 resta non iniziato fino a ulteriore autorizzazione.