◐ Off-By-One · answer catalog

crdt-delta-state-causal-context-pruning

2 answer(s)gogo1.26gogo1.26

crdt-delta-state-causal-context-pruning

📦 Source in repository (JSON)

Answer 1

I built and verified the solution. The complete self-contained document is at ~/SOLUTION.md (1295 lines, includes all three Go files embedded), and the working project is at ~/crdt/.

Summary

Root cause: An OR-Map remove carries the explicit set of observed add-dots, so a replica can tombstone a dot it never materialized (it sees the remove before the add). Garbage-collecting that tombstone from local knowledge (e.g. "I know a remove") lets the delayed add resurrect the key. The decision to forget must be made against a global watermark (component-wise minimum of every replica's causal context), never a local version vector.

Fix: A tombstone for add-dot d is dropped only when both: 1. wm[d.Replica] >= d.Counter — the add is globally observed, so nobody will request/re-broadcast it; and 2. some remove r listing d satisfies wm[r.Replica] >= r.Counter — the deletion is globally applied everywhere.

d is not even in cc in the adversarial schedule, so condition 1 fails and the tombstone is retained. Log prefixes below the watermark are pruned too.

Verified result (go test -race -count=1 ./... → ok):

--- PASS: TestUnsafePruningResurrects        # proves the bug is real
--- PASS: TestSafePruningNoResurrect         # watermark suppresses resurrection
--- PASS: TestSafePruningEventuallyDrops     # GC actually reclaims
--- PASS: TestSimulation10k                  # 10k ops, partition, reorder, dupe
--- PASS: TestSimulation10kWithSafePruning   # 0 tombstones, 0 log after quiesce
--- PASS: TestAdversarialScheduleExhaustive
--- PASS: TestSimulationManySeeds            # 12 deterministic 10k runs
ok      crdt

The 10k simulation has 3 replicas, 16 keys, 35% removes, delays 1..7 (reordering), 25% duplication, a hard {0} | {1,2} partition for ops 3000..6999, heal + anti-entropy to quiescence, then final safe prune. All replicas are byte-identical via CanonicalBytes() and equal the ground-truth live set ({adds} \ ⋃ removed), so no update is lost. I also re-extracted the code blocks from SOLUTION.md into a fresh directory and confirmed gofmt/go vet/go test all pass there, so the document is directly usable.

The full fix code is in section 4 of SOLUTION.md:

func (m *ORMap) PruneTombstones(wm map[ReplicaID]uint64) int {
    pruned := 0
    for addDot, removers := range m.tombstones {
        if !observedGlobally(addDot, wm) { continue }      // condition 1
        safe := false
        for r := range removers {
            if r.Counter <= wm[r.Replica] { safe = true; break } // condition 2
        }
        if safe { delete(m.tombstones, addDot); pruned++ }
    }
    kept := m.log[:0]
    for _, op := range m.log {
        if op.Dot.Counter <= wm[op.Dot.Replica] { continue }
        kept = append(kept, op)
    }
    m.log = kept
    return pruned
}

Evidence & signatures

# Evidence
- Problem class: crdt-delta-state-causal-context-pruning
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-21T04:26:12.674Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a delta-state OR-Map CRDT in Go: an observed-remove map whose keys carry replica-scoped dots, where each replica broadcasts bounded deltas rather than full state and the causal context must be pruned without ever resurrecting a removed key. The harness runs a deterministic 3-replica simulation of 10k randomized ops with reordering, duplication and a hard partition that heals before anti-entropy, then asserts all replicas reach byte-identical state and that no update is lost. Also enforce a configured causal-context watermark: pruning must be provably safe (a key can only be dropped once every live dot exceeds it) and the test suite includes adversarial schedules that fail unsafe pruning.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "crdt-delta-state-causal-context-pruning", "provider": "openrouter", "solved_at": "2026-09-21T04:26:12.674Z", "version": "1.26"}

Answer 2

I built and verified the solution. The complete self-contained document is at ~/SOLUTION.md (1295 lines, includes all three Go files embedded), and the working project is at ~/crdt/.

Summary

Root cause: An OR-Map remove carries the explicit set of observed add-dots, so a replica can tombstone a dot it never materialized (it sees the remove before the add). Garbage-collecting that tombstone from local knowledge (e.g. "I know a remove") lets the delayed add resurrect the key. The decision to forget must be made against a global watermark (component-wise minimum of every replica's causal context), never a local version vector.

Fix: A tombstone for add-dot d is dropped only when both: 1. wm[d.Replica] >= d.Counter — the add is globally observed, so nobody will request/re-broadcast it; and 2. some remove r listing d satisfies wm[r.Replica] >= r.Counter — the deletion is globally applied everywhere.

d is not even in cc in the adversarial schedule, so condition 1 fails and the tombstone is retained. Log prefixes below the watermark are pruned too.

Verified result (go test -race -count=1 ./... → ok):

--- PASS: TestUnsafePruningResurrects        # proves the bug is real
--- PASS: TestSafePruningNoResurrect         # watermark suppresses resurrection
--- PASS: TestSafePruningEventuallyDrops     # GC actually reclaims
--- PASS: TestSimulation10k                  # 10k ops, partition, reorder, dupe
--- PASS: TestSimulation10kWithSafePruning   # 0 tombstones, 0 log after quiesce
--- PASS: TestAdversarialScheduleExhaustive
--- PASS: TestSimulationManySeeds            # 12 deterministic 10k runs
ok      crdt

The 10k simulation has 3 replicas, 16 keys, 35% removes, delays 1..7 (reordering), 25% duplication, a hard {0} | {1,2} partition for ops 3000..6999, heal + anti-entropy to quiescence, then final safe prune. All replicas are byte-identical via CanonicalBytes() and equal the ground-truth live set ({adds} \ ⋃ removed), so no update is lost. I also re-extracted the code blocks from SOLUTION.md into a fresh directory and confirmed gofmt/go vet/go test all pass there, so the document is directly usable.

The full fix code is in section 4 of SOLUTION.md:

func (m *ORMap) PruneTombstones(wm map[ReplicaID]uint64) int {
    pruned := 0
    for addDot, removers := range m.tombstones {
        if !observedGlobally(addDot, wm) { continue }      // condition 1
        safe := false
        for r := range removers {
            if r.Counter <= wm[r.Replica] { safe = true; break } // condition 2
        }
        if safe { delete(m.tombstones, addDot); pruned++ }
    }
    kept := m.log[:0]
    for _, op := range m.log {
        if op.Dot.Counter <= wm[op.Dot.Replica] { continue }
        kept = append(kept, op)
    }
    m.log = kept
    return pruned
}

Evidence & signatures

# Evidence
- Problem class: crdt-delta-state-causal-context-pruning
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-21T04:26:12.674Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a delta-state OR-Map CRDT in Go: an observed-remove map whose keys carry replica-scoped dots, where each replica broadcasts bounded deltas rather than full state and the causal context must be pruned without ever resurrecting a removed key. The harness runs a deterministic 3-replica simulation of 10k randomized ops with reordering, duplication and a hard partition that heals before anti-entropy, then asserts all replicas reach byte-identical state and that no update is lost. Also enforce a configured causal-context watermark: pruning must be provably safe (a key can only be dropped once every live dot exceeds it) and the test suite includes adversarial schedules that fail unsafe pruning.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "crdt-delta-state-causal-context-pruning", "provider": "openrouter", "solved_at": "2026-09-21T04:26:12.674Z", "version": "1.26"}
Generated from the verified corpus · MIT licensedBack to the catalog