Appendix B - 9. Drift & parity gates
The Structure of Drift & parity gates — its shape at a glance:
The gate reads the model and enumerates reality, then checks the two set-inclusions that together make parity: model ⊆ reality (no phantom rows) and reality ⊆ model (nothing on disk goes unmodeled). Either direction failing turns the gate red.
flowchart LR
M[(Typed model)] --> G{Parity gate}
R[(Reality on disk)] --> G
G -->|model ⊆ reality<br/>and reality ⊆ model| Pass([build proceeds])
G -->|either side diverges| Fail([build blocked])
Accessible description: the parity gate takes two inputs — the typed model and the enumerated reality on disk. It checks both inclusions: every model row exists in reality, and every real thing is modeled. When both hold the build proceeds; when either side diverges the build is blocked.
Projected from the catalogue entry system-models / Drift & parity gates.
On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns
Intent
Intent — The fleet of lints and tests that enforce bidirectional parity between each model and reality (every model row ↔ a real thing on disk, and every real thing ↔ a model row), so the models cannot drift.
Motivation
An executable model is only trustworthy if it stays true. The failure this kills is silent model drift: the model says one thing, the code does another, and everything downstream (dispatch, codegen, deploy) reasons from a lie. Because the model looks authoritative, drift is worse than absence. It recurs whenever code changes without the model, or the model changes without the code.
Applicability
- A machine-readable model + a machine-readable reality to compare (the code, the deploy tables, the real trees, the
flocksites). - A bidirectional predicate — both "model ⊆ reality" and "reality ⊆ model," or one side drifts.
- Blocking placement in the gates, or drift is merely reported.
Structure
The Structure diagram appears at the top of this page.
Sample Code
The gate is a set comparison run in both directions. Read the model into a set of expected keys, enumerate reality into a set of actual keys, and fail if either set has a member the other lacks. The two directions are the whole point: one direction alone lets the other side drift undetected.
import sys
def parity_gate(model_keys: set[str], reality_keys: set[str]) -> list[str]:
"""Bidirectional parity: every model row must exist on disk, and every real
thing must be modeled. Either half failing is drift."""
findings = []
for missing in sorted(model_keys - reality_keys):
findings.append(f"model row '{missing}' has no match on disk (phantom row)")
for unmodeled in sorted(reality_keys - model_keys):
findings.append(f"'{unmodeled}' exists on disk but is absent from the model")
return findings
if __name__ == "__main__":
# `load_model` reads the source-of-truth; `scan_reality` enumerates the world it describes.
findings = parity_gate(load_model(), scan_reality())
for f in findings:
print(f"DRIFT: {f}")
sys.exit(1 if findings else 0) # blocking: any drift fails the build
Consequences
- A gate per model to author + maintain — real breadth of enforcement surface.
- Bidirectional is stricter — it catches more, and also fails more often on legitimate transitions (which is the point: the transition must update both sides).
- A wrong parity predicate produces false drift or false confidence.
Example use within DocAble
- The service-flow, public-API-drift, service-call-graph-drift, and deploy-phase-table parity lints; the k8s parity lints; the sync-coverage lint.
- The model↔tree reverse-mapping tests.
Related Patterns
- Counterpart — of every model here: component-zone · synchronization · service-flow · … each typed model (construction) is held true by its drift gate (the counted sensor). This is the family's pervasive construction-held-by-detection pairing.
- See also (sibling) — the product coherence-lints: the same relational-invariant idea, there across product sources, here across model↔reality.