Repository navigation
Description
Summary
New guardrail pattern beyond the existing A–J set: SSOT sync drift. An implementation changes one authoritative artifact (migration, contract, version pin) but forgets the mirror(s) that must end in the same final state. The existing CI contract check correctly fails — but only at PR time, after the implementation already shipped the half-change.
Trigger incident (2026-08-03, Grift PR anomalyco#1761)
Issue anomalyco#1719 asked to drop the now-unused index idx_conversation_turns_case (L-1). The implementer:
- ✅ Added migration
000060_drop_idx_conversation_turns_case.up.sql(DROP INDEX) - ❌ Left
packages/contracts/initial-schema.sql(SSOT) still CREATE-ing the same index - ❌ Left the Alpha expected post-migration version pins at 59 across 4 files (
grift-deployment-policies.json,alpha_migration_preflight.go,check-v2-alpha-deployment-contract.mjs,v2-alpha-cd.yml)
Result: contract-validation (migrate-built DB vs initial-schema-built DB) failed correctly. The pipeline worked as designed; the implementation was half-synced.
Why this is NOT covered by A–J
| Pattern | Why not |
|---|---|
| A (impact/removal) | removal-guard blocks deletions that HAVE reverse references. This index had ZERO readers — that is exactly why it was dropped. No reference search can find the SSOT mirror because the mirror is not a "reference"; it is a duplicate definition. |
| F (falsification) | Not about test quality. The repo even has the check; the implementer just did not run it locally before pushing. |
| J (CI over-application) | Opposite: CI under-application is not the issue — the check exists and fired; the issue is local pre-PR enforcement. |
| B/C/D/E/G/H/I | Unrelated. |
The pattern (generalized)
When a change makes two or more artifacts that must agree on the SAME final state (schema DDL vs migrations, OpenAPI vs generated code, version pins in workflow/policy/preflight), the implementer updates one side and leaves the other(s) stale.
Common shapes:
- DB schema: migration DDL vs
initial-schema.sqlSSOT - API contract:
openapi.yamlvs generated clients / server stubs - Version pins: a version appears in N files (workflow, policy JSON, Go preflight, JS contract check); bumping it in one place is missed in others
- Replicated constants: the same value hardcoded in two languages
Proposed mechanism (mechanism over prose)
- CI wiring stays the source of truth — it already works. Add a local pre-push hook / command (
/ssot-checkor extend/plan-light) that runs the same "migrate-built vs SSOT-built" comparison the CI gate runs, so the drift fails locally instead of at PR time. - Plugin hook (K): detect when a tool call modifies files under a "mirror set" (e.g.,
services/*/migrations/*ORpackages/contracts/initial-schema.sql) and prompt: "this change touches a mirrored artifact — run the SSOT comparison now". Pure guidance, no block (avoid over-restriction, pattern I). - Version-pin wiring test: a test that enumerates every file declaring the expected migration version (workflow, policy, preflight, contract check) and asserts they are equal — this is the F-style CI wiring test applied to K.
- Skill:
ssot-syncskill (parallel toimpact-analysis) — before changing a mirrored artifact, grep the mirror set, update all, and run the comparison.
Acceptance evidence (per pattern I, prove no over-restriction)
- Negative: a migration change that ALSO updates the SSOT in the same commit passes with no warning.
- Positive: a migration-only change triggers the prompt and fails the local comparison.
- Falsification: disabling the guard allows the half-change through (existing CI still catches it, which is the safety net).
Scope
Fork-side packages/guardrails/profile/ plugin/command/skill + test. No upstream opencode changes required.
Refs
- Incident: Cor-Incorporated/Grift#1761, Opencode not loading, OTel bug? anomalyco/opencode#1719
- Related existing patterns: feat(guardrails): implement 8 anti-pattern guards in profile (plugin/command/permission/skill) #284 (A–J set), epic epic: internal AI guardrails thin distribution for Cor-Incorporated #1
Activity
terisuke commentedon Aug 3, 2026
実装マージ済み: #289
ssot-guard.ts: mirror set 片側変更 → 助言のみ(ハードブロックなし = I)/ssot-check+ skillssot-sync+ plan-light / ADR にパターン K 追記OPENCODE_SSOT_GUARD=off)ssot-guard.test.ts13 pass、local:checkgreenローカル検証は entrypoint が
.worktrees/cursor/ssot-sync-guardに pin されています。