feat(scheduler): pipeline notify — ctx.notify for proactive channel delivery#11
Closed
ogarciarevett wants to merge 1 commit into
Closed
feat(scheduler): pipeline notify — ctx.notify for proactive channel delivery#11ogarciarevett wants to merge 1 commit into
ogarciarevett wants to merge 1 commit into
Conversation
…elivery
Pipeline-facing seam so a running pipeline can push a notification to the user
out a connected channel — the outbound complement to the inbound chatbot flow.
- PipelineContext.notify(text, opts?) gated by NETWORK_FETCH; NotifyFn injected
via BuildContextDeps + SchedulerOptions where `complete` is threaded
(top-level + sub-agent). Core stays decoupled (channel: string, not ChannelId).
- Graceful: missing channel/destination/resolver -> {delivered:false,reason};
only a capability violation throws.
- Host makeNotifyFn (CLI) resolves channel + pairing-persisted owner chatId,
sends through the daemon's running handler, audits each send on events
(notification_sent/notification_failed; body + chat id never logged).
- config.notify.defaultChannel normalization; no migration, no new capability,
no new dependency.
890 tests / 0 fail (+20); 100% line+func coverage on new units; Biome clean.
6 tasks
Owner
Author
|
Closing as already-merged: the full pipeline-notify slice (ctx.notify, NotifyFn seam, makeNotifyFn, config.notify, audit kinds + all tests) landed in |
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.
Why
A pipeline running under the scheduler could think (
complete), record, spawn, and read signals — but had no way to reach the user. The transport (OutboundIntent.kind:"notify"+ChannelHandler.send) and the destination (the owner chat id captured at scan-to-connect pairing) both already existed; only the pipeline-facing seam was missing. This adds it: the outbound, pipeline-initiated complement to the shipped inbound chatbot flow.Downstream specs already assume it (
pipeline-career,pipeline-secretaryplan delivery viahandler.send({ kind:"notify", ... })).What changed
PipelineContext.notify(text, opts?)— gated byNETWORK_FETCH(the egress capabilitysendalready requires). Backed by aNotifyFninjected throughBuildContextDeps+SchedulerOptionsexactly wherecompleteis threaded (top-level run and the sub-agent child context).channel?: string, not the connectionsChannelIdunion, sovesper-core/schedulerkeeps zero dependency on the connections feature layer. The host owns channel identity.{ delivered:false, reason }; only a capability violation throws (a side-channel must not crash a pipeline).makeNotifyFn(CLI) — resolves the channel (explicit →config.notify.defaultChannel→ first running channel with a paired owner) and the pairing-persisted ownerdefaultChatId, sends through the daemon's already-authenticated running handler (no re-auth, no second socket), and audits each send on the existingeventstable (notification_sent/notification_failed, reusingrecordConnectionEvent).config.notify.defaultChannelnormalization (drop unknown / non-string, never throw — matchesnormalizePresence).makeNotifyFnlate-binds the channel registry (built after the scheduler) through a getter, injected into theScheduler.No migration, no new capability, no new dependency. Secret/PII containment: the audit payload is
{channel}only — the message body and chat id never reach the log (a test asserts neither serializes).Test plan
bun test— 890 pass / 0 fail (+20: context, scheduler-context, config, make-notify).make-notify.ts,context.ts).bun run lint(Biome) — clean (exit 0).tsc --noEmit— adds 0 new errors (pre-existing errors in unchanged code remain; CI skips tsc).Issue-capped workspace: the record is
specs/pipeline-notify.md(local) + thecycle-log.mdentry + this PR (Rule 11 fallback).