feat(gate): reviewer_memory_promote — deterministic F8 memory-promotion gate

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 13:30:35 +02:00
co-authored by Claude Fable 5
parent bf7e850e6b
commit e25ba5126b
2 changed files with 161 additions and 0 deletions
@@ -0,0 +1,45 @@
const test = require("node:test");
const assert = require("node:assert");
const {
promotionOptions,
promotionContent,
splitPromotionChoices,
} = require("../../tht-gate.js");
// F8 memory-promotion gate: the candidates are DETERMINISTIC (computed by
// `tht memory promote --preview --json`), the model only names the session.
// These tests pin the pure candidate->widget mapping and the choice partition.
const CANDIDATES = [
{ decision_seq: 3, type: "table_promoted", subject: "fact_seeablazione",
detail: "tabella principale ablazioni", rationale: "scelta dal reviewer",
question_context: "quante ablazioni nel 2023", tables: ["fact_seeablazione"], concepts: [] },
{ decision_seq: 5, type: "concept_clarified", subject: "paziente attivo",
detail: "flag_attivo = TRUE", rationale: "",
question_context: "quante ablazioni nel 2023", tables: [], concepts: ["paziente attivo"] },
];
test("promotionOptions maps candidates to seq-keyed options", () => {
assert.deepEqual(promotionOptions(CANDIDATES), [
{ id: "seq-3", label: "table_promoted: fact_seeablazione" },
{ id: "seq-5", label: "concept_clarified: paziente attivo" },
]);
});
test("promotionContent lists every candidate with detail and context", () => {
const c = promotionContent(CANDIDATES);
assert.ok(c.includes("fact_seeablazione"));
assert.ok(c.includes("flag_attivo = TRUE"));
assert.ok(c.includes("quante ablazioni nel 2023"));
});
test("splitPromotionChoices partitions by selection", () => {
const { promote, decline } = splitPromotionChoices(CANDIDATES, ["seq-5"]);
assert.deepEqual(promote.map((c) => c.decision_seq), [5]);
assert.deepEqual(decline.map((c) => c.decision_seq), [3]);
});
test("empty or missing choices declines everything", () => {
assert.equal(splitPromotionChoices(CANDIDATES, []).decline.length, 2);
assert.equal(splitPromotionChoices(CANDIDATES, undefined).decline.length, 2);
});