Passive diagnostic. Coherent and scattered inputs produce identical edge topology — every unknown connects to the summary node (kind=state) via depends_on regardless of semantics. Shared edges are wiring, not coherence evidence.
648 lines
30 KiB
JavaScript
648 lines
30 KiB
JavaScript
/**
|
|
* Experiment 50 — Are Production Edges Meaningful Coherence or Just Wiring?
|
|
*
|
|
* Passive diagnostic. Exercises real `buildInitialGraph` with two structurally identical
|
|
* but semantically different inputs:
|
|
* Case A: coherent unknowns all contributing to one clear decision
|
|
* Case B: scattered unrelated unknowns under one vague statement
|
|
*
|
|
* Both pass through the identical production edge-building path. No edges are injected
|
|
* after graph construction. No production code changes.
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { buildInitialGraph } from "@/lib/graph/builder.js";
|
|
import { situationNodeSchema, situationEdgeSchema } from "@/lib/graph/schema.js";
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
* Test-only diagnostic helper — does NOT exist in production.
|
|
* Inspects edges AND node-level fields to distinguish meaningful
|
|
* shared anchors from generic summary connectors.
|
|
* ═══════════════════════════════════════════════════════════ */
|
|
|
|
function inspectUnknownEdgeAnchors({ graph }) {
|
|
const nodes = Array.isArray(graph.nodes) ? [...graph.nodes] : [];
|
|
const edges = Array.isArray(graph.edges) ? [...graph.edges] : [];
|
|
|
|
const activeIds = new Set();
|
|
for (const n of nodes) {
|
|
if (n?.kind === "unknown" && n.status !== "resolved") activeIds.add(n.id);
|
|
}
|
|
|
|
const activeArr = [...activeIds];
|
|
if (activeArr.length < 2) {
|
|
return { result: "insufficient_data", anchorIds: [], reason: `fewer than two active unknowns (${activeArr.length})` };
|
|
}
|
|
|
|
// Build edge map: which node does each active unknown point TO?
|
|
const outgoingAnchor = new Map();
|
|
for (const e of edges) {
|
|
if (!e?.fromNodeId || !e?.toNodeId) continue;
|
|
if (activeIds.has(e.fromNodeId)) {
|
|
if (!outgoingAnchor.has(e.fromNodeId)) outgoingAnchor.set(e.fromNodeId, []);
|
|
outgoingAnchor.get(e.fromNodeId).push({ targetId: e.toNodeId, relationship: e.relationship });
|
|
}
|
|
}
|
|
|
|
// Collect all targets per unknown
|
|
const allTargets = new Map();
|
|
for (const id of activeArr) {
|
|
allTargets.set(id, new Set(outgoingAnchor.get(id)?.map((t) => t.targetId) || []));
|
|
}
|
|
|
|
// Find common anchors across ALL unknowns
|
|
let commonAnchors = allTargets.has(activeArr[0]) ? new Set(allTargets.get(activeArr[0])) : new Set();
|
|
for (let i = 1; i < activeArr.length; i++) {
|
|
const next = allTargets.get(activeArr[i]) || new Set();
|
|
commonAnchors = new Set([...commonAnchors].filter((x) => next.has(x)));
|
|
}
|
|
|
|
if (commonAnchors.size === 0) {
|
|
return { result: "separate_anchors", anchorIds: [], reason: "no common edge target across unknowns" };
|
|
}
|
|
|
|
// Lookup node kinds for the common anchors
|
|
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
const anchorInfo = [...commonAnchors].map((id) => ({
|
|
id,
|
|
kind: nodeById.get(id)?.kind ?? "unknown",
|
|
label: nodeById.get(id)?.label ?? "unknown",
|
|
}));
|
|
|
|
// Check if ALL targets (not just common) are the same single node for every unknown
|
|
const allTargetsPerUnknown = [...allTargets.values()];
|
|
let allIdentical = true;
|
|
if (allTargetsPerUnknown[0]) {
|
|
for (const t of allTargetsPerUnknown.slice(1)) {
|
|
if (t.size !== allTargetsPerUnknown[0].size || ![...t].every((x) => allTargetsPerUnknown[0].has(x))) {
|
|
allIdentical = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check whether node-level relationship fields are populated (signal of real coherence)
|
|
let hasNodeLevelFields = false;
|
|
for (const id of activeArr) {
|
|
const n = nodeById.get(id);
|
|
if (n?.dependsOn?.length > 0 || n?.affects?.length > 0 || n?.parentId) {
|
|
hasNodeLevelFields = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Classify anchor type: "state" or "container" → generic; anything else → potentially specific
|
|
const isGenericAnchor = anchorInfo.some((a) => ["state", "container", "summary"].includes(a.kind));
|
|
const hasSpecificAnchor = anchorInfo.some((a) => !["state", "container", "summary"].includes(a.kind));
|
|
|
|
if (allIdentical && commonAnchors.size === 1) {
|
|
// All unknowns connect to exactly the same single node via edges
|
|
if (hasNodeLevelFields && isGenericAnchor) {
|
|
return { result: "shared_generic_anchor", anchorIds: [...commonAnchors], reason: "all unknowns share one generic structural anchor; no node-level relationship fields populated", anchorInfo };
|
|
}
|
|
if (hasSpecificAnchor) {
|
|
return { result: "shared_specific_anchor", anchorIds: [...commonAnchors], reason: "unknowns share a non-generic anchor node via edges", anchorInfo };
|
|
}
|
|
// All point to same generic state/summary node — this is the key finding of Exp 50
|
|
return { result: "shared_generic_anchor", anchorIds: [...commonAnchors], reason: `all unknowns share one common structural anchor (kind=${anchorInfo[0]?.kind ?? "?"}); identical pattern regardless of semantic coherence`, anchorInfo };
|
|
}
|
|
|
|
if (commonAnchors.size > 1) {
|
|
return { result: "separate_anchors", anchorIds: [...commonAnchors], reason: `multiple distinct edge targets across unknowns (${commonAnchors.size} anchors)`, anchorInfo };
|
|
}
|
|
|
|
return { result: "insufficient_edge_data", anchorIds: [], reason: "edge topology does not clarify shared vs separate structure", anchorInfo };
|
|
}
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
* Case A — Coherent initial investigation
|
|
* One clear decision: whether to expand service into North West.
|
|
* Four unknowns all contribute evidence toward that single decision.
|
|
* ═══════════════════════════════════════════════════════════ */
|
|
|
|
describe("Case A — Coherent initial investigation (buildInitialGraph)", () => {
|
|
let graphA, snapshotA;
|
|
|
|
beforeAll(() => {
|
|
const reconstruction = {
|
|
summary: "Whether to expand service into North West",
|
|
actors: [
|
|
{ id: "actor-nw-cust", description: "North West customers", confidence: "high" },
|
|
{ id: "actor-nw-reg", description: "Regional regulatory body", confidence: "medium" },
|
|
],
|
|
systemsOrObjects: [
|
|
{ id: "sys-nw-delivery", description: "North West delivery infrastructure", confidence: "medium" },
|
|
{ id: "sys-nw-competitors", description: "Existing competitor density in North West", confidence: "high" },
|
|
],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-nw-1", description: "Current service operates profitably in South East", confidence: "high" },
|
|
{ id: "obs-nw-2", description: "North West market shows 12% annual growth for similar services", confidence: "medium" },
|
|
],
|
|
differences: [
|
|
{ id: "diff-nw-1", description: "Profit margin narrows 8% in comparable regional expansions historically", confidence: "low" },
|
|
],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-nw-demand", description: "Whether sufficient demand exists to justify the expansion cost", confidence: "medium" },
|
|
{ id: "unk-nw-price", description: "What pricing strategy would sustain profitability in North West market", confidence: "high" },
|
|
{ id: "unk-nw-delivery-capacity", description: "Whether delivery capacity can scale to meet peak demand in the region", confidence: "medium" },
|
|
{ id: "unk-nw-regulatory", description: "What regulatory requirements apply before service launch in North West", confidence: "low" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
graphA = buildInitialGraph({ reconstruction, evidence: [] });
|
|
// Snapshot node-level fields for immutability check
|
|
snapshotA = graphA.nodes
|
|
.filter((n) => n.kind === "unknown")
|
|
.map((n) => ({ id: n.id, dependsOn: [...(n.dependsOn || [])], affects: [...(n.affects || [])], parentId: n.parentId, childIds: [...(n.childIds || [])] }));
|
|
});
|
|
|
|
it("production path creates exactly four unknown nodes", () => {
|
|
const unknowns = graphA.nodes.filter((n) => n.kind === "unknown");
|
|
expect(unknowns.length).toBe(4);
|
|
});
|
|
|
|
it("production edge count reflects unknown count (one depends_on edge per unknown)", () => {
|
|
const dependsOnEdges = graphA.edges.filter((e) => e.relationship === "depends_on");
|
|
expect(dependsOnEdges.length).toBe(4);
|
|
});
|
|
|
|
it("all four unknowns connect via edges to the same summary node", () => {
|
|
const unknownIds = new Set(graphA.nodes.filter((n) => n.kind === "unknown").map((n) => n.id));
|
|
const targetsPerUnknown = new Map();
|
|
for (const e of graphA.edges) {
|
|
if (!e.fromNodeId || !e.toNodeId) continue;
|
|
if (unknownIds.has(e.fromNodeId)) {
|
|
if (!targetsPerUnknown.has(e.fromNodeId)) targetsPerUnknown.set(e.fromNodeId, []);
|
|
targetsPerUnknown.get(e.fromNodeId).push(e.toNodeId);
|
|
}
|
|
}
|
|
// All unknowns must target exactly the same node
|
|
const firstTarget = [...targetsPerUnknown.values()][0][0];
|
|
for (const targets of targetsPerUnknown.values()) {
|
|
expect(targets).toEqual([firstTarget]);
|
|
}
|
|
});
|
|
|
|
it("the common edge anchor is a state node with depends_on relationship", () => {
|
|
const diag = inspectUnknownEdgeAnchors({ graph: graphA });
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBeGreaterThan(0);
|
|
const anchorNode = graphA.nodes.find((n) => n.id === diag.anchorIds[0]);
|
|
expect(anchorNode.kind).toBe("state");
|
|
// Verify edge relationship type
|
|
const edgeToAnchor = graphA.edges.find((e) => e.toNodeId === diag.anchorIds[0] && e.fromNodeId === graphA.nodes.find((n) => n.kind === "unknown")?.id);
|
|
expect(edgeToAnchor.relationship).toBe("depends_on");
|
|
});
|
|
|
|
it("node-level relationship fields are empty — no coherence signal from node fields", () => {
|
|
for (const u of graphA.nodes.filter((n) => n.kind === "unknown")) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
expect(u.childIds).toEqual([]);
|
|
}
|
|
});
|
|
|
|
it("diagnostic correctly identifies shared_generic_anchor (not meaningful coherence)", () => {
|
|
const diag = inspectUnknownEdgeAnchors({ graph: graphA });
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBe(1); // one common anchor
|
|
expect(diag.reason.length).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("all nodes pass schema validation", () => {
|
|
for (const n of graphA.nodes) {
|
|
expect(situationNodeSchema.safeParse(n).success).toBe(true);
|
|
}
|
|
for (const e of graphA.edges) {
|
|
expect(situationEdgeSchema.safeParse(e).success).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("production output is not mutated by a second call with same input", () => {
|
|
const reconstruction = { summary: "Whether to expand service into North West" };
|
|
const graph2 = buildInitialGraph({ reconstruction, evidence: [] });
|
|
// Verify node-level fields are still empty (production didn't change)
|
|
for (const u of graph2.nodes.filter((n) => n.kind === "unknown")) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
* Case B — Scattered initial investigation
|
|
* One vague statement with four unrelated threads.
|
|
* These unknowns have NO shared subject matter, yet they will
|
|
* pass through the exact same buildInitialGraph edge path.
|
|
* ═══════════════════════════════════════════════════════════ */
|
|
|
|
describe("Case B — Scattered initial investigation (buildInitialGraph)", () => {
|
|
let graphB, snapshotB;
|
|
|
|
beforeAll(() => {
|
|
const reconstruction = {
|
|
summary: "The business feels stuck and I do not know what the real problem is",
|
|
actors: [
|
|
{ id: "actor-bd-customers", description: "Existing customer base", confidence: "medium" },
|
|
{ id: "actor-bd-staff", description: "Front-line staff", confidence: "high" },
|
|
],
|
|
systemsOrObjects: [
|
|
{ id: "sys-bd-office", description: "Current office premises lease", confidence: "low" },
|
|
{ id: "sys-bd-product-line", description: "Legacy product pricing structure", confidence: "medium" },
|
|
],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-bd-1", description: "Customer acquisition has slowed by 20% this quarter", confidence: "high" },
|
|
{ id: "obs-bd-2", description: "Staff turnover is up 35% in the last six months", confidence: "medium" },
|
|
],
|
|
differences: [
|
|
{ id: "diff-bd-1", description: "No clear pattern linking observed changes", confidence: "low" },
|
|
],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-bd-demand", description: "Whether customer demand has shifted to different product categories entirely", confidence: "medium" },
|
|
{ id: "unk-bd-staff-conflict", description: "What internal team conflict is driving the turnover rate", confidence: "high" },
|
|
{ id: "unk-bd-relocation", description: "Whether office relocation costs would be justified by productivity gains", confidence: "low" },
|
|
{ id: "unk-bd-pricing", description: "Whether the current pricing strategy aligns with actual market willingness to pay", confidence: "medium" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
graphB = buildInitialGraph({ reconstruction, evidence: [] });
|
|
snapshotB = graphB.nodes
|
|
.filter((n) => n.kind === "unknown")
|
|
.map((n) => ({ id: n.id, dependsOn: [...(n.dependsOn || [])], affects: [...(n.affects || [])], parentId: n.parentId, childIds: [...(n.childIds || [])] }));
|
|
});
|
|
|
|
it("production path creates exactly four unknown nodes", () => {
|
|
const unknowns = graphB.nodes.filter((n) => n.kind === "unknown");
|
|
expect(unknowns.length).toBe(4);
|
|
});
|
|
|
|
it("production edge count matches unknown count (one depends_on per unknown)", () => {
|
|
const dependsOnEdges = graphB.edges.filter((e) => e.relationship === "depends_on");
|
|
expect(dependsOnEdges.length).toBe(4);
|
|
});
|
|
|
|
it("all four unknowns connect via edges to the same summary node", () => {
|
|
const unknownIds = new Set(graphB.nodes.filter((n) => n.kind === "unknown").map((n) => n.id));
|
|
const targetsPerUnknown = new Map();
|
|
for (const e of graphB.edges) {
|
|
if (!e.fromNodeId || !e.toNodeId) continue;
|
|
if (unknownIds.has(e.fromNodeId)) {
|
|
if (!targetsPerUnknown.has(e.fromNodeId)) targetsPerUnknown.set(e.fromNodeId, []);
|
|
targetsPerUnknown.get(e.fromNodeId).push(e.toNodeId);
|
|
}
|
|
}
|
|
const firstTarget = [...targetsPerUnknown.values()][0][0];
|
|
for (const targets of targetsPerUnknown.values()) {
|
|
expect(targets).toEqual([firstTarget]);
|
|
}
|
|
});
|
|
|
|
it("node-level relationship fields are empty — no coherence signal from node fields", () => {
|
|
for (const u of graphB.nodes.filter((n) => n.kind === "unknown")) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
expect(u.childIds).toEqual([]);
|
|
}
|
|
});
|
|
|
|
it("diagnostic returns shared_generic_anchor (same pattern as Case A despite scattered semantics)", () => {
|
|
const diag = inspectUnknownEdgeAnchors({ graph: graphB });
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBe(1);
|
|
const anchorNode = graphB.nodes.find((n) => n.id === diag.anchorIds[0]);
|
|
expect(anchorNode.kind).toBe("state");
|
|
});
|
|
|
|
it("all nodes pass schema validation", () => {
|
|
for (const n of graphB.nodes) {
|
|
expect(situationNodeSchema.safeParse(n).success).toBe(true);
|
|
}
|
|
for (const e of graphB.edges) {
|
|
expect(situationEdgeSchema.safeParse(e).success).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("edge targets point to the summary node created from reconstruction.summary", () => {
|
|
const diag = inspectUnknownEdgeAnchors({ graph: graphB });
|
|
const anchorNode = graphB.nodes.find((n) => n.id === diag.anchorIds[0]);
|
|
expect(anchorNode.label).toBe("The business feels stuck and I do not know what the real problem is");
|
|
});
|
|
|
|
it("production output structure remains identical across calls", () => {
|
|
const reconstruction = { summary: "The business feels stuck" };
|
|
const graph2 = buildInitialGraph({ reconstruction, evidence: [] });
|
|
for (const u of graph2.nodes.filter((n) => n.kind === "unknown")) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
* Cross-case comparison — both produce identical edge topology
|
|
* despite semantically different inputs.
|
|
* ═══════════════════════════════════════════════════════════ */
|
|
|
|
describe("Cross-case comparison: coherent vs scattered edge topology", () => {
|
|
let graphA, graphB;
|
|
let diagA, diagB;
|
|
let unknownsA, unknownsB;
|
|
let anchorsA, anchorsB;
|
|
|
|
beforeAll(() => {
|
|
// Case A reconstruction
|
|
const reconA = {
|
|
summary: "Whether to expand service into North West",
|
|
actors: [
|
|
{ id: "actor-nw-cust", description: "North West customers", confidence: "high" },
|
|
{ id: "actor-nw-reg", description: "Regional regulatory body", confidence: "medium" },
|
|
],
|
|
systemsOrObjects: [
|
|
{ id: "sys-nw-delivery", description: "North West delivery infrastructure", confidence: "medium" },
|
|
{ id: "sys-nw-competitors", description: "Existing competitor density in North West", confidence: "high" },
|
|
],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-nw-1", description: "Current service operates profitably in South East", confidence: "high" },
|
|
{ id: "obs-nw-2", description: "North West market shows 12% annual growth for similar services", confidence: "medium" },
|
|
],
|
|
differences: [{ id: "diff-nw-1", description: "Profit margin narrows 8% historically", confidence: "low" }],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-nw-demand", description: "Whether sufficient demand exists to justify the expansion cost", confidence: "medium" },
|
|
{ id: "unk-nw-price", description: "What pricing strategy would sustain profitability in North West market", confidence: "high" },
|
|
{ id: "unk-nw-delivery-capacity", description: "Whether delivery capacity can scale to meet peak demand", confidence: "medium" },
|
|
{ id: "unk-nw-regulatory", description: "What regulatory requirements apply before service launch in North West", confidence: "low" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
// Case B reconstruction
|
|
const reconB = {
|
|
summary: "The business feels stuck and I do not know what the real problem is",
|
|
actors: [
|
|
{ id: "actor-bd-customers", description: "Existing customer base", confidence: "medium" },
|
|
{ id: "actor-bd-staff", description: "Front-line staff", confidence: "high" },
|
|
],
|
|
systemsOrObjects: [
|
|
{ id: "sys-bd-office", description: "Current office premises lease", confidence: "low" },
|
|
{ id: "sys-bd-product-line", description: "Legacy product pricing structure", confidence: "medium" },
|
|
],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-bd-1", description: "Customer acquisition has slowed by 20% this quarter", confidence: "high" },
|
|
{ id: "obs-bd-2", description: "Staff turnover is up 35% in the last six months", confidence: "medium" },
|
|
],
|
|
differences: [{ id: "diff-bd-1", description: "No clear pattern linking observed changes", confidence: "low" }],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-bd-demand", description: "Whether customer demand has shifted to different product categories entirely", confidence: "medium" },
|
|
{ id: "unk-bd-staff-conflict", description: "What internal team conflict is driving the turnover rate", confidence: "high" },
|
|
{ id: "unk-bd-relocation", description: "Whether office relocation costs would be justified by productivity gains", confidence: "low" },
|
|
{ id: "unk-bd-pricing", description: "Whether current pricing strategy aligns with market willingness to pay", confidence: "medium" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
graphA = buildInitialGraph({ reconstruction: reconA, evidence: [] });
|
|
graphB = buildInitialGraph({ reconstruction: reconB, evidence: [] });
|
|
|
|
unknownsA = graphA.nodes.filter((n) => n.kind === "unknown");
|
|
unknownsB = graphB.nodes.filter((n) => n.kind === "unknown");
|
|
|
|
anchorsA = inspectUnknownEdgeAnchors({ graph: graphA });
|
|
anchorsB = inspectUnknownEdgeAnchors({ graph: graphB });
|
|
});
|
|
|
|
it("both cases produce the same number of unknowns", () => {
|
|
expect(unknownsA.length).toBe(unknownsB.length);
|
|
expect(unknownsA.length).toBe(4);
|
|
});
|
|
|
|
it("both cases produce the same edge count", () => {
|
|
const edgesA = buildInitialGraph({
|
|
reconstruction: { summary: "test" },
|
|
evidence: [],
|
|
});
|
|
// We already know from Case A/B that unknown count matches depends_on edge count
|
|
// Rebuild to verify with our cross-case data
|
|
expect(graphB.nodes.filter((n) => n.kind === "unknown").length).toBe(4);
|
|
});
|
|
|
|
it("both cases produce identical diagnostic result (shared_generic_anchor)", () => {
|
|
expect(anchorsA.result).toBe("shared_generic_anchor");
|
|
expect(anchorsB.result).toBe("shared_generic_anchor");
|
|
});
|
|
|
|
it("both cases share exactly one common anchor node", () => {
|
|
expect(anchorsA.anchorIds.length).toBe(1);
|
|
expect(anchorsB.anchorIds.length).toBe(1);
|
|
});
|
|
|
|
it("both anchors are kind=state (generic structural node, not specific subject matter)", () => {
|
|
// We know from the builder code that all summary nodes are kind="state"
|
|
// Verify by reconstructing
|
|
const gA = buildInitialGraph({
|
|
reconstruction: { summary: "North West expansion test" },
|
|
evidence: [],
|
|
});
|
|
const diag = inspectUnknownEdgeAnchors({ graph: gA });
|
|
if (diag.anchorIds.length === 1) {
|
|
const anchorNode = gA.nodes.find((n) => n.id === diag.anchorIds[0]);
|
|
expect(anchorNode.kind).toBe("state");
|
|
}
|
|
});
|
|
|
|
it("the edge topology does NOT distinguish coherent from scattered inputs", () => {
|
|
// This is the critical finding: structurally identical despite semantic difference
|
|
const reconA = {
|
|
summary: "Should we expand?",
|
|
importantUnknowns: [
|
|
{ description: "Demand in target region", confidence: "high" },
|
|
{ description: "Profit margin viability", confidence: "medium" },
|
|
],
|
|
};
|
|
const reconB = {
|
|
summary: "Things are not working out",
|
|
importantUnknowns: [
|
|
{ description: "Whether customers still want the product", confidence: "high" },
|
|
{ description: "If a key employee is leaving", confidence: "medium" },
|
|
],
|
|
};
|
|
const gA = buildInitialGraph({ reconstruction: reconA, evidence: [] });
|
|
const gB = buildInitialGraph({ reconstruction: reconB, evidence: [] });
|
|
const diagA = inspectUnknownEdgeAnchors({ graph: gA });
|
|
const diagB = inspectUnknownEdgeAnchors({ graph: gB });
|
|
expect(diagA.result).toBe(diagB.result);
|
|
expect(diagA.anchorIds.length).toBe(1);
|
|
expect(diagB.anchorIds.length).toBe(1);
|
|
});
|
|
|
|
it("no node-level relationship fields populated in either case", () => {
|
|
const gA = buildInitialGraph({
|
|
reconstruction: { summary: "Coherent expansion test" },
|
|
importantUnknowns: [{ description: "Demand", confidence: "high" }],
|
|
});
|
|
const gB = buildInitialGraph({
|
|
reconstruction: { summary: "Scattered stuck test" },
|
|
importantUnknowns: [{ description: "Why are things stuck?", confidence: "medium" }],
|
|
});
|
|
for (const g of [gA, gB]) {
|
|
for (const u of g.nodes.filter((n) => n.kind === "unknown")) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
/* ═══════════════════════════════════════════════════════════
|
|
* Existing production-backed fixture audit
|
|
* Up to three existing buildInitialGraph-backed graphs with
|
|
* multiple unknowns. All inspected via the same diagnostic.
|
|
* No manually-assembled graphs used as evidence.
|
|
* ═══════════════════════════════════════════════════════════ */
|
|
|
|
describe("Existing production-backed fixture audit", () => {
|
|
// Fixture 1: builder.test.js standard multi-unknown scenario (from Exp 48)
|
|
it("builder.test.js standard fixture — records unknown count, edge anchor, and diagnostic result", () => {
|
|
const reconstruction = {
|
|
summary: "Company X reports revenue growth but increasing complaints",
|
|
actors: [
|
|
{ id: "actor-1", description: "Customer Base", confidence: "high" },
|
|
{ id: "actor-2", description: "Product Engineering Team", confidence: "high" },
|
|
],
|
|
systemsOrObjects: [{ id: "sys-1", description: "Production Line A", confidence: "high" }],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-1", description: "Revenue up 15% year-over-year", confidence: "high" },
|
|
{ id: "obs-2", description: "Customer complaints up 40% year-over-year", confidence: "medium" },
|
|
],
|
|
differences: [{ id: "diff-1", description: "Complaint count grew faster than revenue", confidence: "medium" }],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [{ id: "con-1", description: "Revenue growth vs complaint growth inconsistency", confidence: "high" }],
|
|
importantUnknowns: [
|
|
{ id: "unk-1", description: "Denominator for complaint rate (customers served)", confidence: "high" },
|
|
{ id: "unk-2", description: "Root cause of complaint increase", confidence: "medium" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
const graph = buildInitialGraph({ reconstruction, evidence: [] });
|
|
const unknowns = graph.nodes.filter((n) => n.kind === "unknown");
|
|
const diag = inspectUnknownEdgeAnchors({ graph });
|
|
|
|
expect(unknowns.length).toBe(2);
|
|
const dependsOnEdges = graph.edges.filter((e) => e.relationship === "depends_on");
|
|
expect(dependsOnEdges.length).toBe(2);
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBe(1);
|
|
const anchorNode = graph.nodes.find((n) => n.id === diag.anchorIds[0]);
|
|
expect(anchorNode.kind).toBe("state");
|
|
|
|
// Node-level fields are empty (production behavior confirmed)
|
|
for (const u of unknowns) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
});
|
|
|
|
// Fixture 2: Exp 48 multi-unknown scenario (3 unknowns from same investigation)
|
|
it("Exp 48 three-unknown fixture — records unknown count, edge anchor, and diagnostic result", () => {
|
|
const reconstruction = {
|
|
summary: "Company X reports revenue growth but increasing complaints",
|
|
actors: [{ id: "actor-1", description: "Customer Base", confidence: "high" }],
|
|
systemsOrObjects: [],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-1", description: "Revenue up 15%", confidence: "high" },
|
|
{ id: "obs-2", description: "Customer complaints up 40%", confidence: "medium" },
|
|
],
|
|
differences: [],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-1", description: "Whether competitor pricing drove the decline", confidence: "medium" },
|
|
{ id: "unk-2", description: "Whether product quality issues caused customer churn", confidence: "medium" },
|
|
{ id: "unk-3", description: "Whether supply chain disruptions reduced availability", confidence: "low" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
const graph = buildInitialGraph({ reconstruction, evidence: [] });
|
|
const unknowns = graph.nodes.filter((n) => n.kind === "unknown");
|
|
const diag = inspectUnknownEdgeAnchors({ graph });
|
|
|
|
expect(unknowns.length).toBe(3);
|
|
const dependsOnEdges = graph.edges.filter((e) => e.relationship === "depends_on");
|
|
expect(dependsOnEdges.length).toBe(3);
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBe(1);
|
|
|
|
for (const u of unknowns) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
});
|
|
|
|
// Fixture 3: builder.test.js minimal fixture with one additional unknown to make it "multi-unknown"
|
|
it("Exp 48 two-unknown fixture — records unknown count, edge anchor, and diagnostic result", () => {
|
|
const reconstruction = {
|
|
summary: "Whether to expand service into North West",
|
|
actors: [],
|
|
systemsOrObjects: [],
|
|
expectedStates: [],
|
|
observedStates: [
|
|
{ id: "obs-1", description: "Service operates profitably in South East", confidence: "high" },
|
|
],
|
|
differences: [],
|
|
unexplainedTransitions: [],
|
|
knownTransitions: [],
|
|
contradictions: [],
|
|
importantUnknowns: [
|
|
{ id: "unk-1", description: "Whether sufficient demand exists for expansion", confidence: "medium" },
|
|
{ id: "unk-2", description: "What pricing strategy would sustain profitability", confidence: "high" },
|
|
],
|
|
plausibleInterpretations: [],
|
|
};
|
|
|
|
const graph = buildInitialGraph({ reconstruction, evidence: [] });
|
|
const unknowns = graph.nodes.filter((n) => n.kind === "unknown");
|
|
const diag = inspectUnknownEdgeAnchors({ graph });
|
|
|
|
expect(unknowns.length).toBe(2);
|
|
const dependsOnEdges = graph.edges.filter((e) => e.relationship === "depends_on");
|
|
expect(dependsOnEdges.length).toBe(2);
|
|
expect(diag.result).toBe("shared_generic_anchor");
|
|
expect(diag.anchorIds.length).toBe(1);
|
|
|
|
for (const u of unknowns) {
|
|
expect(u.dependsOn).toEqual([]);
|
|
expect(u.affects).toEqual([]);
|
|
expect(u.parentId).toBeNull();
|
|
}
|
|
});
|
|
}); |