Skip to content

docs: report an execution's outcome to another execution - #97

Closed
psteinroe wants to merge 2 commits into
mainfrom
docs/outcome-recipe
Closed

psteinroe wants to merge 2 commits into
mainfrom
docs/outcome-recipe

Conversation

@psteinroe

Copy link
Copy Markdown
Owner

What

A new recipe page, Report an Execution's Outcome to Another Execution (docs/content/crafting-tasks/report-outcomes.md), added to the nav after Child Invocation. Postgres Conductor dropped the planned onSettled option in favour of this pattern. The page covers:

  • Supervisor: ctx.invoke → ctx.waitForResult → ctx.signalWithStart with { executionId, outcome }. It explains that a finished, short-lived target is started again for the report.
  • Deterministic signal ids: ctx.signalWithStart is memoized, but ctx.sendSignal runs again on every replay, so a signal id derived from the watched execution makes it store once. The target still dedupes by id, because delivery is at least once.
  • Watcher: the work starts a cancelWithParent watcher on its caller, which sends a shutdown signal (or calls ctx.cancel) when the caller fails or is cancelled.
  • Racing an execution against events: ctx.waitForAny with an { execution: id } branch, using an approval card as the example.
  • Retention rule (see below).
  • Known gaps compared with a settlement hook: one extra execution per watched call, and nothing is sent if the supervisor is cancelled or dead-lettered.

Retention rule (tested)

New test in wait-for-result.test.ts: the watched execution settles and is removed at settlement (removeOnComplete: true, or removeOnFail: true with a failure) before the wait registers.

  • ctx.waitForResult, the waitForAny execution branch and conductor.waitForResult all throw Execution <id> not found. None of them hangs, and no wait subscription is left behind.
  • A wait that registered before the removal still gets the outcome. An existing test already covers this.

The page tells readers to keep the watched task's retention longer than the wait, or to start the wait before the work can finish. It also points out that the supervisor races against immediate removal: a tool that finishes between invoke and waitForResult is already gone.

Fixes found along the way

retention.md and api/conductor.md said removeOnComplete: true removes executions "at the next maintenance run". In fact it maps to 0 days and removes the execution when it settles (the new test relies on this). Both pages are corrected.

Verification

  • tests/integration/outcome-recipe.test.ts compiles and runs the page's examples (supervisor with completed and failed outcomes plus a session restart, watcher shutdown on caller cancel, approval-card race).
  • just lint, just format, pnpm typecheck and the full pnpm test pass. The one failure in the full run was a race in the new test, which is fixed: it now waits for the first session to finish.
  • uv run zensical build builds the page, and all cross-page anchors resolve.

Follow-ups

  • docs/zensical.toml lists task-execution/rate-limiting.md, which does not exist (outside this PR's scope).

@psteinroe psteinroe closed this Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant