The full notification-system decision (Option A: converge on the runtime bus), in two commits.
The answer to "which system should a new integration hook?" — the runtime EventBus, via the notifications key in buddy.config.ts. It is the only system that is config-driven, validated at every config load, tested, failure-contained, and HMAC-signed for webhook consumers. Both commits make that answer honest.
Commit 1 — trim setup to its one real job
The setup plugin system declared five events and fired one. Deleted (declared, never wired): the four dead event names (SetupTrigger.event becomes a documented string — old plugin files still load, their hooks simply never run), the never-evaluated condition, the never-used IntegrationPoint/AuthConfig, the never-read per-plugin configuration blocks, and Slack's validation_error trigger. Made real (documented, never wired): the .buddy/slack-webhook-style credential files are now actually read by the senders, and non-interactive setup loads integrations instead of silently skipping them — the docs' promised CI setup notification fires now. Docs corrected across README (+ CLAUDE.md mirror), the guide, and the setup page; seven defect-encoding tests now pin the new surface, two on the wire.
Commit 2 — fire every declared runtime event
8 of the bus's 11 events had no emitter. A config subscribing to review.completed or security.advisories validated cleanly and delivered silence forever — from a validation layer whose own comment says it exists to prevent silent drops. Now every event fires:
| Event | Emitter |
|---|---|
pr.updated | all four update/reopen sites in createPullRequests |
pr.closed | the three auto-close sites, each with a reason (satisfied / obsolete / config change) |
security.advisories | scan annotation, when packages are flagged |
dashboard.updated | dashboard create/refresh |
review.completed | the PR review path, with the finding count |
fixci.completed | inside runFixCi, from the structured outcome |
gate.failed | a blocking gate verdict, with the failed check names |
run.failed | the six runtime command catches (scan, update, update-check, dashboard, review, fix-ci) |
Call sites without a Buddy instance use a new emitEvent helper (builds sinks from config per call). describeEvent gains prose for the six events it rendered as bare names. docs/api/configuration.md finally enumerates the vocabulary, plus the webhook payload shape and x-buddy-signature scheme a consumer needs.
Verification
Full suite 2397 pass / 0 fail across 146 files. Typecheck, pickier, and check:docs (75 pages) clean. New tests: emitEvent delivery + no-config no-op, six new describeEvent cases, dashboard.updated and pr.closed asserted through injected buses in the orchestration suite.
🤖 Generated with Claude Code