go-mvcc-serializable-snapshot-write-skew-scc
I diagnosed the problem, implemented a complete solution, and verified it. The full self-contained write-up is at ~/SOLUTION.md, with working code at ~/ssi/ (ssi.go, ssi_test.go, prop_test.go).
SI is not serializable because it permits write skew. The validator must:
rw = reader of version X → writer of version X+1; wr = writer of version X → reader of X; ww = writer of X → writer of X+1. Conflating these produces a wrong graph.T1 -rw-> T2 -rw-> T3 only matters if there is a real return path T3 →* T1.The commit-order rule T3.Commit < T2.Commit (and < T1.Commit when distinct) is what makes the validator abort the later pivot, matching SSI runtime behavior.
Validate)// Candidate pivots: a -rw-> b -rw-> c, c commits before b (and a), and c ->* a.
for _, e1 := range rw {
a, b := e1.from, e1.to
tb := g.byID[b]
for _, e2 := range rw {
if e2.from != b { continue }
c := e2.to
tc := g.byID[c]
if tc.Commit >= tb.Commit { continue } // target must commit first
if c != a {
if ta := g.byID[a]; ta != nil && tc.Commit >= ta.Commit { continue }
}
if g.reaches(c, a) { candSet[b] = true } // real cycle closure
}
}
// Exact minimum FVS over candidates, branching on a discovered cycle's pivots,
// tie-breaking in favour of aborting later-committing transactions.
The store exposes Begin / Read / Write / TryCommit / Commit / Committed, and Validate(committed []Txn) []string returns the minimal abort set sorted by commit order.
gofmt -l . # clean
go vet ./... # clean
go test -count=1 -v ./...
--- PASS: TestWriteSkew_AbortsLater (write skew -> [T2], only the later pivot)
--- PASS: TestNonCycleDangerousStructure_NoAbort (false-positive guard -> [])
--- PASS: TestWrClosesCycle (wr-closed cycle detected)
--- PASS: TestNoConflict
--- PASS: TestIndependentWriteSkews (disjoint pairs -> [T2 T4])
--- PASS: TestStoreWriteSkew (Begin/Read/Write/Commit integration)
--- PASS: TestRemainingAcyclic (graph acyclic after aborts)
--- PASS: TestPropertyRandomValidSI (50,000 random valid SI histories)
ok ssi 0.41s
The randomized property test generates valid SI histories (reads at snapshot, first-committer-wins enforced) and checks two invariants on every one: removing the reported aborts makes the dependency graph acyclic, and every reported abort is necessary (dropping it reintroduces a cycle).
A key correctness detail discovered during testing: the generator must enforce write-write conflicts exactly as real SI does, otherwise ww edges form cycles that the SSI theorem explicitly excludes; the final code and property test both model first-committer-wins correctly.
# Evidence - Problem class: go-mvcc-serializable-snapshot-write-skew-scc - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-10-02T16:15:27.649Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement Serializable Snapshot Isolation validation for an in-memory MVCC store that hands every transaction a snapshot at begin time. Given committed transaction records (snapshot epoch, read set with versions, write set with versions, commit order), build the rw-antidependency and wr-dependency graph and abort exactly the transactions that participate in a dangerous structure (a pivot with an incoming rw edge from an earlier transaction and an outgoing rw edge to a later one) that closes a cycle under commit order. The answer must expose Begin/Read/Write/Commit/TryCommit primitives plus a Validate(committed []Txn) []string that returns the minimal set of aborted transactions, preserving serializability and throughput by aborting only the later pivot when a cycle is unavoidable.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-mvcc-serializable-snapshot-write-skew-scc", "provider": "openrouter", "solved_at": "2026-10-02T16:15:27.658Z", "version": "1.26"}