feat(tern): shard-aware fail-closed drift guard on materialize#596
feat(tern): shard-aware fail-closed drift guard on materialize#596Kiran01bm wants to merge 3 commits into
Conversation
#535 removed the materialize-time drift guard because it rejected shard-scoped applies, leaving non-primary deployments to silently apply unreviewed DDL. Restore it shard-aware: compare the dispatched reviewed DDL against this deployment's re-plan restricted to the dispatch's shard, failing closed on any mismatch.
There was a problem hiding this comment.
Pull request overview
Reintroduces a fail-closed “materialize-time” drift guard for non-primary deployments in Tern, updated to support per-shard apply fan-out by comparing recomputed local plans against the dispatched (reviewed) DDL on a shard-aware basis.
Changes:
- Add shard-aware drift comparison utilities (exact multiset match keyed by namespace/shard/table/op/canonical DDL) plus VSchema parity checks for whole-deployment dispatches.
- Invoke the drift guard during apply-request plan materialization (non-primary path) to prevent applying reviewed DDL against drifted live schema.
- Add unit tests covering match, canonicalization tolerance, shard-scoped behavior, malformed shard scope, VSchema parity, and recompute errors.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pkg/tern/local_plan_drift.go | Implements shard-aware drift guard (multiset comparison + optional VSchema parity). |
| pkg/tern/local_plan_drift_guard_test.go | Adds unit tests for drift guard behavior across sharded/non-sharded and VSchema cases. |
| pkg/tern/local_client.go | Calls drift guard during plan materialization from dispatch requests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
canonicalDDLForDrift relied on helpers that canonicalize only the first parsed statement, so a multi-statement payload could mask drift on the trailing statements. Enforce exactly one statement.
|
Review summary Verified the property #535 was worried about: the shard key is symmetric across the comparison. Both sides of the multiset read the shard from the same A few non-blocking items:
Verdict: LGTM with nits — the shard-key symmetry holds, it restores the reviewed-DDL boundary it set out to, and it doesn't constrain a future shard-drift reconciliation feature. Item 1 is the only one I'd push to land with the merge. 🤖 This review was generated by Claude Code (claude-opus-4-8) with maintainer approval. |
Summary
Restores the materialize-time drift guard that was removed in #535, this time shard-aware. A non-primary deployment that never planned locally must not silently apply the primary's reviewed DDL against a schema that has drifted; this re-adds the fail-closed check, now compatible with per-shard apply fan-out.
What
(namespace, shard, table, operation, canonical DDL).Why
#535 deleted the guard because it rejected shard-scoped applies, which were incompatible with per-shard fan-out. The interim reconciliation (re-plan at apply/resume) is not fail-closed: it silently completes drifted tables or applies locally recomputed DDL that no reviewer saw, breaking the "what gets applied is what was reviewed" boundary on every non-primary deployment. Making the comparator shard-aware lets the guard return.