Files
ThothII/docs/superpowers/specs/2026-08-23-refactoring-modulare-conservativo-design.md
T

20 KiB

Refactoring modulare conservativo del workflow — Design

Data: 2026-08-23

Stato: approvato dal proprietario

Ambito: modularizzazione interna di Disambiguation, Evidence e Memory senza cambiamenti funzionali

Baseline del codice: b5db0cd3c12a4184a91933f6cf9d4ee13241ba65

Input autorevole: docs/prd/2026-08-23-refactoring-modulare-conservativo-brief.md

1. Scopo

Questa milestone riorganizza il workflow ThothII in tre moduli interni profondi: Disambiguation, Evidence e Memory. Una modifica alla semantica interna di uno di questi domini deve richiedere normalmente interventi nella directory e nei test del modulo relativo. Il workflow core cambia soltanto quando cambia una responsabilità realmente condivisa.

La milestone è un refactoring conservativo. Non aggiunge funzionalità, non cambia il flusso operativo e non trasforma ThothII in una piattaforma di plugin. Pi resta il runtime concreto del workflow assistito dal modello. Il repository, il rilascio e la proprietà del prodotto restano unici.

2. Perimetro deciso

Sono inclusi:

  • estrazione delle responsabilità Disambiguation oggi distribuite fra istruzioni Pi, gate, decisioni e rendering della domanda;
  • consolidamento di Memory, compresi recall F2, promozione F8 e indicizzazione delle domande risolte;
  • consolidamento di Evidence attraverso Python e TypeScript, dall'acquisizione alla citazione;
  • separazione del gate monolitico fra meccanismi condivisi e use case specifici dei moduli;
  • modularizzazione delle istruzioni Pi senza modificare il prompt effettivo;
  • test di caratterizzazione e contract test che dimostrino equivalenza osservabile;
  • un E2E live finale sull'intero workflow.

Sono esclusi:

  • un modulo Admission, anche come pass-through;
  • l'estrazione di Datamart o nuove funzioni dbt/ETL;
  • il futuro ridisegno di F1, inclusi target group, classificazione unanswerable o nuovo retrieval;
  • nuove funzionalità Evidence o Memory;
  • un kernel separato, plugin, registry, manifest o resolver di composizione;
  • un contratto universale fra moduli;
  • ModelRuntime, event bus, nuovo event store, upcaster o artifact universali;
  • modifiche al frontend o all'esperienza del reviewer;
  • migrazioni dei dati o delle sessioni esistenti;
  • correzioni opportunistiche di failure semantics, atomicità o altri comportamenti correnti;
  • un piano esecutivo dettagliato, che sarà un documento successivo.

Admission e Datamart potranno essere progettati soltanto dopo il completamento e l'accettazione di questa milestone.

3. Invarianti di compatibilità

Durante la milestone sono congelati:

  • harness/workflow.yaml, ordine delle fasi e meccanismi di avanzamento;
  • tassonomia, forma e significato delle decisioni del ledger;
  • nomi, parametri, schemi TypeBox e risultati dei tool Pi;
  • comandi tht, grammatica, JSON, stdout, stderr e codici di uscita;
  • nomi, formato e contenuto deterministico dei documenti di sessione;
  • widget descriptor, eventi SSE e loro ordine;
  • prompt Pi effettivo e comportamento di caricamento delle reference;
  • lifecycle e resume delle sessioni;
  • lifecycle delle collection Qdrant e relativi payload condivisi;
  • sequenza delle mutazioni e comportamento degli errori parziali;
  • numero e ordine dei gate, dei turni Pi e delle operazioni esterne per fixture deterministiche.

Gli import Python, JavaScript e TypeScript usati soltanto dentro il repository non sono contratti pubblici e possono cambiare. Qualunque modifica sostanziale a un elemento congelato interrompe il refactoring: deve essere isolata, progettata e autorizzata come lavoro funzionale separato.

Non è sufficiente aggiornare un golden perché un test torni verde. Ogni differenza deve prima essere trattata come possibile regressione.

4. Principi di modularità

4.1 Ownership

L'ownership indica dove vive una regola e quale modulo deve cambiare quando la regola cambia. Non indica chi possiede il repository né quale implementazione scrive fisicamente un file.

