Skip to content

🪲 AM19 races a holder's release: a second attempt is elected and enters cleanup after publication #664

Closed

Description

@taras

Failing test: Tier AM — embedded adapter materialization > AM19: two attempts racing one abandoned ticket leave exactly one holder (packages/acp/tests/adapter-materialization.test.ts:595)

Runtime: Bun 1.3.14, CI job test-bun (1/2)

Run: https://github.com/taras/executable.md/actions/runs/33318388159 (attempt 1, on main at 879c4ff)

Output:

595 |     expect(cleanups).toBe(1);
error: expect(received).toBe(expected)
Expected: 1
Received: 2
(fail) Tier AM — embedded adapter materialization > AM19: two attempts racing one abandoned ticket leave exactly one holder [4595.57ms]

Evidence of intermittence: attempt 2 of the same run, on the identical revision, passed with no change; 879c4ff itself touched only packages/core (the <CodeBlock> component), nothing under packages/acp. The failure opened #663, which closed when the re-run restored main.

Cause: a real ordering gap in recover() (packages/acp/src/adapter-snapshots.ts), not a defective assertion. A waiting attempt polls published only between election passes, and a holder marks its ticket done only after publishing. When the holder's publication and release both land in the window between the waiter's published poll and its next election pass, the waiter is elected and enters the recovery cleanup — invoking beforeRecoveryCleanup a second time — before the in-lock published re-check turns it away. Durable state stays correct (the re-check removes nothing), but the module's own contract, that an attempt which did not do the recovery answers from what the holder published, is violated, and AM19 rightly fails.

Fix: an attempt that wins the election checks published before entering the cleanup; elected behind a finished holder means the work can already be on disk, and the ticket ordering guarantees that publication is visible by then. A deterministic regression (AM20) produces the exact window with an election-pass observer and fails without the fix.

Activity

  1. added
    flakeIntermittent or timing-sensitive failure that can pass without a code change
    on Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    flakeIntermittent or timing-sensitive failure that can pass without a code change

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions