const test = require("node:test"); const assert = require("node:assert/strict"); const { installRepairGate } = require("../memory/repair.js"); function gate({ answers, fail = false, resume = false }) { let tool; const calls = [], widgets = []; const repair = { repair_id: "receipt", choice: null, status: "proposed", can_apply: true, saved: false, indexed: false, options: [{ id: "fix", content: { detail: "Correction" } }] }; installRepairGate({ registerTool: def => { tool = def; } }, { workflow: { activate() {}, phase: () => ({ id: "F4" }) }, memory: { execute: (_ctx, args) => { calls.push(args); if (args[0] === "repair-apply") { const choice = args[args.indexOf("--choice") + 1]; if (choice === "reject") Object.assign(repair, { choice, status: "rejected" }); else Object.assign(repair, { choice, saved: true, indexed: !fail, status: fail ? "pending_activation" : "active" }); fail = false; } return JSON.stringify(repair); } }, waitForReviewer: async (_ctx, descriptor) => { widgets.push(descriptor); assert.ok(answers.length, "gate must not ask an unbounded extra question"); return answers.shift(); }, toTextResult: text => text, }); return { calls, widgets, run: () => tool.execute("id", { session: "s", ...(resume ? { repair_id: "receipt" } : { proposal: { reason: "conflict", options: [] } }), }, null, null, {}) }; } test("human choice applies once and the next widget reports activation", async () => { const g = gate({ answers: [{ choices: ["fix"] }, { choices: ["continue"] }] }); assert.equal(JSON.parse(await g.run()).indexed, true); assert.deepEqual(g.calls.map(args => args[0]), ["repair-prepare", "repair-apply"]); assert.equal(g.widgets[0].repair.saved, false); assert.equal(g.widgets[1].repair.status, "active"); }); test("rejection asks for reformulation without a normal workflow decision", async () => { const g = gate({ answers: [{ choices: ["reject"] }] }); assert.match(await g.run(), /rejected as inadequate/); assert.equal(g.calls.length, 2); }); test("retry keeps the receipt and selected choice, then reports true activation", async () => { const g = gate({ resume: true, fail: true, answers: [{ choices: ["fix"] }, { choices: ["fix"] }, { choices: ["continue"] }] }); assert.equal(JSON.parse(await g.run()).indexed, true); assert.equal(g.widgets[1].repair.status, "pending_activation"); assert.equal(g.calls[0][0], "repair-show"); assert.deepEqual(g.calls[1], g.calls[2]); }); test("free text and forged choices never apply a correction", async () => { for (const response of [{ control: "freetext", text: "Explain the conflict" }, { choices: ["forged"] }]) { const g = gate({ answers: [response] }); await g.run(); assert.equal(g.calls.length, 1); } });