Il modulo possiede:

  • la semantica del proprio dominio;
  • le validazioni specifiche;
  • la presentazione specifica al reviewer;
  • l'ordine delle mutazioni del proprio use case;
  • le istruzioni Pi specifiche;
  • i test attraverso la propria façade.

Il core possiede:

  • ordine e avanzamento delle fasi;
  • lifecycle, resume e finalizzazione delle sessioni;
  • schema e persistenza del ledger;
  • documenti e repository di sessione;
  • locking e scritture atomiche condivise;
  • processo Pi e trasporto backend/frontend;
  • tool reviewer generici e widget transport;
  • enforcement anti-bypass e protezione dei file;
  • registry dei workspace e infrastruttura vector-store condivisa;
  • composizione statica dei moduli.

Il modulo decide cosa mutare, quando e in quale ordine. Il core fornisce il meccanismo con cui la mutazione viene eseguita.

4.2 Moduli profondi e asimmetrici

I moduli non devono avere la stessa forma né implementare una base comune. Ciascuno espone la più piccola façade adatta ai propri use case. Un modulo esiste soltanto nei runtime in cui possiede comportamento reale:

  • Disambiguation è prevalentemente JavaScript e Pi;
  • Memory attraversa Python, JavaScript e Pi;
  • Evidence attraversa Python e TypeScript e fornisce dati al workflow Pi;
  • non vengono creati package vuoti per ottenere simmetria visiva.

Non si introducono classi *Facade, DTO paralleli o un metodo universale execute(). Le interfacce esterne già consumate dal workflow restano la façade pubblica; gli entrypoint di installazione sono soltanto seam interni di composizione.

5. Architettura risultante

                                  workflow core
                     phase order · session · ledger · gate core
                              /          |          \
                             /           |           \
              Disambiguation          Memory         Evidence
               F1/F3 policy       F2/F8 + solved   acquire→cite
                     \               |               /
                      \------ existing contracts ---/
                         ledger · artifacts · CLI/JSON

La composizione avviene tramite import statici. Non esistono discovery, registry o binding runtime. Un modulo non importa l'implementazione di un altro modulo.

Le sole comunicazioni semantiche fra domini sono i contratti già esistenti:

  • Disambiguation → Memory: record del ledger, in particolare concept_clarified;
  • Evidence → Disambiguation/workflow: proiezioni di tht search pack e tht search find;
  • moduli → workflow: decisioni, artefatti e risultati CLI già definiti.

DecisionType, workflow.yaml e i repository restano di proprietà del core. Ogni collegamento fra domini è protetto da un contract test e non da una chiamata diretta.

6. Modulo Disambiguation

Disambiguation possiede:

  • istruzioni Pi di F1 e F3 e la tecnica descritta da rewriting.md;
  • semantica di concept_clarified, ambiguity_open, value_grounded e question_rewritten, senza possedere il registro globale dei tipi;
  • validazione e normalizzazione dei payload Disambiguation inviati ai tool reviewer generici;
  • presentazione delle interpretazioni e dei chiarimenti;
  • tool specializzato rewrite_question;
  • sequenza corrente session set-question → question_rewritten → chiusura F3;
  • rendering del contenuto di question.md, incluse le assunzioni.

Il repository condiviso continua a effettuare la scrittura di question.md. Il core continua a registrare reviewer_select e reviewer_decide; quando il payload appartiene a Disambiguation, delega staticamente policy e normalizzazione al modulo.

Non viene introdotto un motore deterministico di disambiguazione, un nuovo comando CLI o un nuovo tool Pi. Il modello continua a proporre le opzioni secondo le istruzioni correnti.

La façade interna del gate comprende soltanto:

  • installazione di rewrite_question tramite un entrypoint come installDisambiguationGate(deps);
  • policy richiamate staticamente dai tool reviewer generici.

7. Modulo Memory

Memory possiede:

  • ricerca, selezione, dedup e applicazione delle memory in F2;
  • definizione locale dei tipi riusabili, attualmente concept_clarified;
  • calcolo deterministico dei candidati di promozione;
  • presentazione, selezione e promozione in F8;
  • tool reviewer_memory_promote e relativi builder/normalizer;
  • salvataggio mirato nel vector store e decisioni memory_promoted / memory_promotion_declined;
  • indicizzazione best-effort delle domande risolte durante finalize;
  • comportamento e istruzioni Pi Memory.

