Skip to content

feat(sync): seal clamps the HLC physical candidate to server date + MAX_DRIFT (T13314) - #1969

Merged
kryptobaseddev merged 7 commits into
mainfrom
feat/T12343-seal-clock-clamp
Oct 11, 2026
Merged

kryptobaseddev merged 7 commits into
mainfrom
feat/T12343-seal-clock-clamp

Conversation

@kryptobaseddev

Copy link
Copy Markdown
Owner

Task: T13314

Stacked on #1957 (feat/T12343-push). It is a leaf beside #1959, which only touches push.ts's precondition block.

Problem

Spec §1.3, "Local clock ahead": push pauses when this device's clock runs more than MAX_DRIFT ahead of the server's date. But the clamp the spec also requires, "sealing clamps the physical candidate to min(at_ms, serverDate + MAX_DRIFT) when a server date from the last 24 h is known", was missing. Captures stamped while the clock was ahead sealed with future HLCs as soon as the clock was corrected and push resumed. A future HLC wins every LWW race on every replica.

Change

  • push.ts: whenever push has a server offset, it records sync.server_clock = {offsetMs, atMs} before the drift check. markClockAhead becomes setPushMeta(key, value|null), so the gate-28 count is unchanged (one INSERT, one DELETE).
  • clock-store.ts: sealWallCeiling(db, nowMs, maxDriftMs) returns nowMs + offsetMs + MAX_DRIFT. It returns null (unclamped) when the record is missing, fails the zod check, or is more than 24 h old (SERVER_CLOCK_TTL_MS).
  • sealer.ts: it computes the ceiling once per seal transaction and ticks each op at min(at_ms ?? now, ceiling). tick still takes max(last.phys, wall), so HLCs stay monotonic.

Known limit, as the spec defines it: a recorded offset older than the current push, still under 24 h, can clamp captures after the device's clock is corrected. Push re-records the offset before every seal it runs, so this only affects seals outside push.

Tests (push.test.ts)

  • A capture stamped 1 h ahead, pushed with a fresh server offset of 0: sync.server_clock is recorded, and every op's HLC phys is ≤ serverNow + MAX_DRIFT.
  • No observation, then an observation older than 24 h: the op phys equals the capture's at_ms (unclamped).

Verification

  • Mutations (4 of 4 killed): no clamp, no TTL, push not recording, margin ×100.
  • Tests: the files importing the sealer, push and clock-store pass, 226 of 226. nexus-vault.test.ts passes, 100 of 100.
  • Typecheck: core src tsc is clean, and push.test.ts typechecks.
  • Biome: clean.
  • Gates: 28, 36, 37, 38 (--base origin/feat/T12343-push), 40 and 32 pass; lint-changesets passes.

🤖 Generated with Claude Code

kryptobaseddev and others added 6 commits October 6, 2026 20:44
…AX_DRIFT (T13314)

Spec §1.3 "Local clock ahead": sealing clamps the physical candidate to
min(at_ms, serverDate + MAX_DRIFT) when a server date from the last 24 h
is known. Captures stamped while the clock ran ahead used to seal with
future HLCs once push resumed.

- push records sync.server_clock {offsetMs, atMs} whenever it has a
  server offset (setPushMeta replaces markClockAhead; gate 28 count
  unchanged).
- clock-store sealWallCeiling(db, now): now + offset + MAX_DRIFT, or null
  when the observation is missing, unreadable or older than 24 h.
- the sealer computes the ceiling once per seal transaction and ticks
  each op at min(at_ms or now, ceiling).

Tests: an hour-ahead capture after a fresh server date seals at or below
serverNow + MAX_DRIFT; with no observation or a stale one it seals at its
at_ms. Mutations killed: no clamp, no TTL, no record, wrong margin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the stale offset (T13314 review LOW)

When nowMs < atMs the clock was corrected after the observation; using the
stale negative offset would stamp seals outside push up to |offset| in the
past for a day. sealWallCeiling now returns null then. Test: an observation
dated after now leaves sealing unclamped; removing the guard fails it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from feat/T12343-push to main October 10, 2026 21:17
@kryptobaseddev
kryptobaseddev merged commit 8dc0620 into main Oct 11, 2026
103 checks passed
@kryptobaseddev
kryptobaseddev deleted the feat/T12343-seal-clock-clamp branch October 11, 2026 01:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant