Feature/product platform foundation v0.62 #1

Merged
robbond merged 683 commits from feature/product-platform-foundation-v0.62 into feature/emergent-unknowns-v0.5 2026-09-09 07:58:20 +01:00
3 changed files with 37 additions and 0 deletions
Showing only changes of commit a23da2b727 - Show all commits
+2
View File
@@ -1316,6 +1316,8 @@ export default function ReasoningWorkspace({
onUpdateFindingProposition,
/* ── v0.49 — done-for-now promotion callback ───────── */
onSummaryUpdate,
/* ── canonical graph-replacement seam (future Re-open) ── */
onSituationGraphChange,
}) {
const [investigationHistory, setInvestigationHistory] = useState([]);
const turnCounter = useRef(0);
+2
View File
@@ -814,6 +814,8 @@ export default function ScenarioForm() {
onUpdateFindingProposition={updateFindingProposition}
/* v0.49 done-for-now promotion seam */
onSummaryUpdate={handleDoneForNowPromotion}
/* canonical graph-replacement seam (future Re-open) */
onSituationGraphChange={(nextGraph) => setResult((prev) => ({ ...(prev ?? {}), situationGraph: nextGraph }))}
onRestart={() => {
clearInvestigation();
setStatus("idle");
+33
View File
@@ -2114,4 +2114,37 @@ describe("ReasoningWorkspace UI", () => {
expect(html).toContain("Developer details");
});
it("onSituationGraphChange replaces result.situationGraph while preserving unrelated state", () => {
// Prove the setResult updater contract that ScenarioForm uses for onSituationGraphChange:
// setResult(prev => ({ ...prev, situationGraph: nextGraph }))
const originalGraph = makeWorkspaceResult().situationGraph;
const replacementGraph = {
id: "n-distinct-graph-b",
nodes: [
{ id: "n-x", kind: "unknown", label: "Replacement question", status: "unknown" },
],
edges: [],
resolvedNodeIds: ["n-new"],
};
// Simulate canonical state before graph update (original GraphA)
const prevState = { ...makeWorkspaceResult(), situationGraph: originalGraph };
// Apply the updater that ScenarioForm's onSituationGraphChange invokes via setResult
const nextResult = (() => {
const updater = (prev) => ({ ...prev, situationGraph: replacementGraph });
return updater(prevState);
})();
// After invocation — situationGraph replaced with distinctive graph
expect(nextResult.situationGraph).toBe(replacementGraph);
expect(nextResult.situationGraph.id).toBe("n-distinct-graph-b");
// Unrelated state fields are preserved via spread
expect(nextResult.success).toBe(true);
expect(nextResult.selectedQuestion.question).toBe("What denominator is being used for the complaint rate?");
expect(nextResult.diagnostics.modelName).toBe("test");
});
});