Orchestrata Ultimate › Gates › fleet-drift
Gate: fleet-drift (ADR-0077)
| Purpose | Detect drift between the OpenTofu declaration and the live Incus fleets, and between terraform and the committed env/*.env endpoints, "instead of discovered" |
| Where it runs | scripts/check_infra_drift.py: the user unit orchestrata-infra-drift.service on orchestrata-infra-drift.timer (hourly), and scripts/health_check.py. scripts/check_env_fleet_agreement.py: the orchestrata arm of deploy/ship.sh verify |
| Trigger | The timer; every ship of orchestrata-ultimate |
| Exact command | /opt/orchestrata/.venv/bin/python /opt/orchestrata/scripts/check_infra_drift.py --report /var/lib/orchestrata/terraform/drift-latest.json (unit ExecStart); uv run python scripts/check_env_fleet_agreement.py (ship) |
| Blocks | Infra drift: exit 1 on drift, bridge drift, a missing state, no usable binary, or an init, plan or output error; a failed drift unit then fails the promote's verify stage. Env agreement: exit 1 fails the ship with "env files drifted from terraform" |
| Ruling / ADR | ADR-0077 item 4 ("missing is FAIL, never skip"); related: RUL-003 (configuration from env files) |
Both gates were added on 2026-10-08: the drift gate and its timer in f2cef12cb
("execute ADR-0077 — every Incus environment imported into OpenTofu, zero-diff, drift
gate + timer"), the agreement gate in 96087d9ce and its ship wiring in 8d6a282dc.
Infra drift: check_infra_drift.py
From the module docstring (AST toolkit, 2026-10-23):
tofu plan -detailed-exitcodeoverinfra/terraform: exit 0 is zero-diff, exit 2 is drift ("a container, bridge, ACL or profile no longer matches the declaration"), anything else is a tool error.- The three bridge keys the provider never writes to state (
ipv4.address,ipv4.nat,ipv6.address) are proven live withincus network getagainst the root'sbridge_expected_configoutput, "so the plan's silence on them is never mistaken for proof".
Verdicts, as run_gate writes them into the JSON report: zero-diff (exit 0),
no-root (exit 0 with a NOTE, for a checkout with no IaC root), missing-state,
no-binary, init-error, drift, plan-error, bridge-drift (all exit 1). "A missing
state is a failure, never a skip: the September state was lost to a worktree gc and
nothing noticed."
Measured state, 2026-10-23. orchestrata-infra-drift.timer is disabled and
inactive. The last report, /var/lib/orchestrata/terraform/drift-latest.json, was
written at 2026-10-22T19:01:27+00:00: verdict drift, plan_exit 2, 18 drift lines, no
bridge drift, binary ~/bin/tofu. The session's improvement log records the history as
finding F5: the gate "has been red since 2026-10-20 10:00 (last pass 09:02); its timer
then stopped firing until the promote's assets stage re-armed it, and with
Persistent=true it fired at once and failed the promote's verify stage." The planned
correction: 3 to add (prolog node-1..3), 14 to change. The causes are listed on the
Deployment page.
Env agreement: check_env_fleet_agreement.py
env/test.env, env/dev.env and the TEST_* keys of .env.example are derived from
tofu output -json by infra/gen_env.py. The gate (FleetAgreementGate.check)
re-derives them for the test and dev profiles and fails on:
- an owned key whose committed value differs from the derived one;
- an owned key that is commented out (
# KEY=...) or absent; - a
<profile>_fleet_endpointsterraform output that disagrees with the derivation; - a missing
tofubinary or a missing or empty state.
The prod profile is not gated: env/prod.env "deliberately routes through the
coordinators". Why it exists, from the docstring: on 2026-10-08 .env.example had carried
TEST_MEMGRAPH_URI on the retired prod-bridge address for two months with nothing
checking it; and the 2026-09-21 CHANGEME sweep had commented TEST_MEMGRAPH_URI out of the
host .env.
Output: one FAIL: <file>: <KEY>: declared '<value>', derived '<value>' line per
violation, or env/fleet agreement OK: test, dev derived from terraform match their committed files and .env.example. Every recorded ship log of 2026-10-22 read for these
pages (orch_ship10 to orch_ship14_promote, ship15_nopromote) printed the OK line.
Typical failures and how to fix them
| Symptom | Fix |
|---|---|
DRIFT: ... lines from the drift gate |
The infra/README.md rule: "A diff means the .tf must change to match reality - never the reverse." Change the .tf, or apply a change Mohamed ruled |
MISSING STATE: ... the fleet is not imported |
Run infra/terraform/import.sh (ADR-0077 items 3–4); the state lives at /var/lib/orchestrata/terraform/fleet.tfstate, never in a checkout |
no OpenTofu |
Set $TOFU, put tofu on PATH, or install a terraform at or above the 1.6.0 floor |
| A promote fails its verify stage on the drift unit | The drift gate is red (F5 above); fix the drift, not the promote |
| Ship fails "env files drifted from terraform" | uv run python infra/gen_env.py --profile test --write env/test.env (the ship message); never hand-edit a derived key |
Related
- Gates — master index
- Gate: ship-verify
- Gate: env-subnet-scheme, Gate: env-contract
- Deployment (OpenTofu deploy and the drift timer)
- scripts.check_infra_drift reference
- Workflow improvements (open item F5)
- ADR-0077