From 021df20762d96bc58d90a1dfa0fdb884393b1d5d Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 12 Oct 2026 22:51:22 -0500 Subject: [PATCH] test(runner): wait for held recovery authorization entry Preserve the original recovery error and five-second bound while waiting for the actual before-bootstrap callback. Keep every authority, process and durable-state assertion. Co-Authored-By: Paperclip --- doc/plans/2026-10-06-default-agent-runner.md | 42 +++++++++++++++++++ .../src/live/runnerd-codex-transport.test.ts | 15 +++++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/doc/plans/2026-10-06-default-agent-runner.md b/doc/plans/2026-10-06-default-agent-runner.md index 57dc9125668..12612dda7c0 100644 --- a/doc/plans/2026-10-06-default-agent-runner.md +++ b/doc/plans/2026-10-06-default-agent-runner.md @@ -2,6 +2,48 @@ Updated 2026-10-12. +## Held-authorization fixture correction + +The ordinary reconciliation candidate `dae808fe02694d13d322c535944910813b21f6d6` +has fresh Greptile 5/5, all four resolved threads, passing isolated native +compilation and the required browser aggregate. Its runner shard passes both +previously corrected cases, but fails a different `authorize_before_bootstrap` +cell: the same implicit one-second polling deadline expires before the fixture +installs its release callback. The shard records 1,672 passes, one failure and +three skips. The exact failure and gate receipt remain: +`/private/tmp/ci-final-dae808-ci-review-failure-receipt.json`. + +The existing fixture now signals actual entry after installing the release +callback in the exact before-bootstrap authorization hook. Race that signal +against the original recovery request under the unchanged five-second bound. +All authority, stage, denied-work, command queue, process, provider-state, +durable-byte and cleanup assertions remain. On canonical Node 24, controlled +1,250 ms scheduling delay reproduces the old undefined-callback assertion and +passes after correction. An injected early recovery error surfaces unchanged. +The original hosted cause remains inconclusive; this proves fixture weakness +and preserves the next diagnostic. These are historical-mock-binary controls, +not final installed runtime qualification. Matching-source independent review +is clear. Receipts: +`/private/tmp/ci-final-dae808-held-authorization-signal-receipt.json` and +`/private/tmp/pr2-dae808-held-authorization-independent-review.json`. + +The already-running package campaign +https://github.com/paperclipai/paperclip/actions/runs/38342104102 +is immutable to literal `dae808` throughout: daemon, assembly and installed +consumer checkouts use its explicit 40-character SHA, while the tooling checkout +uses the captured workflow SHA. Publishing this test-only correction cannot +change that run's source. Let it finish without rerun or cancellation, keep its +receipts literal and overlap fresh current-head CI with its remaining steps. +No new package campaign starts until the existing one is terminal. + +Both worktrees and root's test-drive data stay preserved. Its loopback health +is OK at literal `fe1ecf1c34`, recovery ready, zero active runs; a sandbox-blocked +read was corrected with the authorized read-only loopback path, without restart +or build. Root HEAD stays `1a0ca662`. Codex and Claude reconciliation/acceptance, +normal code-owner approval, private Cloud composition and production baseline +remain pending. No merge/deployment/default promotion, paid provider call, +new paid host or local native/Docker build occurred. + ## Final CI fixture corrections and current master Published prerequisite `16a53254c495f3e49a28cc911f5dcd60c41779fc` 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 c06f96cc535..b44f6b7c36a 100644 --- a/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts +++ b/packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts @@ -6433,6 +6433,10 @@ it.each([ recoveryFault === "none" ? null : await fingerprintTree(stateDirectory); const authorizationStages: string[] = []; let releaseHeldAuthorization: (() => void) | undefined; + let markHeldAuthorizationEntered!: () => void; + const heldAuthorizationEntered = new Promise((resolve) => { + markHeldAuthorizationEntered = resolve; + }); const authorizationFault = recoveryFault.startsWith("authorize_"); const failedAuthorizationStage = recoveryFault.slice("authorize_".length); const beforeProviderBytes = await readFile( @@ -6492,6 +6496,7 @@ it.each([ ) { await new Promise((resolveGate) => { releaseHeldAuthorization = resolveGate; + markHeldAuthorizationEntered(); }); } if (stage === failedAuthorizationStage) @@ -6524,9 +6529,13 @@ it.each([ authorizationFault && failedAuthorizationStage === "before_bootstrap" ) { - await vi.waitFor(() => - expect(releaseHeldAuthorization).toBeTypeOf("function"), - ); + await within(Promise.race([ + heldAuthorizationEntered, + recoveryRequest.then(() => { + throw new Error("warm restart authorization callback was not entered"); + }), + ])); + expect(releaseHeldAuthorization).toBeTypeOf("function"); const queuedBefore = cores[1]!.store.state.commands.map( (command) => command.commandId, );