Skip to content

RFC: opt-in cron.jobs[].notifyOnCompletion for parent wake after isolated cron run #96190

Description

@alfredjbclaw

Summary

This is an RFC (no PR attached) to surface a fourth silent-drop path from the #89095 cluster as a product decision, not a bug fix. ClawSweeper has held back the same scope on #90178 ("adding retry/expiry config knobs ... is a separate maintainer/product decision"), so this issue exists to give that decision a structured place to land independently of the wait-layer + no-output-payload fixes in #96189, #91370, and #95080.

The path

Parent session calls a yielding tool that ultimately spawns an isolated cron run (`executeDetachedCronJob` in `src/gateway/server-methods/server-cron-*.ts`). The cron runs to completion successfully — the cron registry records a clean terminal outcome — but the parent waiting via `sessions_yield` is never resumed, because isolated cron runs are intentionally decoupled from any parent session's completion delivery path.

This is not a bug in the way RC1–RC3 are bugs: the decoupling is intentional. Isolated crons are not supposed to push completion events to arbitrary parent sessions; that would create a many-to-many wakeup graph the cron runtime has explicitly avoided.

But for the narrow case where a parent explicitly opted in to wait for a specific cron run's completion (because the surface that spawned the cron was thread-bound), the current behavior is indistinguishable from RC1/RC2 from the user's perspective: the parent hangs forever.

Proposed surface (Path B)

Opt-in per cron job:

```yaml
cron:
jobs:
- id: nightly-distillation
schedule: "30 23 * * *"
task: ...
notifyOnCompletion: true # opt-in; default false
```

Or per-spawn for ad-hoc detached cron runs:

```ts
spawnCron({
jobId: "...",
notifyOnCompletion: true,
notifyTarget: { sessionKey: "..." }, // explicit; no implicit "parent" fan-out
});
```

When set, `executeDetachedCronJob` queues a bounded completion event into the named target session at terminal time, with the same shape as the synth notice landing in #96189:

Background cron task `` finished (status: ok | error | timeout). \<terminalSummary | "no visible reply"\>

Default is false — no behavior change for any existing cron job.

Why opt-in, not always-on

  • Many cron jobs intentionally have no parent (truly detached background work). An always-on wake would create noise and would require every cron caller to suppress.
  • Some cron jobs run hundreds of times per day; an always-on wake amplifies any downstream session-routing bug.
  • The opt-in flag makes the wake contract explicit at the spawn site, which matches the existing pattern for `expectsCompletionMessage` on `sessions_spawn`.

Alternatives considered

Path A: implicit wake based on "the spawning session was thread-bound at spawn time." Rejected because (a) it conflates two different contracts (cron lifetime vs. parent-session lifetime), (b) thread-bound spawn sites are not always parent-session-bound, and (c) it would require persisting the parent-session reference inside the cron registry, which the cron runtime has otherwise avoided.

Path C: leave it alone and document that yielded waits on cron must time out. Rejected because the empirical behavior is identical to RC1/RC2 — "yield then nothing forever" — and users will keep filing the same bug report against the cron surface.

Scope of this RFC

This issue is for the product decision and the API surface, not the implementation. If the decision is "ship Path B," a follow-up PR can implement it; if the decision is "don't ship," please document the explicit non-goal so future similar reports can be triaged faster.

Linked context

cc @clawsweeper for triage routing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions