From daf33f77fe02a1ef98acc1389c15ef82fc9393d2 Mon Sep 17 00:00:00 2001 From: mptyl Date: Sat, 27 Jun 2026 16:14:46 +0200 Subject: [PATCH] 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. --- docs/l2-run-report-2026-06-27.md | 126 +++++++++++++++++++++++++++++++ harness/tht/cli/phase_cmd.py | 23 +++--- 2 files changed, 136 insertions(+), 13 deletions(-) create mode 100644 docs/l2-run-report-2026-06-27.md diff --git a/docs/l2-run-report-2026-06-27.md b/docs/l2-run-report-2026-06-27.md new file mode 100644 index 00000000..c65008d8 --- /dev/null +++ b/docs/l2-run-report-2026-06-27.md @@ -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 ""`. +**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. diff --git a/harness/tht/cli/phase_cmd.py b/harness/tht/cli/phase_cmd.py index 6f295281..47aef7ba 100644 --- a/harness/tht/cli/phase_cmd.py +++ b/harness/tht/cli/phase_cmd.py @@ -146,22 +146,19 @@ def show_cmd( def _cfg(): - """Load the workspace config. Tries the shared helper once schema_cmd is ported - (Onda 1.4); falls back to THT_WORKSPACE env + load_config for now.""" + """Load the workspace config. Resolves THT_WORKSPACE/THT_CONFIG first, then + falls back to the CLI default ``config/tht.yaml`` (same convention as + schema_cmd.CONFIG_OPT).""" + import os + from pathlib import Path + + ws = os.environ.get("THT_WORKSPACE") or os.environ.get("THT_CONFIG") + config_path = Path(ws) if ws else Path("config/tht.yaml") try: from tht.cli.schema_cmd import _load_config_or_exit # noqa: F401 (portato in Onda 1.4) - return _load_config_or_exit() + return _load_config_or_exit(config_path) except ImportError: - import os - from tht.workspace import load_config - ws = os.environ.get("THT_WORKSPACE") or os.environ.get("THT_CONFIG") - if not ws: - typer.secho( - "Nessun workspace: imposta THT_WORKSPACE o usa --config.", - fg=typer.colors.RED, err=True, - ) - raise typer.Exit(2) - return load_config(ws) + return load_config(config_path)