Commit Graph

18 Commits

Author SHA1 Message Date
Joseph Doherty 3b7489a7b0 fix(localdb): a rebuilt peer's own writes were silently dropped
The other half of the rebuilt-peer story, and only reachable once 0.1.2 made
back-fill work: with the wiped node repopulated and writing again, its writes
never reached its peer.

last_applied_remote_seq is a watermark in the PEER's seq space, and a rebuilt
peer is a new database whose oplog numbers from 1. Two things then went wrong,
and both had to be fixed — the first alone leaves data stuck:

- The healthy node kept advertising the OLD peer's watermark, and the sending
  side seeds its pump from exactly that number, so the rebuilt node skipped its
  entire oplog. The watermark (and the observed peer clock) is now reset when
  the peer's node id changes. last_acked_seq is deliberately NOT reset: it
  describes our own oplog's pruned horizon and is what tells a rebuilt peer it
  needs a snapshot — clearing it would turn 0.1.2's back-fill back off.

- A peer claiming to have applied more of our stream than we have ever produced
  can only be remembering a previous incarnation of us. That claim is now
  rejected in favour of starting from the beginning; LWW makes the re-send
  harmless. This mirrors the clamp RecordPeerAckAsync already applies to acks.

Found on the OtOpcUa docker-dev rig, where the healthy node held watermark 10
while the rebuilt peer's oplog was seqs 1-3 and its last_acked stayed 0 — the
peer never accepted a single one. Covered by a test that converges with one
peer, replaces it with a fresh database, and requires a write on the new peer
to arrive: RED before this fix, green after. 149/149 pass.

Version 0.1.3.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
2026-07-21 02:06:03 -04:00
Joseph Doherty cad3bcb6bf fix(localdb): snapshot a wiped peer whose deltas were already acked and pruned
A converged pair prunes its oplog on ack, so "no oplog rows at all" is the
steady state of a healthy pair — not an anomaly. ComputeSnapshotRequiredAsync
measured the peer's gap against the oldest surviving oplog row and treated an
empty oplog as "no gap possible", which made that steady state the one state
from which a wiped peer could never be healed: it reconnected with an empty
database and a zero watermark, was told it needed no snapshot, and stayed
empty indefinitely.

With an empty oplog the oldest seq we could still stream is one past
last_acked_seq — ack-pruning is the only thing that empties the oplog without
also flagging needs_snapshot, and it deletes exactly seq <= last_acked_seq.
Measuring the gap against that heals the wiped peer and leaves every other
case identical: a converged peer's watermark equals last_acked_seq (no
snapshot), and a pair that has never written anything has both at zero.

Found by the OtOpcUa LocalDb Phase 1 live gate (check 4), which recorded it as
a documented limitation. Covered by a test that reproduces the live-gate
scenario through the real session stack: RED before this fix (the wiped side
never converges, 15 s timeout), green after. 148/148 pass.

Version 0.1.2.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
2026-07-21 01:17:32 -04:00
Joseph Doherty de65ca2b5d polish(localdb): final integration-review fixes — drift XML doc, trim core deps, metrics doc/encapsulation
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 01:20:08 -04:00
Joseph Doherty c5352f3ed8 feat(localdb): periodic oplog maintenance service (caps enforcement + tombstone pruning, both roles)
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 01:02:06 -04:00
Joseph Doherty eb40cd8f29 fix(localdb): telemetry review fixes — meter naming, snapshot status, session-count Connected
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 00:14:57 -04:00
Joseph Doherty be4ca76f5f feat(localdb): telemetry meters + ISyncStatus
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 00:03:39 -04:00
Joseph Doherty 8befebd476 fix(localdb): snapshot review fixes — MAX-guarded complete watermark, keyset pagination, phantom-row guard
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 23:50:42 -04:00
Joseph Doherty 130e9c918f feat(localdb): snapshot resync (LWW-merging, tombstone-carrying, delta resume)
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 23:35:50 -04:00
Joseph Doherty e92cdc6d3a fix(localdb): adapter review fixes — deterministic pump teardown, always-hosted initiator, backoff clamp
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 23:13:02 -04:00
Joseph Doherty a64fc26391 feat(localdb): gRPC sync adapters, background service, replication DI
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 23:01:29 -04:00
Joseph Doherty 183901e8ac test(localdb): pin drift-watermark branch; guard writer loop against completed-lane spin 2026-07-17 22:50:33 -04:00
Joseph Doherty 92ccbac8db fix(localdb): sync session concurrency fixes — two-lane writer, teardown fault fidelity, per-entry drift, gated snapshot seam 2026-07-17 22:44:42 -04:00
Joseph Doherty 925623b878 feat(localdb): SyncSession protocol state machine (handshake fail-closed, bidirectional delta pump) 2026-07-17 22:26:03 -04:00
Joseph Doherty b223507070 fix(localdb): applier review fixes — null-row_json guard, clock recovery via last_seen_hlc, fidelity + guard tests
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 22:15:51 -04:00
Joseph Doherty d7cbdce65c feat(localdb): LWW applier (hlc+node_id tie-break, applying guard, dead-letter, atomic watermark)
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 22:03:24 -04:00
Joseph Doherty 3cf8cabaf9 fix(localdb): oplog store review fixes — ack clamping, age-based pruning, monotonicity tests
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 21:55:25 -04:00
Joseph Doherty 529585163c feat(localdb): oplog store (batch read, ack watermark, pruning caps, tombstone retention)
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 21:45:20 -04:00
Joseph Doherty 61e5564c26 feat(localdb): scaffold ZB.MOM.WW.LocalDb (core/contracts/replication + tests)
Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-17 20:55:56 -04:00