feat(harness): pure widget-builder functions + JS golden/fuzzy tests (D2, L1)

The gate's widget-descriptor CONSTRUCTION, extracted into pure testable functions.
Each builder turns plain params into a ui_request descriptor (spec §4.1 taxonomy):
buildSelectRequest, buildMultiselectRequest, buildArtifactGate, buildInfoRequest,
buildFreetextRequest, withChildLinkage. No Pi context, no I/O -- the part of the
gate fully testable in L1 (in JS, in-language, no Python mirror).

Validation in the builders (not just happy-path): select requires title + array
options; multiselect allow_empty:false with zero options throws (a broken widget);
artifact-gate requires an artifact with a kind + a valid action.kind
(confirm/approve_reject/view_only); info level must be info/warning/error. The
Altro escape hatch with freetext linkage is always injected on blocking pick
widgets (no-limbo invariant).

L1: 14 node:test cases -- 3 golden files (select_F1, multiselect_F4,
artifact_gate_F5) pin the exact descriptor shape; fuzzy tests assert bad params
throw clearly rather than silently producing a broken widget.

package.json wires 'npm test' -> node --test (runs alongside pytest). The gate
GLUE (emission, anti-bypass, no-limbo loop) is C2, verified at L2.
This commit is contained in:
2026-06-26 23:07:56 +02:00
parent e6eeb2ae3e
commit 7971d73628
6 changed files with 393 additions and 0 deletions
@@ -0,0 +1,15 @@
{
"type": "ui_request",
"id": "u2",
"phase": "F5",
"schema_version": 1,
"widget": "artifact-gate",
"title": "Schema-linking",
"artifact": {
"kind": "schema_linking",
"data": { "candidates": [] },
"version": 1
},
"action": { "kind": "confirm", "prompt": "Confermi?" },
"reserved": ["back", "exit", "other"]
}
@@ -0,0 +1,14 @@
{
"type": "ui_request",
"id": "u3",
"phase": "F4",
"schema_version": 1,
"widget": "multiselect",
"title": "Tabelle",
"allow_empty": false,
"allow_other": true,
"options": [],
"selected": [],
"content": { "candidates": [] },
"reserved": ["back", "exit", "other"]
}
@@ -0,0 +1,17 @@
{
"type": "ui_request",
"id": "u1",
"phase": "F1",
"schema_version": 1,
"widget": "select",
"title": "Disambigua 'ablazione'",
"intro": null,
"allow_other": true,
"recommended": null,
"options": [
{ "id": "o1", "label": "procedura" },
{ "id": "o2", "label": "patologia" },
{ "id": "other", "label": "Altro — specifica…", "opens": { "widget": "freetext", "title": "Specifica…" } }
],
"reserved": ["back", "exit", "other"]
}