Skip to content

fix: make stale lock ticket reaping single-winner on Windows - #444

Merged
TheAmericanMaker merged 5 commits into
mainfrom
paperclip/HUGA-3-fix-435-stale-lock-ticket-reaping-on-windows-removeifpresent-only-treats-enoent-as-a-lost-race
Sep 26, 2026
Merged

TheAmericanMaker merged 5 commits into
mainfrom
paperclip/HUGA-3-fix-435-stale-lock-ticket-reaping-on-windows-removeifpresent-only-treats-enoent-as-a-lost-race

Conversation

@TheAmericanMaker

@TheAmericanMaker TheAmericanMaker commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Closes #435

What changed

  • Create a stable per-ticket marker with exclusive wx before renaming a stale ticket to a unique tombstone. The Windows runner showed two successful renames of the same source path; only the marker creator can now report brokeStale.
  • Treat EPERM, EBUSY, or EACCES on claim rename as a retry while the source exists, or as a lost race if it is gone. Other errors still surface, and the waiter's heartbeat and ticket are cleaned up on exit.
  • Treat only ENOENT from ticket stat as evidence that the owner claim disappeared. Sweep old tombstones and claim markers, and remove a marker once its source is gone.

Regression coverage

  • Windows claim contention retries while the stale ticket still exists: injected EPERM, EBUSY, and EACCES, then succeeded on retry.
  • Windows claim errors after another waiter removed the ticket do not report a break: injected the same codes after removing the source.
  • only one waiter reports a break when Windows exposes the source after rename succeeds: models the behavior observed in Windows CI, ensuring a second waiter does not report a break.
  • a claim error removes this waiter's ticket before rejecting: injected EIO and verified cleanup.
  • Existing injected unlink and non-ENOENT stat tests remain.

Before the follow-up fix, Windows claim contention retries while the stale ticket still exists failed against f0e709e: not ok 1, error: 'ticket held open by another waiter', code: 'EPERM'. Windows CI on d2387b0 recorded two successful renames of the exact same planted ticket path, which prompted the exclusive marker.

Verification

  • npm run build: passed.
  • node --experimental-strip-types --disable-warning=ExperimentalWarning --test tests/state-store.test.mjs: 26 passed, 0 failed.
  • npm test: 1,295 passed, 0 failed.
  • git diff --check: passed.

Windows-only filesystem behavior has not been run locally on this Linux machine; test-windows in CI must verify it alongside test (22) and test (24).

TheAmericanMaker and others added 5 commits September 25, 2026 03:26
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
 review)

AcquireLockOptions is re-exported through core/index.ts, so the fsOps
test seam was emitted into dist/core/status.d.ts and offered to every
consumer of the published types. stripInternal drops members marked
@internal from declarations; runtime code is unchanged. fsOps is the
only @internal in core/, mcp-server/ or extensions/.
@TheAmericanMaker
TheAmericanMaker marked this pull request as ready for review September 26, 2026 07:03
@TheAmericanMaker
TheAmericanMaker merged commit 75c71fc into main Sep 26, 2026
15 checks passed
@TheAmericanMaker
TheAmericanMaker deleted the paperclip/HUGA-3-fix-435-stale-lock-ticket-reaping-on-windows-removeifpresent-only-treats-enoent-as-a-lost-race branch September 26, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test-windows: two waiters can both reap one dead lock ticket (removeIfPresent treats only ENOENT as a lost race)

1 participant