feat: complete evidence restructuring worktree

This commit is contained in:
Codex
2026-08-26 11:39:02 +02:00
parent a54d4769dd
commit 38f02cfd08
56 changed files with 1981 additions and 1801 deletions
+30 -30
View File
@@ -1,10 +1,10 @@
# Componenti, moduli e flussi
# Components, modules, and flows
Questa pagina completa la [panoramica dell'architettura](overview.md) con la struttura dei moduli e i flussi che attraversano ThothII. I diagrammi descrivono il codice corrente, non un'architettura futura.
This page complements the [architecture overview](overview.md) with the module structure and flows through ThothII. The diagrams describe the current code, not a future architecture.
## Moduli e dipendenze
## Modules and dependencies
Il frontend comunica con il backend tramite REST e SSE. Il backend non possiede la persistenza delle sessioni: avvia Pi, invoca la CLI `tht` e inoltra gli eventi. L'harness contiene il workflow, la CLI Python e gli adattatori verso DWH e vector store.
The frontend communicates with the backend through REST and SSE. The backend does not own session persistence: it starts Pi, invokes the `tht` CLI, and forwards events. The harness contains the workflow, the Python CLI, and adapters for the DWH and vector store.
```mermaid
flowchart LR
@@ -14,30 +14,30 @@ flowchart LR
PI --> EXT["harness/.pi/extensions/\ntht-gate.js"]
EXT --> SKILL["harness/.pi/skills/\ntht-sessione"]
EXT --> THT
THT --> FS["Sessioni e artefatti\nworkspace repository"]
THT --> FS["Sessions and artifacts\nworkspace repository"]
THT --> DWH["DWH\nread-only"]
THT --> VDB["Qdrant / vector store"]
BE --> CFG["settings.json\nworkspace registry"]
FE -.->|renderizza widget| EXT
FE -.->|renders widgets| EXT
```
Dipendenze principali:
| Modulo | Dipende da | Responsabilità |
| Module | Depends on | Responsibility |
| --- | --- | --- |
| `frontend/` | API REST e SSE del backend | UI, widget di gate e transcript in memoria |
| `backend/src/` | Pi, `tht`, configurazione e workspace registry | Trasporto, lifecycle delle sessioni e API |
| `harness/.pi/` | Pi e `tht phase` | Orchestrazione del workflow e gate human-in-the-loop |
| `harness/tht/` | filesystem, DWH e vector store | Persistenza, CLI, evidence, schema e preprocessing |
| workspace repository | `source/`, `curated/`, manifest e artefatti | Sorgente versionata delle evidence e output di sessione |
| `frontend/` | Backend REST and SSE APIs | UI, gate widgets, and in-memory transcript |
| `backend/src/` | Pi, `tht`, configuration, and workspace registry | Transport, session lifecycle, and APIs |
| `harness/.pi/` | Pi and `tht phase` | Workflow orchestration and human-in-the-loop gates |
| `harness/tht/` | Filesystem, DWH, and vector store | Persistence, CLI, Evidence, schema, and preprocessing |
| workspace repository | `source/`, `curated/`, manifest, and artifacts | Versioned Evidence source and session output |
## Sequenza di una sessione
## Session sequence
Il percorso principale parte da una domanda dell'utente e termina con un evento SSE. Le decisioni del revisore rientrano nello stesso canale e vengono persistite dall'harness.
The main path starts with a user question and ends with an SSE event. Reviewer decisions use the same channel and are persisted by the harness.
```mermaid
sequenceDiagram
actor U as Utente o revisore
actor U as User or reviewer
participant FE as Frontend
participant BE as Backend
participant PI as Pi RPC
@@ -45,24 +45,24 @@ sequenceDiagram
participant WS as Workspace
participant DWH as DWH
U->>FE: Invia domanda o decisione di gate
U->>FE: Send question or gate decision
FE->>BE: POST session / risposta widget
BE->>PI: RPC input o prompt di resume
PI->>THT: phase/session/evidence commands
THT->>WS: Legge e scrive artefatti di fase
THT->>DWH: Introspezione o query read-only
DWH-->>THT: Schema, risultati o diagnostica
THT-->>PI: JSON e stato della fase
PI-->>BE: Eventi RPC e widget descriptor
THT->>WS: Read and write phase artifacts
THT->>DWH: Introspection or read-only query
DWH-->>THT: Schema, results, or diagnostics
THT-->>PI: JSON and phase state
PI-->>BE: RPC events and widget descriptor
BE-->>FE: SSE text_delta, info, ui_request
FE-->>U: Testo, artefatto o richiesta di revisione
FE-->>U: Text, artifact, or review request
```
Il backend usa `ThtRunner` per i subprocess della CLI, `PiProcessManager` per un processo Pi per sessione, `SessionBridge` per adattare gli eventi RPC e `SseHub` per distribuirli ai client.
The backend uses `ThtRunner` for CLI subprocesses, `PiProcessManager` for one Pi process per session, `SessionBridge` to adapt RPC events, and `SseHub` to distribute them to clients.
## Classi principali del backend
## Main backend classes
Il diagramma mostra le classi che compongono il ponte tra browser, Pi e `tht`. Le route Fastify ricevono le richieste e delegano a questi servizi.
The diagram shows the classes that form the bridge between the browser, Pi, and `tht`. Fastify routes receive requests and delegate to these services.
```mermaid
classDiagram
@@ -114,9 +114,9 @@ classDiagram
SessionBridge --> SseHub
```
## Moduli Python della CLI `tht`
## Python modules in the `tht` CLI
La CLI è composta da comandi Typer e da moduli di dominio. `cli/` traduce gli argomenti in operazioni; `evidence/`, `session/`, `db/`, `adapters/` e gli altri package contengono la logica applicativa.
The CLI consists of Typer commands and domain modules. `cli/` turns arguments into operations; `evidence/`, `session/`, `db/`, `adapters/`, and the other packages contain the application logic.
```mermaid
flowchart TB
@@ -137,11 +137,11 @@ flowchart TB
PHASE --> LEDGER["decisions.py\nreview_decisions"]
```
Il comando di operatore `tht` in `tools/tht/` è distinto dalla CLI Python dell'harness. Il primo gestisce installazione, lifecycle, autenticazione e workspace; il secondo esegue il workflow e le operazioni sui dati.
The operator command `tht` in `tools/tht/` is separate from the harness Python CLI. The former handles installation, lifecycle, authentication, and workspaces; the latter runs the workflow and data operations.
## Workflow a otto fasi e gate
## Eight-phase workflow and gates
La fonte di verità è `harness/workflow.yaml`. La fase corrente si calcola dal decision ledger, non da un campo aggiornato manualmente.
The source of truth is `harness/workflow.yaml`. The current phase is computed from the decision ledger, not from a manually updated field.
```mermaid
flowchart LR
+49 -50
View File
@@ -1,12 +1,11 @@
# Panoramica dell'architettura
# Architecture overview
> Per il dettaglio dei moduli e dei flussi vedi
> [Componenti, moduli e flussi](components.md).
> For details about modules and flows, see [Components, modules, and flows](components.md).
ThothII è un **datamart builder human-in-the-loop**: trasforma una domanda in linguaggio naturale in SQL validato (ed eventualmente un datamart dbt) attraverso un **workflow deterministico a 8 fasi NL→SQL**, in cui il modello *propone* e un revisore umano *decide* ai gate.
ThothII is a **human-in-the-loop datamart builder**. It turns a natural-language question into validated SQL, and optionally a dbt datamart, through a **deterministic eight-phase NL-to-SQL workflow** in which the model *proposes* and a human reviewer *decides* at gates.
L'autenticazione di produzione usa local oppure OIDC generico; il solo CLI operatore è tht.
Per sessioni, ruoli, gruppi, diagnostica e ripristino vedere la [documentazione autenticazione](authentication.md).
Production authentication uses local authentication or generic OIDC. `tht` is the only operator CLI.
For sessions, roles, groups, diagnostics, and recovery, see the [authentication documentation](authentication.md).
```mermaid
flowchart LR
@@ -20,71 +19,71 @@ flowchart LR
THT --> FE
```
## I tre progetti indipendenti
## The three independent projects
```
frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (sola lettura)
frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → DWH (read-only)
```
| Layer | Stack | Ruolo |
|---|---|---|
| **harness/** | Python (`tht` CLI) + Pi gate extension (JS) | Possiede il workflow e **tutta** la persistenza |
| **backend/** | Fastify + TypeScript | Ponte sottile senza database proprio |
| **frontend/** | React 18 + Vite | UI che renderizza i widget di gate e ricostruisce il transcript live dallo stream SSE |
| **harness/** | Python (`tht` CLI) + Pi gate extension (JS) | Owns the workflow and **all** persistence |
| **backend/** | Fastify + TypeScript | Thin bridge with no database of its own |
| **frontend/** | React 18 + Vite | UI that renders gate widgets and rebuilds the live transcript from the SSE stream |
## L'harness possiede il workflow
## The harness owns the workflow
`tht` (Python) è una CLI deterministica; `harness/.pi/extensions/tht-gate.js` è un'estensione Pi che guida il workflow a 8 fasi. La fonte di verità unica del workflow è `harness/workflow.yaml`; le regole di orchestrazione che il modello deve seguire sono in `harness/.pi/skills/tht-sessione/SKILL.md`. La "fase corrente" **non è memorizzata**: viene calcolata piegando il decision ledger (`harness/tht/phase.py`) — va letta prima di ragionare sulla logica di fase.
`tht` (Python) is a deterministic CLI. `harness/.pi/extensions/tht-gate.js` is a Pi extension that guides the eight-phase workflow. `harness/workflow.yaml` is the single source of workflow truth, and `harness/.pi/skills/tht-sessione/SKILL.md` contains the orchestration rules the model must follow. The "current phase" is **not stored**. It is computed by folding the decision ledger (`harness/tht/phase.py`), which must be read before reasoning about phase logic.
## Persistenza = documenti di fase, non chat
## Persistence means phase documents, not chat
Una sessione è una directory sotto `sessions/` (path definito dal workspace): `session_manifest.yaml` + artefatti per fase (`question.md`, `schema_linking.json`, `sql_final.sql`, …) + `review_decisions.jsonl`. Il contratto (SKILL.md): *"lo stato persistito è la verità — ciò che non è registrato non è accaduto"*. Non esiste uno store di transcript verbatim. Un processo Pi ripreso ricostruisce il contesto da `tht session show <id>` + gli artefatti su disco.
A session is a directory under `sessions/` (the workspace defines the path): `session_manifest.yaml`, phase artifacts (`question.md`, `schema_linking.json`, `sql_final.sql`, and others), and `review_decisions.jsonl`. The contract says: *"persisted state is the truth; what is not recorded did not happen"*. There is no verbatim transcript store. A resumed Pi process rebuilds context from `tht session show <id>` and the artifacts on disk.
## Il backend è un ponte sottile senza database
## The backend is a thin bridge with no database
- `ThtRunner` esegue subcommand `tht` in shell
- `PiProcessManager` esegue un processo Pi figlio per sessione e fa da bridge al suo stream RPC
- `SessionBridge` mappa eventi RPC di Pi → eventi client (`ui_request` / `text_delta` / `info`)
- `SseHub` distribuisce questi eventi via SSE al browser
- `ThtRunner` runs `tht` subcommands in a shell.
- `PiProcessManager` runs one Pi child process per session and bridges its RPC stream.
- `SessionBridge` maps Pi RPC events to client events (`ui_request` / `text_delta` / `info`).
- `SseHub` distributes these events to the browser over SSE.
Le impostazioni applicative vivono in un file JSON (`backend/data/settings.json`), non in un database.
Application settings live in a JSON file (`backend/data/settings.json`), not in a database.
## Contratto del gate human-in-the-loop
## Human-in-the-loop gate contract
Il modello propone; un revisore umano decide ai gate tramite widget:
The model proposes; a human reviewer decides at gates through widgets:
- **`reviewer_select`** — scelta singola: un'opzione con `decision` payload auto-conferma/persiste direttamente; un'opzione senza payload chiede soltanto
- **`reviewer_decide`** — multiselect: ogni scelta È una decisione
- **`reviewer_confirm`** — gate su artefatto/fase
- **`reviewer_select`**: single choice. An option with a `decision` payload confirms and persists directly; an option without a payload only asks.
- **`reviewer_decide`**: multiselect. Each choice is a decision.
- **`reviewer_confirm`**: artifact or phase gate.
Il frontend renderizza questi widget-descriptor (registro in `src/widgets/`); il transcript live viene ricostruito in memoria dallo stream SSE (`src/store/sessionStore.ts`) — **non è persistito**.
The frontend renders these widget descriptors (registry in `src/widgets/`). It rebuilds the live transcript in memory from the SSE stream (`src/store/sessionStore.ts`); it is **not persisted**.
## Evidence curata e immutabile
## Curated and immutable Evidence
Il repository del workspace è il confine di pubblicazione: il curatore prepara `evidence/source/`,
revisa le unità in `evidence/curated/`, valida e fa merge. Per `evidence.schema_version: 2` il
runtime materializza l'intero albero `evidence/` dal commit Git esatto, ma il renderer consegna al
preprocessing esattamente `curated/**/*.md` dalla root immutabile della revisione. Sorgenti, manifest
ed evaluation restano disponibili solo per tracciabilità. Il runtime non modifica, stagea, committa
o pubblica il repository di authoring.
The workspace repository is the publication boundary. The curator prepares `evidence/source/`,
reviews units in `evidence/curated/`, validates them, and merges them. With `evidence.schema_version: 2`,
the runtime materializes the full `evidence/` tree from the exact Git commit, but the renderer passes
only `curated/**/*.md` from the immutable revision root to preprocessing. Sources, manifests, and
evaluation data remain available for traceability. The runtime never modifies, stages, commits, or
publishes the authoring repository.
Prima dell'indicizzazione, il corpus curato della revisione pinnata viene validato. La collezione
Qdrant condivisa conserva il vettore dense senza nome di Schema e Memory; il preprocessing Evidence
può aggiungere soltanto in modo additivo il vettore sparse `bm25` con `idf`, senza eliminare,
rinominare o ricreare la collezione. `workspace preprocess evidence` e la parte Evidence di
`workspace preprocess run` sono le sole operazioni pubbliche che effettuano questo upgrade.
Before indexing, the curated corpus from the pinned revision is validated. The shared Qdrant
collection keeps the unnamed dense vector used by Schema and Memory. Evidence preprocessing may
add only the sparse `bm25` vector with `idf`, without deleting, renaming, or recreating the collection.
`workspace preprocess evidence` and the Evidence part of `workspace preprocess run` are the only public
operations that perform this upgrade.
## Punti di attenzione ricorrenti
## Recurring points of attention
- `tht -c`/`--config` è un'opzione **per-comando**: deve seguire il subcommand, mai precederlo (`ThtRunner.buildArgv` lo impone).
- L'output `--json` deve essere JSON puro su stdout — è un contratto machine-readable.
- Le stringhe UI sono in inglese; il *contenuto* dei documenti resta nella lingua del workspace, perché è il dato reale — solo chrome e label sono in inglese.
- Ogni workspace imposta il target DWH e le proprie directory operative. I segreti restano nei file protetti dell'installazione e non nel repository del workspace.
- Le impostazioni sono globali (`backend/data/settings.json`: workspace/provider/modello/thinking); il form di nuova sessione richiede solo la domanda.
- **Resume**: una sessione riprendibile rientra all'ultima fase incompleta. Il backend rifiuta il resume con 409 se `finalized` o `archived`; `PiProcessManager.spawnFor` deve inviare `/riprendi-sessione <id>` (resume) vs `/nuova-domanda` (nuova) — il prompt sbagliato trasforma silenziosamente un resume in una nuova domanda.
- `tht -c`/`--config` is a **per-command** option. It must follow the subcommand, never precede it (`ThtRunner.buildArgv` enforces this).
- `--json` output must be plain JSON on stdout. It is a machine-readable contract.
- UI strings are in English. Document *content* stays in the workspace language because it is the actual data; only chrome and labels are in English.
- Each workspace defines its DWH target and working directories. Secrets remain in protected installation files, not in the workspace repository.
- Settings are global (`backend/data/settings.json`: workspace/provider/model/thinking); the new-session form asks only for the question.
- **Resume**: a resumable session returns to its last incomplete phase. The backend rejects resume with 409 when `finalized` or `archived`; `PiProcessManager.spawnFor` must send `/riprendi-sessione <id>` for resume and `/nuova-domanda` for a new session. The wrong prompt silently turns a resume into a new question.
## Come si lancia lo stack
## Starting the stack
Lo stack locale si avvia con `./scripts/run-stack.sh`, dopo aver creato
`deploy/env/local.env` da `deploy/env/local.env.example`. Il core Compose include Pi; DWH,
vector DB, embedding e LLM sono endpoint esterni configurati nel file locale.
Start the local stack with `./scripts/run-stack.sh` after creating
`deploy/env/local.env` from `deploy/env/local.env.example`. The Compose core includes Pi; DWH,
the vector database, embeddings, and the LLM are external endpoints configured in the local file.