Closes#107. Replaces PR #108 (stale, predates the tertiary-LLM router and CLAUDE_INGEST_SKIP_PROJECTS features that landed on main since — merging it as-is would have silently reverted both).
What this is
Rebase of PR #108's original code (agent/107-loud-unconfigured-alerting, never previously CI-tested — workflow_run_list showed zero runs on that branch) onto current main. No functional change to the original alertingWarnings implementation.
alertingWarnings(getenv func(string) string) []string — pure, env-injected, called once in main() right after the logger is built. Warns once at startup when BRAIN_NTFY_URL is unset, naming what won't fire: brain_edit_root governance rewrites and capture audit degradation. WARN, not fatal — deliberately: this is a degraded-observability case (the unconfigured-homelab path is legitimate), not a bypassed gate.
BRAIN_LOKI_URL — deliberately not added
The original issue's checklist optionally asked for the same treatment on BRAIN_LOKI_URL. Not done here: unlike BRAIN_NTFY_URL unset (alerts silently never fire — a real silent failure), BRAIN_LOKI_URL unset already has a fully working, non-silent fallback — buildAuditSink logs "capture audit: slog sink (BRAIN_LOKI_URL unset)" at Info level and returns a fully functional local sink. Treating it identically to the ntfy case would misrepresent it as a silent failure when it isn't one. The issue said "optionally" for exactly this reason — happy to add a WARN-level echo of the existing Info log if wanted, but didn't want to manufacture false severity to tick a checklist box.
Test plan
TestAlertingWarnings (pre-existing, ported through the rebase): unconfigured case names BRAIN_NTFY_URL/brain_edit_root/audit; configured case is silent.
Verified the tertiary-LLM router block and CLAUDE_INGEST_SKIP_PROJECTS veto-list feature (both landed on main after this branch was originally cut) survived the rebase intact.
Full module gate: go build ./..., go vet ./..., go test ./... -race -count=1 — 31 packages green.
Closes #107. Replaces PR #108 (stale, predates the tertiary-LLM router and `CLAUDE_INGEST_SKIP_PROJECTS` features that landed on main since — merging it as-is would have silently reverted both).
## What this is
Rebase of PR #108's original code (`agent/107-loud-unconfigured-alerting`, never previously CI-tested — `workflow_run_list` showed zero runs on that branch) onto current `main`. No functional change to the original `alertingWarnings` implementation.
`alertingWarnings(getenv func(string) string) []string` — pure, env-injected, called once in `main()` right after the logger is built. Warns once at startup when `BRAIN_NTFY_URL` is unset, naming what won't fire: `brain_edit_root` governance rewrites and capture audit degradation. WARN, not fatal — deliberately: this is a degraded-observability case (the unconfigured-homelab path is legitimate), not a bypassed gate.
## BRAIN_LOKI_URL — deliberately not added
The original issue's checklist optionally asked for the same treatment on `BRAIN_LOKI_URL`. Not done here: unlike `BRAIN_NTFY_URL` unset (alerts silently never fire — a real silent failure), `BRAIN_LOKI_URL` unset already has a fully working, non-silent fallback — `buildAuditSink` logs `"capture audit: slog sink (BRAIN_LOKI_URL unset)"` at Info level and returns a fully functional local sink. Treating it identically to the ntfy case would misrepresent it as a silent failure when it isn't one. The issue said "optionally" for exactly this reason — happy to add a WARN-level echo of the existing Info log if wanted, but didn't want to manufacture false severity to tick a checklist box.
## Test plan
- [x] `TestAlertingWarnings` (pre-existing, ported through the rebase): unconfigured case names `BRAIN_NTFY_URL`/`brain_edit_root`/`audit`; configured case is silent.
- [x] Verified the tertiary-LLM router block and `CLAUDE_INGEST_SKIP_PROJECTS` veto-list feature (both landed on `main` after this branch was originally cut) survived the rebase intact.
- [x] Full module gate: `go build ./...`, `go vet ./...`, `go test ./... -race -count=1` — 31 packages green.
- [x] `task check` green.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---
_Created via git-mcp on behalf of @mathias_
buildNotifier returns a nil interface when BRAIN_NTFY_URL is unset, and
every consumer skips a nil notifier silently. That is right for an
unconfigured homelab and wrong for an alert whose entire value is that
someone finds out: "configured and working" and "never configured" were
byte-identical in behaviour — no error, no warning, only a message that
never arrives, which nobody notices because nobody is waiting for an alert
they have never seen.
Two alerts were dark in production for exactly that reason (#100): the
governance-rewrite alert from #97, and the audit-degradation alert that
reports the audit trail is down. Both were found by firing a real event
and watching nothing happen, not by reading anything.
WARN rather than fatal, deliberately. The brain rule
`empty-credential-must-refuse-to-start-not-switch-modes` says an empty
credential must be a startup error rather than a silent mode switch — but
that is about a control being removed. Here observability degrades, no gate
is bypassed, and refusing to boot would break the unconfigured-homelab case
the nil notifier exists to support. What that rule demands and this
provides is that the mode switch stops being silent.
buildAuditSink already announces its own fallback ("capture audit: slog
sink (BRAIN_LOKI_URL unset)"), so only the notifier needed this.
alertingWarnings is pure and env-injected: the reason this gap survived is
that nothing about it was observable, so the fix is tested rather than
asserted.
Refs #107, #100, #97.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #107. Replaces PR #108 (stale, predates the tertiary-LLM router and
CLAUDE_INGEST_SKIP_PROJECTSfeatures that landed on main since — merging it as-is would have silently reverted both).What this is
Rebase of PR #108's original code (
agent/107-loud-unconfigured-alerting, never previously CI-tested —workflow_run_listshowed zero runs on that branch) onto currentmain. No functional change to the originalalertingWarningsimplementation.alertingWarnings(getenv func(string) string) []string— pure, env-injected, called once inmain()right after the logger is built. Warns once at startup whenBRAIN_NTFY_URLis unset, naming what won't fire:brain_edit_rootgovernance rewrites and capture audit degradation. WARN, not fatal — deliberately: this is a degraded-observability case (the unconfigured-homelab path is legitimate), not a bypassed gate.BRAIN_LOKI_URL — deliberately not added
The original issue's checklist optionally asked for the same treatment on
BRAIN_LOKI_URL. Not done here: unlikeBRAIN_NTFY_URLunset (alerts silently never fire — a real silent failure),BRAIN_LOKI_URLunset already has a fully working, non-silent fallback —buildAuditSinklogs"capture audit: slog sink (BRAIN_LOKI_URL unset)"at Info level and returns a fully functional local sink. Treating it identically to the ntfy case would misrepresent it as a silent failure when it isn't one. The issue said "optionally" for exactly this reason — happy to add a WARN-level echo of the existing Info log if wanted, but didn't want to manufacture false severity to tick a checklist box.Test plan
TestAlertingWarnings(pre-existing, ported through the rebase): unconfigured case namesBRAIN_NTFY_URL/brain_edit_root/audit; configured case is silent.CLAUDE_INGEST_SKIP_PROJECTSveto-list feature (both landed onmainafter this branch was originally cut) survived the rebase intact.go build ./...,go vet ./...,go test ./... -race -count=1— 31 packages green.task checkgreen.🤖 Generated with Claude Code
Created via git-mcp on behalf of @mathias