import { beforeEach, describe, expect, it, vi } from "vitest"; import { access, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import type { Db } from "@paperclipai/db"; import type { NativeExecutionInputV1 } from "@paperclipai/paperclip-runner"; import { createHash } from "node:crypto"; import { createNativeHarnessBackupStamp, verifyNativeHarnessBackupStamp, } from "./native-harness-backup-stamp.js"; type BackendFactoryOptions = { runnerInstanceId?: string; acpxRuntimeDirectory?: string; onSpawn?: (meta: { pid: number; processGroupId: number | null; startedAt: string; }) => Promise; }; const state = vi.hoisted(() => ({ execute: vi.fn(), createBackend: vi.fn( (_input: NativeExecutionInputV1, _options: BackendFactoryOptions) => ({ kind: "test", }), ), cancel: vi.fn(), release: null as null | (() => void), })); vi.mock("@paperclipai/paperclip-runner", () => ({ CAPABILITY_SEMANTIC_TOOL_CATALOG: [], createNativeSessionBackend: state.createBackend, executeNativeSession: state.execute, parsePaperclipQuestionSet: (value: unknown) => value, })); import { continuingPendingInteractionIds, buildNativeProviderEnvironment, buildNativeHarnessBackupManifest, cancelNativeSession, createRunnerdBackend, executePaperclipNativeSession, getNativeSessionSteeringState, NativeSessionSteeringError, assertRemoteRunnerBuildMetadata, nativeSessionFailureDisposition, nativeSessionFailureSourceCode, nativeSessionRecoveryProjection, nativeGovernedWaitResult, parseRemoteExecutableCandidate, mayUsePreinstalledRunnerArtifact, readRemoteProviderPackManifest, providerPlanMarkdown, runtimeInputLifecycleMetric, runtimeQuestionFallbackFromEvent, resolveNativeHarnessPersistenceProfile, semanticProviderPlanMarkdown, sha256DirectoryTree, stageRemoteRunnerDirectory, steerNativeSession, syncRemoteRunnerDirectoryOut, verifyNativeHarnessBackup, shouldRestoreNativeHarnessBackupIntoSandbox, } from "./native-session-executor.js"; describe("remote provider pack manifest", () => { const canonical = (value: unknown): string => { if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`; if (value && typeof value === "object") { const object = value as Record; return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonical(object[key])}`).join(",")}}`; } return JSON.stringify(value); }; it("accepts a fully digested pack and rejects artifact tampering", async () => { const root = await mkdtemp(join(tmpdir(), "paperclip-provider-pack-")); await mkdir(join(root, "dist", "cli"), { recursive: true }); await mkdir(join(root, "node_modules", "node", "bin"), { recursive: true }); await mkdir(join(root, "node_modules", ".bin"), { recursive: true }); await mkdir(join(root, "node_modules", "opencode-ai", "bin"), { recursive: true }); const proxy = "export const proxy = true;\n"; const sidecar = "export const sidecar = true;\n"; const node = "provider-node\n"; const lockfile = "lockfileVersion: '9.0'\n"; const opencodeCommand = "#!/bin/sh\n"; const opencodeExecutable = "opencode-binary\n"; await writeFile(join(root, "dist", "cli", "opencode-app-server-proxy.js"), proxy); await writeFile(join(root, "dist", "cli", "acpx-runtime-sidecar.js"), sidecar); await writeFile(join(root, "node_modules", "node", "bin", "node"), node); await writeFile(join(root, "pnpm-lock.yaml"), lockfile); await writeFile(join(root, "node_modules", ".bin", "opencode"), opencodeCommand); await writeFile(join(root, "node_modules", "opencode-ai", "bin", "opencode.exe"), opencodeExecutable); const digest = (value: string) => `sha256:${createHash("sha256").update(value).digest("hex")}`; const proxySha = `sha256:${createHash("sha256").update(proxy).digest("hex")}`; const sidecarSha = `sha256:${createHash("sha256").update(sidecar).digest("hex")}`; const payload = { pins: { nodeMinimum: "24.11.0", codex: "0.148.0", opencode: "1.18.17", acpx: "0.13.1", piRuntime: "0.84.2", piAcp: "0.0.33", claudeAcp: "0.70.0", codexAcp: "1.6.2", }, target: { platform: "linux", architecture: "x64" }, runnerSourceRevision: "1".repeat(40), distDigest: sha256DirectoryTree(join(root, "dist")), bridgeDigest: "", acpxProfileDigests: { pi: "sha256:8c696f38296d53d0061fa11534570c5ddd951b63532aed30e0f1fcc676dc169f", claude: "sha256:9d73d1f0f121fb96cc8badb28c22d5bff02d8582eb2e40360a81c189e1b9422a", codex: "sha256:94049b3e3c3aee87de62703786e4fa81d031d7bd979f99bdf516d84f28791a79", }, artifacts: { nodeCommand: { path: "node_modules/node/bin/node", sha256: digest(node) }, productionLock: { path: "pnpm-lock.yaml", sha256: digest(lockfile) }, opencodeCommand: { path: "node_modules/.bin/opencode", sha256: digest(opencodeCommand), }, opencodeExecutable: { path: "node_modules/opencode-ai/bin/opencode.exe", sha256: digest(opencodeExecutable), }, opencodeProxy: { path: "dist/cli/opencode-app-server-proxy.js", sha256: proxySha, }, acpxSidecar: { path: "dist/cli/acpx-runtime-sidecar.js", sha256: sidecarSha, }, }, }; payload.bridgeDigest = `sha256:${createHash("sha256") .update(proxySha) .update("\n") .update(sidecarSha) .update("\n") .update(payload.distDigest) .digest("hex")}`; await writeFile( join(root, "provider-pack.json"), JSON.stringify({ schema: "paperclip-runner/remote-provider-pack/v1", digest: `sha256:${createHash("sha256").update(canonical(payload)).digest("hex")}`, payload, }), ); expect(readRemoteProviderPackManifest(root).payload.pins.opencode) .toBe("1.18.17"); await writeFile( join(root, "dist", "cli", "opencode-app-server-proxy.js"), "tampered\n", ); expect(() => readRemoteProviderPackManifest(root)).toThrow( "OpenCode proxy digest mismatch", ); await writeFile( join(root, "dist", "cli", "opencode-app-server-proxy.js"), proxy, ); await writeFile( join(root, "dist", "cli", "transitive-runtime.js"), "changed transitive module\n", ); expect(() => readRemoteProviderPackManifest(root)).toThrow( "provider dist tree digest mismatch", ); await rm(root, { recursive: true, force: true }); }); }); describe("native harness persistence profiles", () => { const profile = (provider: Record, driverKind: string) => resolveNativeHarnessPersistenceProfile({ provider, session: { driverKind, normalizedSessionId: "session", protocolVersion: 1, lifecyclePolicy: { mode: "per_turn", idleTimeoutMs: null }, }, } as unknown as NativeExecutionInputV1); it.each([ ["codex", { kind: "codex" }, "codex_app_server", ["runner", "codex-home"]], ["opencode", { kind: "opencode" }, "opencode_server", ["runner", "opencode"]], ["acpx pi", { kind: "acpx", agent: "pi" }, "acpx_runtime", ["runner", "acpx"]], ["acpx claude", { kind: "acpx", agent: "claude" }, "acpx_runtime", ["runner", "acpx"]], ["acpx codex", { kind: "acpx", agent: "codex" }, "acpx_runtime", ["runner", "acpx"]], ["claude managed", { kind: "claude_managed" }, "claude_managed_agents_api", ["runner"]], ["aws agentcore", { kind: "aws_agentcore" }, "aws_agentcore_harness_api", ["runner"]], ])("declares the complete %s recovery state", (_name, provider, driver, directories) => { expect(profile(provider as Record, driver as string).directories .map((directory) => directory.name)).toEqual(directories); }); it("excludes disposable Codex scratch trees and launch-time credentials", () => { const codex = profile({ kind: "codex" }, "codex_app_server"); expect(codex.directories.find((directory) => directory.name === "codex-home")) .toMatchObject({ excludeTopLevelEntries: ["tmp", ".tmp", "auth.json", "config.toml"], }); }); }); describe("verified native harness backups", () => { const backupExecution = { provider: { kind: "codex", model: "gpt-5.6-sol", approvalPolicy: "never" }, binding: { companyId: "company", runId: "run", issueId: "issue", agentId: "agent", executionWorkspaceId: "workspace", }, workspace: { cwd: "/workspace", repoUrl: "https://example.test/repo.git", repoRef: "main", branchName: "paperclip/test", }, session: { normalizedSessionId: "native-session", driverKind: "codex_app_server", protocolVersion: 1, lifecyclePolicy: { mode: "per_turn", idleTimeoutMs: null }, }, } as unknown as NativeExecutionInputV1; it("restores a verified continuation into an intentionally fresh non-reusable sandbox", () => { expect( shouldRestoreNativeHarnessBackupIntoSandbox({ acquisitionOutcome: "created", reusableLeaseConfigured: false, backupAvailable: true, }), ).toBe(true); expect( shouldRestoreNativeHarnessBackupIntoSandbox({ acquisitionOutcome: "created", reusableLeaseConfigured: true, backupAvailable: true, }), ).toBe(false); expect( shouldRestoreNativeHarnessBackupIntoSandbox({ acquisitionOutcome: "created", reusableLeaseConfigured: false, backupAvailable: false, }), ).toBe(false); }); it("accepts a complete digest-matched backup and rejects corruption", async () => { const root = await mkdtemp(join(tmpdir(), "paperclip-harness-backup-")); try { const current = join(root, "failover-backups", "current"); await mkdir(join(current, "runner"), { recursive: true }); await mkdir(join(current, "codex-home", "sessions"), { recursive: true }); await writeFile(join(current, "runner", "runner-state.json"), "runner-state"); await writeFile(join(current, "codex-home", "sessions", "thread.jsonl"), "thread-state"); const manifest = buildNativeHarnessBackupManifest({ backupRoot: current, execution: backupExecution, runnerInstanceId: "runner-1", providerSessionIdentity: { providerSessionId: "thread-1", providerBackendSessionId: "session-1", providerSessionIdentity: null, }, sourceProviderLeaseId: "sandbox-1", completedAt: "2026-08-26T00:00:00.000Z", }); await writeFile(join(current, "manifest.json"), JSON.stringify(manifest)); expect(verifyNativeHarnessBackup({ root, execution: backupExecution, runnerInstanceId: "runner-1", })).toMatchObject({ root: current, manifest: { sourceProviderLeaseId: "sandbox-1", directories: [ expect.objectContaining({ name: "runner" }), expect.objectContaining({ name: "codex-home" }), ], }, }); const continuationExecution = { ...backupExecution, binding: { ...backupExecution.binding, runId: "run-2", executionWorkspaceId: "run-2", }, } as NativeExecutionInputV1; expect(verifyNativeHarnessBackup({ root, execution: continuationExecution, runnerInstanceId: "runner-1", })).not.toBeNull(); await writeFile(join(current, "codex-home", "sessions", "thread.jsonl"), "corrupt"); expect(verifyNativeHarnessBackup({ root, execution: backupExecution, runnerInstanceId: "runner-1", })).toBeNull(); } finally { await rm(root, { recursive: true, force: true }); } }); it("rejects a backup whose provider identity or harness contract changed", async () => { const root = await mkdtemp(join(tmpdir(), "paperclip-harness-backup-identity-")); try { const current = join(root, "failover-backups", "current"); await mkdir(join(current, "runner"), { recursive: true }); await mkdir(join(current, "codex-home"), { recursive: true }); await writeFile(join(current, "runner", "runner-state.json"), "runner-state"); expect(() => buildNativeHarnessBackupManifest({ backupRoot: current, execution: backupExecution, runnerInstanceId: "runner-1", providerSessionIdentity: { providerSessionId: null, providerBackendSessionId: null, providerSessionIdentity: null, }, sourceProviderLeaseId: "sandbox-1", })).toThrow("runner_harness_state_mismatch"); } finally { await rm(root, { recursive: true, force: true }); } }); it("verifies the lease stamp and all backup directory digests before replacement", async () => { const stateBase = await mkdtemp(join(tmpdir(), "paperclip-harness-stamp-")); const previousStateDirectory = process.env.PAPERCLIP_RUNNER_STATE_DIR; process.env.PAPERCLIP_RUNNER_STATE_DIR = stateBase; try { const sessionRoot = join( stateBase, createHash("sha256").update("native-session").digest("hex"), ); const current = join(sessionRoot, "failover-backups", "current"); await mkdir(join(current, "runner"), { recursive: true }); await mkdir(join(current, "codex-home", "sessions"), { recursive: true }); await writeFile(join(current, "runner", "runner-state.json"), "runner-state"); await writeFile(join(current, "codex-home", "sessions", "thread.jsonl"), "thread-state"); const manifest = buildNativeHarnessBackupManifest({ backupRoot: current, execution: backupExecution, runnerInstanceId: "runner-1", providerSessionIdentity: { providerSessionId: "thread-1", providerBackendSessionId: "session-1", providerSessionIdentity: null, }, sourceProviderLeaseId: "sandbox-1", }); const manifestPath = join(current, "manifest.json"); await writeFile(manifestPath, JSON.stringify(manifest)); const stamp = createNativeHarnessBackupStamp({ manifestPath, normalizedSessionId: "native-session", runnerInstanceId: "runner-1", completedAt: manifest.completedAt, }); expect(verifyNativeHarnessBackupStamp(stamp)).toBe(true); await writeFile(join(current, "runner", "runner-state.json"), "corrupt"); expect(verifyNativeHarnessBackupStamp(stamp)).toBe(false); } finally { if (previousStateDirectory === undefined) { delete process.env.PAPERCLIP_RUNNER_STATE_DIR; } else { process.env.PAPERCLIP_RUNNER_STATE_DIR = previousStateDirectory; } await rm(stateBase, { recursive: true, force: true }); } }); }); describe("remote provider checkpoint snapshots", () => { it("excludes Codex scratch and credential state without mutating the live provider home", async () => { const execute = vi.fn() .mockResolvedValueOnce({ exitCode: 0, timedOut: false, stdout: "", stderr: "" }) .mockResolvedValueOnce({ exitCode: 0, timedOut: false, stdout: "", stderr: "" }) .mockResolvedValueOnce({ exitCode: 0, timedOut: false, stdout: "", stderr: "" }); const syncOut = vi.fn(async (_operations: Array<{ files: Array<{ sourcePath: string; targetPath: string; kind: "file" | "directory"; mode?: number; }>; }>) => undefined); await syncRemoteRunnerDirectoryOut({ runner: { execute, syncOut } as never, sourcePath: "/remote/session/filesystem/codex-home", targetPath: "/tmp/paperclip-checkpoint-test-codex-home", mode: 0o700, excludeTopLevelEntries: ["tmp", ".tmp", "auth.json", "config.toml"], }); expect(execute).toHaveBeenNthCalledWith(1, expect.objectContaining({ args: ["-c", "test -d '/remote/session/filesystem/codex-home'"], })); const snapshotCommand = String(execute.mock.calls[1]?.[0]?.args?.[1]); expect(snapshotCommand).toContain("'--exclude=./tmp'"); expect(snapshotCommand).toContain("'--exclude=./.tmp'"); expect(snapshotCommand).toContain("'--exclude=./auth.json'"); expect(snapshotCommand).toContain("'--exclude=./config.toml'"); expect(snapshotCommand).toContain("-C '/remote/session/filesystem/codex-home'"); expect(snapshotCommand).not.toContain("rm -rf -- '/remote/session/filesystem/codex-home'"); const batch = syncOut.mock.calls[0]?.[0]?.[0]; expect(batch?.files[0]).toMatchObject({ sourcePath: expect.stringMatching( /^\/remote\/session\/filesystem\/\.paperclip-checkpoint-/, ), targetPath: "/tmp/paperclip-checkpoint-test-codex-home", kind: "directory", mode: 0o700, }); expect(String(execute.mock.calls[2]?.[0]?.args?.[1])).toMatch( /^rm -rf -- '\/remote\/session\/filesystem\/\.paperclip-checkpoint-/, ); }); it("rejects non-top-level checkpoint exclusions", async () => { const execute = vi.fn().mockResolvedValue({ exitCode: 0, timedOut: false, stdout: "", stderr: "", }); await expect(syncRemoteRunnerDirectoryOut({ runner: { execute, syncOut: vi.fn() } as never, sourcePath: "/remote/codex-home", targetPath: "/tmp/paperclip-checkpoint-invalid-codex-home", mode: 0o700, excludeTopLevelEntries: ["../outside"], })).rejects.toThrow("runner_remote_checkpoint_exclusion_invalid"); }); }); describe("remote provider checkpoint restores", () => { it("does not upload excluded Codex scratch trees or credentials", async () => { const sourcePath = await mkdtemp(join(tmpdir(), "paperclip-codex-restore-source-")); try { await mkdir(join(sourcePath, "sessions"), { recursive: true }); await mkdir(join(sourcePath, ".tmp"), { recursive: true }); await writeFile(join(sourcePath, "sessions", "thread.jsonl"), "durable session"); await writeFile(join(sourcePath, ".tmp", "scratch.bin"), "disposable scratch"); await writeFile(join(sourcePath, "auth.json"), "credential"); await writeFile(join(sourcePath, "config.toml"), "bearer token"); const syncIn = vi.fn(async (operations: Array<{ files: Array<{ sourcePath: string }>; }>) => { const stagedPath = operations[0]!.files[0]!.sourcePath; expect(stagedPath).not.toBe(sourcePath); await expect(access(join(stagedPath, "sessions", "thread.jsonl"))).resolves.toBeUndefined(); await expect(access(join(stagedPath, ".tmp", "scratch.bin"))).rejects.toThrow(); await expect(access(join(stagedPath, "auth.json"))).rejects.toThrow(); await expect(access(join(stagedPath, "config.toml"))).rejects.toThrow(); }); await stageRemoteRunnerDirectory({ target: { kind: "remote", transport: "provider", remoteCwd: "/remote", runner: { syncIn } as never, } as never, runner: { syncIn } as never, sourcePath, targetPath: "/remote/codex-home", mode: 0o700, excludeTopLevelEntries: ["tmp", ".tmp", "auth.json", "config.toml"], }); expect(syncIn).toHaveBeenCalledOnce(); } finally { await rm(sourcePath, { recursive: true, force: true }); } }); }); describe("remote preinstalled executable discovery", () => { it("accepts one normalized absolute executable path", () => { expect(parseRemoteExecutableCandidate("/home/daytona/.local/bin/paperclip-runnerd\n")) .toBe("/home/daytona/.local/bin/paperclip-runnerd"); }); it.each([ "paperclip-runnerd\n", "/safe/path\n/unexpected/second-line\n", "/safe/path with spaces\n", "/safe/path;touch-bad\n", ])("rejects ambiguous or shell-active output: %j", (stdout) => { expect(parseRemoteExecutableCandidate(stdout)).toBeNull(); }); it("does not accept a merely contract-compatible runnerd when a build-owned artifact is configured", () => { expect(mayUsePreinstalledRunnerArtifact("/artifacts/paperclip-runnerd")).toBe(false); expect(mayUsePreinstalledRunnerArtifact(" ")).toBe(true); expect(mayUsePreinstalledRunnerArtifact(undefined)).toBe(true); }); }); describe("remote runner build metadata", () => { const current = { schema: "paperclip-runner/runnerd-build-metadata/v1", binaryName: "paperclip-runnerd", packageName: "@paperclipai/paperclip-runner", binaryContractVersion: 2, prpTransportModes: ["dial_ws_loopback", "dial_wss", "listen_ws"], }; it("accepts the current contract with the required transport", () => { expect(() => assertRemoteRunnerBuildMetadata(current, "listen_ws")).not.toThrow(); }); it("fails before dispatch when a preinstalled runner uses the stale contract", () => { expect(() => assertRemoteRunnerBuildMetadata({ ...current, binaryContractVersion: 1, }, "listen_ws")).toThrow("runner_remote_artifact_contract_incompatible"); }); it("requires the selected transport without falling through", () => { expect(() => assertRemoteRunnerBuildMetadata({ ...current, prpTransportModes: ["dial_wss"], }, "listen_ws")).toThrow("runner_remote_transport_capability_missing:listen_ws"); }); }); describe("runtime question fallback", () => { const questionSet = { schema: "paperclip.question_set.v1" as const, title: "Configure deployment", description: "These answers are required before work can continue.", submitLabel: "Continue", questions: [ { id: "region", prompt: "Which region?", required: true, answerMode: "single_select" as const, options: [{ id: "us", label: "US" }, { id: "eu", label: "Europe" }], }, { id: "replicas", prompt: "How many replicas?", required: true, answerMode: "text" as const, textValidation: { inputType: "integer" as const, minimum: 1 }, }, ], }; it.each(["provider_process_lost", "durable_handoff"])( "materializes one idempotent durable interaction after %s", (reason) => { const fallback = runtimeQuestionFallbackFromEvent({ eventType: "runtime_request.expired", runId: "00000000-0000-4000-8000-000000000001", payload: { requestId: "elicitation-1", requestKind: "runtime", requestType: "input", reason, replayAllowed: false, request: { schema: "paperclip.runtime_request.v2", requestKind: "runtime", requestId: "elicitation-1", type: "input", status: "pending", prompt: "Configure deployment", turnId: "turn-1", itemId: "item-1", input: questionSet, }, }, }); expect(fallback).toMatchObject({ kind: "ask_user_questions", idempotencyKey: "runtime-input-durable:v1:00000000-0000-4000-8000-000000000001:elicitation-1", sourceRunId: "00000000-0000-4000-8000-000000000001", continuationPolicy: "wake_assignee", payload: { runtimeRequestId: "elicitation-1", questionSet, supersedeOnUserComment: false, questions: [ { id: "region", selectionMode: "single", options: [{ id: "us", label: "US" }, { id: "eu", label: "Europe" }] }, { id: "replicas", selectionMode: "single", options: [{ id: "__paperclip_text__", freeText: true }] }, ], }, }); }, ); it.each([ ["runtime_request.resolved", "provider_process_lost", false], ["runtime_request.cancelled", "provider_process_lost", false], ["runtime_request.expired", "explicit_cancellation", false], ["runtime_request.expired", "provider_process_lost", true], ])("does not fall back for %s / %s / replay=%s", (eventType, reason, replayAllowed) => { expect(runtimeQuestionFallbackFromEvent({ eventType: eventType as never, runId: "00000000-0000-4000-8000-000000000001", payload: { reason, replayAllowed, request: { schema: "paperclip.runtime_request.v2", requestKind: "runtime", requestId: "elicitation-1", type: "input", status: "pending", turnId: "turn-1", itemId: "item-1", input: questionSet, }, }, })).toBeNull(); }); it("emits content-free lifecycle metric dimensions", () => { expect(runtimeInputLifecycleMetric({ eventType: "runtime_request.created", payload: { request: { type: "input", requestId: "input-1", origin: { adapter: "codex-app-server" }, input: questionSet, }, }, })).toEqual({ outcome: "normalized", adapter: "codex-app-server", requestId: "input-1", }); expect(runtimeInputLifecycleMetric({ eventType: "runtime_request.expired", payload: { requestId: "input-1", requestType: "input", reason: "durable_handoff", adapter: "codex-app-server", }, })).toEqual({ outcome: "durable_handoff", adapter: "codex-app-server", requestId: "input-1", }); expect(runtimeInputLifecycleMetric({ eventType: "runtime_request.expired", payload: { requestId: "input-1", requestType: "input", reason: "provider_process_lost", adapter: "codex-app-server", }, })).toEqual({ outcome: "provider_loss_handoff", adapter: "codex-app-server", requestId: "input-1", }); }); }); describe("native provider bootstrap environment", () => { it("inherits the host executable and credential-home context", () => { expect(buildNativeProviderEnvironment({}, { PATH: "/opt/homebrew/bin:/usr/bin", HOME: "/Users/runner", CODEX_HOME: "/Users/runner/.codex", PAPERCLIP_INTERNAL_SECRET: "must-not-leak", })).toEqual({ PATH: "/opt/homebrew/bin:/usr/bin", HOME: "/Users/runner", CODEX_HOME: "/Users/runner/.codex", }); }); it("lets explicitly configured agent env override host defaults", () => { expect(buildNativeProviderEnvironment({ PATH: "/agent/bin", OPENAI_API_KEY: "configured-provider-key", }, { PATH: "/host/bin", HOME: "/Users/runner", })).toEqual({ PATH: "/agent/bin", HOME: "/Users/runner", OPENAI_API_KEY: "configured-provider-key", }); }); }); const execution = { provider: { kind: "codex", model: null }, binding: { companyId: "company", runId: "run-native-cancel", issueId: "issue", agentId: "agent", }, completionContract: { id: "contract", sha256: "sha" }, } as NativeExecutionInputV1; describe("provider plan synchronization", () => { it("prefers the provider's completed Markdown when it is available", () => { expect(providerPlanMarkdown({ markdown: "# Release plan\n\n1. Prepare\n2. Deploy", explanation: "This fallback must not replace the completed plan.", steps: [{ body: "Fallback", status: "pending" }], })).toBe("# Release plan\n\n1. Prepare\n2. Deploy"); }); it("extracts a completed plan from the semantic result artifact", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "\n# Health check\n\n1. Add endpoint\n2. Verify it\n", }], })).toBe("# Health check\n\n1. Add endpoint\n2. Verify it"); }); it("decodes the native provider's compact plan reference into readable Markdown", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "native-provider-plan:health-check-endpoint-v1#1-register-GET-health-return-200-json-status-ok;2-add-API-tests", }], })).toBe([ "# Health check endpoint", "", "1. Register GET /health return 200 JSON status ok", "2. Add API tests", ].join("\n")); }); it("decodes a task-scoped native plan URI", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "native-plan://DOT-13/health-check#1-add-GET-health;2-add-tests", }], })).toBe("# Health check\n\n1. Add GET /health\n2. Add tests"); }); it("retains readable Markdown embedded after a native provider plan reference", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "native-provider-plan:DOT-14-health-check-v1\n1. Add `GET /health`.\n2. Add tests.", }], })).toBe("# Health check\n\n1. Add `GET /health`.\n2. Add tests."); }); it("normalizes a plain numbered native provider plan", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "1. Add GET /health. | 2. Add tests. | 3. Document it.", }], })).toBe("# Plan\n\n1. Add GET /health.\n2. Add tests.\n3. Document it."); }); it("normalizes a task-labelled inline numbered plan", () => { expect(semanticProviderPlanMarkdown({ artifacts: [{ kind: "native_provider_plan", ref: "DOT-16 plan: (1) add GET /health; (2) add tests; (3) document it.", }], })).toBe("# Plan\n\n1. add GET /health\n2. add tests\n3. document it."); }); it("uses an explicitly numbered semantic summary when the artifact is opaque", () => { expect(semanticProviderPlanMarkdown({ summary: "Native provider plan completed: 1) add GET /health; 2) add tests; 3) document it.", artifacts: [{ kind: "native_provider_plan", ref: "native-provider-plan:DOT-18:health-check" }], })).toBe("# Plan\n\n1. add GET /health\n2. add tests\n3. document it."); }); it("renders a bounded Markdown checklist without embedding provenance", () => { const markdown = providerPlanMarkdown({ explanation: "Release safely", steps: [ { body: "Prepare", status: "completed" }, { body: "Deploy", status: "in_progress" }, { body: "Verify", status: "blocked" }, ], runId: "must-not-appear", providerThreadId: "native-secret", }); expect(markdown).toBe([ "Release safely", "", "- [x] Prepare", "- [ ] Deploy _(in progress)_", "- [ ] Verify _(blocked)_", ].join("\n")); expect(markdown).not.toContain("must-not-appear"); expect(markdown).not.toContain("native-secret"); }); }); describe("native governed waits", () => { it("turns a durable pending interaction into a response-wake result", () => { expect(nativeGovernedWaitResult({ interaction: { id: "interaction-1", title: "Choose an output format", summary: null, }, completionContract: { revision: "contract-v3", objective: "Create the requested output", criteria: [{ id: "objective", requirement: "The output is created" }], }, })).toEqual(expect.objectContaining({ schema: "paperclip.run_result.v1", reportedWorkDisposition: "yielded", summary: "Waiting for Choose an output format.", completionClaim: expect.objectContaining({ contractRevision: "contract-v3", objectiveSatisfied: false, criteria: [{ criterionId: "objective", status: "unknown", evidenceRefs: ["interaction:interaction-1"], }], }), evidence: [{ ref: "interaction:interaction-1" }], attentionRequests: [], continuation: { kind: "response_wake", summary: "Resume from the resolved interaction response without repeating prior work.", idempotencyKey: "interaction-response:interaction-1", }, })); }); it("keeps an authority-checked partial item-verdict interaction as the wait target", () => { const partial = structuredClone(execution); partial.interactionResponses = [{ interactionId: "interaction-partial", kind: "request_item_verdicts", response: { status: "pending", result: { version: 1, complete: false, items: [{ id: "alpha", verdict: "approve" }] }, }, }]; expect(continuingPendingInteractionIds(partial)).toEqual(["interaction-partial"]); partial.interactionResponses[0]!.response.status = "answered"; expect(continuingPendingInteractionIds(partial)).toEqual([]); }); }); function leaseDb(boundExecution: NativeExecutionInputV1 = execution): Db { const coordinator = { runId: boundExecution.binding.runId, companyId: boundExecution.binding.companyId, issueId: boundExecution.binding.issueId, phase: "observed", attempt: 0, leaseOwner: null, leaseExpiresAt: null, resultId: null, }; const update = () => ({ set: () => ({ where: async () => [] }), }); const tx = { select: () => ({ from: () => ({ where: () => ({ for: () => ({ limit: () => Promise.resolve([coordinator]), }), }), }), }), update, }; return { transaction: async (operation: (transaction: Db) => Promise) => operation(tx as unknown as Db), update, } as unknown as Db; } describe("native session cancellation", () => { beforeEach(() => { state.cancel.mockReset(); state.release = null; state.execute.mockReset().mockImplementation(async (options) => { options.onSession?.({ cancel: state.cancel }); await new Promise((resolve) => { state.release = resolve; }); options.onSession?.(null); return { result: { summary: "cancelled" }, terminal: { runTerminalState: "cancelled" }, turnId: "turn", normalizedSessionId: "session", providerSessionId: null, driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, }; }); }); it("routes control-plane cancellation to the active normalized session and removes the handle", async () => { const running = executePaperclipNativeSession({ db: leaseDb(), execution, runnerInstanceId: "runner", }); await vi.waitFor(() => expect(state.release).toBeTypeOf("function")); await expect(cancelNativeSession(execution.binding.runId, "budget hard stop")).resolves.toBe(true); await expect(cancelNativeSession(execution.binding.runId, "duplicate budget stop")).resolves.toBe(true); expect(state.cancel).toHaveBeenCalledWith({ reason: "budget hard stop" }); expect(state.cancel).toHaveBeenCalledTimes(1); state.release?.(); await running; await expect(cancelNativeSession(execution.binding.runId, "late cancel")).resolves.toBe(false); }); it("allows cancellation to be retried when the session dispatch fails", async () => { state.cancel.mockRejectedValueOnce(new Error("transport unavailable")); const running = executePaperclipNativeSession({ db: leaseDb(), execution, runnerInstanceId: "runner", }); await vi.waitFor(() => expect(state.release).toBeTypeOf("function")); await expect(cancelNativeSession(execution.binding.runId, "budget hard stop")) .rejects.toThrow("transport unavailable"); await expect(cancelNativeSession(execution.binding.runId, "retry budget stop")) .resolves.toBe(true); expect(state.cancel).toHaveBeenNthCalledWith(2, { reason: "retry budget stop" }); state.release?.(); await running; }); }); describe("native session same-turn steering", () => { const capabilities = vi.fn(); const snapshot = vi.fn(); const steer = vi.fn(); beforeEach(() => { state.release = null; capabilities.mockReset().mockResolvedValue({ steering: true }); snapshot.mockReset().mockResolvedValue({ activeTurnId: "provider-turn-1" }); steer.mockReset().mockResolvedValue(undefined); state.execute.mockReset().mockImplementation(async (options) => { options.onSession?.({ capabilities, snapshot, steer, cancel: vi.fn() }); await new Promise((resolve) => { state.release = resolve; }); options.onSession?.(null); return { result: { summary: "completed" }, terminal: { runTerminalState: "succeeded" }, turnId: "provider-turn-1", normalizedSessionId: "session", providerSessionId: null, driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, }; }); }); async function startActiveSession() { const running = executePaperclipNativeSession({ db: leaseDb(), execution, runnerInstanceId: "runner", }); await vi.waitFor(() => expect(state.release).toBeTypeOf("function")); return { running }; } it("correlates the queued comment with the active provider turn acknowledgement", async () => { const { running } = await startActiveSession(); await expect(getNativeSessionSteeringState(execution.binding.runId)).resolves.toEqual({ disposition: "available", activeTurnId: "provider-turn-1", }); await expect(steerNativeSession({ runId: execution.binding.runId, message: "Check mobile overflow first.", correlationId: "queued-comment-1", })).resolves.toEqual({ turnId: "provider-turn-1" }); expect(steer).toHaveBeenCalledWith({ turnId: "provider-turn-1", message: { role: "user", text: "Check mobile overflow first." }, correlationId: "queued-comment-1", }); state.release?.(); await running; }); it.each([ { label: "unsupported provider", prepare: () => capabilities.mockResolvedValue({ steering: false }), code: "steering_unsupported", }, { label: "stale turn", prepare: () => snapshot.mockResolvedValue({ activeTurnId: null }), code: "steering_stale_turn", }, { label: "provider rejection", prepare: () => steer.mockRejectedValue(new Error("request rejected")), code: "steering_rejected", }, ])("keeps $label retryable with a stable code", async ({ prepare, code }) => { prepare(); const { running } = await startActiveSession(); const error = await steerNativeSession({ runId: execution.binding.runId, message: "Retryable steering", correlationId: "queued-comment-error", }).catch((value) => value); expect(error).toBeInstanceOf(NativeSessionSteeringError); expect(error.code).toBe(code); state.release?.(); await running; }); it("bounds the provider acknowledgement wait", async () => { steer.mockReturnValue(new Promise(() => undefined)); const { running } = await startActiveSession(); const error = await steerNativeSession({ runId: execution.binding.runId, message: "Do not wait forever", correlationId: "queued-comment-timeout", timeoutMs: 5, }).catch((value) => value); expect(error).toBeInstanceOf(NativeSessionSteeringError); expect(error.code).toBe("steering_timeout"); state.release?.(); await running; }); }); describe("native warm session supervision", () => { it("reuses one session across distinct governed runs and closes it after idle expiry", async () => { const close = vi.fn(async () => undefined); const sharedSession = { close }; const base = { ...execution, binding: { ...execution.binding, executionWorkspaceId: "workspace", }, workspace: { cwd: "/tmp/warm-native", repoUrl: null, repoRef: null, branchName: null }, session: { normalizedSessionId: "session-warm-native", driverKind: "codex_app_server" as const, protocolVersion: 1 as const, lifecyclePolicy: { mode: "warm" as const, idleTimeoutMs: 20 }, }, } as NativeExecutionInputV1; const second = { ...base, binding: { ...base.binding, runId: "run-native-warm-second" }, }; const result = { result: { summary: "completed" }, terminal: { runTerminalState: "succeeded" }, turnId: "turn", normalizedSessionId: "session-warm-native", providerSessionId: "provider-warm-native", driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, usage: null, }; state.execute.mockReset() .mockImplementationOnce(async (options) => { expect(options.existingSession).toBeUndefined(); options.onSession?.(sharedSession); return result; }) .mockImplementationOnce(async (options) => { expect(options.existingSession).toBe(sharedSession); return result; }); await executePaperclipNativeSession({ db: leaseDb(base), execution: base, runnerInstanceId: "runner" }); await executePaperclipNativeSession({ db: leaseDb(second), execution: second, runnerInstanceId: "runner" }); expect(close).not.toHaveBeenCalled(); await vi.waitFor(() => expect(close).toHaveBeenCalledWith({ reason: "warm native session idle timeout", }), { timeout: 500 }); }); it("replaces an idle warm provider session when its pinned permission mode changes", async () => { const firstClose = vi.fn(async () => undefined); const secondClose = vi.fn(async () => undefined); const firstSession = { close: firstClose }; const secondSession = { close: secondClose }; const base = { ...execution, schema: "paperclip.native-execution-input.v4", provider: { kind: "codex", model: null, approvalPolicy: "never" }, binding: { ...execution.binding, runId: "run-permission-never", executionWorkspaceId: "workspace" }, workspace: { cwd: "/tmp/warm-native-permission", repoUrl: null, repoRef: null, branchName: null }, session: { normalizedSessionId: "session-warm-permission", driverKind: "codex_app_server" as const, protocolVersion: 1 as const, lifecyclePolicy: { mode: "warm" as const, idleTimeoutMs: 20 }, }, runtimeContext: { aggregateDigest: "runtime-context" }, } as unknown as NativeExecutionInputV1; const lowered = { ...base, provider: { kind: "codex", model: null, approvalPolicy: "on-request" }, binding: { ...base.binding, runId: "run-permission-on-request" }, } as NativeExecutionInputV1; const result = { result: { summary: "completed" }, terminal: { runTerminalState: "succeeded" }, turnId: "turn", normalizedSessionId: "session-warm-permission", providerSessionId: "provider-warm-permission", driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, usage: null, }; state.execute.mockReset() .mockImplementationOnce(async (options) => { expect(options.existingSession).toBeUndefined(); options.onSession?.(firstSession); return result; }) .mockImplementationOnce(async (options) => { expect(options.existingSession).toBeUndefined(); options.onSession?.(secondSession); return result; }); await executePaperclipNativeSession({ db: leaseDb(base), execution: base, runnerInstanceId: "runner" }); await executePaperclipNativeSession({ db: leaseDb(lowered), execution: lowered, runnerInstanceId: "runner" }); expect(firstClose).toHaveBeenCalledWith({ reason: "warm native session configuration changed" }); await vi.waitFor(() => expect(secondClose).toHaveBeenCalledWith({ reason: "warm native session idle timeout", }), { timeout: 500 }); }); }); describe("native session bounded recovery", () => { it("preserves stable provider and runner failure causes", () => { expect(nativeSessionFailureSourceCode(new Error( "provider_frame_too_large: harness stdout frame exceeded 4194304 bytes", ))).toBe("provider_frame_too_large"); expect(nativeSessionFailureSourceCode(new Error( "native_runner_process_exited: runnerd exited unexpectedly with code 1", ))).toBe("native_runner_process_exited"); expect(nativeSessionFailureSourceCode(new Error( "provider_transport_failed: invalid JSON-RPC", ))).toBe("provider_transport_failed"); expect(nativeSessionFailureSourceCode(new Error( "planning_mode_unsupported: installed Codex app-server did not confirm plan mode", ))).toBe("planning_mode_unsupported"); expect(nativeSessionFailureSourceCode(new Error( "native_event_replay_conflict: source sequence 41 contained different bytes", ))).toBe("native_event_replay_conflict"); expect(nativeSessionFailureSourceCode(new Error( "provider_process_exited: provider=acpx stage=initialize exitCode=1", ))).toBe("provider_process_exited"); expect(nativeSessionFailureSourceCode(new Error( "provider_stdout_closed: provider=codex stage=initialize", ))).toBe("provider_stdout_closed"); expect(nativeSessionFailureSourceCode(new Error( "provider_process_status_failed: provider=acpx stage=session.open", ))).toBe("provider_process_status_failed"); expect(nativeSessionFailureSourceCode(new Error( "provider_initialize_timeout: provider=opencode stage=health", ))).toBe("provider_initialize_timeout"); expect(nativeSessionFailureSourceCode(new Error( "provider_initialize_protocol_error: provider=codex stage=initialize", ))).toBe("provider_initialize_protocol_error"); expect(nativeSessionFailureSourceCode(new Error( "provider_request_timeout: provider=acpx stage=run.attach", ))).toBe("provider_request_timeout"); expect(nativeSessionFailureSourceCode(new Error( "runner_remote_provider_artifact_incompatible: OpenCode version mismatch", ))).toBe("runner_remote_provider_artifact_incompatible"); }); it("retries the same run twice and stops at the third failed attempt", () => { const now = new Date("2026-08-09T00:00:00.000Z"); expect(nativeSessionFailureDisposition(1, now)).toEqual({ phase: "retryable_failure", failureCode: "native_session_interrupted", nextAttemptAt: new Date("2026-08-09T00:00:30.000Z"), }); expect(nativeSessionFailureDisposition(2, now)).toEqual({ phase: "retryable_failure", failureCode: "native_session_interrupted", nextAttemptAt: new Date("2026-08-09T00:00:30.000Z"), }); expect(nativeSessionFailureDisposition(3, now)).toEqual({ phase: "terminal_failure", failureCode: "native_session_retry_exhausted", nextAttemptAt: null, }); expect(nativeSessionFailureDisposition(1, now, "native_event_replay_conflict")).toEqual({ phase: "terminal_failure", failureCode: "native_event_replay_conflict", nextAttemptAt: null, }); expect(nativeSessionFailureDisposition( 1, now, "runner_remote_provider_artifact_incompatible", )).toEqual({ phase: "terminal_failure", failureCode: "runner_remote_provider_artifact_incompatible", nextAttemptAt: null, }); }); it("escalates exhausted result-less sessions to board review instead of leaving the provider as its own owner", () => { expect(nativeSessionRecoveryProjection({ phase: "retryable_failure", failureCode: "native_session_interrupted", agentId: "agent-low-capability", })).toEqual({ exhausted: false, issueStatus: null, recoveryOwner: { kind: "agent", agentId: "agent-low-capability" }, recoveryActionOwnerType: "agent", recoveryActionOwnerAgentId: "agent-low-capability", recoveryActionCause: "native_session_interrupted", supersedeOnIdentityChange: true, }); expect(nativeSessionRecoveryProjection({ phase: "terminal_failure", failureCode: "native_session_retry_exhausted", agentId: "agent-low-capability", })).toEqual({ exhausted: true, issueStatus: "in_review", recoveryOwner: { kind: "board" }, recoveryActionOwnerType: "board", recoveryActionOwnerAgentId: null, recoveryActionCause: "native_session_retry_exhausted", supersedeOnIdentityChange: true, }); }); }); describe("native process ownership", () => { it("forwards the app-server PID and process group through the production backend seam", async () => { const processMetadata = { pid: 42_001, processGroupId: 42_001, startedAt: "2026-08-18T18:00:00.000Z", }; const onSpawn = vi.fn(async () => undefined); state.createBackend.mockClear(); state.execute.mockReset().mockImplementation(async (options) => { await options.backend.onSpawn(processMetadata); return { result: { summary: "completed" }, terminal: { runTerminalState: "succeeded" }, turnId: "turn", normalizedSessionId: "session", providerSessionId: null, driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, }; }); state.createBackend.mockImplementationOnce((_input, options) => ({ kind: "test", onSpawn: options.onSpawn, })); await executePaperclipNativeSession({ db: leaseDb(), execution, runnerInstanceId: "runner", onSpawn, }); expect(state.createBackend).toHaveBeenCalledWith(execution, expect.objectContaining({ runnerInstanceId: "runner", onSpawn, })); expect(onSpawn).toHaveBeenCalledWith(processMetadata); }); }); describe("runnerd provider runtime wiring", () => { it("uses the remote workspace for both the runner backend and native session", async () => { const remoteCwd = "/home/daytona/paperclip-workspace"; const remoteExecution = { ...execution, binding: { ...execution.binding, runId: "run-remote-workspace-test" }, task: { identifier: "DOT-REMOTE", title: "Remote workspace test", description: null, prompt: "Verify the remote workspace.", workMode: "standard", }, workspace: { cwd: "/host/paperclip-workspace", repoUrl: null, repoRef: null, branchName: null, }, session: { normalizedSessionId: "remote-workspace-session", driverKind: "codex_app_server", protocolVersion: 2, lifecyclePolicy: { mode: "per_turn", idleTimeoutMs: null }, }, provider: { kind: "codex", model: null, approvalPolicy: "never", }, executionMode: "default", planningContext: null, interactionResponses: [], credentialBindings: [], } as unknown as NativeExecutionInputV1; state.createBackend.mockClear(); state.execute.mockReset().mockResolvedValue({ result: { summary: "completed" }, terminal: { runTerminalState: "succeeded" }, turnId: "turn", normalizedSessionId: "session", providerSessionId: null, driverKind: "test", driverVersion: "1", nativeEventCount: 1, highestContiguousSourceSeq: 1, }); await executePaperclipNativeSession({ db: leaseDb(remoteExecution), execution: remoteExecution, runnerInstanceId: "runner", useRunnerd: true, runnerExecutionTarget: { kind: "remote", transport: "ssh", remoteCwd, spec: { host: "runner.internal", port: 22, username: "runner", remoteWorkspacePath: remoteCwd, remoteCwd, privateKey: null, knownHosts: null, strictHostKeyChecking: true, }, }, runnerPublicUrl: "wss://paperclip.example.test", }); expect(state.createBackend).toHaveBeenCalledWith( expect.objectContaining({ workspace: expect.objectContaining({ cwd: remoteCwd }) }), expect.any(Object), ); expect(state.execute).toHaveBeenCalledWith( expect.objectContaining({ input: expect.objectContaining({ workspace: expect.objectContaining({ cwd: remoteCwd }), }), }), ); }); it("passes the isolated ACPX runtime directory to the native backend factory", async () => { const acpxExecution = { ...execution, schema: "paperclip.native-execution-input.v3", task: { identifier: "DOT-ACPX", title: "ACPX task", description: null, prompt: "Complete the ACPX task.", workMode: "standard", }, workspace: { cwd: "/tmp/acpx-native", repoUrl: null, repoRef: null, branchName: null }, session: { normalizedSessionId: "acpx-session", driverKind: "acpx_runtime", protocolVersion: 1, lifecyclePolicy: { mode: "per_turn", idleTimeoutMs: null }, }, provider: { kind: "acpx", agent: "codex", model: "gpt-5.6-sol", permissionPolicy: "interactive", profile: { driverKind: "acpx_runtime", protocolVersion: 1, acpxVersion: "0.13.1", agent: "codex", agentProfileVersion: 1, agentServerPackage: "@agentclientprotocol/codex-acp", agentServerVersion: "1.6.2", agentRuntimePackage: null, agentRuntimeVersion: null, commandDigest: "sha256:test", }, }, executionMode: "default", planningContext: null, interactionResponses: [], credentialBindings: [], runtimeContext: {}, } as unknown as NativeExecutionInputV1; state.createBackend.mockClear(); createRunnerdBackend({ db: leaseDb(acpxExecution), execution: acpxExecution, runnerInstanceId: "runner", }); expect(state.createBackend).toHaveBeenCalledWith(acpxExecution, expect.objectContaining({ acpxRuntimeDirectory: expect.stringContaining("/runtime/paperclip-runner/acpx"), })); }); });