experiment: qualify condition status by evidence scope
This commit is contained in:
@@ -84,7 +84,9 @@ describe("assessDecisionConditionStatus — established", () => {
|
|||||||
expect(result.evidenceNodeIds).toHaveLength(0);
|
expect(result.evidenceNodeIds).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns established when resolved unique feature evidence supports differentiation", () => {
|
it("returns unresolved when evidence mentions a unique feature but scope is not direct_match", () => {
|
||||||
|
// Evidence contains support keywords but does not share the core "differentiat" keyword
|
||||||
|
// required by CONCEPT_FAMILIES for differentiation category. Scope = unrelated → unresolved.
|
||||||
const graph = makeGraph(
|
const graph = makeGraph(
|
||||||
[makeNode("d-1", "Our platform offers unique real-time collaboration with no European equivalent", { status: "resolved" })],
|
[makeNode("d-1", "Our platform offers unique real-time collaboration with no European equivalent", { status: "resolved" })],
|
||||||
["d-1"],
|
["d-1"],
|
||||||
@@ -95,8 +97,24 @@ describe("assessDecisionConditionStatus — established", () => {
|
|||||||
graph,
|
graph,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(result.status).toBe("unresolved");
|
||||||
|
expect(result.evidenceNodeIds).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns established when evidence has direct_match scope and supports differentiation", () => {
|
||||||
|
// Evidence contains core keyword "differentiat" → direct_match + supports → established
|
||||||
|
const graph = makeGraph(
|
||||||
|
[makeNode("d-3", "Our product offers a clear competitive differentiation against existing players", { status: "resolved" })],
|
||||||
|
["d-3"],
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = assessDecisionConditionStatus({
|
||||||
|
condition: CONDITIONS[3],
|
||||||
|
graph,
|
||||||
|
});
|
||||||
|
|
||||||
expect(result.status).toBe("established");
|
expect(result.status).toBe("established");
|
||||||
expect(result.evidenceNodeIds).toContain("d-1");
|
expect(result.evidenceNodeIds).toContain("d-3");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns established for compliance with GDPR match", () => {
|
it("returns established for compliance with GDPR match", () => {
|
||||||
@@ -148,7 +166,10 @@ describe("assessDecisionConditionStatus — contradicted", () => {
|
|||||||
expect(result.evidenceNodeIds).toContain("x-1");
|
expect(result.evidenceNodeIds).toContain("x-1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("contradiction takes precedence over support when both exist", () => {
|
it("contradiction takes precedence over support only within direct scope", () => {
|
||||||
|
// s-1 gets direct_match scope (present-state evidence about present compliance)
|
||||||
|
// c-1 gets unrelated scope (evidence text does not match compliance category)
|
||||||
|
// With scope-aware logic: only s-1 contributes → established, contradicted status = unresolved
|
||||||
const graph = makeGraph(
|
const graph = makeGraph(
|
||||||
[
|
[
|
||||||
makeNode("s-1", "Our platform meets GDPR requirements for compliance", { status: "resolved" }),
|
makeNode("s-1", "Our platform meets GDPR requirements for compliance", { status: "resolved" }),
|
||||||
@@ -162,6 +183,25 @@ describe("assessDecisionConditionStatus — contradicted", () => {
|
|||||||
graph,
|
graph,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Only direct-scope evidence counts; s-1 supports, c-1 is unrelated → established
|
||||||
|
expect(result.status).toBe("established");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("contradiction takes precedence over support within the same direct scope", () => {
|
||||||
|
// Both evidence nodes have direct_match scope for compliance
|
||||||
|
const graph = makeGraph(
|
||||||
|
[
|
||||||
|
makeNode("p-1", "Our platform meets compliance requirements", { status: "resolved" }),
|
||||||
|
makeNode("p-2", "But it does not support EU data residency mandates", { status: "resolved" }),
|
||||||
|
],
|
||||||
|
["p-1", "p-2"],
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = assessDecisionConditionStatus({
|
||||||
|
condition: CONDITIONS[1],
|
||||||
|
graph,
|
||||||
|
});
|
||||||
|
|
||||||
expect(result.status).toBe("contradicted");
|
expect(result.status).toBe("contradicted");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -196,14 +236,51 @@ describe("assessDecisionConditionStatus — contradicted", () => {
|
|||||||
expect(result.status).toBe("established");
|
expect(result.status).toBe("established");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns contradicted when node text contains 'not achievable' phrase", () => {
|
it("returns unresolved when evidence contains 'not achievable' but scope is unrelated", () => {
|
||||||
|
// Evidence mentions "not achievable" (a contradiction phrase) but is about market share,
|
||||||
|
// not value_cost. Scope check correctly classifies as unrelated → contradiction ignored.
|
||||||
const graph = makeGraph(
|
const graph = makeGraph(
|
||||||
[makeNode("na-1", "Target market share is not achievable given incumbent dominance", { status: "resolved" })],
|
[makeNode("na-1", "Target market share is not achievable given incumbent dominance", { status: "resolved" })],
|
||||||
["na-1"],
|
["na-1"],
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = assessDecisionConditionStatus({
|
const result = assessDecisionConditionStatus({
|
||||||
condition: CONDITIONS[2], // value_cost — "achievable" matches CONTRADICTION_PHRASES via substring
|
condition: CONDITIONS[2], // value_cost — unrelated subject → scope=unrelated
|
||||||
|
graph,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.status).toBe("unresolved");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns unresolved when evidence scope is different_timeframe for future-feasibility condition", () => {
|
||||||
|
// A condition using "can be achieved" triggers the different_timeframe scope check
|
||||||
|
// because the scope module recognises this as a future-feasibility phrase.
|
||||||
|
const graph = makeGraph(
|
||||||
|
[makeNode("c-3", "Our platform does not currently support EU data residency requirements", { status: "resolved" })],
|
||||||
|
["c-3"],
|
||||||
|
);
|
||||||
|
|
||||||
|
// This condition text triggers different_timeframe scope detection (contains "can be achieved"),
|
||||||
|
// so present-state evidence cannot establish or contradict it.
|
||||||
|
const result = assessDecisionConditionStatus({
|
||||||
|
condition: "European compliance can be achieved",
|
||||||
|
graph,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.status).toBe("unresolved");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("present-state compliance condition with contradictory evidence returns contradicted", () => {
|
||||||
|
// Focused test: a genuinely present-state compliance condition should be contradicted
|
||||||
|
// when evidence directly negates the claim. Requires a separate unknown node for category
|
||||||
|
// matching and an observation-type node as contradicting evidence.
|
||||||
|
const cs1 = makeNode("cs-1", "Our platform does not support EU data residency requirements", { kind: "observation", status: "resolved" });
|
||||||
|
const ux = makeNode("u-x", "Whether our product meets EU compliance requirements", { kind: "unknown", status: "resolved" });
|
||||||
|
|
||||||
|
const graph = makeGraph([cs1, ux], ["cs-1", "u-x"]);
|
||||||
|
|
||||||
|
const result = assessDecisionConditionStatus({
|
||||||
|
condition: "The platform currently supports EU data residency requirements",
|
||||||
graph,
|
graph,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -442,23 +519,26 @@ describe("assessDecisionConditionStatus — long investigation sequence", () =>
|
|||||||
expect(valueCostResult.status).toBe("unresolved");
|
expect(valueCostResult.status).toBe("unresolved");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("turn 4 has two established and one contradicted", () => {
|
it("turn 4 has demand established, compliance contradicted, value_cost unresolved, differentiation unresolved", () => {
|
||||||
// Turn 4 resolved=[u-1,u-2,u-3,u-4]
|
// Turn 4 resolved=[u-1,u-2,u-3,u-4]
|
||||||
// demand=established, compliance=contradicted, value_cost=unresolved, differentiation=established
|
// demand=established (obs-2 direct_match + supports)
|
||||||
|
// compliance=contradicted (obs-3 direct_match + contradicts)
|
||||||
|
// value_cost=unresolved (obs-4 informs — no directional signal)
|
||||||
|
// differentiation=unresolved (obs-5 unrelated scope for CONDITIONS[3] keywords)
|
||||||
const turn4 = allResults.filter((r) => r.turn === 4);
|
const turn4 = allResults.filter((r) => r.turn === 4);
|
||||||
const establishedCount = turn4.filter((r) => r.status === "established").length;
|
|
||||||
expect(establishedCount).toBeGreaterThanOrEqual(2);
|
|
||||||
|
|
||||||
const contradictedCount = turn4.filter((r) => r.status === "contradicted").length;
|
|
||||||
expect(contradictedCount).toBeGreaterThanOrEqual(1);
|
|
||||||
|
|
||||||
// Demand is established
|
|
||||||
const demandResult = turn4.find((r) => r.condition.includes("demand"));
|
const demandResult = turn4.find((r) => r.condition.includes("demand"));
|
||||||
expect(demandResult.status).toBe("established");
|
expect(demandResult.status).toBe("established");
|
||||||
|
|
||||||
// Differentiation is established (no direct European equivalent)
|
const complianceResult = turn4.find((r) => r.condition.includes("compliance"));
|
||||||
|
expect(complianceResult.status).toBe("contradicted");
|
||||||
|
|
||||||
|
const valueCostResult = turn4.find((r) => r.condition.includes("value"));
|
||||||
|
expect(valueCostResult.status).toBe("unresolved");
|
||||||
|
|
||||||
const diffResult = turn4.find((r) => r.condition.includes("competitive"));
|
const diffResult = turn4.find((r) => r.condition.includes("competitive"));
|
||||||
expect(diffResult.status).toBe("established");
|
// obs-5 "unrelated" scope for CONDITIONS[3] → unresolved
|
||||||
|
expect(diffResult.status).toBe("unresolved");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("status transitions make sense: unresolved → determined over turns", () => {
|
it("status transitions make sense: unresolved → determined over turns", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user