Skip to content

reconcile drift

When the 30-min state-sweep reports contract_drift=true for a registered consumer, the consumer’s .petrova/contract.yaml has moved ahead of (or behind) the contract_sha recorded in registry.yaml > repos[<slug>]. The petrova_act_reconcile_drift verb realigns the registry to match the consumer’s source of truth, recording the realignment in a dated ADR. The substantive contract change is the consumer’s responsibility and is captured in their git history — the verb only records that the control plane has acknowledged it.

This is a control-plane self-edit. The PR is opened against petrova-codes/petrova:main with labels registry-edit + awaiting-human-merge and does not auto-merge (MR-12).

  • /console/phases shows the slug in the contract_drift=true chip, and
  • The state-sweep that generated that signal is recent (≤60 min old) — the verb refuses on stale data.

If the sweep is stale, trigger a fresh one first:

Terminal window
gh workflow run state-sweep.yml -R petrova-codes/petrova
# or, locally:
npx petrova-cli sweep-state --apply
Terminal window
yq '.contract_drift, .actual_contract_sha, .last_full_sweep' \
state/<slug>.yaml

You want true, a 12-char hex SHA, and a timestamp within the last hour.

Terminal window
echo '{"slug":"<slug>"}' | \
petrova petrova_act_reconcile_drift petrova-codes

Review the dry-run output:

  • before_contract_sha / after_contract_sha match what state/<slug>.yaml reports.
  • diff_preview.files contains exactly two entries: registry.yaml (modify) and a dated ADR (create).
  • diff_preview.branch is petrova/registry-edit/petrova_act_reconcile_drift/<slug>.
Terminal window
echo '{"slug":"<slug>"}' | \
petrova petrova_act_reconcile_drift petrova-codes --apply

Returns the PR URL. The PR will not auto-merge — review it and gh pr merge --merge by hand.

After the PR merges:

Terminal window
git -C ~/code/workspace/petrova-codes pull
gh workflow run state-sweep.yml -R petrova-codes/petrova
# wait ~60s, then:
yq '.contract_drift' state/<slug>.yaml # should now be `false`

If contract_drift is still true, the consumer pushed another contract change between the dry-run and the sweep. Repeat from step 1.

CodeMeaningFix
SLUG_NOT_IN_REGISTRYNo state/<slug>.yaml — slug isn’t registered or has never been sweptUse petrova_act_register_consumer first
STALE_SWEEP_REPORTlast_full_sweep > 60 min oldTrigger a fresh sweep, retry
NO_DRIFT_DETECTEDcontract_drift is false/null, or actual_contract_sha is nullNothing to do; the chip is stale, refresh the dashboard
REGISTRY_VALIDATION_FAILEDThe new SHA fails registry schema (e.g. wrong length)Inspect state/<slug>.yaml; the sweep wrote a bad value

Before TASKSET 5b, the drift signal had no actor. The dashboard could surface drift but the only way to clear it was a hand-edited PR against registry.yaml. That friction caused several stale entries in the registry. This verb closes the loop: signal → verb → PR → human-merge → cleared signal — all without manual YAML editing, and with a permanent ADR trail per MR-7.

The verb targets petrova-codes itself. MR-12 (control-plane firewall) requires every change to the registry to pass human review. The awaiting-human-merge label is the firewall — agent fleets and automation can compose the PR, but a human always merges it.