reasoning: use structured semantic fidelity contract
This commit is contained in:
@@ -1161,8 +1161,8 @@ describe("applyValidatedProposal", () => {
|
||||
"Risk is of greater relative importance than growth.",
|
||||
possibleInference:
|
||||
"This may imply caution, but does not establish whether risk is a hard constraint.",
|
||||
supportCategory: "relative_priority_only",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1204,8 +1204,8 @@ describe("applyValidatedProposal", () => {
|
||||
"Avoiding additional risk is a preference/trade-off rather than a hard constraint.",
|
||||
possibleInference:
|
||||
"The user prioritizes risk mitigation over aggressive growth strategies.",
|
||||
supportCategory: "relative_priority_only",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1253,8 +1253,8 @@ describe("applyValidatedProposal", () => {
|
||||
"The user would normally avoid more risk, but for the right opportunity might accept some.",
|
||||
possibleInference:
|
||||
"This may support eventual clarification, but the qualifying condition remains material.",
|
||||
supportCategory: "conditional_tradeoff",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1264,7 +1264,7 @@ describe("applyValidatedProposal", () => {
|
||||
expect(result.errors.join(" ")).toContain("conditional qualification");
|
||||
});
|
||||
|
||||
it("accepts the Experiment 56A supportCategory wording variant and still applies the existing Regression B guard", () => {
|
||||
it("rejects the Experiment 56A supportCategory wording variant at the schema boundary", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
@@ -1305,10 +1305,10 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.stage).toBe("proposal_compatibility");
|
||||
expect(result.errors.join(" ")).toContain("conditional qualification");
|
||||
expect(result.errors.join(" ")).toContain("Invalid enum value");
|
||||
});
|
||||
|
||||
it("accepts the Experiment 56B live wording variants and still applies the existing Regression B guard", () => {
|
||||
it("rejects the Experiment 56B live wording variants at the schema boundary", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
@@ -1350,10 +1350,10 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.stage).toBe("proposal_compatibility");
|
||||
expect(result.errors.join(" ")).toContain("conditional qualification");
|
||||
expect(result.errors.join(" ")).toContain("Invalid enum value");
|
||||
});
|
||||
|
||||
it("B live-variant 1: negated hard-constraint mention stays conditional rather than explicit hard constraint", () => {
|
||||
it("B live-variant 1: invalid live wording is rejected before semantic validation", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
@@ -1395,13 +1395,13 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.stage).toBe("proposal_compatibility");
|
||||
expect(result.errors.join(" ")).toContain("conditional qualification");
|
||||
expect(result.errors.join(" ")).toContain("Invalid enum value");
|
||||
expect(result.errors.join(" ")).not.toContain(
|
||||
"explicitly stated hard constraint",
|
||||
);
|
||||
});
|
||||
|
||||
it("B live-variant 2: default preference plus override stays conditional rather than other", () => {
|
||||
it("B live-variant 2: invalid free-text structured hints are rejected before semantic validation", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
@@ -1441,10 +1441,7 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.stage).toBe("proposal_compatibility");
|
||||
expect(result.errors.join(" ")).toContain("conditional qualification");
|
||||
expect(result.errors.join(" ")).not.toContain(
|
||||
"does not clearly establish one of the protected reasoning categories",
|
||||
);
|
||||
expect(result.errors.join(" ")).toContain("Invalid enum value");
|
||||
});
|
||||
|
||||
it("Regression B: preserves conditional trade-off when userSupportedMeaning stays within the raw answer", () => {
|
||||
@@ -1555,8 +1552,8 @@ describe("applyValidatedProposal", () => {
|
||||
"Avoiding additional risk is a preference rather than a hard constraint.",
|
||||
possibleInference:
|
||||
"The user may be signaling caution and a willingness to trade off growth for lower risk.",
|
||||
supportCategory: "other",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1717,7 +1714,7 @@ describe("applyValidatedProposal", () => {
|
||||
"There is proven broad market demand for a product that delivers these savings.",
|
||||
possibleInference:
|
||||
"The savings target could imply broader applicability if others share similar overhead pressures.",
|
||||
supportCategory: "other",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
@@ -1761,8 +1758,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"The user is not sure whether avoiding additional risk is a hard constraint or a preference/trade-off.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1803,8 +1800,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"Avoiding additional risk is a hard constraint and the user does not want any increase in risk.",
|
||||
possibleInference: null,
|
||||
supportCategory: "explicit_hard_constraint",
|
||||
resolutionGuidance: "must_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1905,7 +1902,7 @@ describe("applyValidatedProposal", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("fails safely when answerMeaning does not clearly establish one of the protected categories", () => {
|
||||
it("fails at the schema boundary when answerMeaning uses unsupported structured values", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
@@ -1944,9 +1941,7 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.stage).toBe("proposal_compatibility");
|
||||
expect(result.errors.join(" ")).toContain(
|
||||
"unsupported stronger meaning than answerMeaning.userSupportedMeaning establishes",
|
||||
);
|
||||
expect(result.errors.join(" ")).toContain("Invalid enum value");
|
||||
});
|
||||
|
||||
it("active unknown matches selected question node", () => {
|
||||
@@ -2566,7 +2561,8 @@ describe("applyValidatedProposal", () => {
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue: "The user needs evidence for projected office savings realism.",
|
||||
newValue:
|
||||
"The user needs evidence for projected office savings realism.",
|
||||
reason: "The answer directs focus to savings realism evidence.",
|
||||
},
|
||||
],
|
||||
@@ -2583,8 +2579,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"I need evidence that projected office savings are realistic.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -2601,7 +2597,8 @@ describe("applyValidatedProposal", () => {
|
||||
// without resolving the original question. Both children are independently verified.
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer: "I need evidence the savings are realistic and evidence the move will not materially increase loss of key engineers.",
|
||||
answer:
|
||||
"I need evidence the savings are realistic and evidence the move will not materially increase loss of key engineers.",
|
||||
previousQuestion:
|
||||
"What problem would this need to solve to justify continuing development?",
|
||||
proposal: {
|
||||
@@ -2617,7 +2614,8 @@ describe("applyValidatedProposal", () => {
|
||||
}),
|
||||
makeNode({
|
||||
id: "n-retention-impact",
|
||||
label: "Whether the move materially increases loss of key engineers",
|
||||
label:
|
||||
"Whether the move materially increases loss of key engineers",
|
||||
description:
|
||||
"Need to check whether the relocation increases risk of losing key engineers, because that matters for continuity.",
|
||||
kind: "unknown",
|
||||
@@ -2648,8 +2646,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"I need evidence the savings are realistic and evidence the move will not materially increase loss of key engineers.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -2664,7 +2662,8 @@ describe("applyValidatedProposal", () => {
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer: "We are looking at this mainly for cost reduction — roughly £2M annual savings on office overhead.",
|
||||
answer:
|
||||
"We are looking at this mainly for cost reduction — roughly £2M annual savings on office overhead.",
|
||||
previousQuestion:
|
||||
"What problem would this need to solve to justify continuing development?",
|
||||
proposal: {
|
||||
@@ -2695,7 +2694,8 @@ describe("applyValidatedProposal", () => {
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: {
|
||||
nodeId: "n-office-paint-colour",
|
||||
question: "What evidence supports the office paint colour hypothesis?",
|
||||
question:
|
||||
"What evidence supports the office paint colour hypothesis?",
|
||||
reason: "Unrelated unknown — should be rejected.",
|
||||
},
|
||||
answerMeaning: {
|
||||
@@ -2730,7 +2730,8 @@ describe("applyValidatedProposal", () => {
|
||||
makeNode({
|
||||
id: "n-workforce-stability",
|
||||
label: "Whether workforce stability affects the decision",
|
||||
description: "Need to check whether workforce stability matters, because that could impact scheduling.",
|
||||
description:
|
||||
"Need to check whether workforce stability matters, because that could impact scheduling.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
@@ -2747,8 +2748,10 @@ describe("applyValidatedProposal", () => {
|
||||
reason: "Inferred consequential unknown — should be rejected.",
|
||||
},
|
||||
answerMeaning: {
|
||||
userSupportedMeaning: "The project timeline is critical to the decision.",
|
||||
possibleInference: "Workforce stability may matter for scheduling and continuity.",
|
||||
userSupportedMeaning:
|
||||
"The project timeline is critical to the decision.",
|
||||
possibleInference:
|
||||
"Workforce stability may matter for scheduling and continuity.",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
@@ -2802,7 +2805,8 @@ describe("applyValidatedProposal", () => {
|
||||
toNodeId: "n-savings-realism-5",
|
||||
relationship: "depends_on",
|
||||
confidence: "medium",
|
||||
description: "Savings realism is a dependency of commercial justification.",
|
||||
description:
|
||||
"Savings realism is a dependency of commercial justification.",
|
||||
}),
|
||||
],
|
||||
removedEdgeIds: [],
|
||||
@@ -2817,8 +2821,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"We need evidence that projected office savings are realistic.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -2884,6 +2888,376 @@ describe("applyValidatedProposal", () => {
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("Structured fidelity: raw unsure + structured uncertain does not false-reject on populated structured path", () => {
|
||||
const graph = makeCommercialUpdateFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I am unsure whether the projected office savings from the relocation are realistic.",
|
||||
proposal: {
|
||||
...makeMeaningfulNoOpProposal(),
|
||||
addedNodes: [
|
||||
makeNode({
|
||||
id: "n-savings-anchor",
|
||||
label: "Savings realism investigation context",
|
||||
description:
|
||||
"Answer-derived context for savings realism because the commercial decision depends on it.",
|
||||
kind: "state",
|
||||
status: "known",
|
||||
confidence: "medium",
|
||||
}),
|
||||
makeNode({
|
||||
id: "n-savings-realism",
|
||||
label: "Whether the projected office savings are realistic",
|
||||
description:
|
||||
"Need to know whether the projected office savings are realistic because that matters to whether continuing development is commercially justified.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
}),
|
||||
],
|
||||
addedEdges: [
|
||||
makeEdge({
|
||||
id: "e-anchor-savings-realism",
|
||||
fromNodeId: "n-savings-anchor",
|
||||
toNodeId: "n-savings-realism",
|
||||
relationship: "depends_on",
|
||||
confidence: "medium",
|
||||
description:
|
||||
"The answer-derived savings context depends on savings realism.",
|
||||
}),
|
||||
],
|
||||
selectedQuestion: {
|
||||
nodeId: "n-savings-realism",
|
||||
question:
|
||||
"What evidence would clarify whether the projected office savings are realistic?",
|
||||
reason:
|
||||
"The structured uncertainty remains unresolved and is the next consequential unknown.",
|
||||
},
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"The user is currently uncertain whether the projected office savings from the relocation are realistic.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("Structured fidelity: equivalent paraphrase wording does not change acceptance when structured category is populated", () => {
|
||||
const graph = makeCommercialUpdateFixture();
|
||||
const baseProposal = {
|
||||
...makeMeaningfulNoOpProposal(),
|
||||
addedNodes: [
|
||||
makeNode({
|
||||
id: "n-savings-anchor",
|
||||
label: "Savings realism investigation context",
|
||||
description:
|
||||
"Answer-derived context for savings realism because the commercial decision depends on it.",
|
||||
kind: "state",
|
||||
status: "known",
|
||||
confidence: "medium",
|
||||
}),
|
||||
makeNode({
|
||||
id: "n-savings-realism",
|
||||
label: "Whether the projected office savings are realistic",
|
||||
description:
|
||||
"Need to know whether the projected office savings are realistic because that matters to whether continuing development is commercially justified.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "medium",
|
||||
}),
|
||||
],
|
||||
addedEdges: [
|
||||
makeEdge({
|
||||
id: "e-anchor-savings-realism",
|
||||
fromNodeId: "n-savings-anchor",
|
||||
toNodeId: "n-savings-realism",
|
||||
relationship: "depends_on",
|
||||
confidence: "medium",
|
||||
description:
|
||||
"The answer-derived savings context depends on savings realism.",
|
||||
}),
|
||||
],
|
||||
selectedQuestion: {
|
||||
nodeId: "n-savings-realism",
|
||||
question:
|
||||
"What evidence would clarify whether the projected office savings are realistic?",
|
||||
reason:
|
||||
"The structured uncertainty remains unresolved and is the next consequential unknown.",
|
||||
},
|
||||
};
|
||||
|
||||
const answers = [
|
||||
"The user is currently uncertain whether the projected office savings from the relocation are realistic.",
|
||||
"The user remains unclear whether the projected office savings from the relocation are realistic.",
|
||||
];
|
||||
|
||||
for (const userSupportedMeaning of answers) {
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I am unsure whether the projected office savings from the relocation are realistic.",
|
||||
proposal: {
|
||||
...baseProposal,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning,
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("Structured fidelity: must_remain_unresolved rejects relevant resolution mutation", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I am not sure whether avoiding additional risk is a hard constraint.",
|
||||
proposal: {
|
||||
addedNodes: [],
|
||||
updatedNodes: [
|
||||
{
|
||||
nodeId: riskUnknownId,
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue: "Avoiding additional risk is a hard constraint.",
|
||||
reason:
|
||||
"Incorrectly resolves an uncertainty that should remain unresolved.",
|
||||
},
|
||||
],
|
||||
addedEdges: [],
|
||||
removedEdgeIds: [],
|
||||
resolvedUnknownNodeIds: [riskUnknownId],
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: null,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"The user is not sure whether avoiding additional risk is a hard constraint or a preference/trade-off.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "must_remain_unresolved",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors.join(" ")).toContain(
|
||||
"answerMeaning.resolutionGuidance is must_remain_unresolved",
|
||||
);
|
||||
});
|
||||
|
||||
it("Structured fidelity: null structured fields retain existing lexical fallback", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I am unsure whether avoiding additional risk is a hard constraint.",
|
||||
proposal: {
|
||||
addedNodes: [],
|
||||
updatedNodes: [
|
||||
{
|
||||
nodeId: riskUnknownId,
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue: "Avoiding additional risk is a hard constraint.",
|
||||
reason:
|
||||
"Incorrectly resolves an uncertainty that should remain unresolved.",
|
||||
},
|
||||
],
|
||||
addedEdges: [],
|
||||
removedEdgeIds: [],
|
||||
resolvedUnknownNodeIds: [riskUnknownId],
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: null,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"The user is not sure whether avoiding additional risk is a hard constraint or a preference/trade-off.",
|
||||
possibleInference: null,
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors.join(" ")).toContain("must remain unresolved");
|
||||
});
|
||||
|
||||
it("Structured fidelity: populated conditional_tradeoff uses structured path without lexical verification", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I'd normally avoid more risk, but for the right opportunity I might accept some.",
|
||||
proposal: {
|
||||
addedNodes: [],
|
||||
updatedNodes: [
|
||||
{
|
||||
nodeId: riskUnknownId,
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue:
|
||||
"Avoiding additional risk is flexible under certain conditions.",
|
||||
reason: "The answer provides a conditional trade-off.",
|
||||
},
|
||||
],
|
||||
addedEdges: [],
|
||||
removedEdgeIds: [],
|
||||
resolvedUnknownNodeIds: [riskUnknownId],
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: null,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"Avoiding additional risk is flexible under certain conditions.",
|
||||
possibleInference: null,
|
||||
supportCategory: "conditional_tradeoff",
|
||||
resolutionGuidance: "may_resolve",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("Structured fidelity: populated explicit_hard_constraint uses structured path without lexical verification", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer: "It's a hard constraint. I don't want any increase in risk.",
|
||||
proposal: {
|
||||
addedNodes: [],
|
||||
updatedNodes: [
|
||||
{
|
||||
nodeId: riskUnknownId,
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue: "Avoiding additional risk is non-negotiable.",
|
||||
reason: "The answer establishes a hard constraint.",
|
||||
},
|
||||
],
|
||||
addedEdges: [],
|
||||
removedEdgeIds: [],
|
||||
resolvedUnknownNodeIds: [riskUnknownId],
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: null,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning: "Avoiding additional risk is non-negotiable.",
|
||||
possibleInference: null,
|
||||
supportCategory: "explicit_hard_constraint",
|
||||
resolutionGuidance: "must_resolve",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it("Structured fidelity: possibleInference remains non-authoritative", () => {
|
||||
const graph = makeCommercialUpdateFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer: "The project timeline is critical to the decision.",
|
||||
proposal: {
|
||||
...makeMeaningfulNoOpProposal(),
|
||||
addedNodes: [
|
||||
makeNode({
|
||||
id: "n-workforce-stability",
|
||||
label: "Workforce stability impact",
|
||||
description:
|
||||
"Need to know workforce stability impact because that could affect delivery confidence.",
|
||||
kind: "unknown",
|
||||
status: "unknown",
|
||||
confidence: "low",
|
||||
}),
|
||||
],
|
||||
addedEdges: [
|
||||
makeEdge({
|
||||
id: "e-parent-workforce-stability",
|
||||
fromNodeId: "n-commercial-parent",
|
||||
toNodeId: "n-workforce-stability",
|
||||
relationship: "depends_on",
|
||||
confidence: "low",
|
||||
description:
|
||||
"Commercial justification depends on workforce stability.",
|
||||
}),
|
||||
],
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"The project timeline is critical to the decision.",
|
||||
possibleInference:
|
||||
"Workforce stability may matter for scheduling and continuity.",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors.join(" ")).toContain(
|
||||
"explicitly related to an answer-derived node",
|
||||
);
|
||||
});
|
||||
|
||||
it("Structured fidelity: no new synonym or keyword logic was added to lexical fallback", () => {
|
||||
const { graph, riskUnknownId } = makeRiskClarificationFixture();
|
||||
|
||||
const result = applyValidatedProposal({
|
||||
situationGraph: graph,
|
||||
answer:
|
||||
"I am unsure whether avoiding additional risk is a hard constraint or a preference/trade-off.",
|
||||
proposal: {
|
||||
addedNodes: [],
|
||||
updatedNodes: [
|
||||
{
|
||||
nodeId: riskUnknownId,
|
||||
previousStatus: "unknown",
|
||||
newStatus: "resolved",
|
||||
previousValue: null,
|
||||
newValue: "Avoiding additional risk is a hard constraint.",
|
||||
reason:
|
||||
"Incorrectly resolves an uncertainty that should remain unresolved.",
|
||||
},
|
||||
],
|
||||
addedEdges: [],
|
||||
removedEdgeIds: [],
|
||||
resolvedUnknownNodeIds: [riskUnknownId],
|
||||
affectedNodeIds: [],
|
||||
selectedQuestion: null,
|
||||
answerMeaning: {
|
||||
userSupportedMeaning:
|
||||
"The user is currently uncertain whether avoiding additional risk is a hard constraint or a preference/trade-off.",
|
||||
possibleInference: null,
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors.join(" ")).toContain(
|
||||
"overstates a raw answer that remains uncertain",
|
||||
);
|
||||
});
|
||||
|
||||
// ── Case 7 — no support and no linkage ──
|
||||
it("Case 7: unknown with neither user support nor structural linkage is rejected", () => {
|
||||
const graph = makeCommercialUpdateFixture();
|
||||
@@ -2996,8 +3370,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"We need evidence that cost reduction is achievable through office overhead and savings.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -3059,8 +3433,8 @@ describe("applyValidatedProposal", () => {
|
||||
userSupportedMeaning:
|
||||
"We need cost reduction through office overhead savings.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -3180,7 +3554,8 @@ describe("applyValidatedProposal", () => {
|
||||
toNodeId: "n-boundary-c",
|
||||
relationship: "depends_on",
|
||||
confidence: "medium",
|
||||
description: "Parent depends on commercial justification verification.",
|
||||
description:
|
||||
"Parent depends on commercial justification verification.",
|
||||
}),
|
||||
],
|
||||
removedEdgeIds: [],
|
||||
@@ -3192,10 +3567,11 @@ describe("applyValidatedProposal", () => {
|
||||
reason: "Consequential unknown verified by user-supported meaning.",
|
||||
},
|
||||
answerMeaning: {
|
||||
userSupportedMeaning: "We are considering relocation for cost savings.",
|
||||
userSupportedMeaning:
|
||||
"We are considering relocation for cost savings.",
|
||||
possibleInference: null,
|
||||
supportCategory: "uncertain",
|
||||
resolutionGuidance: "may_resolve",
|
||||
supportCategory: null,
|
||||
resolutionGuidance: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user