feat(reconciler): event-driven trigger core (ADR 0037 phase 1) #238

Sammanfogat
supernaut sammanfogade 1 incheckning från feat/reconcile-trigger-core in i main 2026-07-28 21:39:11 +00:00
Ägare

Phase 1 (infra half) of the event-driven reconcile trigger — epic bitborg-docs#54, closes #235. Pairs with bitborg-web#97 (the triggerReconcile adapter).

Puts a prompt trigger in front of the existing reconciler without changing the reconciler: a systemd .path unit fires the oneshot when web writes a sentinel, so sign-up / trial / Renovate apply in seconds instead of waiting up to 5 min for the timer. The reconciler container unit + timer are untouched; the timer stays the backstop.

Changes

  • group_vars: shared reconcile_trigger_dir/reconcile_trigger_sentinel/reconcile_trigger_min_interval (web creates + mounts the dir since it starts before the reconciler role; the reconciler role installs the units).
  • web role: create the sentinel dir; bind-mount it rw; set RECONCILE_TRIGGER_PATH; add UserNS=keep-id:uid=1000,gid=1000 so node(1000) maps to gitborg and the host .path/kick (running as gitborg) can read + delete what web writes — the same trick the reconciler uses for its textfile mount.
  • reconciler role: bitborg-reconcile.path → debounced bitborg-reconcile-kick.service → starts the oneshot. Kick enforces a 30 s min-interval floor (coalesces bursts), removes the sentinel before the run (at-least-once-after-last-write), and never fails the kick on a reconcile error (ReconcilerFailed already covers that).

Validation

  • ansible-playbook --syntax-check ✓
  • ansible-lint (production profile) — 0 failures ✓
  • shellcheck on the rendered kick script ✓

⚠️ Operator-verify before apply (via the gated infra-apply flow — NOT applied here)

  • The web UserNS=keep-id addition recreates the web container on apply; confirm web comes back healthy (it's a read-only network app, so keep-id should be inert, but verify).
  • After apply: touch the sentinel as gitborg and confirm the reconciler fires within seconds (journalctl --user -u gitborg-reconcile-kick); confirm bursts coalesce to ~1 run / 30 s.
  • Confirm gitborg lingering is enabled (already required by the existing reconciler timer).
**Phase 1 (infra half)** of the event-driven reconcile trigger — epic bitborg-docs#54, closes #235. Pairs with bitborg-web#97 (the `triggerReconcile` adapter). Puts a prompt trigger in front of the existing reconciler **without changing the reconciler**: a systemd `.path` unit fires the oneshot when web writes a sentinel, so sign-up / trial / Renovate apply in seconds instead of waiting up to 5 min for the timer. **The reconciler container unit + timer are untouched; the timer stays the backstop.** ## Changes - **group_vars:** shared `reconcile_trigger_dir`/`reconcile_trigger_sentinel`/`reconcile_trigger_min_interval` (web creates + mounts the dir since it starts before the reconciler role; the reconciler role installs the units). - **web role:** create the sentinel dir; bind-mount it `rw`; set `RECONCILE_TRIGGER_PATH`; add `UserNS=keep-id:uid=1000,gid=1000` so `node`(1000) maps to `gitborg` and the host `.path`/kick (running as `gitborg`) can read + delete what web writes — the same trick the reconciler uses for its textfile mount. - **reconciler role:** `bitborg-reconcile.path` → debounced `bitborg-reconcile-kick.service` → starts the oneshot. Kick enforces a **30 s min-interval floor** (coalesces bursts), **removes the sentinel before the run** (at-least-once-after-last-write), and never fails the kick on a reconcile error (`ReconcilerFailed` already covers that). ## Validation - `ansible-playbook --syntax-check` ✓ - `ansible-lint` (production profile) — 0 failures ✓ - `shellcheck` on the rendered kick script ✓ ## ⚠️ Operator-verify before apply (via the gated infra-apply flow — NOT applied here) - The web `UserNS=keep-id` addition **recreates the web container** on apply; confirm web comes back healthy (it's a read-only network app, so keep-id should be inert, but verify). - After apply: touch the sentinel as `gitborg` and confirm the reconciler fires within seconds (`journalctl --user -u gitborg-reconcile-kick`); confirm bursts coalesce to ~1 run / 30 s. - Confirm `gitborg` lingering is enabled (already required by the existing reconciler timer).
supernaut lade till 1 incheckning 2026-07-28 19:53:40 +00:00
feat(reconciler): event-driven trigger core (ADR 0037 phase 1)
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m30s
5e94fe8fb6
Add a .path unit that fires the existing oneshot reconciler when web
writes a sentinel, so a Kanidm entitlement change applies promptly
instead of waiting up to 5 min for the timer. The reconciler container
unit + timer are UNCHANGED; the timer stays the backstop.

- group_vars: shared reconcile_trigger_dir/sentinel/min_interval (web
  creates + mounts the dir; the reconciler role installs the units).
- web: create the sentinel dir, bind-mount it, set RECONCILE_TRIGGER_PATH,
  and map node(1000)->gitborg via UserNS=keep-id so the host .path unit
  can read/delete what web writes (mirrors the reconciler textfile mount).
- reconciler: gitborg-reconcile.path -> debounced kick service -> starts
  the oneshot. Kick enforces a 30s min-interval floor (coalesces bursts),
  removes the sentinel before the run (at-least-once-after-last-write),
  and never fails on a reconcile error (ReconcilerFailed already covers it).

Validated: ansible syntax-check + ansible-lint (production) + shellcheck.
Not yet applied to prod (infra-apply is gated). Phase 1 infra half of
the epic; pairs with the web triggerReconcile adapter.
supernaut sammanfogade incheckning adb2fd87b7 till main 2026-07-28 21:39:11 +00:00
supernaut tog bort grenen feat/reconcile-trigger-core 2026-07-28 21:39:11 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra!238
Ingen beskrivning angiven.