Harden the reconcile gate + retire shadow-recovery scaffolding (DEPLOY-GATED)#151
Harden the reconcile gate + retire shadow-recovery scaffolding (DEPLOY-GATED)#151Stvad wants to merge 1 commit into
Conversation
… scaffolding The "fully move" off the Layout-B recovery machinery, now that it's safe: shadows can no longer form (mints are 0-stamped) and the legacy population was reconciled by the recovery rollout (validated ~0 fleet-wide). - decideStagingRow: restore newer-OR-equal nonzero-local skip-stale (was equal-only). Under server-enforced updated_at monotonicity an older-or-equal staging stamp is a stale delivery, so a nonzero local row at-or-above it is authoritative — protect it. This kills the transient DISK clobber too (not just the cache flash that 4e4037fd fixed): a strictly-newer local edit facing a stale rescan replay is no longer reverted on disk. The `!== 0` exemption keeps the deterministic-id heal + cross-device convergence (0-stamped yields). This restores the protection e7fc79b had to relax when speculative defaults were minted with a real `now` stamp — the 0-sentinel makes it unnecessary now. - Retire scheduleReconcileRescan / runReconcileRescan / awaitReconcileRescans + the reconcile_rescan_v1: marker (clientSchema + createTestDb cleanup) + the App.tsx on-open call. The rescan only healed shadows via the INDISCRIMINATE gate; with the gate hardened it can't heal nonzero shadows anyway, and there are none left — so it's dead weight (and a per-workspace first-open re-scan cost). drainSyncWorkspace stays (e2ee-unlock re-materialization). - Tests flipped to the protected behavior (reconcile / materialize / observer / the ack-to-echo freeze canary); removed the rescan lifecycle suite. DEPLOY-GATED: this is the irreversible-ish step (a hardened gate strands any still-unhealed nonzero shadow on a device we couldn't inspect, e.g. mobile, and is incompatible with a future *zeroing* system: cleanup). Land only after a coordinated drain + confirming every device has converged on the new bundle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a38e8e5f82
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if ( | ||
| local.localUpdatedAt !== null && | ||
| local.localUpdatedAt === stagingUpdatedAt && | ||
| local.localUpdatedAt >= stagingUpdatedAt && |
There was a problem hiding this comment.
Allow server-clamped echoes to replace fast-clock stamps
When the editing device's clock is ahead, the upload echo can come back with a lower updated_at than the local row: local txs stamp from Date.now(), while blocks_clamp_updated_at future-clamps NEW.updated_at to server time before flooring/bumping (supabase/migrations/20260612000000_add_user_updated_at_monotonic_clamp.sql lines 31-37). With this >= check, that authoritative echo is consumed as skip-stale, leaving the local row pinned at the future stamp; subsequent collaborator/server edits whose server stamps are below that future value will also be ignored until wall-clock time catches up.
Useful? React with 👍 / 👎.
One-time §7 cleanup: strip the system: author prefix and re-stamp 787 legacy pre-c0d606f6 mint rows to the updated_at=0 pristine sentinel, so they re-replicate and converge every device (incl. shadows on uninspectable clients) via the gate's stamp-0 exemption. Transactional (clamp+history triggers toggled off so the 0 lands); backup table for rollback. Must run + converge BEFORE PR #151 merges. Held for a drain window. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Warning
DO NOT MERGE YET — deploy is order-gated. Merging auto-deploys the client bundle. The hardened gate must NOT ship until the
system:zeroing cleanup has run and converged on every device (incl. Weave/e2ee and mobile). See the checklist below.What this does (the "fully move" off Layout-B recovery scaffolding)
Now safe to do: shadows can no longer form (mints are 0-stamped) and the legacy population was reconciled by the recovery rollout (validated ~0 strictly-newer shadows fleet-wide via the bridge).
decideStagingRow: restore newer-OR-equal nonzero-local skip-stale (was equal-only). Under server-enforcedupdated_atmonotonicity an older-or-equal staging stamp is a stale delivery, so a nonzero local row at-or-above it is authoritative — protect it. This kills the transient disk clobber too (not just the cache flash that the prior fix addressed): a strictly-newer local edit facing a stale rescan replay is no longer reverted on disk. The!== 0exemption keeps the deterministic-id heal + cross-device convergence (0-stamped yields). Restores the protectione7fc79b2had to relax when speculative defaults were minted with a realnowstamp — the 0-sentinel makes it unnecessary now.scheduleReconcileRescan/runReconcileRescan/awaitReconcileRescans, thereconcile_rescan_v1:marker (+ test-DB cleanup), and the App.tsx on-open call. The rescan only healed shadows via the indiscriminate gate; with the gate hardened it can't heal nonzero shadows anyway, and there are none left — so it's dead weight (and a per-workspace first-open re-scan cost).drainSyncWorkspacestays (e2ee-unlock re-materialization).yarn run checkgreen (3209 tests).Why it's deploy-gated
system:cleanup. That cleanup heals by zeroing (updated_at = 0); a 0-stamped server row only lands on a client whose local copy is nonzero when the gate is indiscriminate. The hardened gate here would skip-stale it (local_nonzero >= 0) → never heals. So the zeroing must run + fully propagate before this merges. (787system:rows server-side, 779 in the e2eeWeaveworkspace.)Merge checklist
system:zeroing cleanup executed (clamp trigger disabled so 0 lands;e2ee_plaintext_risk = 0confirmed)ps_crud → 0) and the 787 zeroed rows converged everywhere (incl. Weave + mobile)diverged_strictly_newercheck on each reachable device returns 0🤖 Generated with Claude Code