feat(surface,sdk,kernel): event triggers via webhook + inbox watcher (#301) - #317
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
maintainability lens — FAILReview — MAINTAINABILITY lens on PR #317 Blockers
Concerns
Notes
REVIEW_FAILED |
history lens — PASSBlockers: none identified in PR #317 at Notes
Concerns, not blockers
I inspected the requested history and governing documents; tests were not executed for this review. The RFC-referenced REVIEW_PASSED |
structure lens — MISSING |
|
🎯 review-swarm: FAILED (M:fail H:pass S:missing) Lens transcripts posted as sibling comments above. |
70ac3d5 to
2b46eb3
Compare
40a9b26 to
17c00e4
Compare
217dcd0 to
a66485f
Compare
#301) Session-Id: 01a08f7e-5920-7321-9c9b-ed10eb8ac4b8 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
…riant E's trigger check imports the authored module before daemon-attach because trigger sources are only observable after `flow(...).on(webhook(...))` has run — the CI failure on direct-input.test.ts:121 was the old assertion catching this legitimate import. The load-bearing invariant is that the authored BODY is not called before daemon availability; the fixture now records import vs body separately and the test targets the body-run marker. Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
Cursor Bugbot MED at packages/sdk/src/cli.ts:115: flows check on a .flow.ts routed through checkAuthoredTriggers (webhook-trigger preflight) but silently skipped checkHelperBody (added for f.slack in PR#314). A .flow.ts using f.slack.post without SLACK_BOT_TOKEN passed check and only crashed at run. Fix by folding the slack helper preflight into checkAuthoredTriggers on the same loaded definition, merging diagnostics. Direct-run also inherits the helper check because it calls the same function. Regression test: a .flow.ts using f.slack.post with no SLACK_BOT_TOKEN must produce helper_slack.credential_missing via flows check --json. Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82 Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
…ia mocked authored flows
direct-run-failure.test.ts mocks getDefinition to return {} to simulate
loader failures. Both preflightHelpers (slack) and checkMcpHeader
unguarded-read definition.header, causing the tests to trap on TypeError
instead of surfacing the mocked worker-error classification.
Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82
a66485f to
ebfadb7
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ebfadb7. Configure here.
| spec.validate().context("invalid run spec")?; | ||
| if inbox_resume.is_some() { | ||
| self.preflight_placement(&spec)?; | ||
| } |
There was a problem hiding this comment.
Event spawn skips workspace binding
Medium Severity
The new webhook submit path calls preflight_placement but never bind_local_workspaces before drive. run.start journals those local workspace pins right after register so a later resume cannot inherit a different daemon cwd. Event-triggered runs with workspace-required deterministic steps lose that binding.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit ebfadb7. Configure here.
SqliteJournal::create ran execute_batch(SCHEMA) in autocommit before the meta INSERT transaction. SIGKILL in that microsecond window left the file with schema but no meta row, so open()'s SELECT ... FROM meta returned NoRows (surfaced as 'Query returned no rows' on resume). The webhook-live SIGKILL-after-spawn-before-ack test reproduced this deterministically on GH runners. Fold DDL + meta/segment inserts into a single WAL transaction. Either SIGKILL leaves an empty file (no tables) or a fully initialized journal — nothing in between. Session-Id: efeda5df-9b7c-48d4-b2ce-957f5bef0a82


Closes #301.
Summary
Event triggers end-to-end via a generic HTTP webhook + inbox watcher:
flow.on(webhook('name', filter?), (f, event) => body)flows serve-webhook --data-dir <dir> --port <p>HTTP-mounts events to<data-dir>/inbox/<trigger>/<uuid>.jsonrelayflowdpicks up new inbox files and spawns runs of matching flows, passing parsed event as second body argwebhook('X')refused unlessXis in flows.jsonexecutorsarrayNot in scope (deferred follow-ups)
slack.mention()body-content matching (those come with each helper namespace — B pattern)Written by codex agent
spec-E-triggers-v3on finn-mini; head at70ac3d5.Test plan
🤖 Generated with Claude Code
Note
Medium Risk
Changes event submission, dedupe/resume, and journal creation durability; filesystem inbox ack boundaries must stay correct to avoid lost or double-processed webhooks.
Overview
Adds webhook-triggered flows end-to-end: authored flows declare handlers with
flow(...).on(webhook('name', filter?), body), the CLI exposesflows serve-webhookto accept POST JSON into<data-dir>/inbox/<name>/, andrelayflowdruns a 1 Hz inbox watcher that loadstriggers/<name>.json, submits events, drives or resumes the run, then archives files only after a durable receipt.The engine gains
submit_webhook_eventso deduped inbox retries resume the existing run instead of returning no run;run.spawnedjournals now include the event payload (additive flattened shape).SqliteJournal::createwraps schema + meta/segment inserts in one transaction so SIGKILL between create and first append no longer yields journals that fail to open on resume.Preflight refuses webhook names not listed in
flows.jsonexecutors, wired intoflows checkand directflows runon.flow.ts(plus Slack helper checks on that path). Tests cover unit ingress, kernel watcher behavior, and live daemon + SIGKILL replay scenarios.Reviewed by Cursor Bugbot for commit 4e0a02a. Bugbot is set up for automated code reviews on this repo. Configure here.