feat(server): say at startup when alerting is unconfigured (#107) #108
Closed
mathias
wants to merge 1 commits from
agent/107-loud-unconfigured-alerting into main
pull from: agent/107-loud-unconfigured-alerting
merge into: :main
:main
:fix/pipeline-writes-158
:fix/edit-path-io-192
:fix/create-regular-188
:fix/guard-special-179
:fix/linkcheck-keeps-write-178
:fix/write-dir-redirect-173
:fix/tunnel-detect-174
:fix/pipeline-root-157
:w3/154-mcp-auth-wiring
:fix/tunnel-traversal
:test/in-brain-targets-171
:fix/brain-scan-root-157
:fix/graph-wiki-root-157
:fix/vectorstore-root-157
:fix/notes-root-157
:fix/search-root-157
:fix/brainwide-root-157
:fix/raw-symlinks-153
:feat/symlink-tripwire-157
:fix/rest-auth-149
:fix/123-brain-edit-envelope-check
:feat/106-page-aware-extraction
:fix/105-source-drift-on-main
:fix/104-surface-merge-conflicts-on-main
:agent/b1-compile-on-ingest
:agent/104-surface-merge-conflicts
:agent/105-source-drift
:agent/107-loud-unconfigured-alerting
:feat/brain-read-edit
:fix/capture-i1-refusal-names-target
:renovate/configure
:feat/consolidate-single-harness
:icebox/cmd-routing
:feat/brain-pending-promote
:fix/close-session-classification-refresh
:fix/capture-summarywriter
No Reviewers
Labels
Clear labels
agent/ready
blocked/client
blocked/supplier
blocked/upstream
risk/high
risk/low
risk/medium
size/l
size/m
size/s
size/xs
status:dispatch
status:dispatched
status:review
status:reviewing
type/chore
type/decision
type/docs
type/feat
type/fix
type/ops
type/research
type/test
Meets the agent-ready contract; authorizes unattended execution
Waiting on the client
Waiting on a supplier
Waiting on an upstream project or vendor
Irreversible, security-relevant, or control plane
Reversible, local, test-covered
Touches shared state, deploys or data
Too big - split it
Under two days
Under half a day
Under an hour
Maintenance, no behaviour change
Human decision required; never agent/ready
Documentation only
New capability
Corrects broken behaviour
Infrastructure, deploy, runtime
Investigate; output is a finding, not code
Test coverage only
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: mathias/hyperguild#108
Reference in New Issue
Block a user
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. Ten lines plus a test, from the #100 post-mortem.
What it fixes
buildNotifier()returns a nil interface whenBRAIN_NTFY_URLis unset, and every consumer skips a nil notifier silently. Correct for an unconfigured homelab; wrong for an alert whose entire value is that someone finds out.The cost was that "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 sat dark in production on exactly that (#100), and both were found by firing a real event and watching nothing happen, not by reading anything.
Now:
WARN, not fatal — deliberately
Brain carries a stronger sibling rule:
empty-credential-must-refuse-to-start-not-switch-modes— an empty credential must be a startup error, never a silent mode switch. That rule is about a control being removed (if token == "" { skip auth }). Here observability degrades and no gate is bypassed, and refusing to boot would break the unconfigured-homelab case the nil notifier exists to support.What the rule does demand, and what this provides, is that the mode switch stops being silent.
Scope narrowed after checking
buildAuditSinkalready announces its own fallback (capture audit: slog sink (BRAIN_LOKI_URL unset)), so loki's absence was never silent. Only the notifier needed this — one warning, not a sweep.Tests
Red-first against a stub: unconfigured names the variable and both alerts it disables; configured produces nothing.
alertingWarningsis pure with an injectedgetenvrather than reading the environment directly — the reason this gap survived a review is that nothing about it was observable, so the fix is tested rather than asserted.task checkexit 0.Risk: LOW — logging only, no behaviour change to any alert path.
Superseded by #140 — same code, rebased onto current
main(this branch predated the tertiary-LLM router andCLAUDE_INGEST_SKIP_PROJECTSfeatures and was never CI-tested; merging as-is would have silently reverted both). Closing in favor of #140.Created via git-mcp on behalf of @mathias
Pull request closed