Files
marcopan 4042d0b44d feat(replay): fixtures + augment script for v2 artifact-gate viewers
Add cte-plan-fixture.json, cte-result-fixture.json, and
phase-summary-fixture.json — realistic Italian-language payloads for the
cardiology DWH replay session, conforming exactly to contracts.md (A/B/C).

Add augment-review-gates.mjs (pattern of augment-schema-linking.mjs): finds
the F6 cte_plan gate, first CTE 1 cte_result gate, and Fase 5 phase-summary
gate by title regex and swaps in the v2 artifact.data, so CtePlanViewer,
CteResultViewer, and PhaseSummaryViewer render in the offline replay.
Idempotent; exits 1 if an expected gate is missing.

Document the augment scripts and re-extract note in tools/replay/README.md.
2026-07-07 01:19:44 +02:00

126 lines
6.1 KiB
Markdown

# ThothII reviewer replay
Riproduce su `http://localhost:5333` la **vera UI** dei widget reviewer di una
sessione registrata, **senza VPN, Pi, Python, né DWH**. Si usano i descriptor
dei gate così come furono proposti al revisore (catturati nel transcript Pi),
nello stesso ordine, con le scelte realmente fatte mostrate come badge di
confronto.
## Schema del flusso
```
browser (SPA reale, :5333)
│ REST + SSE, same-origin
▼
server.mjs (node:http, zero dipendenze)
├─ static: serve il bundle SPA da tools/replay/web/
└─ replay SSE: GET /sessions/:id/events → event: ui_request (gate N)
POST /sessions/:id/response → badge "scelta reale" + gate N+1
│
legge
▼
replay.json (fixture estratta dal transcript)
│ prodotta da
▼
extract.mjs (legge ~/.pi/agent/sessions/…/*.jsonl + question.md)
```
Niente backend Fastify, niente `pi --mode rpc`, niente `tht`, niente DB: il
server gira direttamente sui descriptor registrati.
## Comandi
```bash
# Estrai la fixture per una sessione (id, file, o directory di transcript):
scripts/replay.sh extract 2026-07-03-132933-fammi-la-lista-dei-pazienti-che-negli-ul
scripts/replay.sh extract ~/.pi/agent/sessions/--Users-mp-projects-ThothII-harness--/
# (una tantum, o dopo modifiche al frontend) costruisci il bundle SPA:
scripts/replay.sh build
# Avvia il server su :5333:
scripts/replay.sh run
# Scorciatoia: extract (default) + build (se manca) + run:
scripts/replay.sh
```
**Cosa può estrarre `extract`:**
| Input | Comportamento |
|---|---|
| *(nessuno)* | La sessione di default (3 lug 17:07, 20 gate). |
| `<session-id>` | Scansiona **tutti** i transcript nella directory Pi per quel session-id. Gestisce automaticamente sessioni spezzate su più file (resume): raccoglie i gate da tutti i transcript, li ordina cronologicamente, e scarta i gate senza risposta (quelli riproposti al resume). |
| `<file.jsonl>` | Un singolo transcript. |
| `<directory>` | Tutti i `*.jsonl` nella directory; se contengono sessioni diverse, tiene quella dominante (con più gate). |
La domanda della sessione è letta da `session_manifest.yaml` (campo `question`),
cercando la directory sessions in ogni workspace di `harness/workspaces/` (via
`paths.sessions`, assoluto o relativo). Niente più path hardcoded.
## Cosa vedi nel browser
1. Apri `http://localhost:5333`. La lista sessioni mostra **una** sessione
(quella riprodotta) con la domanda reale.
2. Cliccala: appare il **gate 1** — un `reviewer_select` (widget select) con il
titolo, l'intro e le opzioni esatte che il modello propose il 3 luglio,
incluso il badge "consigliato" sull'opzione raccomandata.
3. Clicca un'opzione. Sotto la tua scelta compare un `info` con la **scelta
reale del 3 luglio** (`📌 SCELTA REALE (3 lug 2026): …`), e — se coincide — un
`✓ Hai scelto come il 3 luglio.`
4. Avanzi attraverso tutti i gate nell'ordine loggato: `select` (F1 chiarimenti,
F6 conferma piano), `multiselect` (F3 riscrittura, F4 schema linking, F6
piano CTE), `artifact-gate` (F2/F3/F4/F5 phase advance, F6 approvazione CTE
con SQL visibile nell'`ArtifactView`).
5. Dopo l'ultimo gate: `✓ Replay completato — 20/20 gate`.
I 20 gate della sessione 17:07: 4 `select` + 11 `confirm` + 5 `decide`.
## Limiti e fedeltà al log
- **Sessioni multi-file (resume)**: gestite. L'estrattore raccoglie i gate da
tutti i transcript della sessione, li ordina per timestamp del messaggio, e
scarta i gate senza `toolResult` (quelli dove il revisore chiuse Pi senza
rispondere e che furono riproposti al resume). Risultato: la sequenza
esatta dei gate che il revisore ha effettivamente visto e deciso.
- **Workspace discovery**: la domanda è letta da `session_manifest.yaml`,
cercando `paths.sessions` nei workspace di `harness/workspaces/`. Funziona
per qualunque cliente (non solo `psd`), purché il workspace yaml sia
presente e `paths.sessions` sia un path assoluto o relativo (non espanso
con `${VAR}` — in quel caso il path non è risolvibile offline e la domanda
resta vuota).
- **Phase compute disattivata**: la fase corrente (colorazione `F1`…`F8`) non è
ricalcolata dal ledger (richiederebbe `tht phase`); i gate usano un phase-tag
neutro `replay`. L'ordine e i descriptor sono quelli reali.
- **Gate falliti/saltati**: alcuni gate non hanno una "scelta reale" perché
nella sessione live furono saltati (memorie vuote → avanzamento auto) o
falliti (es. `cte_plan` con tipo invalido). Il badge
`⚠ Gate fallito nella sessione reale` lo segnala fedelmente — riflette il
log, non un bug del replay.
- **`text_delta`/ragionamenti del modello**: omessi (scelta "solo gate"). Per
vederli, estendi `extract.mjs` per raccogliere anche i `text_delta`.
- **Reserved controls** (`back`/`exit`/`other`): nel replay sono ammessi come
qualunque altra risposta, ma non hanno semantica (non c'è stato di
navigazione da ripristinare); trattali come "procedi".
- **Single-user, single-session**: il server tiene un solo cursore globale; non
è pensato per più client concorrenti (un refresh del browser riprende dal
gate corrente).
## File
- `extract.mjs` — estrattore fixture dal transcript Pi JSONL.
- `augment-schema-linking.mjs` — riscrive il gate F4 tabelle/colonne come
descrittore `schema-linking` (vedi `schema-linking-fixture.json`).
- `augment-review-gates.mjs` — riscrive i gate F6 piano CTE, CTE 1 approvato e
Fase 5 completata come descrittori v2 (`cte_plan`/`cte_result`/`phase`, vedi
`cte-plan-fixture.json`, `cte-result-fixture.json`,
`phase-summary-fixture.json`). **Nota:** questi tre gate sono ancora
fixture sintetiche coerenti coi contratti v2 — dopo la prima sessione live
che passa per un gate `cte_plan`/`cte_result`/`phase` reale, rilancia
`extract.mjs` per catturare i descrittori v2 reali e sostituire le fixture.
- `server.mjs` — server HTTP+SSE standalone (node:http, zero deps).
- `replay.json` — fixture generata (committata per comodità; rigenerata con
`augment-schema-linking.mjs` poi `augment-review-gates.mjs`, in quest'ordine).
- `web/` — bundle SPA costruito da `frontend/` con
`VITE_BACKEND_URL=http://localhost:5333` (gitignorato; prodotto da `build`).