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.
126 lines
6.1 KiB
Markdown
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`).
|