the reconciler: the declared forge, read back and made so #37

Merged
larandar merged 2 commits from agent.teyla/Jostoph:tango/33-the-reconciler into main 2026-08-13 07:22:46 +00:00
Contributor

The engine #34 exposed as missing: the estate had a declaration (nix/forgejo.nix renders it), it had findings (#33 measured the drift by hand), and it had nothing between them — so drift got fixed the way drift always gets fixed without an engine, by a person with an API call.

jostoph conform --spec /etc/jostoph/forgejo-repos.json --api … --token-file …:

  • reads the rendered desired state and the live forge, and names every field where they disagree — repo settings field-for-field in Forgejo's own names, org labels split into create/update/undeclared. Report mode is read-only, exits 1 on drift.
  • --apply performs exactly the edits the report names (settings PATCHed one request per repo, labels created or updated by the forge's own id), then observes again and reports what still drifts — the proof is the forge, not the request log.
  • Add-and-repair, never delete: an absent repo is a finding, not a creation (birth is an act, law 12); an undeclared label is a question for a person and does not block the apply. Webhooks, push mirrors, deploy keys stay with the nixops4 provider — forge-assigned identity is state, which is requireState.

Run against the live forge in report mode, it reproduces #33's findings mechanically: 40+ drifted settings fields across the estate, and Ting's six declared org labels all absent.

Rides on tango/28-steward-conformance (a9a4627, in review as it lands). The first commit fixes a test that is red on main today: every_finding_lands_in_one_commentstatus_effect was declared per conclusion expecting downstream dedup that doesn't happen, so two findings declared two identical comments. It now rides exactly one conclusion (agg-min reason, deterministic), and the body already carries them all.

nix flake check fully green (it was not on main); cargo fmt/clippy -D warnings clean.

Note on base: this branch includes a9a4627 (tango/28), which is pushed but had no PR yet — review that commit there or here as you prefer.

In scope: the conform engine, its CLI, the spec on disk via the module, the one-comment fix. Out of scope: performing ruling effects (the executor, #26), branch protections (#32), repo/branch creation. Boundary: src/reconcile.rs + CLI wiring; one derivation fix in src/policy.rs; module ships a file. Acceptance: report reproduces #33's measurements; apply is idempotent by re-observation; tests green.

Closes #33.

The engine #34 exposed as missing: the estate had a declaration (`nix/forgejo.nix` renders it), it had findings (#33 measured the drift by hand), and it had nothing between them — so drift got fixed the way drift always gets fixed without an engine, by a person with an API call. `jostoph conform --spec /etc/jostoph/forgejo-repos.json --api … --token-file …`: - reads the rendered desired state and the live forge, and names every field where they disagree — repo settings field-for-field in Forgejo's own names, org labels split into create/update/undeclared. Report mode is read-only, exits 1 on drift. - `--apply` performs **exactly the edits the report names** (settings PATCHed one request per repo, labels created or updated by the forge's own id), then observes again and reports what still drifts — the proof is the forge, not the request log. - Add-and-repair, never delete: an absent repo is a finding, not a creation (birth is an act, law 12); an undeclared label is a question for a person and does not block the apply. Webhooks, push mirrors, deploy keys stay with the nixops4 provider — forge-assigned identity is state, which is `requireState`. Run against the live forge in report mode, it reproduces #33's findings mechanically: 40+ drifted settings fields across the estate, and Ting's six declared org labels all absent. Rides on `tango/28-steward-conformance` (a9a4627, in review as it lands). The first commit fixes a test that is red on `main` today: `every_finding_lands_in_one_comment` — `status_effect` was declared per conclusion expecting downstream dedup that doesn't happen, so two findings declared two identical comments. It now rides exactly one conclusion (agg-min reason, deterministic), and the body already carries them all. `nix flake check` fully green (it was not on `main`); `cargo fmt`/`clippy -D warnings` clean. Note on base: this branch includes a9a4627 (`tango/28`), which is pushed but had no PR yet — review that commit there or here as you prefer. In scope: the conform engine, its CLI, the spec on disk via the module, the one-comment fix. Out of scope: performing ruling effects (the executor, #26), branch protections (#32), repo/branch creation. Boundary: `src/reconcile.rs` + CLI wiring; one derivation fix in `src/policy.rs`; module ships a file. Acceptance: report reproduces #33's measurements; apply is idempotent by re-observation; tests green. Closes #33.
law 13's states and overlays) as org labels in the desired-state document,
and nix/policy.nix refuses at eval time to read a label the estate does not
declare.

policy's memberships, both directions, read-only, exit 1 on drift. Wired as
an optional oneshot-on-a-timer in the module, holding a token the answering
service never sees. Verified against the live forge: names agent.teyla as
active-but-undeclared.

versus Policy::kinds_read(). An empty record is the loudest finding; the
first real approval delivery names the approval_kinds spelling to keep.

torn lines skipped without poisoning the record. serve --audit-log tees it
behind the ring, so /v1/audit answers across a restart and the executor
(#26) has a record to start from. StateDirectory=jostoph in the module.
larandar approved these changes 2026-08-12 03:33:15 +00:00
larandar force-pushed tango/33-the-reconciler from ab98b36370 to 7ae6889d44 2026-08-13 06:12:35 +00:00 Compare
larandar deleted branch tango/33-the-reconciler 2026-08-13 07:22:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Ting/Jostoph!37
No description provided.