go-raft-read-index-lease-expiry-fencing
Done. I built and verified a self-contained Go package and wrote the full solution document to ~/solution.md (1049 lines, balanced fences, includes complete sources).
Root cause: The read path trusts three facts whose scopes must all agree — leadership, the lease, and quorum acks — but validates them only at capture time and over a single configuration. The concrete defects are:
waitApplied → serves stale data after an in-flight expiry.ReadID → reordered/delayed responses from an earlier round inflate the current round.Fix (fencing): Bind every lease and ack to (term, ReadID, Configuration).
- ReadIndex captures (term, commit, cfg), tries the lease fast path, then re-validates the lease after applied >= commit; if lapsed, it falls back to a real quorum round.
- The round echoes Term+ReadID; only matching, current-term, in-config acks count; any higher term steps the node down immediately.
- hasQuorum requires a majority of every config component (joint consensus); SetConfiguration invalidates the lease.
- Leases use a monotonic Clock and electionTimeout − maxClockDrift.
- The round returns as soon as quorum is reached (bounded latency, no straggler wait).
Verification (~/readindex, 81% coverage, race-clean):
$ go vet ./...
$ go test -count=1 -race ./...
ok readindex 1.032s
10 adversarial tests cover lease expiry mid-read, term change before ack, reordered/stale acks, joint-consensus both-majorities, config-change lease invalidation, straggler latency, deposed leader, and a mixed reordering fuzz case.
Artifacts:
- ~/solution.md — full write-up + embedded sources
- ~/readindex/readindex.go — production fix
- ~/readindex/readindex_test.go — adversarial suite
- ~/readindex/go.mod
# Evidence - Problem class: go-raft-read-index-lease-expiry-fencing - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-10-11T10:14:31.040Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a linearizable read-index path for a Raft-like replicated key-value store where leader leases may expire during an in-flight read and terms can change before the quorum acknowledgment arrives. The implementation must fence stale leaders, preserve bounded read latency under message reordering, and pass adversarial schedules with joint-consensus membership changes.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-raft-read-index-lease-expiry-fencing", "provider": "openrouter", "solved_at": "2026-10-11T10:14:31.044Z", "version": "1.26"}