|
| 1 | +# Runbook: Fix Meta-Coordinator Health Check (blind under `no_new_privs`) |
| 2 | + |
| 3 | +**Issue**: `terraphim/terraphim-ai#3005` (tracker id `4300`) |
| 4 | +**Theme-ID**: `adf-health-alert` |
| 5 | +**Severity**: P1 — a monitor that reports false-green while the system is red is worse |
| 6 | +than no monitor; it suppresses human attention. |
| 7 | +**Status**: Patch verified end-to-end on bigbox; awaiting operator apply (root required). |
| 8 | + |
| 9 | +## Symptom |
| 10 | + |
| 11 | +The ADF meta-coordinator health-check cron reports **0 stalls / 0 failures / 0 timeouts** |
| 12 | +in windows where the orchestrator is actually degraded. On 2026-06-29 it reported 0 stalls |
| 13 | +in the same 4h window where `#3004` documents **207 stalls, max 55s**. |
| 14 | + |
| 15 | +## Root cause — verified by reproduction |
| 16 | + |
| 17 | +The health-check task block invokes `sudo journalctl -u adf-orchestrator`. On this host |
| 18 | +the `alex` user (and the orchestrator runtime) runs under the **`no_new_privs`** flag, so |
| 19 | +`sudo` is refused: |
| 20 | + |
| 21 | +``` |
| 22 | +$ sudo -n true |
| 23 | +sudo: The "no new privileges" flag is set, which prevents sudo from running as root. |
| 24 | +``` |
| 25 | + |
| 26 | +Every `sudo journalctl ... | grep -c ... || true` therefore evaluates to `0`, and each |
| 27 | +guard treats `0` as healthy. Reproduced this session (2026-06-29 22:10 +02:00): |
| 28 | + |
| 29 | +| Invocation | Lines in 4h window | `reconcile_tick SLOW` count | |
| 30 | +|------------|-------------------:|----------------------------:| |
| 31 | +| `sudo journalctl ...` (current/buggy) | **0** | **0** ← false green | |
| 32 | +| `journalctl -q ...` (fixed) | 19,079 | **164** ← true signal | |
| 33 | + |
| 34 | +The `alex` user already has journal read access via ACL on `/var/log/journal` |
| 35 | +(group `systemd-journal`). **`sudo` is not only unnecessary here — it is actively harmful.** |
| 36 | + |
| 37 | +## Affected file |
| 38 | + |
| 39 | +The defect lives in the **deployed, unversioned** runtime config (NOT in this repo): |
| 40 | + |
| 41 | +``` |
| 42 | +/opt/ai-dark-factory/conf.d/terraphim.toml (root:alex 0640) |
| 43 | +``` |
| 44 | + |
| 45 | +Occurrences (as of 2026-06-23 mtime, still present 2026-06-29): |
| 46 | + |
| 47 | +| Line | Block | Pattern | |
| 48 | +|------|-------|---------| |
| 49 | +| 68 | `### 1. Tick-Stall Detection` | `sudo journalctl -u adf-orchestrator ...` | |
| 50 | +| 76 | `### 2. Agent Failure Report` | `sudo journalctl -u adf-orchestrator ...` | |
| 51 | +| 86 | `### 2b. Agents Exceeding max_cpu_seconds` | `sudo journalctl -u adf-orchestrator ...` | |
| 52 | +| 832 | Mneme fleet-health synthesis | `sudo -n journalctl -u adf-orchestrator ...` | |
| 53 | + |
| 54 | +> **Note**: the meta-coordinator agent commented on `#3005` at 10:05 claiming the fix was |
| 55 | +> "applied". That was **inaccurate** — the agent ran one cycle manually without `sudo` but |
| 56 | +> never edited the config. File mtime `2026-06-23 16:44` confirms the file is untouched. |
| 57 | +> Verify any future "fixed" claim with `stat -c '%y' /opt/ai-dark-factory/conf.d/terraphim.toml`. |
| 58 | +
|
| 59 | +## The patch (verified) |
| 60 | + |
| 61 | +Two surgical changes: |
| 62 | + |
| 63 | +### Change 1 — remove `sudo` from all `journalctl` invocations |
| 64 | + |
| 65 | +```bash |
| 66 | +sudo cp /opt/ai-dark-factory/conf.d/terraphim.toml \ |
| 67 | + /opt/ai-dark-factory/conf.d/terraphim.toml.bak-3005-$(date +%Y%m%d-%H%M%S) |
| 68 | +sudo sed -i \ |
| 69 | + -e 's/sudo -n journalctl/journalctl -q/g' \ |
| 70 | + -e 's/sudo journalctl/journalctl -q/g' \ |
| 71 | + /opt/ai-dark-factory/conf.d/terraphim.toml |
| 72 | +``` |
| 73 | + |
| 74 | +`-q` suppresses journalctl's "not seeing messages from other users" hint cleanly |
| 75 | +(recommended in the issue's confirmation comment). No privilege escalation needed. |
| 76 | + |
| 77 | +### Change 2 — add a fail-loud telemetry precondition |
| 78 | + |
| 79 | +Insert immediately after the `export PATH=...` line (currently line 64), before |
| 80 | +`## ADF Meta-Coordinator: Monitoring and Health Checks`, so the script aborts loudly |
| 81 | +instead of emitting a false-green if telemetry ever breaks again: |
| 82 | + |
| 83 | +```bash |
| 84 | +# Telemetry precondition: fail loud rather than report false-green. |
| 85 | +_TELEMETRY_LINES=$(journalctl -q -u adf-orchestrator --since '4 hours ago' 2>/dev/null | wc -l | tr -d ' ') |
| 86 | +if [ "${_TELEMETRY_LINES:-0}" -lt 50 ]; then |
| 87 | + echo "FATAL: journalctl returned ${_TELEMETRY_LINES} lines in 4h — telemetry broken, aborting (would produce false green)" >&2 |
| 88 | + gtr create-issue --owner terraphim --repo terraphim-ai \ |
| 89 | + --title "[ADF] Health check telemetry broken (${_TELEMETRY_LINES} lines in 4h)" \ |
| 90 | + --body "journalctl returned ${_TELEMETRY_LINES} lines in a 4h window. The health check aborted to avoid a false-green report. Investigate journal access / ACL on /var/log/journal. |
| 91 | +Theme-ID: adf-health-alert" 2>/dev/null || true |
| 92 | + exit 1 |
| 93 | +fi |
| 94 | +``` |
| 95 | + |
| 96 | +## Apply procedure (operator with root) |
| 97 | + |
| 98 | +```bash |
| 99 | +# 1. Back up + patch (Change 1) |
| 100 | +sudo cp /opt/ai-dark-factory/conf.d/terraphim.toml \ |
| 101 | + /opt/ai-dark-factory/conf.d/terraphim.toml.bak-3005-$(date +%Y%m%d-%H%M%S) |
| 102 | +sudo sed -i -e 's/sudo -n journalctl/journalctl -q/g' -e 's/sudo journalctl/journalctl -q/g' \ |
| 103 | + /opt/ai-dark-factory/conf.d/terraphim.toml |
| 104 | + |
| 105 | +# 2. Verify the patch took (expect 0 matches) |
| 106 | +grep -c 'sudo .*journalctl' /opt/ai-dark-factory/conf.d/terraphim.toml # must print 0 |
| 107 | + |
| 108 | +# 3. Apply Change 2 (fail-loud precondition) — operator edits the task block, |
| 109 | +# or re-deploys from a versioned template once #see-followup is implemented. |
| 110 | + |
| 111 | +# 4. Reload the orchestrator so it re-reads conf.d |
| 112 | +sudo systemctl restart adf-orchestrator.service |
| 113 | + |
| 114 | +# 5. Smoke-test the next health check cycle manually (no sudo): |
| 115 | +journalctl -q -u adf-orchestrator --since '4 hours ago' | grep -c 'reconcile_tick SLOW' |
| 116 | +``` |
| 117 | + |
| 118 | +## Verification (acceptance) |
| 119 | + |
| 120 | +After the next 4h cron cycle, the health check MUST surface the real signal: |
| 121 | + |
| 122 | +- [ ] `stat -c '%y' /opt/ai-dark-factory/conf.d/terraphim.toml` shows a fresh mtime. |
| 123 | +- [ ] `grep -c 'sudo .*journalctl' /opt/ai-dark-factory/conf.d/terraphim.toml` returns `0`. |
| 124 | +- [ ] The next cycle's `[ADF] Tick-stall detected: N in 4h` issue (if any) reports a |
| 125 | + non-zero `N` consistent with `#3004`-class telemetry (order of 10², not 0). |
| 126 | +- [ ] No new spurious all-green cycle appears while `#3004`/`#4299` remain open. |
| 127 | + |
| 128 | +## Deeper defect (filed separately) |
| 129 | + |
| 130 | +The deployed `/opt/ai-dark-factory/conf.d/*.toml` is **unversioned** — not in any git |
| 131 | +repo. That is the root cause that allowed this defect to persist silently for 6 days and |
| 132 | +that let the meta-coordinator's "applied" comment go unchecked. The version-controlled |
| 133 | +twins in `terraphim-agents/.../tests/fixtures/conf.d/` and `orchestrator.example.toml` |
| 134 | +diverge from production and do **not** contain this task block at all. Bringing |
| 135 | +`conf.d/` under version control (or generating it from a tracked template at deploy |
| 136 | +time) is the structural fix that prevents recurrence. Tracked as a follow-up issue. |
| 137 | + |
| 138 | +## Why this runbook lives in `terraphim-ai` (not `terraphim-agents`) |
| 139 | + |
| 140 | +The health check creates issues in **this** repo (`terraphim/terraphim-ai`) and references |
| 141 | +this repo's worktrees and binaries. Per AGENTS.md dual-remote protocol, this runbook is |
| 142 | +pushed to both `origin` (GitHub) and `gitea` mirrors, giving operators a reviewable, |
| 143 | +reproducible artefact that satisfies the spirit of Bigbox Rule #1 (git pull/push, not |
| 144 | +ad-hoc `scp`) even though the target file itself is not yet version-controlled. |
0 commit comments