test(harness): report L2 cardioversione+ablazione + fix phase show (#2)

Prima sessione L2 end-to-end dopo il porting. Il loop skill->LLM->gate funziona nel
dominio (ricerche, evidence, quadro corretto su fact_cardioversione/fact_see_ablazione)
ma si blocca a F1 sul bug fatale #4 (ctx.sendRaw non esiste nel runtime Pi).

Bug emersi (4):
  #1 tht non nel PATH di Pi (basso, workaround wrapper)
  #2 phase show non passava config (medio, FIXATO: _cfg() risolve env+default)
  #3 session check signature inconsistente (basso, da verificare)
  #4 ctx.sendRaw is not a function (FATALE, mismatch architetturale: il porting ha
     sostituito i dialog nativi ctx.ui.* con ctx.sendRaw, API non esposta in questo Pi)

Analisi #4 (verificata sul runtime installato):
  - ctx.sendRaw non esiste; extension_ui_request e' emesso solo dal runtime
    (modes/rpc) come traduzione di ctx.ui.select/confirm/input, non come API extension
  - canali RPC per decisioni: enum chiuso select/confirm/input/editor (no custom)
  - ctx.ui.custom (multiselect TUI di ChironeWp3) e' no-op in RPC mode
  - conseguenza: multiselect F4 non ha canale in RPC -> decisione di design del gate
    aperta (opzioni A/B/C nel report, C=scartato), merita brainstorming dedicato

Fix #2 (dal modello in sessione, validato e ripulito): phase_cmd._cfg() ora risolve
THT_WORKSPACE/THT_CONFIG env poi fallback config/tht.yaml (stessa convenzione CONFIG_OPT).
Testato phase show OK, suite 165 passed.