La CLI tht memory ... conserva integralmente la propria interfaccia e diventa un adapter sottile verso il modulo. Il core continua a possedere repository, ledger, fase, finalizzazione e vector-store generico.

La façade esterna resta composta dai comandi tht memory ..., dal tool reviewer_memory_promote e dall'hook solved invocato durante finalize. L'entrypoint JavaScript interno è del tipo installMemoryGate(deps); non costituisce un protocollo condiviso con gli altri moduli.

8. Modulo Evidence

Evidence possiede:

  • port e adapter filesystem, HTTP e S3;
  • acquisizione e materializzazione;
  • modelli canonici, normalizzazione, chunking, staging e publication del corpus;
  • ricerca Evidence e formula store;
  • contratti Evidence-specific dei comandi preprocessing e search;
  • risoluzione degli ID citabili;
  • proiezione {id, file, esito, decision_seq} usata nei documenti di sessione;
  • orchestrazione TypeScript specifica di Evidence oggi dispersa nel sottosistema workspace.

Il core passa decisioni e schema linking al projector Evidence e scrive il risultato tramite il repository di sessione. Schema linking, sintesi e relativi widget restano nel workflow core.

Restano condivisi:

  • registry e configurazione dei workspace;
  • orchestrazione generale del preprocessing;
  • lifecycle e indici obbligatori della collection Qdrant;
  • vector store, embedder e configurazione infrastrutturale;
  • persistenza delle sessioni.

La façade inter-language resta il contratto CLI/JSON esistente. Non viene introdotta una nuova interfaccia generale Python/TypeScript.

9. Mappa fisica

La struttura obiettivo è:

harness/.pi/extensions/gate/
  core/                       # hook, enforcement e meccanismi generici
  disambiguation/             # policy F1/F3, rewrite tool, test
  memory/                     # F2/F8, promotion tool, test

harness/.pi/skills/tht-sessione/modules/
  disambiguation/
  memory/

harness/tht/
  memory/                     # assorbe memory.py e solved.py
  evidence/                   # assorbe port, adapter, corpus e search/evidence

harness/tests/
  disambiguation/
  memory/
  evidence/

backend/src/workspaces/evidence/
  materialization.ts
  preprocessing.ts

backend/test/workspaces/evidence/

harness/.pi/extensions/tht-gate.js, harness/.pi/skills/tht-sessione/SKILL.md, le CLI e backend/src/workspaces/preprocessing-service.ts restano entrypoint stabili. Delegano ai moduli tramite import espliciti.

Più precisamente:

  • harness/tht/memory.py e harness/tht/solved.py confluiscono nel package harness/tht/memory/;
  • harness/tht/corpus/, harness/tht/search/evidence.py, il port Evidence e gli adapter Evidence confluiscono sotto harness/tht/evidence/;
  • le funzionalità non Evidence di harness/tht/search/ restano condivise;
  • backend/src/workspaces/evidence-materialization.ts confluisce nel modulo Evidence;
  • da preprocessing-service.ts viene estratta soltanto l'orchestrazione specifica Evidence;
  • qdrant-collection.ts, registry, stato e coordinamento generale restano nel package workspace;
  • i test di dominio seguono il modulo; il comando pubblico npm test del harness continua a eseguire l'intera suite JavaScript anche dopo l'aggiornamento della discovery interna.

Non viene creata una directory Evidence nel gate finché non esiste comportamento JavaScript specifico da collocarvi.

10. Istruzioni Pi

Le istruzioni dei moduli diventano frammenti sorgente sotto harness/.pi/skills/tht-sessione/modules/. SKILL.md rimane nel percorso attuale come proiezione generata, deterministica e committata.

Il generatore:

  • usa una lista statica e ordinata di frammenti;
  • non effettua discovery;
  • produce output ripetibile;
  • viene verificato da un test che fallisce se SKILL.md non coincide con i frammenti;
  • nella prima estrazione deve riprodurre byte per byte il SKILL.md della baseline.

