feat(engine): module substrate wave 2 — events, outbox drain, webhook delivery, admin API (HT-69) - #78
Closed
zaridan wants to merge 2 commits into
Closed
Conversation
… delivery, admin API (HT-69) Implements specs/modules/substrate-v1.md §4/§5 on top of wave 1's schema and stores (HT-68): transactional event emission at every non-deleted state change (conversation.created/message_received in the ingestion append path, status_changed/tags_changed/assignee_changed on the corresponding ConversationStore writes, reply_sent on the delivery-status→'sent' transition), a cron-driven outbox drain that fans each event out to its matching active webhook endpoints via the existing queue, a signed HTTPS delivery handler with resolve-then-connect SSRF pinning and its own retry/dead-letter ceiling, and the webhooks admin API (CRUD + test-ping) mirroring agents.ts's conventions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…edupe-key doc (HT-69 review) MAJOR: releaseThreadLease's 'sent' branch emitted conversation.reply_sent unconditionally, but delivery is not conversation-status-scoped — a thread claimed/leased before its conversation was soft-deleted could still be force-delivered afterward and fire the event, breaching spec §4's absolute "no event of any type fires for a soft-deleted conversation" exclusion. Gate the outbox append (not the delivery-status write, which must still proceed — mail already went out) on the conversation's live status, read in the SAME UPDATE...RETURNING statement via a correlated subquery, mirroring listAwaitingDrafts' existing status <> 'deleted' carve-out for drafts. MINOR: migration 023's doc comment said the outbox->queue hand-off is keyed by dedupe_key = event_id (singular); corrected to the implemented per-(event, endpoint) fan-out key event_id:endpointId, and dropped outbox-drain.ts's now- redundant "written before finalized" apology. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
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
Wave 2 of the module substrate (HT-69; spec §4/§5 on #76). Stacked on #77 (wave 1) — no new migrations; retarget to main after #77 merges.
eventId:endpointId.t=…, v1=…HMAC (secrets decrypted only at signing time), 10s timeout, redirects never followed, hand-rolled SSRF guard (v4+v6 private/link-local/metadata/NAT64/6to4/Teredo ranges; DNS answers all validated; resolved IP pinned into the TLS connection — live-verified against a real server, including anode:net.BlockListfootgun that justified hand-rolling), retry/dead-letter via QueueProvider, auto-disable at 20 via the wave-1 store.POST/GET/PATCH/DELETE /api/v1/webhooks+POST …/{id}/test(real delivery path), secret shown once,agents.tsconventions; PATCH re-enable resets the counter./internal/healthwebhooks section (auto-disabled endpoints + 24h dead-letter growth, same 200/503 contract), outbox-drain cron invercel.json, runbook Part G updated.Review trail
Sonnet-authored → Opus adversarial review: FIX-FIRST (1 MAJOR, 1 MINOR — both fixed): the MAJOR was the soft-delete/delivery race above. The review also ran the producer signature implementation directly against the consumer verifier in the draft-assistant module repo: byte-exact interop confirmed (seconds-unit timestamp, lowercase hex, multi-v1, constant-time both sides).
Gates
typecheck 0 · lint 0 · test 0 — 1230 passed (~115 new). Per the maintainer's overnight ground rules this PR stays open for morning review.
🤖 Generated with Claude Code