docs: revise schema-v3-only cleanup plan

This commit is contained in:
2026-08-10 19:50:24 +02:00
parent ce90b4410d
commit 5d016ce635
@@ -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.