/* RFC-0968/RFC-1124: tests for sternsystem.handover.complete — dry-run shim plus the RFC-1124 Worker-unreachable path (handover completes, journaled retry entry written). Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only. RFC-1124: AC-3/AC-7 coverage — Worker unreachable completes handover with journaled retry. */ import "./handover-dry-run.test.ts"; import { execFileSync } from "node:child_process"; import { existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import type { KernelCommandInput, KernelRuntimeContext } from "@warpgogol/werkstatt-shared/kernel"; import { generateKeyPair, toHex, toPem } from "@warpgogol/werkstatt-engine/signing"; import { signAuthorization, writeAuthorization, type HandoverAuthorizationV1 } from "./handover.ts"; import { buildPassportPayload, signPassport, type SignedSitePassport } from "./passport.ts"; import { writePassport } from "./registry-io.ts"; import { runSternsystemHandoverComplete } from "./sternsystem-handover-complete.ts"; import { createDefaultIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io"; let tmpDir: string; let recipientRoot: string; const systemId = "handover-site"; const savedEnv: Record = {}; beforeEach(() => { tmpDir = mkdtempSync(join(tmpdir(), "handover-complete-")); // werkstatt root nested — systems-cache resolves as its sibling inside tmpDir. recipientRoot = join(tmpDir, "werkstatt"); mkdirSync(recipientRoot, { recursive: true }); for (const k of [ "SIGNING_PRIVATE_KEY", "SIGNING_PRIVATE_KEY_PATH", "FLEET_OWNERSHIP_REGISTRY_URL", ]) { savedEnv[k] = process.env[k]; } }); afterEach(() => { for (const [k, v] of Object.entries(savedEnv)) { if (v === undefined) delete process.env[k]; else process.env[k] = v; } rmSync(tmpDir, { recursive: true, force: true }); }); function setupSystem(root: string, id: string): void { const cacheDir = join(root, "..", "systems-cache", id); mkdirSync(join(cacheDir, "missions"), { recursive: true }); mkdirSync(join(cacheDir, "bordbuch"), { recursive: true }); writeFileSync( join(cacheDir, "system-config.yaml"), [ `schemaVersion: system-config/v1`, `id: ${id}`, `cosmicStar: Vega`, `mirrors:`, ` - path: ../systems-cache/${id}`, ` storageType: non-bare`, ` - path: ../systems-git/${id}.git`, ` storageType: bare`, `pinnedPlatform: 6.0.0`, `status: active`, `registeredAt: "2026-01-01T00:00:00Z"`, `notes: ""`, ``, ].join("\n"), ); } function mockContext(root: string): KernelRuntimeContext { const noop = () => {}; return { io: createDefaultIO().io, workspaceRoot: root, logger: { info: noop, warn: noop, error: noop, success: noop, debug: noop, notice: noop, }, } as unknown as KernelRuntimeContext; } describe("RFC-1124 AC-3/AC-7: handover.complete with unreachable Worker", () => { it("completes the handover and writes a journaled retry entry", async () => { setupSystem(recipientRoot, systemId); // Sender passport + signed authorization in the recipient's cache clone. const senderKeyPair = await generateKeyPair(); const senderPayload = await buildPassportPayload({ systemId, werkstattRoot: recipientRoot, creatorIdentity: "human:sender", creatorPublicKey: toHex(senderKeyPair.publicKey), }); const senderSigned = await signPassport(senderPayload, senderKeyPair.privateKey); const senderPassport: SignedSitePassport = { payload: senderPayload, passportHash: senderSigned.passportHash, signature: senderSigned.signature, }; await writePassport(recipientRoot, systemId, senderPassport); const recipientKeyPair = await generateKeyPair(); const now = new Date(); const authPayload: HandoverAuthorizationV1 = { schema: "handover-authorization/v1", systemId, sender: { identity: "human:sender", publicKey: toHex(senderKeyPair.publicKey) }, recipient: { identity: "human:recipient", publicKey: toHex(recipientKeyPair.publicKey) }, passportHash: senderPassport.passportHash, bordbuchHead: "", authorizedAt: now.toISOString(), expiresAt: new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000).toISOString(), }; const signedAuth = await signAuthorization(authPayload, senderKeyPair.privateKey); await writeAuthorization(recipientRoot, systemId, signedAuth); // Recipient key via env; Worker URL points at a dead port. process.env.SIGNING_PRIVATE_KEY = toPem(recipientKeyPair.privateKey, "private"); process.env.FLEET_OWNERSHIP_REGISTRY_URL = "http://127.0.0.1:1/"; const input: KernelCommandInput = { argv: [], flags: { id: systemId, actor: "human:recipient" }, }; const result = await runSternsystemHandoverComplete(input, mockContext(recipientRoot)); // AC-3: handover completes despite Worker failure (no throw = success). expect(result.data?.ownershipRegistryUpdated).toBe(false); expect(result.data?.newCreator).toBe("human:recipient"); // AC-7: journaled retry entry in the cache clone's operations/journal/. const journalDir = join( recipientRoot, "..", "systems-cache", systemId, "operations", "journal", ); expect(existsSync(journalDir), "retry journal dir must exist").toBe(true); const journals = readdirSync(journalDir).filter((f) => f.endsWith(".jsonl")); expect(journals.length).toBeGreaterThan(0); const content = journals .map((f) => execFileSync("cat", [join(journalDir, f)], { encoding: "utf8" })) .join(""); expect(content).toContain("fleet.ownership.transfer"); expect(content).toContain("step-failed"); }); });