/* RFC-1297: unit tests for recordSiteRollback — AC-1: lastPropagated records the rolled-back release with state "rolled-back"; AC-2: the Bordbuch carries one deployment-rolled-back event. Also pins gateForChannel. Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1297: initial — AC-1/AC-2 probes. RFC-1297 */ import { test, expect, beforeEach, afterEach } from "vitest"; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { createDefaultIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io"; import { recordSiteRollback } from "./rollback-state.ts"; import { gateForChannel } from "./deploy-helpers.ts"; import { readSystemState } from "../sternsystem/registry-io.ts"; import { readBordbuch } from "../bordbuch/bordbuch-io.ts"; const systemId = "acme"; let tmpDir: string; let werkstattRoot: string; beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "rollback-state-")); werkstattRoot = join(tmpDir, "werkstatt"); const cacheDir = join(tmpDir, "systems-cache", systemId); mkdirSync(werkstattRoot, { recursive: true }); mkdirSync(cacheDir, { recursive: true }); writeFileSync( join(cacheDir, "system-state.yaml"), [ "schemaVersion: 1.0.0", `systemId: ${systemId}`, "currentMission: null", "lastRelease: acme-r000036", "lastPropagated:", " main:", " releaseId: acme-r000036", " at: 2026-10-14T19:53:51.751Z", " healthy: true", " state: succeeded", " operationId: op-test-0001", " leaseExpiresAt: null", "", ].join("\n"), ); }); afterEach(() => { rmSync(tmpDir, { recursive: true, force: true }); }); test("AC-1: recordSiteRollback writes lastPropagated.main with state rolled-back", async () => { const result = await recordSiteRollback({ workspaceRoot: werkstattRoot, systemId, channel: "main", operationId: "op-test-rollback", rollbackTarget: { releaseId: "acme-r000035", versionId: "worker-version-1" }, io: createDefaultIO().io, }); expect(result.releaseId).toBe("acme-r000035"); expect(result.stateWritten).toBe(true); const state = await readSystemState(werkstattRoot, systemId); const main = state.lastPropagated.main; expect(main?.releaseId).toBe("acme-r000035"); expect(main?.state).toBe("rolled-back"); expect(main?.healthy).toBeNull(); expect(main?.operationId).toBe("op-test-rollback"); expect(main?.workerVersionId).toBe("worker-version-1"); }); test("AC-2: recordSiteRollback appends one deployment-rolled-back Bordbuch event", async () => { await recordSiteRollback({ workspaceRoot: werkstattRoot, systemId, channel: "main", operationId: "op-test-rollback", rollbackTarget: { releaseId: "acme-r000035" }, io: createDefaultIO().io, }); const entries = await readBordbuch(werkstattRoot, systemId); const rollbacks = entries.filter((e) => e.kind === "deployment-rolled-back"); expect(rollbacks).toHaveLength(1); expect(rollbacks[0].summary).toContain("acme-r000035"); }); test("gateForChannel maps channels to their gates", () => { expect(gateForChannel("dev")).toBe("dev-deploy"); expect(gateForChannel("alt")).toBe("propagate-alt"); expect(gateForChannel("main")).toBe("promote-main"); });