diff --git a/doc/plans/2026-10-02-stock-harness-paperclip-checklist.md b/doc/plans/2026-10-02-stock-harness-paperclip-checklist.md index 41b463160cd..9cca9bf8324 100644 --- a/doc/plans/2026-10-02-stock-harness-paperclip-checklist.md +++ b/doc/plans/2026-10-02-stock-harness-paperclip-checklist.md @@ -131,6 +131,30 @@ and existing-test update. `paperclip_finish`/`paperclip_block` guidance must not leak into legacy completion paths, which use the operational skill and API. +Dotta approved the six proposed 2.3 changes and clarified that native tool +guidance must stay separate from legacy runners on 2026-10-02. Legacy adapters +use their existing Paperclip skill/API and adapter completion paths; they must +not inherit instructions to call unavailable native finish/block tools. + +- [ ] **2.3.1 Share native finish/block tool documentation.** First slice: + one canonical description per tool for Codex and native MCP bridges; refresh + retained provider threads through the native tool-contract fingerprint. + Executable coverage: SH-4-tools checks actual wire/catalog delivery across + all five native provider kinds; SH-4-resume checks v13 checkpoint rotation + without changing the Paperclip task or prior history. Live qualification is + pending; use native profile comparisons, with legacy results kept separate. +- [ ] **2.3.2 Move document/file delivery procedures into native tool docs.** + Include the live server override and preserve prepared versus delivered receipts. +- [ ] **2.3.3 Move hiring/dependency recipes into native discovery/tool docs.** + Preserve existing blocker IDs and workspace-release behavior. +- [ ] **2.3.4 Reduce the fixed native prompt.** Retain the pre-choice connection + cue and the one-accepted-result boundary. +- [ ] **2.3.5 Remove repeated native task/backend procedures.** Preserve runtime + facts and specialized mode, answer, and recovery constraints. +- [ ] **2.3.6 Qualify the combined native reduction.** Record prompt/tool + revisions, exact source fingerprints, fresh/resumed sessions, and matched + GitHub behavior results before claiming improvement. + ### Follow-up 2.1 implementation and verification The common task and conversation defaults now share the same identity sentence diff --git a/packages/paperclip-runner/src/contracts/completion-result.test.ts b/packages/paperclip-runner/src/contracts/completion-result.test.ts index c23a7e8563d..065b68c0be3 100644 --- a/packages/paperclip-runner/src/contracts/completion-result.test.ts +++ b/packages/paperclip-runner/src/contracts/completion-result.test.ts @@ -3,8 +3,10 @@ import { describe, expect, it } from "vitest"; import { PRP_BLOCK_RESULT_OUTPUT_SCHEMA, PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, PRP_COMPLETION_RESULT_OUTPUT_SCHEMA, PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, } from "./completion-result.js"; import { codexSemanticToolSpecs } from "../drivers/codex/codex-driver-values.js"; @@ -83,6 +85,8 @@ describe("provider-neutral completion result schema", () => { ); expect(finish.inputSchema).toEqual(PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA); expect(block.inputSchema).toEqual(PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA); + expect(finish.description).toBe(PRP_COMPLETION_TOOL_DESCRIPTION); + expect(block.description).toBe(PRP_BLOCK_TOOL_DESCRIPTION); }); it("allows only a response-wake continuation when completion explicitly yields", () => { diff --git a/packages/paperclip-runner/src/contracts/completion-result.ts b/packages/paperclip-runner/src/contracts/completion-result.ts index dec93a2f1de..b727a942965 100644 --- a/packages/paperclip-runner/src/contracts/completion-result.ts +++ b/packages/paperclip-runner/src/contracts/completion-result.ts @@ -1,6 +1,11 @@ /** Provider-neutral semantic completion tools and their strict model-facing schemas. */ export const PRP_COMPLETION_TOOL_NAME = "paperclip_finish" as const; export const PRP_BLOCK_TOOL_NAME = "paperclip_block" as const; +/** Native Runner guidance; legacy adapters use their own skill/API completion paths. */ +export const PRP_COMPLETION_TOOL_DESCRIPTION = + "Report completed work (done), work requiring review (needs_review), or an explicit wait for the next response (yielded with response_wake). Use the current completion contract and supporting evidence. If rejected, correct the report and retry. After acceptance, read the returned outcome; do not claim completion while gated. Explain any required approval with its supplied link and action, then write the final response and end the turn without further tool calls."; +export const PRP_BLOCK_TOOL_DESCRIPTION = + "Report work that cannot continue because of a concrete blocker. Identify the blocker, its owner, and the action needed to unblock it; use the current completion contract and supporting evidence. If rejected, correct the report and retry. After acceptance, read the returned outcome, explain the blocker and any required action in the final response, and end the turn without further tool calls."; export const PRP_SEMANTIC_TOOL_NAMES = [ PRP_COMPLETION_TOOL_NAME, PRP_BLOCK_TOOL_NAME, diff --git a/packages/paperclip-runner/src/drivers/codex/codex-app-server-driver.lifecycle.test.ts b/packages/paperclip-runner/src/drivers/codex/codex-app-server-driver.lifecycle.test.ts index 81e8a3def93..c5ade4c19c2 100644 --- a/packages/paperclip-runner/src/drivers/codex/codex-app-server-driver.lifecycle.test.ts +++ b/packages/paperclip-runner/src/drivers/codex/codex-app-server-driver.lifecycle.test.ts @@ -1,3 +1,9 @@ +import { + PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, + PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, +} from "../../contracts/completion-result.js"; import { CODEX_BLOCK_RESULT_OUTPUT_SCHEMA, CODEX_INVALID_REQUEST, @@ -540,6 +546,10 @@ describe("Codex app-server Codex driver", () => { expect(started.developerInstructions).toBe(conversationMode === "direct" ? undefined : baseInstructions); expect(resumed.developerInstructions).toBe(conversationMode === "direct" ? "" : baseInstructions); expect(resumed.dynamicTools).toEqual(started.dynamicTools); + expect(started.dynamicTools).toEqual(conversationMode === "direct" ? [] : [ + { name: "paperclip_finish", description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA }, + { name: "paperclip_block", description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA }, + ]); expect(resumed.config).toEqual(started.config); await recovered.session?.close({ reason: "verified additive recovery" }); }); diff --git a/packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts b/packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts index 68c32a3c9a6..5d4b9c9c7f2 100644 --- a/packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts +++ b/packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts @@ -1,5 +1,9 @@ import type { PersistedHarnessProviderIdentity } from "../../contracts/harness-driver.js"; import type { NativeUserMessage } from "../../contracts/types.js"; +import { + PRP_BLOCK_TOOL_DESCRIPTION, + PRP_COMPLETION_TOOL_DESCRIPTION, +} from "../../contracts/completion-result.js"; import { CODEX_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, CODEX_BLOCK_TOOL_NAME, @@ -232,8 +236,7 @@ export function differingJsonPaths( function finishToolSpec(): Record { return { name: CODEX_COMPLETION_TOOL_NAME, - description: - "Return the one semantic completion result for this task, including an explicit response_wake yield when waiting for the next response.", + description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: CODEX_RESULT_PROVIDER_INPUT_SCHEMA, }; } @@ -241,8 +244,7 @@ function finishToolSpec(): Record { function blockToolSpec(): Record { return { name: CODEX_BLOCK_TOOL_NAME, - description: - "Return the one semantic result when the task cannot continue.", + description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: CODEX_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, }; } diff --git a/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.test.ts b/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.test.ts index 6539a14b52a..07681400ddd 100644 --- a/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.test.ts +++ b/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.test.ts @@ -1,4 +1,10 @@ import { afterEach, describe, expect, it, vi } from "vitest"; +import { + PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, + PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, +} from "../../contracts/completion-result.js"; import { canonicalOpenCodeMcpToolName, startOpenCodeMcpBridge, type OpenCodeMcpBridge } from "./mcp-bridge.js"; @@ -38,8 +44,8 @@ describe("OpenCode MCP bridge", () => { expect(await listed.json()).toMatchObject({ result: { tools: [ { name: "documents.read" }, - { name: "paperclip_finish" }, - { name: "paperclip_block" }, + { name: "paperclip_finish", description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA }, + { name: "paperclip_block", description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA }, ] }, }); }); diff --git a/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts b/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts index 79ce6770375..1bf1555dd16 100644 --- a/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts +++ b/packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts @@ -4,8 +4,10 @@ import { Ajv2020, type ValidateFunction } from "ajv/dist/2020.js"; import { PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, PRP_BLOCK_TOOL_NAME, PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, PRP_COMPLETION_TOOL_NAME, } from "../../contracts/completion-result.js"; @@ -117,8 +119,8 @@ function normalizeTools( seen.add(name); } if (includeTerminalTools) for (const terminal of [ - { name: PRP_COMPLETION_TOOL_NAME, description: "Return the semantic completion result.", inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA }, - { name: PRP_BLOCK_TOOL_NAME, description: "Return the semantic blocked result.", inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA }, + { name: PRP_COMPLETION_TOOL_NAME, description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA }, + { name: PRP_BLOCK_TOOL_NAME, description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA }, ]) { if (!seen.has(terminal.name)) tools.push(terminal); } diff --git a/packages/paperclip-runner/src/drivers/runner-tool-bridge.test.ts b/packages/paperclip-runner/src/drivers/runner-tool-bridge.test.ts index b552adcb28a..5bf87169d24 100644 --- a/packages/paperclip-runner/src/drivers/runner-tool-bridge.test.ts +++ b/packages/paperclip-runner/src/drivers/runner-tool-bridge.test.ts @@ -1,6 +1,12 @@ import { connect } from "node:net"; import { afterEach, describe, expect, it, vi } from "vitest"; +import { + PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, + PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, +} from "../contracts/completion-result.js"; import { canonicalRunnerToolName, @@ -48,8 +54,8 @@ describe("runner semantic MCP bridge", () => { result: { tools: [ { name: "documents.read" }, - { name: "paperclip_finish" }, - { name: "paperclip_block" }, + { name: "paperclip_finish", description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA }, + { name: "paperclip_block", description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA }, ], }, }); diff --git a/packages/paperclip-runner/src/drivers/runner-tool-bridge.ts b/packages/paperclip-runner/src/drivers/runner-tool-bridge.ts index e59535171be..c8207c71833 100644 --- a/packages/paperclip-runner/src/drivers/runner-tool-bridge.ts +++ b/packages/paperclip-runner/src/drivers/runner-tool-bridge.ts @@ -10,8 +10,10 @@ import { Ajv2020, type ValidateFunction } from "ajv/dist/2020.js"; import { PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_BLOCK_TOOL_DESCRIPTION, PRP_BLOCK_TOOL_NAME, PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, + PRP_COMPLETION_TOOL_DESCRIPTION, PRP_COMPLETION_TOOL_NAME, } from "../contracts/completion-result.js"; @@ -70,12 +72,12 @@ const MAX_RESULT_CHUNK_BYTES = 64 * 1024; const RESERVED_TOOLS: readonly RunnerToolDefinition[] = [ { name: PRP_COMPLETION_TOOL_NAME, - description: "Return the semantic completion result.", + description: PRP_COMPLETION_TOOL_DESCRIPTION, inputSchema: PRP_COMPLETION_RESULT_PROVIDER_INPUT_SCHEMA, }, { name: PRP_BLOCK_TOOL_NAME, - description: "Return the semantic blocked result.", + description: PRP_BLOCK_TOOL_DESCRIPTION, inputSchema: PRP_BLOCK_RESULT_PROVIDER_INPUT_SCHEMA, }, ]; diff --git a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts index 4a38700939a..50544213ea3 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts @@ -54,6 +54,10 @@ import { CODEX_SKILLLESS_BASE_INSTRUCTIONS, createCodexTaskEnvelope, } from "../contracts/codex.js"; +import { + PRP_BLOCK_TOOL_DESCRIPTION, + PRP_COMPLETION_TOOL_DESCRIPTION, +} from "../contracts/completion-result.js"; import { CodexAppServerDriver, codexSemanticToolSpecs, @@ -1336,14 +1340,19 @@ it("includes ACPX terminal tools in the authenticated bridge catalog", () => { }); }); -it("preserves answer and internal wait descriptions in the serialized native tool catalog", () => { +it.each(["codex", "opencode", "claude_managed", "aws_agentcore", "acpx"] as const)("preserves answer and internal wait descriptions in the serialized native %s tool catalog", (provider) => { const catalog = JSON.parse( - JSON.stringify(authorizedToolSetForProvider("codex", codexSemanticToolSpecs())), + JSON.stringify(authorizedToolSetForProvider(provider, codexSemanticToolSpecs())), ); const finish = catalog.operations.find( (operation: { operationId: string }) => operation.operationId === "paperclip_finish", ); + const block = catalog.operations.find( + (operation: { operationId: string }) => operation.operationId === "paperclip_block", + ); + expect(finish.description).toBe(PRP_COMPLETION_TOOL_DESCRIPTION); + expect(block.description).toBe(PRP_BLOCK_TOOL_DESCRIPTION); expect(finish.inputSchema.properties.summary.description).toContain( "complete user-facing answer", ); diff --git a/server/src/services/native-runtime/native-session-resume.test.ts b/server/src/services/native-runtime/native-session-resume.test.ts index cab88d8ea9b..0247fc8868f 100644 --- a/server/src/services/native-runtime/native-session-resume.test.ts +++ b/server/src/services/native-runtime/native-session-resume.test.ts @@ -1840,6 +1840,12 @@ describe("rebindNativeSessionCheckpoint", () => { retainedFingerprint: "sha256:5b7b302db36f7ed6686f9ea1ba70bbf79ebd7fabf86953b548d966a2bc38b648", }, + { + contract: "native completion tool guidance", + // Deployed v13 local catalog before canonical finish/block descriptions. + retainedFingerprint: + "sha256:68a51d34e091c55ee5d0d2b563153454dd727d72db16e6a27c358d342ae489c9", + }, { contract: "task-bound human-input description", // Deployed v9 still advertises the generic mock-task question description. diff --git a/server/src/services/native-runtime/native-session-resume.ts b/server/src/services/native-runtime/native-session-resume.ts index f50b6bb0962..7f2ac7ea3f1 100644 --- a/server/src/services/native-runtime/native-session-resume.ts +++ b/server/src/services/native-runtime/native-session-resume.ts @@ -23,7 +23,7 @@ export function nativeToolContractFingerprintForTarget( return `sha256:${createHash("sha256") .update( JSON.stringify({ - schema: "paperclip.native-tool-contract.v13", + schema: "paperclip.native-tool-contract.v14", executionTargetKind, advertisementPolicy: { // Direct provider threads retain declarations from thread/start. diff --git a/tests/runner-e2e/STOCK-HARNESS.md b/tests/runner-e2e/STOCK-HARNESS.md index 461ed5b4735..aeb27e6148b 100644 --- a/tests/runner-e2e/STOCK-HARNESS.md +++ b/tests/runner-e2e/STOCK-HARNESS.md @@ -14,6 +14,13 @@ agent-creation route materialize the shipped default. | SH-1: native Codex preserves vendor base instructions | Serialized start/resume requests from the TypeScript driver, recovery paths, runnerd transport, Runner Lab/live sessions, and Rust provider use additive developer instructions. | Real new native Codex hires execute the three journeys below. Task success alone cannot prove vendor base preservation. | | SH-2: identity-only default hire manual | Existing public agent-creation and onboarding-asset tests cover default, custom, and CEO exceptions. | The public bundle is exactly one `AGENTS.md` containing the eight-word shipped identity, checked before provider execution and again during cleanup. | | SH-3: reduced shared legacy task/chat defaults and resume delta | Shared prompt tests and ACPX, Codex, OpenCode, Pi, Hermes, and Cursor Cloud adapter regressions retain runtime context and exclude removed generic procedures. | Actual legacy `adapter.invoke` prompts retain fresh identity/connection guidance, omit the removed procedures, and have complete receipts for every observed run. | +| SH-4: shared native finish/block tool guidance | Actual authenticated MCP catalogs, Codex start/resume frames, serialized daemon catalogs for all five native provider kinds, and rotation of a retained v13 thread to the new tool contract. | The three native profiles run the existing skill, continuation, and chat journeys. Configured coverage is not a live qualification result. | + +SH-4 changes native Runner tools only. Legacy adapters do not receive +`paperclip_finish` or `paperclip_block` from this change. Their skill/API +completion paths remain separate. The shared legacy prompt tests in SH-3 +continue to check their exact minimal defaults. The fixed native prompt and +task constraints are not reduced in this first tool-documentation slice. `pnpm test:e2e:runner:stock-harness` runs these credential-free prerequisites, including the Rust test. It writes JSON reports, the source SHA, a working-source diff --git a/tests/runner-e2e/stock-harness-checks.mjs b/tests/runner-e2e/stock-harness-checks.mjs index ec89e0ee5e1..d9cf2f5c10d 100644 --- a/tests/runner-e2e/stock-harness-checks.mjs +++ b/tests/runner-e2e/stock-harness-checks.mjs @@ -38,6 +38,20 @@ export const stockHarnessGates = [ { id: "SH-3-hermes", name: "Hermes shared-prompt delivery", cwd: "packages/adapters/hermes", files: ["src/server/prompt-rendering.test.ts"], required: ["renders standard assignment wake with task authority", "renders scoped planning wake authority"] }, + { id: "SH-4-tools", name: "Native completion tool delivery", cwd: "packages/paperclip-runner", files: [ + "src/contracts/completion-result.test.ts", "src/drivers/runner-tool-bridge.test.ts", + "src/drivers/opencode/mcp-bridge.test.ts", "src/drivers/codex/codex-app-server-driver.lifecycle.test.ts", + "src/live/runnerd-codex-transport.test.ts", + ], testPattern: "propagates answer and wait descriptions|binds to loopback|preserves stock Codex instructions on|preserves answer and internal wait descriptions", + required: ["propagates answer and wait descriptions", "runner semantic MCP bridge binds to loopback", + "OpenCode MCP bridge binds to loopback", "preserves stock Codex instructions on task recovery", + "preserves stock Codex instructions on prepared recovery", "preserves stock Codex instructions on direct recovery", + ...["codex", "opencode", "claude_managed", "aws_agentcore", "acpx"].map(provider => + `preserves answer and internal wait descriptions in the serialized native ${provider} tool catalog`)] }, + { id: "SH-4-resume", name: "Refresh retained native completion guidance", cwd: ".", files: [ + "server/src/services/native-runtime/native-session-resume.test.ts", + ], testPattern: "refreshes retained", + required: ["native completion tool guidance"] }, { id: "SH-eval", name: "Independent oracle and qualification admission", cwd: ".", config: "tests/runner-e2e/vitest.config.ts", files: ["tests/runner-e2e/stock-harness.test.ts", "tests/runner-e2e/stock-harness-checks.test.mjs", @@ -73,6 +87,11 @@ export function sourceFingerprint() { "packages/adapter-utils/src/server-utils.ts", "packages/shared/src/connection-intent-guidance.ts", "server/src/onboarding-assets/default/AGENTS.md", "server/src/routes/agents.ts", "scripts/ensure-plugin-build-deps.mjs", "packages/paperclip-runner/src/drivers/codex/codex-app-server-driver-impl.ts", + "packages/paperclip-runner/src/contracts/completion-result.ts", + "packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts", + "packages/paperclip-runner/src/drivers/runner-tool-bridge.ts", + "packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts", + "server/src/services/native-runtime/native-session-resume.ts", "packages/paperclip-runner/src/live/runnerd-codex-transport.ts", "packages/paperclip-runner/src/live/live-session.ts", "packages/paperclip-runner/runner/crates/runner-core/src/codex_provider.rs", diff --git a/tests/runner-e2e/stock-harness-checks.test.mjs b/tests/runner-e2e/stock-harness-checks.test.mjs index 92d34337e11..42cb87515ae 100644 --- a/tests/runner-e2e/stock-harness-checks.test.mjs +++ b/tests/runner-e2e/stock-harness-checks.test.mjs @@ -7,7 +7,7 @@ const report = () => ({ testResults: [{ name: "/repo/boundary.test.ts", status: numTotalTests: 1, numPassedTests: 1, numFailedTests: 0, numPendingTests: 0 }); describe("stock harness prerequisite coverage", () => { it("maps every implemented change to an executable gate", () => { - expect(stockHarnessGates.map(gate => gate.id)).toEqual(["SH-1", "SH-2", "SH-3", "SH-3-hermes", "SH-eval"]); + expect(stockHarnessGates.map(gate => gate.id)).toEqual(["SH-1", "SH-2", "SH-3", "SH-3-hermes", "SH-4-tools", "SH-4-resume", "SH-eval"]); expect(stockHarnessGates.every(gate => gate.files.length > 0 && gate.required.length > 0)).toBe(true); }); it("accepts an executed passing boundary", () => expect(gradeGate(gate, report(), 0).passed).toBe(true)); diff --git a/tests/runner-e2e/stock-harness-digest.test.ts b/tests/runner-e2e/stock-harness-digest.test.ts index 0f51c70ee69..e705913096b 100644 --- a/tests/runner-e2e/stock-harness-digest.test.ts +++ b/tests/runner-e2e/stock-harness-digest.test.ts @@ -5,7 +5,14 @@ import { stockHarnessSourceDigest } from "./stock-harness.js"; vi.mock("node:fs", async importOriginal => ({ ...await importOriginal(), readFileSync: vi.fn() })); describe("stock harness instruction revision", () => { - it.each(["server/src/onboarding-assets/default/AGENTS.md", "packages/adapter-utils/src/server-utils.ts", "packages/shared/src/connection-intent-guidance.ts"])( + it.each([ + "server/src/onboarding-assets/default/AGENTS.md", "packages/adapter-utils/src/server-utils.ts", + "packages/shared/src/connection-intent-guidance.ts", "packages/paperclip-runner/src/contracts/completion-result.ts", + "packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts", + "packages/paperclip-runner/src/drivers/runner-tool-bridge.ts", + "packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts", + "server/src/services/native-runtime/native-session-resume.ts", + ])( "changes when the evaluated %s changes", source => { vi.mocked(readFileSync).mockImplementation(() => Buffer.from("unchanged")); const original = stockHarnessSourceDigest(); diff --git a/tests/runner-e2e/stock-harness.ts b/tests/runner-e2e/stock-harness.ts index 017a0972ccf..84b4bc01bd5 100644 --- a/tests/runner-e2e/stock-harness.ts +++ b/tests/runner-e2e/stock-harness.ts @@ -114,6 +114,11 @@ export function stockHarnessSourceDigest() { "../../server/src/onboarding-assets/default/AGENTS.md", "../../packages/adapter-utils/src/server-utils.ts", "../../packages/shared/src/connection-intent-guidance.ts", + "../../packages/paperclip-runner/src/contracts/completion-result.ts", + "../../packages/paperclip-runner/src/drivers/codex/codex-driver-values.ts", + "../../packages/paperclip-runner/src/drivers/runner-tool-bridge.ts", + "../../packages/paperclip-runner/src/drivers/opencode/mcp-bridge.ts", + "../../server/src/services/native-runtime/native-session-resume.ts", ]) hash.update(source).update(readFileSync(new URL(source, import.meta.url))); return hash.digest("hex"); }