fix(gate): stop injecting the redundant Altro option on select gates
buildSelectRequest injected an `altroOption` ({id:"other", opens:freetext}) into the
select descriptor, but SelectWidget/MultiselectWidget never route option.opens — so it
rendered as an inert "Altro — specifica…" button next to the working reserved
"Other — specify" control (which now owns free-text since the reviewer-gate-ux fix).
Remove the injection, the now-unused altroOption()/ALTRO_LABEL, and the unused
allow_other flag from both builders (no frontend consumer). Free-text stays offered on
every gate via the reserved "Other" control. The ArtifactGateWidget opens/LinkageHost
linkage (reject-with-reason capability) is intentionally kept — it is a separate,
tested feature, not the injected duplicate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,20 +33,17 @@ test("select F1 matches golden shape", () => {
|
||||
assert.equal(result.type, "ui_request");
|
||||
assert.equal(result.schema_version, 1);
|
||||
assert.deepEqual(result.reserved, g.reserved); // back/exit/other framework hatches
|
||||
assert.deepEqual(
|
||||
result.options.filter((o) => o.id !== "other"),
|
||||
g.options.filter((o) => o.id !== "other"),
|
||||
);
|
||||
assert.deepEqual(result.options, g.options);
|
||||
});
|
||||
|
||||
test("select always carries the Altro escape hatch with freetext linkage", () => {
|
||||
test("select no longer injects an Altro option (free-text is the reserved 'Other' control)", () => {
|
||||
const result = buildSelectRequest({
|
||||
id: "u", phase: "F1", title: "x",
|
||||
options: [{ id: "a", label: "A" }],
|
||||
});
|
||||
const other = result.options.find((o) => o.id === "other");
|
||||
assert.ok(other, "Altro option must always be present");
|
||||
assert.equal(other.opens.widget, "freetext");
|
||||
assert.equal(result.options.find((o) => o.id === "other"), undefined, "no injected Altro option");
|
||||
assert.ok(!("allow_other" in result), "the unused allow_other flag is gone");
|
||||
assert.deepEqual(result.reserved, ["back", "exit", "other"], "Altro still offered via the reserved control");
|
||||
});
|
||||
|
||||
test("select surfaces a recommended marker when given", () => {
|
||||
@@ -70,6 +67,7 @@ test("multiselect F4 matches golden + carries content + allowEmpty", () => {
|
||||
const g = golden("multiselect_F4.json");
|
||||
assert.equal(result.widget, "multiselect");
|
||||
assert.equal(result.allow_empty, false);
|
||||
assert.ok(!("allow_other" in result), "the unused allow_other flag is gone");
|
||||
assert.ok("content" in result);
|
||||
assert.deepEqual(result.reserved, g.reserved);
|
||||
});
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"widget": "multiselect",
|
||||
"title": "Tabelle",
|
||||
"allow_empty": false,
|
||||
"allow_other": true,
|
||||
"options": [],
|
||||
"selected": [],
|
||||
"content": { "candidates": [] },
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
"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…" } }
|
||||
{ "id": "o2", "label": "patologia" }
|
||||
],
|
||||
"reserved": ["back", "exit", "other"]
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
const SCHEMA_VERSION = 1;
|
||||
const RESERVED = ["back", "exit", "other"];
|
||||
|
||||
const ALTRO_LABEL = "Altro — specifica…";
|
||||
const VALID_ACTION_KINDS = new Set(["confirm", "approve_reject", "view_only"]);
|
||||
const VALID_INFO_LEVELS = new Set(["info", "warning", "error"]);
|
||||
|
||||
@@ -33,21 +32,12 @@ function requireArray(value, name, ctx) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// An "other" option that opens a freetext child widget. Always present on
|
||||
// blocking pick widgets so the reviewer is never trapped in the listed options.
|
||||
function altroOption() {
|
||||
return {
|
||||
id: "other",
|
||||
label: ALTRO_LABEL,
|
||||
opens: { widget: "freetext", title: "Specifica…" },
|
||||
};
|
||||
}
|
||||
|
||||
// Build a `select` ui_request (single-pick). Reserved hatches (Altro/Back/Exit)
|
||||
// are injected; Altro carries the freetext linkage (§4.2). `recommended` is the
|
||||
// id of the option to highlight as "(consigliato)".
|
||||
// Build a `select` ui_request (single-pick). The framework escape hatches
|
||||
// (Back/Exit/Other) come from `reserved` (rendered by ReservedControls, which owns
|
||||
// the free-text linkage on "Other"). `recommended` is the id of the option to
|
||||
// highlight as "(consigliato)".
|
||||
function buildSelectRequest({
|
||||
id, phase, title, options, intro = null, allowOther = true, recommended = null,
|
||||
id, phase, title, options, intro = null, recommended = null,
|
||||
}) {
|
||||
requireString(title, "title", "select");
|
||||
const opts = requireArray(options, "options", "select");
|
||||
@@ -59,9 +49,8 @@ function buildSelectRequest({
|
||||
widget: "select",
|
||||
title,
|
||||
intro,
|
||||
allow_other: allowOther,
|
||||
recommended,
|
||||
options: allowOther ? [...opts, altroOption()] : [...opts],
|
||||
options: [...opts],
|
||||
reserved: RESERVED,
|
||||
};
|
||||
return out;
|
||||
@@ -71,7 +60,7 @@ function buildSelectRequest({
|
||||
// context (e.g. schema candidates); `selected` the pre-checked option ids;
|
||||
// `allowEmpty:false` with zero options is a broken widget and throws.
|
||||
function buildMultiselectRequest({
|
||||
id, phase, title, options, content = null, selected = [], allowEmpty = false, allowOther = true,
|
||||
id, phase, title, options, content = null, selected = [], allowEmpty = false,
|
||||
}) {
|
||||
requireString(title, "title", "multiselect");
|
||||
const opts = requireArray(options, "options", "multiselect");
|
||||
@@ -88,7 +77,6 @@ function buildMultiselectRequest({
|
||||
widget: "multiselect",
|
||||
title,
|
||||
allow_empty: allowEmpty,
|
||||
allow_other: allowOther,
|
||||
options: [...opts],
|
||||
selected: [...selected],
|
||||
content,
|
||||
|
||||
Reference in New Issue
Block a user