practice: untagged problems — target optional, topic sessions work (owner round 12)

A session whose material is not in the map is a SUPPORTED mode now:
target is optional (absent = untagged problem, poses freely), an
explicit [] heals away at the seam (the record's canonical form is
tagged-or-absent), and when targets ARE present the round-9 law is
unchanged — whole-graph validation, names normalized to ids. The
rejection message teaches the exit ('omit target entirely'), so a
model inventing targets for an off-graph topic converges to omitting
on the retry; omitting always works, no brick is possible. Prompt
carries the clause: material in the map → ids; not → omit, problems
stand on their own.
This commit is contained in:
amosblomqvist
2026-10-05 20:23:48 +03:00
parent 1f7a3516fe
commit 4f3bbf61d0
3 changed files with 42 additions and 14 deletions
+12
View File
@@ -167,12 +167,24 @@ describe("target validation — names normalize to ids, unknowns reject", () =>
assert.equal(rejected.isError, true);
assert.match((rejected.details as { problems: string[] }).problems[0]!, /ghost-prop/);
assert.match((rejected.details as { problems: string[] }).problems[0]!, /proposition ids from the session context/);
// the message teaches the exit (round 12): omitting always works
assert.match((rejected.details as { problems: string[] }).problems[0]!, /omit target entirely/);
// honest activation (the BKT law): a rejected pose frees the slot —
// the next, valid pose goes through.
const valid = await tool.execute("call_y", { ...PROBLEM_INPUT, target: ["n_parity"] } as never);
assert.equal(valid.isError, undefined);
});
it("UNTAGGED PROBLEMS (owner round 12): absent target poses freely; [] heals away to absent", async () => {
const tool = problemTool(createPracticeGate(ctxOf([])), graphNodes);
const absent = await tool.execute("call_a", { statement: "S", mode: "recall", modelSolution: "M" } as never);
assert.equal(absent.isError, undefined, "no targets = an untagged problem, never a rejection");
const healed = tool.prepareArguments!({ statement: "S", mode: "recall", target: [], modelSolution: "M" }) as {
target?: string[];
};
assert.ok(!healed.target || healed.target.length === 0, "an explicit [] is the model saying no-targets — healed away");
});
it("NO node source (the legacy/test wiring) = no validation, free strings ack", async () => {
const result = await problemTool(createPracticeGate(ctxOf([]))).execute("call_x", PROBLEM_INPUT as never);
assert.equal(result.isError, undefined);