tools: the standard argument heal — every registry, both seams
The whitehead incident (2026-10-09): glm-5.3 emitted quiz type with
quotes baked in ('"predict"') — rejected ten times, byte-identical
retries, the lesson never started — and correctAnswer with the JSON
key-value colon glued on ([':parmenides']). Third GLM wobble incident,
and each prior heal was wired only where its incident landed; this one
landed precisely where the practice heal never reached.
Layer 1 — healEncodedArguments moves to core/argument-heal (the display
seam needs it too — the tool-parts law) with withArgumentHeal +
healToolRecord (agent/tools/heal) wired at EVERY registry: prober,
teacher, practice, bareQuestionTools (it had no prepareArguments at
all), demo-builder, and submit-agent (composing after
healStringifiedArrays; the auditor's extraTools wrapped).
Layer 2 — stripModelValueDebris (core/value-debris): leading/trailing
colons, quotes, backticks, whitespace strip at the MEMBERSHIP seams —
coerceCorrectAnswer (boundary check + display + grading in one),
normalizeQuizType (persisted wobbled records keep their role),
resolveTargetId (copy-syntax on targets).
Layer 3 — schema description hygiene: the quiz type and practice
mode/outcome/rung/missClass values now read as bare words — the quoted
JSON-key style invited quote-copying.
Display mirror — parseQuizInput heals the raw record on read, so a
boundary-healed quiz whose record keeps raw args renders instead of
becoming an invisible pending quiz (learner lockout).
Pins: tests/tool-heal.test.ts (the incident shapes end-to-end through
pi-ai validation, the wiring, the strips, the mirror). The stringy-
options pins flip to boundary-parity per tool-parts' own law; the
chat-flow garbage pin keeps its honest-reject intent with an unhealable
shape. 1471 tests, typecheck, lint green.
This commit is contained in:
@@ -73,9 +73,18 @@ describe("parseQuizInput", () => {
|
||||
assert.ok(parseQuizInput(PROBER_QUIZ));
|
||||
});
|
||||
|
||||
it("the live crash shape — options as a JSON string — does not parse", () => {
|
||||
it("boundary parity: the 2026-09-26 string-options shape heals on read (universal-heal mirror, 2026-10-09)", () => {
|
||||
// The boundary now heals a JSON-encoded options string at EVERY
|
||||
// registry (healToolRecord, owner 2026-10-09 — the bare-quiz sets
|
||||
// carried no prepareArguments at all), and the record keeps the RAW
|
||||
// args — so the display parse heals the same shape, per this file's
|
||||
// own parity law: anything the boundary accepts, the display parse
|
||||
// accepts, or the posed quiz renders nowhere while the turn has
|
||||
// ended = learner lockout.
|
||||
const stringified = { ...PROBER_QUIZ, options: JSON.stringify(PROBER_QUIZ.options) };
|
||||
assert.equal(parseQuizInput(stringified), undefined);
|
||||
const parsed = parseQuizInput(stringified);
|
||||
assert.ok(parsed, "the healed-at-boundary record must parse on read");
|
||||
assert.deepEqual(parsed.options, PROBER_QUIZ.options);
|
||||
});
|
||||
|
||||
it("boundary parity under Value.Convert: a NUMERIC correctAnswer parses (live-smoke lockout fix, 2026-09-26)", () => {
|
||||
|
||||
Reference in New Issue
Block a user