import { describe, expect, it } from "bun:test"; import * as graphPlans from "./plan-graphs"; import { implementationGraphs } from "./plan-graphs"; import { MemoryStorage } from "../storage/memory/adapter"; import { close, open } from "../plan/service"; import type { Server } from "bun"; import type { Backend, Plan } from "../plan/service"; import type { JsonValue } from "../storage/model"; import type { SocketData } from "../wire"; const now = new Date("2026-08-13T12:00:00.000Z"); async function hosted() { let storage = new MemoryStorage(); await storage.users.put({ id: "U_octocat", login: "octocat", avatarUrl: "", now }); let channel = await storage.channels.create({ id: crypto.randomUUID(), repositoryId: "R_score", repositoryOwner: "octo-org", repositoryName: "score", title: "Implementation plan", createdBy: "U_octocat", now, }); let lease = await storage.leases.acquire("writer", "graph-test", 60_000); if (!lease) throw new Error("could not acquire test lease"); let backend: Backend = { storage, lease: () => lease, fatal: error => { throw error; }, }; let server = { publish() {} } as unknown as Server; return { storage, channel, lease, backend, server }; } const definition = { tasks: [{ id: "model", title: "Model graphs", context: "The sidecar owns the graph.", goal: "Persist implementation work.", acceptance: ["The graph is durable.", "The plan remains MDX only."], dependsOn: [], }], }; describe("the plan graph adapter", () => { it("keeps implementation preparation policy with graph persistence", async () => { let context = await hosted(); let plan = await open(context.channel.id, context.backend, context.server); let readiness = (graphPlans as typeof graphPlans & { implementationReadiness?: (plan: Plan, revision: unknown) => unknown; }).implementationReadiness; expect(readiness).toBeTypeOf("function"); if (typeof readiness !== "function") return; plan.records.set("open", { id: "open", status: "open" } as never); plan.threads.set("accepted", { id: "accepted", status: "accepted", notes: [] } as never); expect(readiness(plan, -1)).toEqual({ ok: false, blockers: [ "unanswered questionnaires", "accepted comments awaiting plan changes", "invalid plan revision", ], }); plan.records.clear(); plan.threads.clear(); expect(readiness(plan, plan.revision)).toEqual({ ok: true, revision: plan.revision }); await close(plan); }); it("keeps a document graph in the hosted sidecar through a restart", async () => { let context = await hosted(); let first = await open(context.channel.id, context.backend, context.server); let graph = await implementationGraphs().revise(first, { planRevision: 0, graphRevision: 0, operations: definition.tasks.map(task => ({ op: "add", task })), }); expect(graph.ok).toBe(true); await close(first); let stored = await context.storage.collaboration.load(context.channel.id, now); expect(stored?.sidecar).toMatchObject({ graph: { versions: [{ state: "draft", planRevision: 0, definition }] }, }); let restored = await open(context.channel.id, context.backend, context.server); expect( (await implementationGraphs().revise(restored, { planRevision: 0, graphRevision: 1, operations: [{ op: "replace", id: "model", task: definition.tasks[0] }], })).ok, ).toBe(true); await close(restored); }); it("ignores a malformed graph record while reopening the document", async () => { let context = await hosted(); let first = await open(context.channel.id, context.backend, context.server); await close(first); let stored = await context.storage.collaboration.load(context.channel.id, now); if ( !stored?.snapshot || !stored.snapshot.sidecar || typeof stored.snapshot.sidecar !== "object" ) { throw new Error("channel was not initialized"); } await context.storage.collaboration.commit({ channelId: context.channel.id, lease: context.lease, expectedRevision: stored.channel.revision, operationId: "malformed-graph", epoch: stored.snapshot.epoch, sidecar: { ...stored.snapshot.sidecar, graph: {} } as JsonValue, events: [], now, }); let restored = await open(context.channel.id, context.backend, context.server); expect( await implementationGraphs().revise(restored, { planRevision: 0, graphRevision: 0, operations: definition.tasks.map(task => ({ op: "add", task })), }), ).toMatchObject({ ok: true }); await close(restored); }); });