workflow: close the review-found cancellation and child-lifecycle gaps

Three review findings on the engine's child seam, one mechanism each:

- Cancellation now bridges to run.cancel() on every in-flight child, not
  just the shared request signal — the subagent seam leaves a provider
  free to honor either channel, so the consumer drives both (listener
  removed in the child finally).
- A child result REJECTION (an infrastructure fault the seam allows) now
  emits the paired workflow/agent-end before propagating, and propagates
  as a fatal WorkflowError with the new AGENT_RESULT code — previously it
  skipped agent-end (permanently open child for seq-matching observers)
  and dissolved to a per-item null inside parallel()/pipeline(), letting
  a broken provider read as an ordinary failed child. A rejection landing
  after cancel stays a cancellation (cancelled outcome + CANCELLED).
- Every hook now guards its entry with a shared throwIfCancelled():
  phase()/log() no longer emit observer events after a script caught an
  earlier cancelled rejection, and parallel()/pipeline() refuse entry —
  cancellation is the next HOOK boundary, not just the next agent().
This commit is contained in:
Tianyi Cui
2026-07-06 21:02:41 +08:00
parent e70227d581
commit db4a39b024
4 files changed
+148 -13

No files matched your search

+4
View File
@@ -127,6 +127,9 @@ export type WorkflowEventName =
* subset (see dsh-tools).
* - `AGENT_CAP` / `ITEM_CAP` — the run/agent caps tripped.
* - `AGENT_START` — the subagent seam refused to start a child.
* - `AGENT_RESULT` — a child's `result` REJECTED: an infrastructure fault at
* the subagent seam, distinct from a child that failed and resolved (which
* is the per-item `null`, never an error).
* - `RESULT_UNSERIALIZABLE` — a value crossing the script/host value boundary
* is not plain JSON data.
* - `CANCELLED` — the run was cancelled; pending and future hooks reject
@@ -141,6 +144,7 @@ export type WorkflowErrorCode =
| 'AGENT_CAP'
| 'ITEM_CAP'
| 'AGENT_START'
| 'AGENT_RESULT'
| 'RESULT_UNSERIALIZABLE'
| 'CANCELLED'