diff --git a/AGENTS.md b/AGENTS.md index 46840fc0..680da210 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -86,3 +86,20 @@ frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → resume with 409 when `finalized` or `archived`, and `PiProcessManager.spawnFor` must send `/riprendi-sessione ` (resume mode) vs `/nuova-domanda` (new) — sending the wrong prompt silently turns a resume into a new question. + +## Agent skills + +### Issue tracker + +Issues and specifications are tracked in GitHub Issues for `mptyl/ThothII`. See +`docs/agents/issue-tracker.md`. + +### Triage labels + +The repository uses the default canonical triage labels. See +`docs/agents/triage-labels.md`. + +### Domain docs + +The repository uses a single-context domain model rooted at `CONTEXT.md`, with +architectural decisions under `docs/adr/`. See `docs/agents/domain.md`. diff --git a/CONTEXT.md b/CONTEXT.md index e244e670..3ea06eb6 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -1,95 +1,42 @@ # Contesto di dominio di ThothII -## Architettura del workflow +## Workflow -**Workflow Kernel** — Il coordinatore deterministico che possiede lo stato del workflow, -le transizioni, il rollback, la finalizzazione e l'applicazione atomica degli esiti dei -moduli. +**Workflow core** — La parte condivisa del workflow NL→SQL che governa la sequenza +delle fasi, il ciclo di vita delle sessioni, la revisione umana e la persistenza. Non è +un processo distinto né un sistema estensibile di plugin. -**Workflow Module** — Una capacità incapsulata che espone un contratto versionato. Un -modulo può partecipare a più stage e non modifica direttamente lo stato del workflow. +**Internal workflow module** — Un insieme coeso di comportamento e conoscenza di +dominio sviluppato e rilasciato insieme a ThothII. È isolato per rendere locali le +modifiche, non per essere caricato dinamicamente o sostituito da implementazioni esterne. -**Stage** — Un punto del workflow, identificato semanticamente, nel quale viene invocato -un modulo. L'identità dello stage è indipendente dalla sua posizione visiva. +**Pi** — Il runtime agentico concreto usato da ThothII per le elaborazioni che +richiedono un modello. Segue le istruzioni del workflow e usa gli strumenti messi a +disposizione dai moduli interni. -**Display code** — L'etichetta di presentazione associata a uno stage, per esempio da -`F1` a `F8`. I display code alimentano gli indicatori di avanzamento nel frontend, ma non -sono usati come identità del workflow o chiavi di dipendenza. +**Admission** — Il controllo che stabilisce se una domanda può entrare nel workflow +NL→SQL oppure deve essere riformulata o rifiutata. -**Module outcome** — Il risultato proposto da un modulo: eventi tipizzati, modifiche agli -artifact, un'eventuale richiesta di revisione umana e uno stato di esecuzione. Il -Workflow Kernel valida e applica l'esito. +**Disambiguation** — La responsabilità di rendere esplicita e sottoporre a revisione +l’interpretazione di una domanda ambigua prima della generazione SQL. -**Revision request** — La proposta tipizzata con cui un modulo segnala che lo stage -corrente non può concludersi validamente senza rieseguire lo stesso stage o uno stage -precedente. Non produce direttamente una transizione: il Workflow Kernel valida la -richiesta, sospende l'avanzamento e, per riaprire uno stage già completato, attende una -decisione umana tipizzata. Il Kernel, non il modulo, determina gli eventi e gli artifact -causalmente da rendere stale. +**Evidence** — La conoscenza di dominio curata e citabile usata per fondare +l’interpretazione della domanda e le scelte effettuate durante il workflow. -**Question Admission** — Il controllo preliminare eseguito prima delle fasi da `F1` a -`F8`. Nella prima release distingue una domanda utilizzabile da input garbage e verifica -che la domanda appartenga allo scope dichiarato dal workspace. Il suo stato è mostrato -separatamente dagli otto indicatori di fase. +**Memory** — La conoscenza riutilizzabile derivata da decisioni o sessioni precedenti e +resa disponibile alle elaborazioni successive. -**Workspace scope** — La dichiarazione gestita e versionata di ciò che il database di un -workspace rappresenta e delle domande alle quali è destinato a rispondere. Question -Admission la usa come riferimento per valutare la pertinenza di una domanda. +**Datamart** — L’attività finale già esistente che gestisce l’eventuale produzione del +datamart dopo la generazione del SQL. -**Datamart Plugin** — Il modulo sostituibile che implementa lo stage semantico -`datamart`, presentato con display code `F8`. La promozione della memory e la -finalizzazione della sessione non appartengono al Datamart Plugin. - -**Ordered workflow** — La pipeline deterministica composta dal preflight Admission, -dagli otto stage principali ordinati da `F1` a `F8` e dalla finalizzazione. L'ordine -degli stage è esplicito; il workflow non è un DAG generale. - -**Extension point** — Una posizione semantica nel lifecycle dell'Ordered workflow alla -quale possono contribuire uno o più moduli senza diventare nuovi stage visibili. Un -extension point non possiede un display code. - -**Stage state** — La proiezione deterministica degli eventi del workflow che descrive -uno stage come `pending`, `ready`, `running`, `awaiting_human`, `completed`, `skipped` o -`failed`. Non è un valore corrente memorizzato separatamente dal ledger. - -**Required contribution** — Il contributo di un modulo a un extension point che deve -concludersi o essere esplicitamente saltato secondo policy prima che il workflow possa -avanzare. - -**Best-effort contribution** — Il contributo di un modulo il cui fallimento viene -registrato e mostrato come warning, ma non impedisce al workflow di avanzare. - -**Blocked workflow** — La proiezione complessiva di un workflow che non può avanzare a -causa di uno stage o di un contributo required fallito o non disponibile. `Blocked` non -è uno Stage state autonomo. - -**Module invocation** — Una singola richiesta del Workflow Kernel a un modulo in uno -stage o extension point. Conserva la stessa identità attraverso eventuali retry, che -sono tentativi distinti della medesima invocation. - -**Stage skip** — La conclusione esplicita di uno stage senza eseguirne il comportamento. -È ammessa soltanto dalla policy dello stage e registra motivo e attore; un fallimento non -equivale mai implicitamente a uno skip. - -**Stage reopen** — La riapertura di uno stage non finalizzato che rende stale gli esiti -causalmente successivi. Gli effetti esterni già prodotti richiedono una marcatura o una -compensazione esplicita e non sono presentati come automaticamente annullati. Può essere -applicata dal Workflow Kernel in seguito all'approvazione di una Revision request, ma -non può essere eseguita direttamente da Pi o da un Workflow Module. - -**Completion policy** — La regola con cui uno stage si conclude: `automatic` quando il -kernel può verificarne deterministicamente l'esito, oppure `review_required` quando è -necessaria un'approvazione umana tipizzata. - -**Paused session** — Una sessione interrotta intenzionalmente ma resumibile. L'azione +**Paused session** — Una sessione interrotta intenzionalmente ma resumibile. L’azione “Stop and save” mette la sessione in pausa; non la completa e non la marca come fallita. -**Finalized session** — Una sessione completata con esito canonico e immutabile. Una -correzione successiva crea una nuova sessione derivata, collegata a quella precedente. +**Finalized session** — Una sessione completata che non accetta ulteriori modifiche al +proprio risultato. -**After-finalize hook** — Una notifica o attività best-effort eseguita tramite outbox -dopo la finalizzazione. Non può modificare il ledger, gli artifact canonici o lo stato -terminale della sessione. +**Workspace scope** — La dichiarazione di ciò che il database di un workspace +rappresenta e delle domande alle quali è destinato a rispondere. ## Catalogo dei metadati @@ -103,8 +50,12 @@ Workspace Database. Non definisce quali elementi partecipano al workflow SQL. **Database Profile** — L'insieme curato di scope, descrizioni e metadati semantici associato a un Workspace Database. -**AI Proposal** — Un contenuto generato con l'ausilio dell'AI che non è ancora stato -approvato come contenuto canonico. +**Generated comment** — Il testo descrittivo prodotto dall'AI per una tabella o una +colonna. Rimane distinto dalla descrizione finché l'utente non ne richiede la copia. + +**Core Schema Selection** — Il sottoinsieme di tabelle, colonne e relazioni di un +Workspace Database reso disponibile al processo core di ThothII. È distinto dal +Workspace scope, che descrive il dominio e le domande ammesse. **Publication** — Una versione approvata e immutabile dei contenuti del Metadata Catalog resa disponibile ai suoi consumatori. diff --git a/docs/agents/domain.md b/docs/agents/domain.md new file mode 100644 index 00000000..b17f6571 --- /dev/null +++ b/docs/agents/domain.md @@ -0,0 +1,25 @@ +# Domain documentation + +ThothII uses a single domain context. + +## Before exploring + +Read: + +- `CONTEXT.md` for the canonical domain vocabulary; +- relevant ADRs under `docs/adr/`, when present. + +Missing documents are not an error. Domain terms and ADRs are created only when an +actual decision makes them necessary. + +## Vocabulary + +Use the canonical terms defined in `CONTEXT.md`. Avoid introducing synonyms for +concepts already defined there. + +When a required concept is absent, use `domain-modeling` to clarify and record it. + +## Architectural decisions + +If proposed work contradicts an existing ADR, surface the conflict explicitly rather +than overriding the decision silently. diff --git a/docs/agents/issue-tracker.md b/docs/agents/issue-tracker.md new file mode 100644 index 00000000..bc048ada --- /dev/null +++ b/docs/agents/issue-tracker.md @@ -0,0 +1,33 @@ +# Issue tracker: GitHub + +Issues and specifications for this repository live in GitHub Issues. Use the `gh` CLI +for all operations. + +## Repository + +- Repository: `mptyl/ThothII` +- URL: https://github.com/mptyl/ThothII +- Pull requests as a triage surface: no + +## Conventions + +- Create issues with `gh issue create`. +- Read issues and comments with `gh issue view`. +- Apply labels with `gh issue edit`. +- Record resolutions in a comment before closing an issue. +- Refer to issues by their linked title in user-facing documentation, not only by + number. + +## Wayfinding operations + +- A Wayfinder map is an issue labelled `wayfinder:map`. +- Decision tickets are child issues labelled `wayfinder:research`, + `wayfinder:prototype`, `wayfinder:grilling` or `wayfinder:task`. +- Use native GitHub sub-issues and issue dependencies when available. +- If native sub-issues are unavailable, use a task list in the map and add + `Part of #` to each ticket. +- If native dependencies are unavailable, add `Blocked by: #` to the ticket. +- An open, unassigned and unblocked child issue belongs to the frontier. +- Claim a ticket by assigning it before beginning work. +- Resolve a ticket by recording the decision in a comment, closing it and adding a + linked one-line summary to the map. diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md new file mode 100644 index 00000000..d9dc919d --- /dev/null +++ b/docs/agents/triage-labels.md @@ -0,0 +1,9 @@ +# Triage labels + +| Canonical role | GitHub label | Meaning | +| ----------------- | ----------------- | --------------------------------------------- | +| `needs-triage` | `needs-triage` | The issue still needs evaluation | +| `needs-info` | `needs-info` | More information is required | +| `ready-for-agent` | `ready-for-agent` | Ready for autonomous agent work | +| `ready-for-human` | `ready-for-human` | Requires human intervention or implementation | +| `wontfix` | `wontfix` | Will not be actioned | diff --git a/docs/prd/2026-08-21-modularizzazione-disambiguazione-evidence-memory-prd.md b/docs/prd/2026-08-21-modularizzazione-disambiguazione-evidence-memory-prd.md new file mode 100644 index 00000000..3eed171d --- /dev/null +++ b/docs/prd/2026-08-21-modularizzazione-disambiguazione-evidence-memory-prd.md @@ -0,0 +1,279 @@ +# PRD — Modularizzazione a moduli incapsulati: disambiguazione, evidence, memory + +**Status:** riflessione architetturale di plausibilità — nessuna decisione implementativa presa qui; il +documento fissa confini, contratti condivisi e precondizioni da cui potranno nascere ticket e piani separati +**Data:** 2026-08-21 +**Autore:** analisi del codice su main (`5f05754`), su richiesta del proprietario; incrocia e non sostituisce +i documenti evidence-canonica già esistenti (sez. 9) +**Uso:** riferimento per il programma di sviluppo parallelo dei tre sottosistemi (disambiguazione, gestione +evidence, gestione memory); definisce cosa deve essere vero *prima* che i tre flussi possano girare in +parallelo senza impatti incrociati + +--- + +## 1. L'obiettivo del proprietario + +Avviare uno sviluppo che cambi **in parallelo** tre aree del sistema: + +1. **disambiguazione** (estratta e separata dal workflow); +2. **gestione delle evidence** — nuovo componente che espone un'API verso il resto del workflow ma resta + ben incapsulato al suo interno; +3. **gestione della memory** — con lo stesso grado di forte incapsulamento. + +Vincolo accettato: le modifiche fatte su un modulo **non devono impattare gli altri moduli** se non per +eventuali ridefinizioni dei contratti (API) esposti. + +## 2. Verdetto sintetico + +**Plausibile, e il codebase è insolitamente ben predisposto per farlo.** Ma con tre precisazioni oneste: + +1. i tre componenti sono oggi a **tre livelli di maturità diversi**: evidence è quasi un modulo, memory è + già incapsulata meglio di quanto sembri, la disambiguazione **non è un componente di codice** e + "estrarla" è un lavoro di natura diversa (sez. 4); +2. esistono **due "quinti moduli" nascosti** — il ledger dei tipi di decisione con `workflow.yaml`, e il + gate `tht-gate.js` con il vector store — che il piano a tre vie deve contemplare, altrimenti il + parallelismo si rompe dove non si sta guardando (ledger e gate sono spiegati in sez. 3; le implicazioni + in sez. 5); +3. gli accoppiamenti reali **non sono negli import Python**: sono nei decision type del ledger, nelle + proiezioni `search pack`/`search find`, nel modello di contenuto della memory e negli id evidence + citabili. Sono quelli i contratti da definire e versionare **prima** del parallelismo (sez. 6–7). + +## 3. Ledger e gate: i due elementi cardine del workflow + +Il resto del documento usa di continuo due concetti che conviene fissare qui, perché sono +i punti dove i tre moduli si incontrano davvero: il **ledger** (dove lo stato viene +registrato) e il **gate** (chi decide e chi scrive). + +### 3.1 Il ledger — il registro delle decisioni (`review_decisions.jsonl`) + +Una sessione è una directory: manifest + artefatti per fase (`question.md`, +`schema_linking.json`, `sql_final.sql`, …) + un file `review_decisions.jsonl`. Il ledger +è **append-only**: una riga JSON per ogni decisione del reviewer, con numero progressivo +`seq`, timestamp, `type`, `subject`, `detail`, `rationale` (più i campi di rollback +`retracts`/`phase`). I `DecisionType` definiti in `tht/decisions.py` sono esattamente 30. + +Esempio concreto: a F1 il reviewer sceglie "per 'ablazione' intendo la colonna +`flag_ablazione` della fact delle procedure" → nel ledger viene accodata una riga come +`{"seq": 3, "ts": "…", "type": "concept_clarified", "subject": "ablazione", "detail": "…", +"rationale": "…"}`. + +Due proprietà lo rendono cardine: + +1. **la fase corrente non è memorizzata: è calcolata** rileggendo (fold) il ledger + (`tht/phase.py`). Il ledger è la fonte di verità — "ciò che non è registrato non è + accaduto". Il rollback non cancella nulla: aggiunge `decision_retracted`/ + `phase_reopened` e la vista *effettiva* (`effective_decisions`) esclude le righe + ritirate e quelle rimaste stale oltre il punto di rollback; +2. **è il canale di comunicazione tra i moduli**: la disambiguazione *scrive* + `concept_clarified`/`ambiguity_open`/`value_grounded`; l'evidence *scrive* + `evidence_accepted`/`evidence_rejected`/`concept_formula_approved|rejected`; la memory + *legge* `concept_clarified` (per costruire le promozioni) e *scrive* `memory_promoted`/ + `memory_promotion_declined`. Per questo l'insieme dei decision type **è** un contratto: + ridefinirlo (sez. 6.1) è l'equivalente di cambiare una API tra moduli. + +### 3.2 Il gate — l'estensione che impone il human-in-the-loop (`tht-gate.js`) + +ThothII non esegue il workflow con codice: lo esegue **un agente LLM (Pi)** che segue +SKILL.md. Il modello propone, ma non decide e non persiste direttamente. Il gate è +l'estensione JavaScript di Pi (~2000 righe, `harness/.pi/extensions/tht-gate.js`) che +svolge tre lavori: + +1. **traduce le proposte del modello in widget per l'umano**: il modello chiama un tool + del gate — `reviewer_select` (scelta singola), `reviewer_decide` (multiselect), + `reviewer_confirm` (gate su artefatto/fase) più i specializzati `rewrite_question`, + `reviewer_schema_linking`, `reviewer_datamart`, `reviewer_memory_promote`, + `write_schema_linking`, `write_cte_sql`, `write_final_sql`; il gate costruisce il + descriptor del widget → RPC → backend → SSE → browser, dove il frontend lo renderizza + dal registry `src/widgets/`; +2. **persiste attraverso un unico canale**: alla risposta del reviewer, è il gate (non il + modello) a invocare la CLI `tht` (es. `tht memory promote --preview --json`, + `tht session sync-schema-linking`) e ad accodare la riga nel ledger; +3. **fa rispettare le regole (enforcement)**: l'hook anti-bypass blocca `tht phase + advance`, `tht decision add`, `tht memory promote|save-one` se il modello prova a + eseguirli direttamente dalla shell; i payload vengono validati (TypeBox) e gli + artefatti mostrati al reviewer sono ricostruiti in modo deterministico (es. il widget + CTE mostra il SQL persistito via `tht cte info`, non il testo del modello); le + chiusure di fase deterministiche sono automatiche. + +Esempio concreto (F8): il modello chiama `reviewer_memory_promote`; il gate esegue +`tht memory promote --preview --json`, costruisce la checklist pre-selezionata; il +reviewer conferma; il gate salva le memory scelte (`memory save-one`), registra +`memory_promoted`/`memory_promotion_declined` nel ledger e finalizza la sessione. Il +modello non ha mai scritto nulla di propria mano. + +Perché è cardine per la modularizzazione: il gate è **l'unico punto** in cui i tre moduli +appaiono all'utente e in cui le loro regole vengono imposte — ogni cambiamento a +disambiguazione/evidence/memory ha quasi sempre una controparte nel gate (sez. 5.2). + +## 4. Stato attuale dei tre componenti + +### 4.1 Evidence — il più vicino a essere un modulo + +Fatti verificati nel codice: + +- esiste già un **port vero** (`harness/tht/ports/evidence.py`: `discover`/`acquire`, credential-free, + contratti Pydantic congelati) con **tre adapter** dietro il port (`adapters/evidence/{filesystem,http,s3}.py`); +- la pipeline di canonizzazione/indicizzazione vive in `harness/tht/corpus/` (sorgente → normalize → + chunk → embed → vector store, generazioni isolate stage→publish); +- la **superficie di consumo del workflow è già quasi tutta incanalata in due comandi con JSON pulito**: + `tht search pack` (sezione evidence: top 5, proiezione `{title, status, excerpt[:400]}`) e + `tht search find [--kind evidence|formula]`. Quella proiezione è già di fatto un'API: evidence-canonica + può rifare tutto dietro di essa (card, involucro tipizzato, retrieval duale) senza che F1 se ne accorga, + finché il contratto di proiezione regge; +- l'**inventario dei punti di consumo è già fatto**: `verifica-workflow.md` elenca i 12 touchpoint (T1–T12) + con meccanismo e requisito. Quel documento **è** la bozza del contratto esterno del modulo. + +Ciò che manca all'incapsulamento sono esattamente i tre GAP lì identificati: + +- **GAP 1 — identità citabile**: il processo tratta l'id evidence come documento (F3 lo cita, F4 lo attacca + ai candidati, il report di sessione lo risolve in file via `resolve_evidence_file`/`rglob`). La decisione + già presa (id citabile `doc#card`) richiede l'estensione del resolver: è l'ultimo passo di contratto da + chiudere; +- **GAP 2 — formula store**: lettura cablata e funzionante, scrittura senza proprietario di produzione. + La decisione già presa (le card famiglia 3 del corpus canonico sono fonte di verità; i `.sql.md` sono + derivati della pipeline) assegna il proprietario senza toccare il contratto di lettura D14b; +- **GAP 3 — conoscenza di dominio nei testi istruzionali**: dialetto, ricette temporali PSD, esempi clinici + dentro SKILL.md e reference doc. È contenuto evidence sparso nel workflow: la migrazione verso il corpus + canonico **è parte del lavoro di confine**, non un'attività cosmetica successiva. + +Nota trasversale: il ciclo di vita evidence attraversa **due linguaggi** — materializzazione e ciclo di vita +della collection stanno nel backend TypeScript (P4/P6), corpus e ricerca nello harness Python. L'API del +modulo deve quindi essere il contratto CLI/JSON (che è già lo stile di casa: `--json` pristine), non +un'interfaccia Python. + +### 4.2 Memory — già incapsulata, con un accoppiamento semantico da esplicitare + +Fatti verificati: + +- il modulo vive in `harness/tht/memory.py` + `tht/solved.py` + `cli/memory_cmd.py`, con registro JSONL + a scrittura atomica e dedup del contenuto reviewer-visibile; +- i punti di contatto col workflow sono **esattamente tre**: F2 (ricerca + applicazione via gate), F8 + (gate di promozione), finalize (indicizzazione `solved_question`, best-effort); +- il gate consuma la memory **solo tramite CLI**: `tht memory promote --preview --json` e + `memory save-one`; la logica di calcolo dei candidati (dedup, decisioni storie post-rollback, seq + rifiutate, esclusione delle già decise nella sessione) è tutta dentro memory.py. È incapsulamento vero, + già operativo. + +L'accoppiamento che conta non è di codice ma **semantico**: `REUSABLE_TYPES = {"concept_clarified"}` — +il modello di contenuto della memory è definito dal tipo di output della disambiguazione. Se il ridisegno +F1 cambia cosa sia un chiarimento (target group, tassonomia dell'ambiguità, caso unanswerable), cambia +anche cosa la memory può promuovere e come. **Il contratto disambiguazione→memory va definito prima di +far girare i due flussi in parallelo**, o si scontreranno esattamente lì. + +### 4.3 Disambiguazione — non è un componente di codice + +Il punto onesto: **non c'è niente da "estrarre" nel senso classico**. Oggi la disambiguazione è il +comportamento dell'LLM in F1/F3/F4, governato da (ledger e gate: sez. 3): + +- **prosa** (SKILL.md + `rewriting.md`): una sola ambiguità per volta, opzioni informate, "lascia aperta + l'ambiguità" esplicita; +- **retrieval**: pack iniettato (`retrieval_pack.md`), `tht search find`, `tht schema render`, LSH con + `aggregate_lsh_multi` che espone *tutte* le colonne dove un valore appare (es. "ablazione" su flag + booleano + campo patologia testuale); +- **ledger**: `concept_clarified`, `ambiguity_open`, `value_grounded`, `question_rewritten`; +- **gate**: i widget che presentano le interpretazioni candidate. + +"Extractorla" significa quindi, in ordine: + +1. **definire il suo contratto input/output** — in: domanda + contesto di retrieval; out: ambiguità con + target group, opzioni candidate, segnale unanswerable distinto dall'ambiguo. È ciò che + `impact-ridisegno-disambiguazione.md` §3 già elenca (retrieval duale lessicale+semantico, target group, + unanswerable); +2. **darle una superficie** che l'orchestratore consuma (sezione del pack, comando, sezione skill dedicata) + invece di comportamento libero del modello; +3. **spostare la conoscenza che usa** fuori da SKILL.md e dentro le evidence (GAP 3). + +Rischio specifico e strutturale: l'LLM è colla che **può bypassare qualunque contratto su carta**. In +questo codebase l'unico enforcement che funziona è a livello gate/CLI — il pattern è già dimostrato +dall'hook anti-bypass che blocca `tht phase advance`/`decision add` da shell e `tht memory promote`/ +`save-one` fuori dal gate. Finché il contratto di disambiguazione non è enforcement (hook + CLI + skill +come contratto completo), la proprietà "le modifiche non impattano altri moduli" è una speranza, non una +proprietà verificabile. + +## 5. I due quinti moduli nascosti + +### 5.1 Il ledger + `workflow.yaml` — la colonna vertebrale condivisa + +Tutti e tre i moduli leggono/scrivono il decision ledger (`review_decisions.jsonl`, sez. 3.1): la +disambiguazione +emette `concept_clarified`/`value_grounded`; l'evidence emette `evidence_accepted`/`evidence_rejected`/ +`concept_formula_approved|rejected`; la memory legge `concept_clarified` ed emette `memory_*`. Il campo +`emits` di `workflow.yaml` accoppia fasi e decision type; `phase.py` piega il ledger per calcolare la +fase corrente. + +Questo è un **bene**: il ledger è già un contratto a eventi tra i moduli. Ma è superficie condivisa — +tutti e tre i flussi vorranno toccarla. Va trattata come contratto a sé (quarto), con controllo dei +cambiamenti, non come territorio libero. + +### 5.2 Il gate (`tht-gate.js`) e il vector store — i punti caldi di merge + +- **Il gate** (sez. 3; ~2000 righe + builders/enrich/artifact-contracts) renderizza candidati evidence, dedup + opzioni memory, costruisce il widget schema-linking con id evidence, guida F2/F8 memory e fa enforcement + anti-bypass. **Tutti e tre i flussi avranno bisogno di modifiche al gate**: se non viene spaccato lungo + gli stessi confini dei moduli, diventa il punto caldo di merge del programma parallelo. +- **Il vector store**: una collection Qdrant per workspace, kind-separata (`schema_table`, `schema_column`, + `evidence`, `memory`, `solved_question`); il contratto di collection e payload-index è di proprietà del + backend TS (P4), lettura/scrittura sono Python. I record schema/evidence sono revision-scoped (P3), + memory/solved workspace-wide. Se evidence-canonica cambia la forma dei record/payload (il frontmatter + già fluisce libero nei metadata), gli assunti di indicizzazione della memory ne risentono. Il vector + store va designato come **infrastruttura condivisa con contratto proprio**, non come territorio + implicito di uno dei tre. + +## 6. I contratti che sono le vere API + +Il parallelismo è protetto da quattro contratti, nessuno dei quali è un'interfaccia Python: + +1. **Decision type del ledger** (`workflow.yaml` `emits` + `decisions.py`): l'interfaccia a eventi tra i + tre moduli e il workflow. Ogni ridefinizione è una modifica di contratto, va versionata e comunicata; +2. **Proiezioni di consumo evidence** (`search pack` / `search find --kind evidence|formula`): la forma di + ciò che F1/F3/F4 vedono. È il cuore del ticket "Consumo per fase", che già porta i requisiti della F1 + ridisegnata e **non va congelato prima** che il disegno F1 abbia almeno uno schizzo; +3. **Modello di contenuto memory** (`REUSABLE_TYPES` + campi del record + proiezione `promote --preview + --json`): dipende semanticamente dal contratto di output della disambiguazione (sez. 4.2); +4. **Id evidence citabile** (`doc#card` + estensione del resolver id→file): il contratto che tiene insieme + F3 (citazioni), F4 (candidati), decisions (subject) e report di sessione. + +## 7. Ordine di sviluppo consigliato + +Coerente con quanto già deciso in `map.md` e nell'impact doc: + +1. **schizzo del disegno F1** della disambiguazione (anche non finale): target group, retrieval duale, + unanswerable — perché il contratto di consumo va progettato *contro la F1 ridisegnata*; +2. **chiusura del contratto "Consumo per fase"** (cerniera tra evidence-canonica e F1): proiezioni, + filtri, id citabili `doc#card` con resolver esteso; +3. **definizione del contratto disambiguazione→memory** (cosa è riusabile, con quali campi); +4. **solo allora** i tre flussi girano in parallelo, ciascuno nel suo worktree. + +Strumento di protezione del parallelismo già disponibile in casa: il **pattern dei port-contract test** +(`test_evidence_port_contract.py`, `test_vector_port_contract.py`, `test_dwh_port_contract.py`). +Estenderlo ai nuovi confini (proiezioni evidence, contratto memory, enforcement di disambiguazione) è il +modo più economico per rendere l'indipendenza dei moduli **verificabile** invece che sperata: un flusso +rompe l'altro se e solo se rompe un test di contratto, non per effetti nascosti. + +## 8. Rischi e mitigazioni + +| Rischio | Natura | Mitigazione | +|---|---|---| +| L'LLM orchestratore bypassa il contratto di disambiguazione | strutturale (il workflow è LLM-driven) | enforcement gate/CLI sul modello dell'anti-bypass esistente; SKILL come contratto completo, non consiglio | +| Collisione disambiguazione↔memory su `concept_clarified` | semantica | contratto esplicito (sez. 6.3) definito prima del parallelismo | +| `tht-gate.js` punto caldo di merge | organizzativa | spaccare il gate lungo gli stessi confini dei moduli (builders per modulo) | +| Deriva del contratto vector store tra TS e Python | infrastrutturale | contratto di collection/payload/kind di proprietà unica, test di contratto su entrambi i lati | +| modifiche contagiose a `workflow.yaml`/ledger | processo | change control sul ledger come quarto contratto; `emits` data-driven già aiuta | +| contratti congelati troppo presto (Consumo per fase) | sequenza | ordine sez. 7: prima schizzo F1, poi chiusura contratto | + +## 9. Riferimenti + +- `docs/wayfinder/evidence-canonica/map.md` — mappa del sottoprogetto evidence-canonica (destinazione, + decisioni chiuse, nebbie); +- `docs/wayfinder/evidence-canonica/prototypes/verifica-workflow.md` — i 12 touchpoint evidence (T1–T12) e + i GAP 1–3: l'inventario dell'interfaccia esterna del futuro modulo evidence; +- `docs/wayfinder/evidence-canonica/prototypes/impact-ridisegno-disambiguazione.md` — valutazione d'impatto + del ridisegno F1 (requisiti: retrieval duale, target group, unanswerable; coordinamento dei due progetti); +- `docs/wayfinder/evidence-canonica/prototypes/PROTOTIPO-formato-unita-canonica.md` e `tipologia-evidence.md` + — formato card+involucro chiuso il 2026-08-21 e casistica a 7 famiglie; +- `docs/disambiguazione-iniziale.md` — stato attuale della disambiguazione; +- `docs/gestione-memory.md` — disegno della gestione memory; +- `harness/workflow.yaml`, `harness/.pi/skills/tht-sessione/SKILL.md`, `harness/.pi/extensions/tht-gate.js` + — le fonti di codice citate (fasi, discipline, gate); +- `docs/prd/2026-08-09-workspace-preprocessing-prd.md` — il PRD da cui nasce l'attuale catena + preprocessing/registry (contesto P2–P6 citato in sez. 4.1 e 5.2). diff --git a/docs/prd/2026-08-23-refactoring-modulare-conservativo-brief.md b/docs/prd/2026-08-23-refactoring-modulare-conservativo-brief.md new file mode 100644 index 00000000..56638d3d --- /dev/null +++ b/docs/prd/2026-08-23-refactoring-modulare-conservativo-brief.md @@ -0,0 +1,141 @@ +# Brief — Refactoring modulare conservativo del workflow + +**Stato:** input autorevole per `grill-with-docs`; non è ancora una specifica +implementativa. + +## Obiettivo + +Riorganizzare l’attuale applicazione ThothII per rendere locali e manutenibili le +modifiche a Disambiguation, Evidence e Memory, preservando integralmente comportamento, +frontend e flusso operativo esistenti. + +La prima milestone è esclusivamente un refactoring. Non introduce nuove funzionalità e +non generalizza ThothII come piattaforma di plugin. + +## Vincoli già decisi + +- Il progetto continuerà a essere sviluppato e mantenuto da un solo proprietario, in un + unico repository e con un unico rilascio. +- I moduli sono package interni secondo normali criteri di programmazione a oggetti. + Non devono essere distribuibili indipendentemente, caricati dinamicamente o scritti da + terze parti. +- I moduli non devono condividere un contratto universale. Ogni modulo può presentare al + workflow una piccola façade adatta alla propria responsabilità. +- Moduli e fasi non coincidono necessariamente: un modulo può contribuire a più fasi e + una fase può coordinare più moduli senza introdurre un protocollo generale. +- Pi resta il runtime concreto per le elaborazioni assistite dal modello. Non viene + introdotta un’astrazione `ModelRuntime`. +- Il workflow resta ordinato e continua a usare `harness/workflow.yaml`, il ledger delle + decisioni, i documenti di sessione e gli attuali gate human-in-the-loop. +- Frontend, eventi SSE, widget, comandi `tht`, JSON, codici di uscita e formato delle + sessioni devono rimanere compatibili. +- Non sono previste migrazioni dei dati delle sessioni esistenti. +- Il flusso SQL centrale, inclusi schema linking, sintesi, CTE e SQL finale, resta nel + workflow core durante questa milestone. +- Un altro componente futuro, estraneo al workflow e al core, non appartiene a questo + refactoring. + +## Moduli interni desiderati + +### Admission + +Occupa l’inizio logico del workflow. Nella prima milestone è un pass-through e ammette +sempre la domanda, così il comportamento osservabile non cambia. + +Per una fase futura è già stata scelta questa policy: una domanda non ammessa può essere +riformulata nella stessa sessione; dopo il terzo tentativo fallito la sessione fallisce. +La classificazione e l’esperienza utente non fanno parte del primo refactoring. + +### Disambiguation + +Raccoglie senza cambiarne il comportamento la logica attuale di chiarimento, +interpretazione revisionata e riscrittura della domanda, comprese istruzioni Pi, +validazioni e presentazione delle relative decisioni. + +### Evidence + +Consolida le superfici esistenti di acquisizione, canonizzazione, ricerca e citazione. +Mantiene i seam già reali verso filesystem, HTTP e S3 e il contratto CLI/JSON necessario +fra Python e TypeScript. Non introduce un contratto generale per gli altri moduli. + +### Memory + +Raccoglie senza variazioni funzionali ricerca, selezione, promozione e conoscenza delle +domande già risolte, insieme alle istruzioni e ai gate specifici oggi dispersi. + +### Datamart + +Incapsula senza modificarla la parte di gestione del datamart oggi svolta nella fase F8. +La fase F8 rimane visivamente e funzionalmente invariata, ma l’eventuale comportamento +Memory che contiene appartiene al modulo Memory. La futura integrazione intelligente del +SQL in un progetto dbt o in un flusso ETL è deliberatamente rinviata al momento in cui +questo modulo verrà sviluppato. + +## Responsabilità che restano condivise + +Il workflow core conserva soltanto ciò che appartiene realmente all’intero flusso: + +- ordine e avanzamento delle fasi; +- ciclo di vita e resume delle sessioni; +- ledger e documenti di sessione esistenti; +- persistenza e locking comuni; +- processo Pi e trasporto backend/frontend; +- gate generici, sicurezza anti-bypass e finalizzazione; +- coordinamento esplicito dei moduli tramite import statici. + +I moduli non si scoprono tramite registry e non comunicano tramite event bus. Le +dipendenze condivise vengono ricevute dal modulo oppure coordinate dal workflow core; +un modulo non importa direttamente l’implementazione di un altro. + +## Architettura esplicitamente rifiutata + +Questa iniziativa non deve introdurre: + +- Kernel separato dall’attuale harness; +- manifest, registry, binding o composition resolver; +- negoziazione e versionamento di un contratto universale; +- adapter di esecuzione `in_process`, `process` o `job`; +- `WorkflowDefinition`, `WorkflowCommit`, nuovo event store o upcaster; +- artifact slot e revisioni universali; +- Review Port, Interaction Request/Result o Instruction Bundle generici; +- plugin dbt o automazioni ETL nella prima milestone. + +## Fatti rilevanti sul codice attuale + +- `harness/.pi/extensions/tht-gate.js` è il principale punto caldo condiviso, con circa + 2.000 righe e logica relativa a più domini. +- `harness/.pi/skills/tht-sessione/SKILL.md` contiene circa 450 righe di istruzioni che + attraversano tutte le fasi. +- Evidence possiede già un port reale e tre adapter per filesystem, HTTP e S3. +- Memory possiede già codice dedicato, ma responsabilità e integrazione sono distribuite + tra modulo Python, CLI, gate e istruzioni Pi. +- Disambiguation oggi è soprattutto comportamento distribuito fra istruzioni, decisioni + e gate, non un package applicativo autonomo. +- `harness/workflow.yaml` è già la fonte condivisa dell’ordine e dei requisiti delle + fasi e deve rimanere tale. + +L’analisi più ampia del problema corrente resta disponibile in +[`2026-08-21-modularizzazione-disambiguazione-evidence-memory-prd.md`](2026-08-21-modularizzazione-disambiguazione-evidence-memory-prd.md). + +## Criterio di riuscita + +Dopo il refactoring, una modifica interna a Disambiguation, Evidence o Memory deve +richiedere normalmente interventi nella directory e nei test del relativo modulo. Il +workflow core cambia soltanto quando cambia davvero il flusso condiviso. + +La suite esistente, i test di caratterizzazione e i test end-to-end devono dimostrare +che il frontend e ogni comportamento osservabile sono rimasti invariati. + +## Questioni da affidare a `grill-with-docs` + +L’intervista deve concentrarsi soltanto sulle decisioni necessarie al refactoring: + +1. ownership esatta dei file e delle responsabilità attuali; +2. façade minima e specifica di ciascun modulo; +3. collocazione delle istruzioni Pi e degli helper del gate relativi a ciascun dominio; +4. dipendenze condivise che devono essere ricevute dai moduli; +5. ordine di estrazione incrementale e test di caratterizzazione per ogni passaggio; +6. criteri oggettivi che impediscano al refactoring di introdurre cambiamenti funzionali. + +Le funzioni future di Admission e Datamart/dbt sono fuori dal frontier dell’intervista: +vanno discusse soltanto dopo il completamento del refactoring conservativo. diff --git a/docs/superpowers/specs/2026-08-23-refactoring-modulare-conservativo-design.md b/docs/superpowers/specs/2026-08-23-refactoring-modulare-conservativo-design.md new file mode 100644 index 00000000..0be018d2 --- /dev/null +++ b/docs/superpowers/specs/2026-08-23-refactoring-modulare-conservativo-design.md @@ -0,0 +1,486 @@ +# 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`](../../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 + +```text + 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 è: + +```text +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.