fix(zulip-monitor): stream alert body carries real content; WARN on delivery failure #68

Merged
abiba-bot merged 3 commits from fm/zulip-monitor-stream-body-20260909 into master 2026-09-09 04:21:37 +00:00
Owner

Silent alert-loss fix in scripts/zulip-monitor.sh, found by firstmate on 2026-09-09 while cross-checking a false "fleet degraded" report; the defect reached master through PR #66 (merge 028f276).

Defect. notify()'s second delivery path (the #agent-hub / zulip-health stream post) built its body with urllib.parse.quote(str()), which evaluates to the empty string, and used backslash-escaped \& separators inside a double-quoted -d argument (Zulip rejects that form with 400 Invalid type). Both failures were swallowed by > /dev/null 2>&1 || true, so stream alerts never arrived and nothing reported it. The private-DM path above it worked, which is why no one noticed.

Change (script-only + 2 doc lines).

  • Stream post now carries the real message text, piped through the encoder rather than interpolated into a python literal, with plain & parameter separators.
  • Delivery failure now appends exactly one WARN line (with curl's exit status) to the monitor's own log; it stays non-fatal so an alert-delivery failure can never read as a fleet fault. No retries, no new channel, no other behaviour touched (probes, the any-HTTP-response alive rule from #66, pct exec 112 Tanko vantage, DM path, exit codes, log format all unchanged).
  • Header comment corrected: it said "Alerts via Telegram"; alerts go by Zulip DM plus the #agent-hub stream.
  • README.md: dropped the unsupported claim that agent-health-check.py "Replaced zulip-monitor.sh" (the zulip-health contract still maintains it as executor). Deliberately not replaced with the opposite claim - live deployment truth is not verifiable from the diff, and reconciling infrastructure-control.prose.md's parallel claim is filed as separate follow-up work.
  • CLAUDE.md: scaffold-mandated fm-ensure-agents-md.sh pointer conversion (symlink -> @AGENTS.md file). Unrelated to the fix; called out here so the net diff is honest.

Proof. no-mistakes run passed: review 0 findings, test clean, lint clean, document gate answered (firstmate authority, run 01M221Y6V1TDAA1X46VR3G7XGX). bash -n clean. Behavioural checks green via a curl-stub recorder proving the posted content decodes to the real alert text, plus a forced-failure case proving the WARN line lands and the exit status stays non-fatal. Branch pushed: git ls-remote origin fm/zulip-monitor-stream-body-20260909 -> 7ff7ce5b336964100c23c91a385aada7e49863dc.

Silent alert-loss fix in `scripts/zulip-monitor.sh`, found by firstmate on 2026-09-09 while cross-checking a false "fleet degraded" report; the defect reached master through PR #66 (merge 028f276). **Defect.** `notify()`'s second delivery path (the `#agent-hub` / `zulip-health` stream post) built its body with `urllib.parse.quote(str())`, which evaluates to the empty string, and used backslash-escaped `\&` separators inside a double-quoted `-d` argument (Zulip rejects that form with `400 Invalid type`). Both failures were swallowed by `> /dev/null 2>&1 || true`, so stream alerts never arrived and nothing reported it. The private-DM path above it worked, which is why no one noticed. **Change (script-only + 2 doc lines).** - Stream post now carries the real message text, piped through the encoder rather than interpolated into a python literal, with plain `&` parameter separators. - Delivery failure now appends exactly one `WARN` line (with curl's exit status) to the monitor's own log; it stays non-fatal so an alert-delivery failure can never read as a fleet fault. No retries, no new channel, no other behaviour touched (probes, the any-HTTP-response alive rule from #66, `pct exec 112` Tanko vantage, DM path, exit codes, log format all unchanged). - Header comment corrected: it said "Alerts via Telegram"; alerts go by Zulip DM plus the #agent-hub stream. - `README.md`: dropped the unsupported claim that `agent-health-check.py` "Replaced zulip-monitor.sh" (the zulip-health contract still maintains it as executor). Deliberately not replaced with the opposite claim - live deployment truth is not verifiable from the diff, and reconciling `infrastructure-control.prose.md`'s parallel claim is filed as separate follow-up work. - `CLAUDE.md`: scaffold-mandated `fm-ensure-agents-md.sh` pointer conversion (symlink -> `@AGENTS.md` file). Unrelated to the fix; called out here so the net diff is honest. **Proof.** no-mistakes run passed: review 0 findings, test clean, lint clean, document gate answered (firstmate authority, run 01M221Y6V1TDAA1X46VR3G7XGX). `bash -n` clean. Behavioural checks green via a curl-stub recorder proving the posted `content` decodes to the real alert text, plus a forced-failure case proving the WARN line lands and the exit status stays non-fatal. Branch pushed: `git ls-remote origin fm/zulip-monitor-stream-body-20260909` -> `7ff7ce5b336964100c23c91a385aada7e49863dc`.
abiba-bot added 3 commits 2026-09-09 03:57:16 +00:00
The #agent-hub / zulip-health stream post in notify() encoded content with
python quote(str()) (always empty), so every stream alert posted empty
content and Zulip rejected it silently behind '|| true'. The merged body
also used backslash-escaped ampersands inside double quotes, which curl
transmits literally (type=stream\ -> Zulip 400 'Invalid type').

Stream post now percent-encodes the real message text by piping it through
the encoder (locale-proof: quote_from_bytes on stdin.buffer), uses plain &
separators, and on failure appends one WARN line to the monitor log with
the curl exit status instead of silently swallowing it. Delivery failure
stays non-fatal and unretried. DM path, probes, alive rule, exit codes and
log format unchanged.
fm-ensure-agents-md.sh converted the tracked AGENTS.md symlink into the
real-file pointer form, removing the dangling-symlink hazard.
no-mistakes(document): docs: fix stale replaced-claim and Telegram header comment
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 2s
7ff7ce5b33
abiba-bot merged commit 91d16d2693 into master 2026-09-09 04:21:37 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SyslogSolution/prose-contracts#68