Il gate continua a leggere e iniettare SKILL.md come oggi. I reference document che il modello legge durante le fasi, inclusi rewriting.md, cte.md e sql-generation.md, mantengono in questa milestone percorso e comportamento correnti. Non viene introdotta composizione dinamica al runtime.

11. Capability e sicurezza

Ogni modulo riceve un oggetto di capability specifico, costruito dal core. Non esiste ModuleContext universale.

Le capability JavaScript ammissibili, assegnate nel sottoinsieme minimo necessario, sono:

  • esecuzione controllata della CLI;
  • emissione e attesa di una UI request;
  • registrazione di una decisione;
  • lettura della fase corrente;
  • avanzamento o chiusura della fase;
  • notifica al reviewer.

Le dipendenze Python ammissibili sono repository di sessione, port Evidence, vector store, embedder e clock, soltanto per i moduli che li usano. Le dipendenze TypeScript Evidence comprendono accesso controllato a filesystem, process runner e stato del preprocessing.

Un modulo non crea direttamente factory globali, non legge configurazione globale e non accede all'implementazione di un altro modulo. Somiglianze fra due oggetti di capability non giustificano la loro unificazione.

Restano esclusivamente nel gate core:

  • hook anti-bypass;
  • input lock e steering del testo libero;
  • kickoff di nuova sessione e resume;
  • protezione dei file e del codice del gate;
  • agent_end safety;
  • tool reviewer generici;
  • enforcement dei codici di uscita e delle regole condivise.

I moduli non registrano hook globali e non ricevono accesso diretto a filesystem o ledger. Tutte le mutazioni passano dalle capability controllate.

12. Failure semantics

Il refactoring conserva anche gli stati intermedi oggi osservabili, non soltanto gli happy path.

Esempi vincolanti:

  • Memory continua a salvare nel vector store prima di registrare memory_promoted; se la seconda operazione fallisce, conserva le attuali istruzioni di recupero;
  • rewrite_question continua a scrivere la domanda, poi il ledger e infine ad avanzare F3;
  • codici di uscita 5 e 6 conservano il significato corrente per il gate;
  • retry, resume e finalizzazione continuano a reagire agli errori nello stesso modo;
  • materializzazione Evidence e checkpoint del preprocessing conservano gli attuali stati di successo, attesa e fallimento.

Migliorare atomicità, retry o messaggi richiede un ticket funzionale successivo.

13. Sequenza di estrazione

L'ordine obbligatorio delle slice è:

  1. aggiungere i test di caratterizzazione mancanti senza spostare codice;
  2. estrarre Memory e introdurre il pattern di capability specifiche;
  3. estrarre Disambiguation e la composizione deterministica delle istruzioni;
  4. consolidare Evidence lato Python;
  5. consolidare Evidence lato TypeScript;
  6. ripulire il core, rimuovere shim e verificare l'assenza di duplicazioni.

Ogni slice deve essere un commit verificabile e revertibile. Gli shim di re-export sono ammessi fra due commit per mantenere il repository verde, ma devono sparire entro la milestone, salvo che proteggano un import dimostrabilmente consumato fuori dal repository.

Non si eseguono le tre estrazioni in parallelo: Memory stabilisce il pattern, Disambiguation lo applica al gate e alle istruzioni, Evidence chiude il lavoro più ampio e cross-runtime.

14. Strategia di caratterizzazione

14.1 Catalogo dei contratti

Prima della prima estrazione viene committato un catalogo leggibile dei contratti congelati. Ogni voce collega:

  • comportamento protetto;
  • owner corrente e owner risultante;
  • fixture o golden;
  • test che lo verifica;
  • tipo di uguaglianza richiesto.

Si usano fixture e golden leggibili per payload strutturati. Gli hash sono riservati a contenuti testuali grandi, come il prompt Pi. Non viene introdotto un unico manifest opaco di hash.

14.2 Matrice minima delle sessioni

