Conversation
…open by design) Implements stateless one-shot tool that reads on-disk signals (heartbeat age, merge-queue state, exception count, open PR count) and POSTs compact status payloads to configured Slack/Discord webhooks. Fail-open design: missing config, network errors, and unavailable tools all exit 0 cleanly. Supports Slack blocks and Discord embeds output formats. Never logs or exposes webhook URLs. All timeouts enforced (10s default). Skips gh command silently if unavailable (no credential hunting). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…: lines #751 moved the per-tool index out of tools/CLAUDE.md into each tool's own INDEX: header line, from which tools/INDEX.md is generated, because the inline list was the top merge-queue conflict surface. This branch was cut before that and still carried its documentation update as an edit to the old inline list. Resolved by taking main's 33-line tools/CLAUDE.md and porting this branch's updated description(s) into the tool's own INDEX: line, then regenerating tools/INDEX.md: alerts_webhook.py (new tool, INDEX: line added) No documentation content lost; only the obsolete inline index lines are gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tools/alerts_webhook.py opened state/.orchestrator-heartbeat directly,
which is an unbaselined stateapi_lint violation (the read must go through
the sanctioned state_store.read_api facade). Fixed properly rather than
baselined: baselining a brand-new file would weaken the ratchet.
- read_heartbeat_age() -> read_heartbeat_stalled(), delegating to
ReadAPI.check_heartbeat_fresh(".orchestrator-heartbeat", threshold).
The filename is now an identifier passed TO the facade, which owns the
file access and the staleness contract; the tool never opens it.
- Adopts the facade's fail-closed semantic: a missing or unreadable
heartbeat now reports as stalled instead of the previous "active
(age: unknown)", which silently swallowed the exact alarm condition.
- Facade import guarded; unavailable/erroring facade degrades to an
"unknown" heartbeat status so the alert path stays fail-open.
- Payload text reports fresh/stalled/unknown rather than a raw age,
since the facade exposes freshness, not age.
- Drops the now-unused time import; tools/INDEX.md regenerated.
Tests: 7 new regression tests pin the facade delegation (call args),
the fail-closed missing-heartbeat path, the unknown/degraded path, and
a source guard asserting no direct heartbeat open remains.
stateapi_lint: PASS, All 40 violations match baseline (0 new; baseline
file untouched).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements stateless one-shot tool that reads on-disk signals and POSTs compact status payloads to configured Slack/Discord webhooks.
Payload Composition
Reads from disk only:
Composes Slack blocks or Discord embeds with fleet status summary.
Fail-Open Design
Advisory tool: all errors exit 0 cleanly:
Implementation Details
python tools/alerts_webhook.py [--config PATH] [--dry-run]Testing
19 comprehensive TDD tests covering:
All tests pass. Secret scan clean. Tool gating: claudemd_lint OK, test suite count +19.
🚫 Follow-up PRs (deferred to daemons/ wiring layer):
📍 Generated with Claude Code