refine answerMeaning contract around user-supported meaning

This commit is contained in:
2026-08-09 08:50:37 +01:00
parent 869afee1ab
commit 7965375aff
8 changed files with 208 additions and 57 deletions
+39 -26
View File
@@ -75,7 +75,7 @@ describe("parseGraphUpdateProposal", () => {
expect(result.normalisationsApplied.length).toBeGreaterThan(0);
});
it("normalises confirmed enum alias and preserves IDs", () => {
it("normalises confirmed node-kind alias and preserves IDs", () => {
const result = parseGraphUpdateProposal({
...makeValidProposal(),
addedNodes: [
@@ -96,12 +96,35 @@ describe("parseGraphUpdateProposal", () => {
},
],
});
expect(result.success).toBe(true);
expect(result.proposal.addedNodes[0].kind).toBe("reported_claim");
expect(result.proposal.addedNodes[0].id).toBe("n-new");
});
it("normalises equivalent answerMeaning supportCategory labels to the canonical contract", () => {
it("accepts live-style free-text answerMeaning hints without requiring enum tokens", () => {
const result = parseGraphUpdateProposal({
...makeValidProposal(),
answerMeaning: {
userSupportedMeaning:
"I'd normally avoid more risk, but for the right opportunity I might accept some.",
possibleInference:
"This may support later clarification, but the condition remains material.",
supportCategory: "conditional_preference",
resolutionGuidance:
"Identify and quantify the threshold conditions that trigger risk acceptance.",
},
});
expect(result.success).toBe(true);
expect(result.proposal.answerMeaning).toMatchObject({
supportCategory: "conditional_preference",
resolutionGuidance:
"Identify and quantify the threshold conditions that trigger risk acceptance.",
});
});
it("accepts the earlier live Regression B wording variant without special aliasing", () => {
const result = parseGraphUpdateProposal({
...makeValidProposal(),
answerMeaning: {
@@ -110,25 +133,18 @@ describe("parseGraphUpdateProposal", () => {
possibleInference:
"This may support later clarification, but the condition remains material.",
supportCategory: "conditional_qualification",
resolutionGuidance: "may_resolve",
resolutionGuidance: "may resolve once the condition is clarified",
},
});
expect(result.success).toBe(true);
expect(result.proposal.answerMeaning.supportCategory).toBe(
"conditional_tradeoff",
);
expect(result.normalisationsApplied).toEqual(
expect.arrayContaining([
expect.objectContaining({
path: ["answerMeaning", "supportCategory"],
change: "Converted conditional_qualification to conditional_tradeoff",
}),
]),
);
expect(result.proposal.answerMeaning).toMatchObject({
supportCategory: "conditional_qualification",
resolutionGuidance: "may resolve once the condition is clarified",
});
});
it("unknown enum values still fail", () => {
it("unknown node enum values still fail", () => {
const result = parseGraphUpdateProposal({
...makeValidProposal(),
addedNodes: [
@@ -152,25 +168,22 @@ describe("parseGraphUpdateProposal", () => {
expect(result.success).toBe(false);
});
it("still rejects unsupported answerMeaning supportCategory labels", () => {
it("does not reject unsupported free-text answerMeaning labels at parse time", () => {
const result = parseGraphUpdateProposal({
...makeValidProposal(),
answerMeaning: {
userSupportedMeaning: "Risk matters more to me.",
userSupportedMeaning: "Risk and growth are both important.",
possibleInference: null,
supportCategory: "constraint_preference_mix",
resolutionGuidance: "must_remain_unresolved",
resolutionGuidance: "needs more nuance",
},
});
expect(result.success).toBe(false);
expect(result.errors).toEqual(
expect.arrayContaining([
expect.objectContaining({
path: ["answerMeaning", "supportCategory"],
}),
]),
);
expect(result.success).toBe(true);
expect(result.proposal.answerMeaning).toMatchObject({
supportCategory: "constraint_preference_mix",
resolutionGuidance: "needs more nuance",
});
});
it("defaults missing selectedQuestion to null", () => {