Outbound owner notification, and the stall it exists for #171
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent
Part of #137.
What to build
The dashboard stops being pull-only, for exactly one class of fault: silent on every Reader surface, wrong, repairable only by the owner, and persisting past twelve hours. That rule is the decision — the conditions are only what it selects, and a fifth candidate must pass all four tests.
The first condition is a stall: a Lane that owed Polls, made none, and has nothing to say for it. Every other fault finds itself within one reading session — the web UI dies visibly, the userscript degrades to its cache with a pending count and loses no Progress — so backend downtime is deliberately not pushed.
This ticket builds the whole path plus that one condition. No new timer: each Lane already wakes at least hourly and is its own clock.
Acceptance criteria
DISCORD_WEBHOOK_URLis read at startup; unset means the whole path is off, logged once, exactly as the browser URL behaves — a local stack must not need a webhook to run. The variable is added to.env.exampleand listed in the compose service environment (an env var not listed there never reaches the container), with an empty default and never a required-guard.due > 0, none checked, no skip value, and no refusal. That last clause is the amendment: the twice-refused break is inside the pass loop, not an early return, so a newly-gated Site would otherwise send two messages. Rejected alternative: a new skip value, because the vocabulary holds one value per return path and this is a break inside one.Blocked by
Landed on spec-137 at
3d74609. Outbound owner notification path: DISCORD_WEBHOOK_URL env (unset = off, never logged), owner_notices suppression table (migration 0020), Notifier seam on Poller (nil = off), FaultsFrom/Fault/ConditionStall seam in internal/latest for #172/#173 to consume, internal/notify Discord embed client (stdlib only, danger colour, no OAuth/session import). Stall fires once per episode, clears on recovery, excludes refused/paused. Rollout note: owner_notices starts empty, first pass after deploy sends for pre-existing conditions; prod step is create webhook + set DISCORD_WEBHOOK_URL + redeploy. Tests: faults/poller/notify/store/main all green. Review: 1 hard violation (duplicate compose depends_on) + AC12 rollout note gap, both fixed in 6af8859; 3 judgement calls fixed, humanAge boundary tests declined (cosmetic formatter).