diff --git a/tests/runner-e2e/STOCK-HARNESS.md b/tests/runner-e2e/STOCK-HARNESS.md index 70ecfb1827..c5df1e385c 100644 --- a/tests/runner-e2e/STOCK-HARNESS.md +++ b/tests/runner-e2e/STOCK-HARNESS.md @@ -151,6 +151,11 @@ builds that daemon from the locked Rust source before TypeScript gates, retains The required daemon-frame test selects that built debug binary explicitly, without replacing staged product binaries. The receipt records its SHA-256; verification rejects a changed binary before provider admission. +The [next cold pilot](https://github.com/paperclipai/paperclip/actions/runs/37040493183) +at `ac6ddefb589c18fa9c30946db40e58499e9fb0e0` then found the required fake Codex +protocol fixture absent. It also stopped before paid providers. Setup uses the +package's ordinary locked workspace `--bins` build, covering both the daemon +and its fixture; verification binds both binaries to the retained receipt. Dispatch the trusted workflow from `master`, with `target_branch` naming the same-repository candidate and an exact cell selector first. The workflow resolves diff --git a/tests/runner-e2e/stock-harness-checks.mjs b/tests/runner-e2e/stock-harness-checks.mjs index b818e4673b..7fcd16b364 100644 --- a/tests/runner-e2e/stock-harness-checks.mjs +++ b/tests/runner-e2e/stock-harness-checks.mjs @@ -74,6 +74,9 @@ export function sourceFingerprint() { "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", + "packages/paperclip-runner/runner/crates/runner-core/src/bin/fake-codex-app-server.rs", + "packages/paperclip-runner/runner/Cargo.toml", "packages/paperclip-runner/runner/Cargo.lock", + "packages/paperclip-runner/runner/crates/runner-core/Cargo.toml", "packages/paperclip-runner/runner/crates/runner-core/tests/codex_provider.rs", ]); const sourceErrors = []; @@ -91,6 +94,7 @@ export function assertPreflightReceipt(report, current) { report.setup?.passed !== true || report.setup?.exitCode !== 0 || report.setup?.sdkExitCode !== 0 || report.setup?.runnerdExitCode !== 0 || report.setup?.runnerdSha256 !== current.runnerdSha256 || + report.setup?.fakeCodexSha256 !== current.fakeCodexSha256 || report.providerCalls !== 0 || report.sourceSha !== current.sha || report.sourceFingerprint !== current.fingerprint || report.sourceErrors?.length !== 0 || !Array.isArray(report.gates) || report.gates.length !== expected.length || @@ -116,6 +120,8 @@ export function main(args = process.argv.slice(2)) { sha: git.stdout.trim(), fingerprint: source.fingerprint, runnerdSha256: createHash("sha256").update(readFileSync(join(root, "packages/paperclip-runner/runner/target/debug", `paperclip-runnerd${process.platform === "win32" ? ".exe" : ""}`))).digest("hex"), + fakeCodexSha256: createHash("sha256").update(readFileSync(join(root, + "packages/paperclip-runner/runner/target/debug/fake-codex-app-server"))).digest("hex"), }); const output = resolve(verify, ".."); for (const gate of stockHarnessGates) { @@ -144,7 +150,7 @@ export function main(args = process.argv.slice(2)) { // cells do not download native artifacts, so compile it before TS discovery. const runnerd = setupRun.status === 0 ? spawnSync("cargo", ["build", "--locked", ...(args.includes("--allow-rust-network") ? [] : ["--offline"]), - "-p", "paperclip-runner-core", "--bin", "paperclip-runnerd"], { + "--workspace", "--bins"], { cwd: join(root, "packages/paperclip-runner/runner"), env, encoding: "utf8", timeout: 10 * 60_000, }) : null; writeFileSync(join(output, "runnerd-build.txt"), `${runnerd?.stdout ?? ""}\n${runnerd?.stderr ?? ""}`); @@ -164,6 +170,8 @@ export function main(args = process.argv.slice(2)) { const runnerdBinary = join(root, "packages/paperclip-runner/runner/target/debug", `paperclip-runnerd${process.platform === "win32" ? ".exe" : ""}`); setup.runnerdSha256 = createHash("sha256").update(readFileSync(runnerdBinary)).digest("hex"); + setup.fakeCodexSha256 = createHash("sha256").update(readFileSync(join(root, + "packages/paperclip-runner/runner/target/debug/fake-codex-app-server"))).digest("hex"); const results = []; for (const gate of stockHarnessGates) { console.log(`Checking ${gate.id}: ${gate.name}`); diff --git a/tests/runner-e2e/stock-harness-checks.test.mjs b/tests/runner-e2e/stock-harness-checks.test.mjs index 428cfa9ac0..92d34337e1 100644 --- a/tests/runner-e2e/stock-harness-checks.test.mjs +++ b/tests/runner-e2e/stock-harness-checks.test.mjs @@ -40,9 +40,10 @@ describe("stock harness prerequisite coverage", () => { }); describe("stock harness prerequisite admission", () => { - const current = { sha: "a".repeat(40), fingerprint: "b".repeat(64), runnerdSha256: "c".repeat(64) }; + const current = { sha: "a".repeat(40), fingerprint: "b".repeat(64), runnerdSha256: "c".repeat(64), fakeCodexSha256: "e".repeat(64) }; const receipt = () => ({ schema: "paperclip.stock-harness-preflight.v3", passed: true, - setup: { passed: true, exitCode: 0, sdkExitCode: 0, runnerdExitCode: 0, runnerdSha256: current.runnerdSha256 }, + setup: { passed: true, exitCode: 0, sdkExitCode: 0, runnerdExitCode: 0, runnerdSha256: current.runnerdSha256, + fakeCodexSha256: current.fakeCodexSha256 }, providerCalls: 0, sourceSha: current.sha, sourceFingerprint: current.fingerprint, sourceErrors: [], gates: [...stockHarnessGates.map(g => g.id), "SH-1-rust"].map(id => ({ id, passed: true, exitCode: 0 })) }); it("admits the same passing source revision", () => expect(assertPreflightReceipt(receipt(), current).passed).toBe(true)); @@ -58,6 +59,7 @@ describe("stock harness prerequisite admission", () => { ["failed cold setup", r => { r.setup.passed = false; r.setup.exitCode = 1; }], ["missing daemon build", r => { delete r.setup.runnerdExitCode; }], ["changed daemon binary", r => { r.setup.runnerdSha256 = "d".repeat(64); }], + ["changed protocol fixture", r => { r.setup.fakeCodexSha256 = "d".repeat(64); }], ])("rejects %s before providers", (_name, mutate) => { const r = receipt(); mutate(r); expect(() => assertPreflightReceipt(r, current)).toThrow("exact source SHA and fingerprint"); });