Repository navigation
Conversation
There is no way for another system to react to platform activity, for example a chat message when a gate needs a human, without polling the API. With notification_events_enabled (default false) the deployment creates an EventBridge bus (notification_event_bus_name, default <project>-<environment>-events). The projects, discussions and v2-orchestrator Lambdas get NOTIFICATION_EVENT_BUS, NOTIFICATION_EVENT_SOURCE (default collaborative-ai-dlc) and events:PutEvents on that bus only. They publish: - space.created when a space is created - gate.pending when an intent waits at a gate, from a durable step so a replay does not publish twice - discussion.message and discussion.resolved for intent discussions Publishing (lambda/shared/notification-events.js) is best-effort: it never throws, gives up after two seconds, and without a bus does nothing and never loads the EventBridge client. The bus name and ARN are root outputs, and docs/using-the-platform/notification-events.md documents the event schema. Disabled, nothing is created and no Lambda changes. Co-authored-by: ashley.fairclough <ashley.fairclough@cdl.co.uk> Co-authored-by: Matt Houghton <matthew.houghton@cdl.co.uk>
gate.pending only fired for agent gates and its prompt was always null: agent questions carry a questions JSON array, not a prompt. - prompt falls back to the first entry of the gate's questions. - gate.pending adds need (answer, or approval for checkpoints and engine gates), intentTitle and startedBy. - Engine gates (validation, walking skeleton, batch, autonomy ladder, lane failure) publish gate.pending from inside their existing gate-open step, so the durable step sequence is unchanged. stage is the stage id where there is one, else a readable gate label. - Every event's detail has schemaVersion (1) and an eventId for deduplication. The docs now say delivery is at least once. All additive: no field is renamed or removed, and nothing changes without a bus configured. Co-authored-by: Adrian Robinson <adrian.robinson@cdl.co.uk>
There was a problem hiding this comment.
I’m requesting changes before merge for these two issues affecting project attribution and human-gate handling.
lambda/discussions/handlers.js:517
[P2] Discussion events can be attributed to an unauthorized project
authorizeScope resolves the intent’s actual project and checks membership there, but scope.projectId still comes from the URL. A member of project A can therefore post to an A discussion through /projects/B/intents/intent-A/... and emit an event labelled as project B; the resolution event has the same issue at line 943. That gives project-filtered integrations a false attribution. Using the canonical auth.projectId in both payloads, or rejecting the path mismatch, would preserve the authorization boundary.
lambda/shared/notification-events.js:153–156
[P2] Optional gate enrichment can outlast the notification deadline
These reads finish before the two-second EventBridge timeout starts. Engine gates supply the gate but not META, so a slow getExecution keeps the gate-open step waiting before its callback is created; agent gates similarly wait on getHumanTask. This makes optional notification work delay the gate beyond the documented bound. An overall deadline covering enrichment and publication would protect that behavior, with a slow-read case providing useful regression coverage.
- discussion.message and discussion.resolved take projectId from the intent's own project, as checked by authorizeScope, not the URL path. - notifyGatePending bounds its optional gate and META reads (one second) and the publish by a single two-second deadline, so a slow read no longer delays the gate. A dropped read's fields are sent as null. - publishNotificationEvent's deadline also covers loading the client and can be supplied by the caller.
|
Thanks @eipasteur, both fixed in 8e9d3ee. Discussion event attribution ( Gate enrichment deadline ( |
|
Automatically computed PR review signals (deterministic) Complexity and branch coverage help focus review on functions and their tests; these signals are advisory. Complexity and test coverage5 changed JS/TS files analyzed · 4 flagged functions.
🟢 Improving · 🟠 Needs attention · 🔴 High risk · 🟣 Highest risk — = unavailable · n/a = not applicable · * = incomplete tests Isobar repository mapThis fixed repository map locates changed files and their possible reach through static links. Signals
Legend
|

Issue #, if available: Closes #689
Description of changes:
Problem
Nothing outside the platform can react to what happens in it without polling the API. Common asks are a chat message when a gate is waiting for a human, a notice when a discussion is resolved, or an audit record when a space is created.
Solution
An opt-in outbound event feed on Amazon EventBridge. The platform publishes, and integrations subscribe with their own rules, in this deployment or another.
Terraform (root variables, all optional):
notification_events_enabled(defaultfalse) creates anaws_cloudwatch_event_businmodules/api/lambda.notification_event_bus_name(default empty, which means<project_name>-<environment>-events).notification_event_source(defaultcollaborative-ai-dlc). It's validated, and must not start withaws..NOTIFICATION_EVENT_BUS,NOTIFICATION_EVENT_SOURCE, and a separateevents:PutEventspolicy on that bus alone.notification_event_bus_nameandnotification_event_bus_arn.Events:
space.createdgate.pendingdiscussion.messagediscussion.resolvedEvery detail has
schemaVersion(1) and aneventIdfor deduplication.gate.pendingalso carriesneed(answerfor an agent question,approvalfor checkpoints and engine gates),kind,stage,intentTitle,startedByandprompt(an agent question's first question), so a consumer can render a useful message without calling back into the API.docs/using-the-platform/notification-events.md, added to the nav, documents every detail field, delivery semantics (normally once, at least once) and an example rule.Publishing (
lambda/shared/notification-events.js) is best-effort:gate-openstep. Either way, without a bus the step sequence of existing executions is unchanged.@aws-sdk/client-eventbridgeis added to the root devDependencies at the version the other clients use (^3.1106.0). That's wherelambda/sharedresolves its clients. The projects and v2-orchestrator bundles include it, and discussions uses the runtime's SDK like its other clients.Testing
lambda/shared/test/notification-events.test.jscovers no bus (no client load), the entry shape and default source, a custom source, rejected entries, send failures, client load failures, the real client loaded lazily, and thegate.pendingdetail:need, the prompt from aquestionsarray, clipping, and reading the gate and META only when not given them.lambda/v2-orchestrator/test/engine-gate-notification.test.jscovers engine gates: one publish per gate with the expected detail, nothing when the run was replaced, and an identical step sequence with and without a bus.npm run lint,npm run format:check, and the discussions, projects, v2-orchestrator and shared vitest projects pass, includingbundle-smoke.test.js. The projects and discussions bundles also import cleanly with a bus configured.terraform fmt -check,terraform validate -no-testsand everyterraform testsuite from the Terraform workflow pass on Terraform 1.15.0, as does the SSO plan-privacy test. There's no new Terraform test: a plan ofmodules/api/lambdabuilds every Lambda package.Impact
Disabled (the default), nothing is created and no Lambda's configuration changes. Event details include user names, email addresses and message text; the docs page says so.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.