fix: realign workflow advance semantics and phase labels with workflow.yaml

Audit findings 2.1 + 2.2 (high).

2.1 WorkflowBar's static phase list was fiction from F2 on (F2 "Schema
linking" vs memoria, F4 "SQL plan" vs schema_linking, …): every live
session showed the wrong phase name. Both maps now mirror
harness/workflow.yaml (F1 chiarimento … F8 datamart).

2.2 forceAdvance (6ee5bda) let reviewer_decide advance:true bypass the
phase gate on ANY phase, contradicting SKILL.md's "auto-advance only
empty F2 / skipped F6". reviewer_decide is back on advanceIfReady (exit-6
no-op) and tells the model to close via reviewer_confirm; forceAdvance
stays only where selection IS the approval by design: reviewer_schema_linking
(F4) and the F8 promotion close path. SKILL.md now names the three
self-closing gates (F3 rewrite_question, F4 schema-linking advance:true,
F8 memory_promote) so gate and skill state one contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 01:28:18 +02:00
co-authored by Claude Fable 5
parent 075883370e
commit 3e072fe652
3 changed files with 39 additions and 26 deletions
+12 -5
View File
@@ -367,9 +367,10 @@ function advanceIfReady(ctx, session) {
}
}
// Unconditional phase advance — the reviewer already approved via the widget interaction
// (reviewer_decide selection IS the human confirmation). Used when reviewer_decide persists
// substantive decisions with advance:true, so no separate reviewer_confirm gate is needed.
// Unconditional phase advance — the reviewer already approved via the widget interaction.
// ONLY for gates whose selection IS the phase approval by design: reviewer_schema_linking
// (F4 curation) and the F8 close path. Generic reviewer_decide must use advanceIfReady —
// forcing there bypasses the reviewer_confirm phase gate and contradicts SKILL.md.
function forceAdvance(ctx, session) {
try {
tht(ctx, ["phase", "advance", "--session", session]);
@@ -891,9 +892,15 @@ export default function (pi) {
const msg = "Nessuna decisione registrata (il reviewer non ha selezionato opzioni di merito).";
return textResult(adv.advanced ? msg + " Fase avanzata automaticamente." : msg);
}
const adv = advance ? forceAdvance(ctx, session) : { advanced: false };
// SKILL.md contract: advance:true means auto-advance-IF-ELIGIBLE (empty F2 /
// skipped F6), never a bypass of the phase gate once substantive decisions
// exist. The only gates that close their phase on selection are
// reviewer_schema_linking (F4) and reviewer_memory_promote (F8).
const adv = advance ? advanceIfReady(ctx, session) : { advanced: false };
const parts = [`Registrate ${toAdd.length} decisioni: ${toAdd.map((d) => d.type).join(", ")}.`];
if (adv.advanced) parts.push("Fase avanzata automaticamente — nessun gate aggiuntivo necessario.");
parts.push(adv.advanced
? "Fase avanzata automaticamente."
: 'La fase resta aperta: chiudila con reviewer_confirm kind:"phase" quando pronta.');
return textResult(parts.join(" "));
} catch (fatal) {
const msg = (fatal.stderr || fatal.message || String(fatal)).toString().trim();