Report: docs/l2-run-report-2026-06-27.md.
This commit is contained in:
2026-06-27 16:14:46 +02:00
parent 386ec3b833
commit daf33f77fe
2 changed files with 136 additions and 13 deletions
+126
View File
@@ -0,0 +1,126 @@
# L2 Run Report — 2026-06-27 (sessione cardioversione + ablazione)
> Esito della prima sessione L2 end-to-end dopo il porting CLI+skill (Onda -1→4 +
> Skill + 0b). Sessione non-deterministica, esito informativo non bloccante per il
> "done" del porting codice (come da piano L2.1, riga 1187).
## Setup al momento del run
- Pi: `@earendil-works/pi-coding-agent`, provider `zai`, model `glm-5.2` (default).
- Harness: Onda -1→4 + Skill committate; Onda 0b (workspace cliente `tht-workspace-psd`,
indice LSH 75737 valori, evidence 35).
- `.env` popolato, VPN OK, DWH REST 200, Ollama UP.
- Pre-run fix applicati in questa sessione: `_YamlModel.to_yaml` (bloccava `session new`),
`config/tht.yaml` symlink al workspace cliente (il gate chiama `tht` senza `-c`).
## Come è partita la sessione
Lancio `pi --mode rpc` + `/nuova-domanda "<cardioversione + ablazione same-year>"`.
**Nota critica su `--mode rpc`:** la TUI interattiva di Pi (`pi` senza `--mode`) **non
renderizza** i widget `extension_ui_request` del gate (gestiti solo in `modes/rpc/`).
La modalità RPC emette i widget come JSONL su stdio per un client esterno — che non
esiste ancora in ThothII. Il run è stato possibile solo perché il modello, non vedendo
UI, ha operato via shell/tool fino al blocco fatale (vedi bug #4).
## Cosa ha fatto il modello (transcript: 117 eventi, 365KB)
Sessione Pi: `~/.pi/agent/sessions/--Users-mp-projects-ThothII-harness--/2026-06-27T13-44-51...jsonl`.
Sessione tht: `tht-workspace-psd/sessions/2026-06-27-134553-crea-una-lista...` (status: open, F1).
Il modello ha lavorato molto e correttamente nel dominio:
- Ha creato la sessione, caricato la skill, iniziato F1.
- Ha eseguito ricerche semantiche (evidence + LSH), individuato le tabelle centrali
(`fact_cardioversione_elettrica`, `fact_see_ablazione`, `dim_patient`).
- Ha letto evidence molto pertinenti (esempio NLQ, glossario coorti/universi), costruendo
un quadro dominio corretto e verificato sulle tabelle reali.
Il workflow **non è avanzato oltre F1**: nessuna decisione registrata
(`review_decisions.jsonl` assente). Il modello si è arenato su bug di porting (sotto).
## Bug di porting emersi (4, di cui 1 fatale)
### #1 — `tht` non nel PATH del processo Pi [basso]
Il gate chiama `execFileSync("tht", args, {cwd: ctx.cwd})`. L'eseguibile nel venv non è nel
PATH di Pi. Il modello ha creato un wrapper in `~/.local/bin` (workaround).
**Fix root-cause:** installare `tht` in una dir nel PATH (pip install -e . con entry point
globale, o symlink `/usr/local/bin/tht -> harness/.venv/bin/tht`).
### #2 — `phase show` non passava il config [medio, FIXATO]
`phase_cmd._cfg()` non passava il config a `_load_config_or_exit()`, quindi falliva con
"File non trovato config/tht.yaml" quando non c'era `THT_WORKSPACE` env.
**Fix applicato (dal modello in sessione, validato e pulito):** `_cfg()` ora risolve
`THT_WORKSPACE`/`THT_CONFIG` env, poi fallback a `config/tht.yaml` (stessa convenzione di
`CONFIG_OPT`). Testato: `phase show` funziona. Suite 165 passed.
### #3 — `session check` signature inconsistente [basso, da verificare]
Il modello ha notato che `session check` prende la sessione come argomento posizionale,
non `--session` come gli altri cmd. Da verificare e allineare.
### #4 — `ctx.sendRaw is not a function` [FATALE, blocca tutti i widget]
Il gate `tht-gate.js:164` emette i widget con `ctx.sendRaw({type:"extension_ui_request"...})`.
Il runtime Pi installato **non espone `ctx.sendRaw`** sul context delle extensions. Il
modello l'ha verificato leggendo le type definitions (`ExtensionContext` espone `ui`,
`mode`, `hasUI`, `cwd`, `abort` — ma non `sendRaw`). **Nessun widget può essere emesso in
nessuna modalità.** Questo ha fermato il workflow a F1.
## Analisi del bug #4 (mismatch architetturale, non un typo)
Il commento nel gate stesso (righe 2-6) dice: *"REWRITE of the reference implementation...
replaces ctx.ui.* blocking primitives"*. Il porting ha **sostituito** i dialog nativi di Pi
con `ctx.sendRaw`, presumendo un'API widget-descriptor diretta che **questa versione di Pi
non espone alle extensions**. Verifiche sul runtime installato:
- `ctx.sendRaw`: **non esiste** (0 refs in `core/extensions/`).
- `extension_ui_request`: emesso **solo dal runtime** (`modes/rpc/rpc-mode.js`), come
traduzione dei dialog nativi (`ctx.ui.select` → `{method:"select"}`), non come API per
le extensions.
- Canali disponibili in RPC mode per ricevere una decisione umana (enum chiuso):
`ctx.ui.select` / `confirm` / `input` / `editor` (+ `notify` one-way). I `method` di
`extension_ui_request` sono: select/confirm/input/editor/notify/setWidget/setStatus/
set_editor_text. **Nessun method custom** per widget-descriptor.
- `ctx.ui.custom` (usato da ChironeWp3 per il multiselect TUI): in RPC mode è un **no-op**
(`return undefined`, commento: "Custom UI not supported in RPC mode").
### Conseguenza per i 6 widget della spec §4
- `select` (scelta singola) → ✅ `ctx.ui.select`
- `confirm` (approvazione) → ✅ `ctx.ui.confirm`
- `input` (testo libero / Altro) → ✅ `ctx.ui.input`
- `multiselect` (scelta multipla — **critico per F4 schema-linking**) → ❌ nessun canale
in RPC. Solo `ctx.ui.custom` lo faceva (TUI only).
Il multiselect è il vero ostacolo. F4 richiede di promuovere/escludere **più** tabelle/
colonne in una volta.
## Opzioni per il design del gate (decisione architetturale APERTA)
Il design del gate influenza tutta la relazione harness↔backend↔FE. Non è un fix da
inserire in coda a una sessione di porting; merita brainstorming dedicato. Opzioni:
- **A — Torna a `ctx.ui.*` nativi.** Il gate riscrive `emitAndWait` su `ctx.ui.select`/
`confirm`/`input` (come ChironeWp3 originale). Multiselect F4 emulato (serie di select, o
un input). Funziona con il Pi installato ora. Perde i widget-descriptor ricchi spec §4;
il FE riceve method nativi, la mappatura kind→method va nel backend/FE.
- **B — Versione di Pi con API widget custom.** Verificare se un Pi più recente/preview
espone `ctx.sendRaw` o un method custom. Se sì, il gate attuale funziona. Rischio:
inseguire un'API magari non pubblica; aggiornare Pi può rompere provider/auth.
- **C — Wrapper ibrido (valutato, NON realizzabile).** Registrare un handler che intercetti
gli `extension_ui_request` nativi e li arricchisca nel formato widget-descriptor spec §4
prima di mandarli al client RPC. **Scartato:** non c'è canale per widget-descriptor custom
in RPC (method è enum chiuso, `ctx.ui.custom` è no-op in RPC).
## Artefatti prodotti
- `tht-workspace-psd/sessions/2026-06-27-134553-.../` (manifest + question.md, F1, open).
- Sessione Pi transcript (vedi sopra) — fonte primaria per il debug.
- Fix codice: `_cfg()` in `phase_cmd.py` (bug #2), applicato pulito.
## Conclusione
**La sessione L2 ha colto bug di porting reali — ha fatto il suo lavoro.** Il loop
skill→LLM→gate funziona nel dominio (ricerche, evidence, quadro corretto) ma si blocca a
F1 sul bug fatale #4. Tre dei quattro bug sono risolvibili a basso costo (#1, #2 fixato,
#3); il #4 è una decisione di design del gate che richiede brainstorming prima del codice.
**Stato del porting codice (Onda -1→4 + Skill + 0b):** completo e verificato a livello L0/L1
(165 passed) + L2 value-grounding (PASS). I bug L2 emersi sono incrementi di qualità, non
regressioni del porting — L2 coglie ciò che L0/L1 per design non possono.