tooling: expose closure metadata in live harness
This commit is contained in:
@@ -343,6 +343,16 @@ async function runUpdateOnlyMode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Capture explicit closure metadata from accepted update ─
|
||||||
|
const finalActiveUnknownNodeId =
|
||||||
|
updatedGraph?.activeUnknownNodeId === undefined
|
||||||
|
? null
|
||||||
|
: updatedGraph.activeUnknownNodeId;
|
||||||
|
console.log(
|
||||||
|
`finalActiveUnknownNodeId: ${JSON.stringify(finalActiveUnknownNodeId)}`,
|
||||||
|
);
|
||||||
|
console.log(`finalSelectedQuestion: ${JSON.stringify(sq)}`);
|
||||||
|
|
||||||
// ── Capture persistent graph after update ───────────────
|
// ── Capture persistent graph after update ───────────────
|
||||||
const pNodes = updatedGraph?.nodes ?? [];
|
const pNodes = updatedGraph?.nodes ?? [];
|
||||||
const pEdges = updatedGraph?.edges ?? [];
|
const pEdges = updatedGraph?.edges ?? [];
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ function runPreAnchoredSimulationWithFixture(cfg) {
|
|||||||
proposal: proposal ? { addedNodes: proposal.addedNodes ?? [], addedEdges: proposal.addedEdges ?? [], updatedNodes: proposal.updatedNodes ?? [], resolvedUnknownNodeIds: proposal.resolvedUnknownNodeIds ?? [] } : null,
|
proposal: proposal ? { addedNodes: proposal.addedNodes ?? [], addedEdges: proposal.addedEdges ?? [], updatedNodes: proposal.updatedNodes ?? [], resolvedUnknownNodeIds: proposal.resolvedUnknownNodeIds ?? [] } : null,
|
||||||
structuralActionRequired: sar,
|
structuralActionRequired: sar,
|
||||||
selectedQuestion: sq && typeof sq === "object" ? { question: sq.question, nodeId: sq.nodeId } : null,
|
selectedQuestion: sq && typeof sq === "object" ? { question: sq.question, nodeId: sq.nodeId } : null,
|
||||||
|
finalActiveUnknownNodeId: uj.updatedSituationGraph?.activeUnknownNodeId === undefined ? null : uj.updatedSituationGraph.activeUnknownNodeId,
|
||||||
|
finalSelectedQuestion: sq,
|
||||||
graph: { nodes: uj.updatedSituationGraph?.nodes ?? [], edges: uj.updatedSituationGraph?.edges ?? [] },
|
graph: { nodes: uj.updatedSituationGraph?.nodes ?? [], edges: uj.updatedSituationGraph?.edges ?? [] },
|
||||||
},
|
},
|
||||||
capturedUpdateBody,
|
capturedUpdateBody,
|
||||||
@@ -477,6 +479,68 @@ describe("reproduce-multi-turn-investigation harness: one-shot semantics", () =>
|
|||||||
expect(graph.edges[0].relationship).toBe("depends_on");
|
expect(graph.edges[0].relationship).toBe("depends_on");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("accepted Update exposes explicit null finalActiveUnknownNodeId", () => {
|
||||||
|
const r = runSimulationWithResponseShape({
|
||||||
|
scenario: "test_ok",
|
||||||
|
maxUpdates: 1,
|
||||||
|
answers: ["good answer"],
|
||||||
|
onResponseUpdate: () => ({
|
||||||
|
success: true,
|
||||||
|
stage: "update_applied",
|
||||||
|
updatedSituationGraph: { nodes: [], edges: [], activeUnknownNodeId: null },
|
||||||
|
selectedQuestion: { question: "q2", nodeId: "n_pending" },
|
||||||
|
updatedProposal: { addedNodes: [], addedEdges: [], updatedNodes: [], resolvedUnknownNodeIds: [] },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(r.captured?.finalActiveUnknownNodeId).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepted Update exposes explicit null finalSelectedQuestion", () => {
|
||||||
|
const r = runSimulationWithResponseShape({
|
||||||
|
scenario: "test_ok",
|
||||||
|
maxUpdates: 1,
|
||||||
|
answers: ["good answer"],
|
||||||
|
onResponseUpdate: () => ({
|
||||||
|
success: true,
|
||||||
|
stage: "update_applied",
|
||||||
|
updatedSituationGraph: { nodes: [], edges: [], activeUnknownNodeId: null },
|
||||||
|
selectedQuestion: null,
|
||||||
|
updatedProposal: { addedNodes: [], addedEdges: [], updatedNodes: [], resolvedUnknownNodeIds: [] },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(r.captured?.finalSelectedQuestion).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepted Update preserves populated closure metadata unchanged", () => {
|
||||||
|
const r = runSimulationWithResponseShape({
|
||||||
|
scenario: "test_ok",
|
||||||
|
maxUpdates: 1,
|
||||||
|
answers: ["good answer"],
|
||||||
|
onResponseUpdate: () => ({
|
||||||
|
success: true,
|
||||||
|
stage: "update_applied",
|
||||||
|
updatedSituationGraph: {
|
||||||
|
nodes: [],
|
||||||
|
edges: [],
|
||||||
|
activeUnknownNodeId: "n_example",
|
||||||
|
},
|
||||||
|
selectedQuestion: {
|
||||||
|
nodeId: "n_example",
|
||||||
|
question: "What evidence would clarify this example?",
|
||||||
|
},
|
||||||
|
updatedProposal: { addedNodes: [], addedEdges: [], updatedNodes: [], resolvedUnknownNodeIds: [] },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(r.captured?.finalActiveUnknownNodeId).toBe("n_example");
|
||||||
|
expect(r.captured?.finalSelectedQuestion).toEqual({
|
||||||
|
nodeId: "n_example",
|
||||||
|
question: "What evidence would clarify this example?",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("rejected Update still exposes rejectedProposalSnapshot", () => {
|
it("rejected Update still exposes rejectedProposalSnapshot", () => {
|
||||||
const r = runSimulation({ scenario: "test_ok", maxUpdates: 1, answers: ["answer_reject"] });
|
const r = runSimulation({ scenario: "test_ok", maxUpdates: 1, answers: ["answer_reject"] });
|
||||||
expect(r.startCalls).toBe(1);
|
expect(r.startCalls).toBe(1);
|
||||||
@@ -1715,7 +1779,14 @@ function runSimulationWithResponseShape(cfg) {
|
|||||||
const answers = cfg.answers || [];
|
const answers = cfg.answers || [];
|
||||||
const maxUpdates = typeof cfg.maxUpdates === "number" ? cfg.maxUpdates : 2;
|
const maxUpdates = typeof cfg.maxUpdates === "number" ? cfg.maxUpdates : 2;
|
||||||
const limit = Math.min(maxUpdates, answers.length);
|
const limit = Math.min(maxUpdates, answers.length);
|
||||||
let captured = { answerMeaning: null, proposal: null, selectedQuestion: null, graph: null };
|
let captured = {
|
||||||
|
answerMeaning: null,
|
||||||
|
proposal: null,
|
||||||
|
selectedQuestion: null,
|
||||||
|
finalActiveUnknownNodeId: null,
|
||||||
|
finalSelectedQuestion: null,
|
||||||
|
graph: null,
|
||||||
|
};
|
||||||
|
|
||||||
for (let i = 0; i < limit; i++) {
|
for (let i = 0; i < limit; i++) {
|
||||||
const upResp = api.post("/api/cases/update", { situationGraph: graph, previousQuestion: question, answer: answers[i] });
|
const upResp = api.post("/api/cases/update", { situationGraph: graph, previousQuestion: question, answer: answers[i] });
|
||||||
@@ -1747,6 +1818,10 @@ function runSimulationWithResponseShape(cfg) {
|
|||||||
|
|
||||||
const sq = uj.selectedQuestion ?? null;
|
const sq = uj.selectedQuestion ?? null;
|
||||||
if (sq && typeof sq === "object") captured.selectedQuestion = { question: sq.question, nodeId: sq.nodeId };
|
if (sq && typeof sq === "object") captured.selectedQuestion = { question: sq.question, nodeId: sq.nodeId };
|
||||||
|
captured.finalSelectedQuestion = sq;
|
||||||
|
|
||||||
|
captured.finalActiveUnknownNodeId =
|
||||||
|
graph?.activeUnknownNodeId === undefined ? null : graph.activeUnknownNodeId;
|
||||||
|
|
||||||
captured.graph = { nodes: graph?.nodes ?? [], edges: graph?.edges ?? [] };
|
captured.graph = { nodes: graph?.nodes ?? [], edges: graph?.edges ?? [] };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user