Files
ThothII/docs/plans/2026-08-18-evidence-canonica-design.md
T

218 lines
11 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Evidence canonica — struttura tipizzata per disambiguazione, schema linking e SQL
> **Superseded (2026-08-24).** Questo documento conserva la storia della prima
> proposta. Il disegno approvato è
> [`2026-08-24-evidence-restructuring-design.md`](2026-08-24-evidence-restructuring-design.md)
> e il relativo piano esecutivo è
> [`2026-08-24-evidence-restructuring.md`](2026-08-24-evidence-restructuring.md).
## Contesto e decisioni prese
ThothII ha già due livelli separati che non si parlano:
- **`EvidenceDoc`** (`harness/tht/evidence/model.py`) — runtime: frontmatter piatto
(`id/title/tier/status/tables/concepts/sources`) + `body` markdown libero. `tier`
distingue solo `structural|concept`, insufficiente rispetto ai 6 tipi reali del corpus.
- **Pipeline corpus** (`harness/tht/corpus/`) — canonizzazione *tecnica* (hash,
provenienza, chunking, vettorizzazione), agnostica rispetto al tipo di evidenza.
Il corpus reale (`ChironeWp3/artifacts/evidence/`) ha una tassonomia implicita in 6
directory (`00-glossario`, `10-domini-clinici`, `20-valori-enum`, `30-esempi-nlq`,
`40-mapping-semantico`, `50-metadati-normalizzazione`) ma:
- frontmatter piatto, `tier` inadeguato;
- file già rotti (`--` invece di `---`, bullet `•⁠ ⁠` invece di `-`) che `EvidenceDoc.parse`
rifiuterebbe;
- al retrieval la struttura si perde: `tht search pack` proietta solo `title` + 400 char.
**Decisioni (confermate nel brainstorming):**
1. **Obiettivo**: strutturare il *contenuto* runtime, non toccare la pipeline corpus.
2. **Forma**: ibrido — frontmatter tipizzato + sezioni canoniche per `kind`.
3. **Tassonomia**: doppia — `kind` (contenuto) + `applies_to` (destinazioni:
`disambiguation`, `rewriting`, `schema_linking`, `sql_generation`, `memory`).
4. **Anchors come fonte primaria** per il value-grounding in F4; LSH solo fallback.
5. **Approccio**: contratto in `tht` + authoring sottile (niente app separata, niente
client LLM diretto in `tht`).
6. **Modello sorgente→canonizzato** (non sovrascrittura in place): file umani in
`source_root/evidence/`, canonizzati derivati in `artifacts/evidence/`, coerente con
l'esistente `tht evidence extract`.
7. **Review**: batch con diff aggregato (approvazione per file).
8. **Rielaborazione**: LLM-assistita via Pi (sessione di manutenzione + gate), con parte
deterministica in `tht`.
## Modello canonico v2
### `CanonicalEvidence` (frontmatter tipizzato)
```yaml
---
schema_version: 2
id: ev-dom-ablazione-see
title: Dominio Ablazione e SEE
kind: domain # glossario | domain | enum | example | mapping | normalization
applies_to: # destinazioni d'uso
- disambiguation # F1
- schema_linking # F4
- sql_generation # F6/F7
status: reviewed
language: it
concepts:
- term: ablazione
synonyms: [ablazione transcatetere, SEE, studio elettrofisiologico]
- term: fibrillazione atriale
synonyms: [FA]
tables:
- name: datawarehouse.fact_studio_elettrofisiologico_endocavitario_ablazione
role: fact
columns: [ablazione_transcatetere, cod_paz, num]
anchors:
- column: datawarehouse.fact_see_ablazione_procedura_patologia.patologia
value: ablazione
match: exact
sources: [...]
# provenienza del derivato (aggiunta dal canonicalize, non dall'umano):
source_file: 10-domini-clinici/ablazione.md
source_fingerprint: sha256:...
canonicalized_at: 2026-08-18T...
---
```
Il `body` resta markdown, ma con **titoli di sezione canonici per `kind`**:
- `glossario`: `## Definizione`
- `domain`: `## Cosa rappresenta`, `## Schema a stella`, `## Granularità`, `## Domande di business tipiche`
- `enum`: `## Valori ammessi`
- `example`: `## Domanda → SQL` + `## Nota clinica`
- `mapping`: `## Trasformazioni disponibili`
- `normalization`: `## Regole di normalizzazione`
Le sezioni canoniche permettono al retrieval di estrarre solo la sezione rilevante per
fase invece di 400 caratteri generici.
### `kind` vs `applies_to`
- `kind` descrive il *contenuto* (i 6 tipi già impliciti).
- `applies_to` descrive *quando usarlo*. Esempi: `enum-tipo-intervento` è `kind: enum` ma
`applies_to: [disambiguation, sql_generation]`; un `example` è
`applies_to: [sql_generation, memory]`.
## Modello a 3 livelli
```
source_root/evidence/*.md (umano, libero, può essere sporco)
│ tht evidence canonicalize (deterministico + LLM via Pi + review batch)
▼
artifacts/evidence/*.md (canonico, validato, derivato, rigenerabile)
│ tht evidence index (esistente)
▼
corpus / vector store (vettorializzato dal canonico, mai dal sorgente)
```
Il canonizzato porta `source_file` + `source_fingerprint`: se il sorgente cambia, la
canonizzazione ripropone il diff; se invariato, no-op.
## Componenti da creare/modificare
### 1. `harness/tht/evidence/model.py` (modifica)
- Aggiungere `CanonicalEvidence` (pydantic, v2) con `schema_version`, `kind`,
`applies_to`, `concepts[]` (`{term, synonyms[]}`), `tables[]`
(`{name, role, columns[]}`), `anchors[]` (`{column, value, match}`), `source_file`,
`source_fingerprint`, `canonicalized_at`.
- Validatore strict: `kind` ammesso, `applies_to` ammesso, `anchors[].column` deve
essere `schema.colonna` ben formato, `match` in `{exact, contains, regex, substring}`.
- `EvidenceDoc` v1 resta per leggere il sorgente e per retro-compatibilità dei vecchi
canonizzati; `CanonicalEvidence` è un modello separato, non una sottoclasse.
- Validatore che garantisce `source_fingerprint` = sha256 del contenuto sorgente.
### 2. `harness/tht/evidence/lint.py` (nuovo, deterministico)
- `lint_source(path) -> list[Diagnostic]`: frontmatter rotto, `tier`/`status` non validi,
bullet Unicode, campi mancanti, `tables` non qualificate con schema, concetti senza
sinonimi, sezioni non canoniche per il `kind` atteso.
- Exit code 0 se nessun errore, 1 se warning, 2 se errori. Nessun LLM.
### 3. `harness/tht/evidence/canonicalize.py` (nuovo)
- `plan(sources, artifacts) -> CanonicalizePlan`: confronta fingerprint dei sorgenti con
i canonizzati esistenti, produce la lista dei file da (ri)canonizzare.
- `render_proposal(source, llm_completions) -> CanonicalEvidence`: assembla il
canonizzato da parsing deterministico + campi semantici forniti da Pi.
- `apply(plan, approved_ids) -> None`: scrive solo i canonizzati approvati in
`artifacts/evidence/`, atomico per file, mantiene la gerarchia per dominio.
- `diff(source, candidate) -> str`: diff markdown per il gate.
### 4. `harness/tht/vectorstore/records.py` (modifica)
- `evidence_records()`: metadata ora include `kind`, `applies_to`, `anchors` (non solo
`status/tier/tables/concepts`).
- Il `content` di ogni record resta title+body, ma per file con sezioni canoniche si
indicizza anche un record per sezione (id `evidence:<id>:<sezione>`) così il retrieval
può restringere per sezione oltre che per documento.
### 5. `harness/tht/search/__init__.py` + `cli/search_cmd.py` (modifica)
- `SearchResult` e `combined_search` accettano `applies_to` come filtro metadata.
- `tht search pack`: la sezione "Evidence rilevanti" ora proietta `kind` + sezione
canonica pertinente (non solo excerpt generico); usa `applies_to` per non mischiare
destinazioni.
- `tht search find --kind evidence --applies-to <dest>` per il retrieval mirato.
### 6. `harness/tht/cli/evidence_cmd.py` (modifica)
- Nuovi comandi:
- `tht evidence lint --source <path|dir>` — diagnostica deterministica.
- `tht evidence canonicalize plan --source-root <dir> --json` — piano di
(ri)canonizzazione.
- `tht evidence canonicalize apply --plan <file> --approved <ids> --json` — applica.
- `--json` sempre pristine (solo JSON su stdout), come da contratto di progetto.
### 7. `harness/.pi/extensions/tht-gate.js` (modifica)
- Nuovo tool `reviewer_evidence_batch`: riceve il piano + i diff aggregati e presenta un
multiselect per file (approva/rifiuta/richiedi modifica). Le scelte approvate vengono
persistite tramite `tht evidence canonicalize apply`.
- Aggiungere `tht evidence canonicalize apply` alla FORBIDDEN anti-bypass list (il
modello non può applicare canonizzazioni senza review).
### 8. Sessione di manutenzione Pi (nuova skill o sezione SKILL)
- Una skill dedicata `tht-evidence-canonicalize` (o un comando slash nel gate) descrive
la sessione di manutenzione: il modello legge i sorgenti marcati dal piano, propone i
campi semantici (`kind`, `applies_to`, `concepts` con sinonimi, `tables` con ruolo,
`anchors`) e li invia al `reviewer_evidence_batch`.
- Il gate è l'unico canale di review; il modello non scrive mai direttamente
`artifacts/evidence/`.
### 9. `harness/.pi/skills/tht-sessione/SKILL.md` (modifica)
- Aggiornare i punti F1/F4/F6-F7 dove il modello legge evidence: spiegare che l'evidence
canonica espone `kind`/`applies_to`/`anchors`, che gli `anchors` sono la fonte primaria
per il value-grounding in F4, e che le sezioni canoniche vanno citate per destinazione.
- Aggiungere il nuovo tool `reviewer_evidence_batch` alla lista dei tool disponibili.
## Migrazione del corpus (incrementale, v1+v2 convivono)
- `CanonicalEvidence` (v2) convive con `EvidenceDoc` (v1): `lint` segnala i non-canonici
ma nulla si rompe; `load_evidence_dir` carica entrambi.
- Convertire a lotti, partendo da `20-valori-enum` e `10-domini-clinici` (impatto
maggiore su F1/F4, anchors più ricchi).
- Il canonizzato derivato in `artifacts/evidence/` sostituisce progressivamente il file
sorgente mirrorato; finché un sorgente non è canonizzato, `extract` continua a
rispecchiare il v1 come oggi.
## Ordine di implementazione
1. `CanonicalEvidence` + `lint` (TDD, nessun LLM).
2. `canonicalize.py` (plan/apply/diff) + comandi CLI (TDD).
3. `records.py` + filtro `applies_to` in `search` + proiezione pack (TDD).
4. Gate `reviewer_evidence_batch` + skill manutenzione Pi.
5. Aggiornamento `SKILL.md` tht-sessione.
6. Conversione primo lotto (`enum` + `domain`) con review batch.
## Verifica
- `cd harness && .venv/bin/pytest -q` — test nuovi per model/lint/canonicalize/records/search.
- `node --test` sul gate per `reviewer_evidence_batch` e anti-bypass.
- Su un campione del corpus: `tht evidence lint` riporta i file rotti (frontmatter `--`,
bullet Unicode) senza crash; `tht evidence canonicalize plan --json` produce piano
corretto; `apply` con fingerprint invariato è no-op.
- `tht search pack "<domanda ablazione>"` mostra evidence con `kind`/sezione pertinente e
gli anchor presenti; `tht search find --kind evidence --applies-to schema_linking`
restituisce solo evidence pertinenti.
- Live: una sessione F4 su psd usa un anchor canonico per il value-grounding invece del
solo LSH (verificabile dal `reviewer_decide` con opzioni `value_grounded` provenienti
dall'evidence, non dal ranking LSH).
- `git diff --check` e typecheck/ruff puliti.