fix(focused-investigation): suppress incompatible question strategies

This commit is contained in:
2026-10-08 17:48:53 +01:00
parent 92ae463d10
commit f74fe6de10
6 changed files with 672 additions and 16 deletions
+246
View File
@@ -1614,6 +1614,252 @@ describe("60B.75 — real decision detection for sufficiency question", () => {
});
});
// ── Experiment 3 Iteration 3 — Deterministic Reproduction Recovery ──────────
// Hypothesis: A Whether ... uncertainty passed into baseline_reconstruction
// interpolates into a template requiring a noun phrase, producing malformed output.
// Fixed input: "Whether additional skilled staff needed for expansion can be recruited"
describe("Experiment 3 — Whether proposition in baseline reconstruction", () => {
it("suppresses the reproduced malformed baseline template at the focused-investigation compatibility boundary", () => {
const unknown = makeNode({
id: "n-experiment3-staffing",
label: "Staffing certainty gap",
description:
"Whether additional skilled staff needed for expansion can be recruited",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const graph = makeGraph({
centralStatement:
"We need to compare our current baseline against the comparable state before staffing is secured for expansion.",
nodes: [unknown],
edges: [],
activeUnknownNodeId: unknown.id,
resolvedNodeIds: [],
currentSummary: "Test summary",
});
const proposed = formulateQuestion({ node: unknown, graph });
// Preserve the deterministic reproduction that identified the bug.
expect(proposed.strategy).toBe("baseline_reconstruction");
expect(proposed.question).toBe(
"What was the comparable state before whether additional skilled staff needed for expansion can be recruited?",
);
const corrected = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "baseline_reconstruction",
relevance: "compatible",
},
strategyTemplateCompatibility: "incompatible",
},
});
expect(corrected.strategy).toBeNull();
expect(corrected.question).toBe(
"What evidence would clarify whether additional skilled staff needed for expansion can be recruited?",
);
expect(corrected.question.toLowerCase()).not.toContain("before whether");
});
});
// ── Experiment 14 — Deterministic Compatibility Verdict Contract ───────────
describe("Experiment 14 — strategy compatibility verdict", () => {
function makeBaselineWhetherFixture() {
const unknown = makeNode({
id: "n-experiment14-staffing",
label: "Staffing certainty gap",
description:
"Whether additional skilled staff needed for expansion can be recruited",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const graph = makeGraphFor(unknown, {
centralStatement:
"We need to compare our current baseline against the comparable state before staffing is secured for expansion.",
});
return { unknown, graph };
}
it("preserves existing strategy and question when no verdict is supplied", () => {
const { unknown, graph } = makeBaselineWhetherFixture();
const result = formulateQuestion({ node: unknown, graph });
expect(result.strategy).toBe("baseline_reconstruction");
expect(result.question).toBe(
"What was the comparable state before whether additional skilled staff needed for expansion can be recruited?",
);
});
it("permits the matching proposed strategy when the verdict is compatible", () => {
const { unknown, graph } = makeBaselineWhetherFixture();
const result = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "baseline_reconstruction",
relevance: "compatible",
},
},
});
expect(result.strategy).toBe("baseline_reconstruction");
expect(result.question).toBe(
"What was the comparable state before whether additional skilled staff needed for expansion can be recruited?",
);
});
it("suppresses an incompatible proposed strategy and uses the existing evidence path", () => {
const { unknown, graph } = makeBaselineWhetherFixture();
const graphSnapshot = JSON.stringify(graph);
const result = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "baseline_reconstruction",
relevance: "incompatible",
},
},
});
expect(result.strategy).toBeNull();
expect(result.question).toBe(
"What evidence would clarify whether additional skilled staff needed for expansion can be recruited?",
);
expect(JSON.stringify(graph)).toBe(graphSnapshot);
});
it("does not let invalid or mismatched verdicts authorise a proposed strategy", () => {
const { unknown, graph } = makeBaselineWhetherFixture();
const invalid = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "baseline_reconstruction",
relevance: "unknown",
},
},
});
const mismatched = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "evidence_gathering",
relevance: "compatible",
},
},
});
expect(invalid.strategy).toBeNull();
expect(mismatched.strategy).toBeNull();
expect(invalid.question).toContain("What evidence would clarify whether");
expect(mismatched.question).toContain("What evidence would clarify whether");
});
it("allows a compatible historical strategy for a coherent Whether-proposition", () => {
const unknown = makeNode({
id: "n-experiment14-historical",
label: "Earlier comparable state",
description: "Whether the prior staffing level was sufficient for expansion",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
const graph = makeGraphFor(unknown, {
centralStatement:
"Compare the prior staffing baseline with the level needed before the expansion.",
});
const result = formulateQuestion({
node: unknown,
graph,
context: {
strategyCompatibilityVerdict: {
strategyKey: "baseline_reconstruction",
relevance: "compatible",
},
},
});
expect(result.strategy).toBe("baseline_reconstruction");
});
});
// ── Experiment 6 — Graph-Context Causal Comparison ─────────────────────────────
// Hypothesis: baseline_reconstruction strategy on the recruitment unknown is driven
// by historical-baseline vocabulary in graph-level context (centralStatement), not
// in the recruitment uncertainty itself. Removing that vocabulary should prevent
// the specific baseline-selection route while preserving all node-level input.
describe("Experiment 6 — Isolate graph-context influence on strategy selection", () => {
it("removing baseline vocabulary from centralStatement changes strategy away from baseline_reconstruction", () => {
// ── shared open-question fixture (identical in both variants) ──
const openQuestion = makeNode({
id: "n-experiment3-staffing",
label: "Staffing certainty gap",
description:
"Whether additional skilled staff needed for expansion can be recruited",
kind: "unknown",
status: "unknown",
confidence: "medium",
});
// ── Variant A — baseline context present (existing fixture) ──
const graphA = makeGraph({
centralStatement:
"We need to compare our current baseline against the comparable state before staffing is secured for expansion.",
nodes: [openQuestion],
edges: [],
activeUnknownNodeId: openQuestion.id,
resolvedNodeIds: [],
currentSummary: "Test summary",
});
// ── Variant B — baseline context absent (neutral wording) ──
const graphB = makeGraph({
centralStatement:
"Current staffing levels are being reviewed as we prepare for the planned expansion.",
nodes: [openQuestion],
edges: [],
activeUnknownNodeId: openQuestion.id,
resolvedNodeIds: [],
currentSummary: "Test summary",
});
// ── Execute both variants ──
const resultA = formulateQuestion({ node: openQuestion, graph: graphA });
const resultB = formulateQuestion({ node: openQuestion, graph: graphB });
// Record for report
console.log("[Exp6-A] strategy:", resultA.strategy, "| question:", resultA.question);
console.log("[Exp6-B] strategy:", resultB.strategy, "| question:", resultB.question);
// Causal contrast: baseline_reconstruction requires BOTH graph-level AND node-level
// baseline vocabulary to match the first (strict) selection path.
// Variant A must select baseline_reconstruction.
expect(resultA.strategy).toBe("baseline_reconstruction");
// Variant B must NOT select baseline_reconstruction (graph-level baseline removed).
expect(resultB.strategy).not.toBe("baseline_reconstruction");
// The malformed "before whether" output must disappear in Variant B.
expect(resultB.question.toLowerCase()).not.toContain(
"before whether",
);
});
});
// ── 60B.80 — sufficiency re-selection after proposal application (no false State B) ────
describe("60B.80 — no false State B after proposal adds unresolved material factor", () => {