js-quorum-lease-clock-skew-fencing-recovery-20261010
Artifacts
- ~/solution.md — the required write-up (title, root-cause analysis, exact fix with full runnable code, verification).
- ~/solution.js — the self-contained implementation + simulator + test suite. Verified: node solution.js → ALL CHECKS PASSED (exit 0). The code embedded in the markdown is byte-identical to the runnable file (checked programmatically).
The failure is a worker committing after its lease was transferred away. Three independent defects produce it:
2*maxSkew + maxDelay; if the next lease is granted inside that window, holders overlap.>= promise, in-memory maxPromised, in-memory resource maxToken, or no quorum promise all let stale/duplicate tokens through.// Voter: STRICT promise, persist BEFORE ack -> unique, globally increasing tokens
const ok = token > this.maxPromised; // NOT >=
if (!ok) return { ok:false, reason:'stale' };
this.maxPromised = token; this.persist();
// Resource: reject anything below the durable high-water mark (never consults a clock)
if (token < this.maxToken) return { ok:false, reason:'fenced', maxToken:this.maxToken };
this.maxToken = token; this.persist();
// Coordinator: transfer is complete only after the durable fence moves
const adv = this.resource.advance(token);
if (!adv.ok) return { ok:false, reason:'fence-unavailable', token }; // burn the token
// Worker: bounded clock margin for liveness only
const usable = Math.max(0, duration - (2*this.cfg.maxSkew + this.cfg.maxDelay));
Safety is clock-free (majority quorum intersection + strict token monotonicity + durable fence). Clocks only bound the usable lease window.
GRANT_NOT_MONOTONIC, TOKEN_REUSE, STALE_ACCEPT, STALE_AFTER_TRANSFER, COMMIT_AFTER_LEASE_END.mulberry32-seeded) varying quorums, concurrent same-token proposals, crashes/recoveries, whole-cluster restarts, resource crashes, and fast→slow clock flips discovers all 5 defect classes (e.g. no-fencing: 57, non-strict-promise: 254, non-durable-nodes: 190, naive-clock-margin: 214).no-quorum; duration <= 2*maxSkew+maxDelay yields zero usable time.# Evidence - Problem class: js-quorum-lease-clock-skew-fencing-recovery-20261010 - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-10-10T22:11:41.123Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a lease coordinator for a partitioned service where workers have bounded but changing clock skew, delayed messages, and crash-recovery from persisted state. Prevent stale holders from committing after lease transfer using fencing tokens while preserving availability under the stated quorum rules, and supply a deterministic event simulator that finds safety violations in adversarial schedules.", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "js-quorum-lease-clock-skew-fencing-recovery-20261010", "provider": "openrouter", "solved_at": "2026-10-10T22:11:41.123Z", "version": "20"}