La matrice di caratterizzazione comprende:

  • F1 con chiarimento approvato;
  • F1 con ambiguità lasciata aperta;
  • F2 con memory applicata;
  • F2 con memory rifiutata;
  • F2 senza memory;
  • F3 con domanda riscritta e assunzioni;
  • Evidence usata nello schema linking;
  • Evidence esplicitamente accettata e scartata;
  • sessione legacy senza corpus canonico;
  • F8 con candidati promossi;
  • F8 con candidati rifiutati;
  • F8 senza candidati;
  • resume nelle fasi interessate;
  • repository filesystem e PostgreSQL dove la semantica differisce;
  • failure path e recuperi elencati nella sezione 12.

Per ogni fixture devono restare uguali documenti, ledger, stato, tool, payload, sequenza CLI ed eventi osservabili.

14.3 Gate per ogni slice

Ogni estrazione richiede:

  • uguaglianza esatta dei payload deterministici;
  • stessi tool registrati e stessi schemi TypeBox;
  • stessa sequenza CLI e stesso comportamento d'errore;
  • stessi artefatti e ledger per fixture equivalenti;
  • test della façade con capability fake;
  • suite completa del layer interessato;
  • nessun aggiornamento non spiegato dei golden;
  • nessun nuovo gate, turno Pi o I/O esterno.

I vecchi test di helper possono essere eliminati soltanto quando la stessa proprietà è coperta attraverso la nuova façade. I test non devono restare permanentemente duplicati su entrambi i lati del seam.

14.4 Gate finale

La milestone richiede:

  • suite completa Python del harness;
  • suite JavaScript completa del gate;
  • suite, typecheck e build di backend e frontend;
  • test di caratterizzazione e contract test completi;
  • verifica delle sessioni legacy;
  • git diff --check;
  • un E2E live completo dalla nuova domanda alla finalizzazione;
  • nel live E2E, almeno un percorso Evidence, un percorso Memory e una ripresa di sessione.

Il live E2E è eseguito una volta alla fine, non dopo ogni slice. Se ambiente, DWH o credenziali non sono disponibili, l'automazione può risultare verde ma la milestone resta con gate manuale pendente e non è dichiarata completa.

15. Budget operativo

Per una fixture deterministica, prima e dopo il refactoring devono coincidere:

  • numero e ordine dei widget reviewer;
  • numero e ordine dei comandi tht;
  • numero di turni Pi necessari;
  • query a DWH, Qdrant ed Evidence;
  • avanzamenti di fase;
  • retry e percorso di resume.

Sono ammesse soltanto differenze trascurabili di import e startup locale. Non è ammesso nuovo I/O esterno. Il fake runtime deve registrare comandi e interazioni in modo che il budget sia verificato automaticamente.

16. Criteri di accettazione

Il refactoring è accettato soltanto quando:

  1. esistono moduli profondi Disambiguation, Memory ed Evidence secondo questa ownership;
  2. non esistono moduli Admission o Datamart introdotti dalla milestone;
  3. tht-gate.js contiene solo composizione e responsabilità realmente condivise;
  4. una modifica interna tipica richiede interventi nel modulo e nei suoi test, non nel core;
  5. nessun modulo importa l'implementazione di un altro;
  6. non esiste un contratto universale, registry o discovery di moduli;
  7. SKILL.md è generato dai frammenti e inizialmente byte-identico alla baseline;
  8. tutti i contratti congelati e il budget operativo risultano invariati;
  9. sessioni esistenti, legacy e riprese producono gli stessi risultati;
  10. failure semantics e recuperi correnti sono preservati;
  11. tutti i gate automatizzati e il gate live finale sono verdi;
  12. non restano shim temporanei, codice duplicato, cartelle vuote o fonti istruzionali divergenti;
  13. frontend, SSE, widget, CLI e formati persistiti non hanno richiesto modifiche funzionali.

17. Lavoro successivo

Dopo l'accettazione potranno essere progettati separatamente:

  • Admission e la policy dei tre tentativi;
  • evoluzione funzionale di Disambiguation;
  • nuovo contratto di consumo Evidence per una F1 ridisegnata;
  • evoluzione del contratto Disambiguation → Memory;
  • Datamart intelligente, dbt o automazioni ETL;
  • miglioramenti di atomicità e recovery emersi durante la caratterizzazione.

Nessuno di questi elementi può essere anticipato nel refactoring sotto forma di scaffold, astrazione o comportamento dormiente.