chore: preserve root worktree documents

This commit is contained in:
Codex
2026-08-31 15:34:55 +02:00
parent b5db0cd3c1
commit fa7380b3a3
8 changed files with 1021 additions and 80 deletions
@@ -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).
@@ -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.