subagent: capture overrides at delegation; stamp ahead of prompt vetoes
Review fixes (ds-review-bot on #623): - Capture-at-delegation: the driver now reads overrideOf(parent.session) for both knobs synchronously before its first await, and the prompt-submit listener stamps those captured values — a parent switch racing the child's asynchronous creation belongs to the parent's future, not the child. The inheritOverride(parent, child) service method is split into its two halves (overrideOf / stampOverride) accordingly. - Veto safety: the one-shot prompt-submit listener registers with prepend: true, so a veto-capable listener (a denying UserPromptSubmit hook) cannot close the child's first turn without the durable stamp. Both regressions are pinned red-first in inheritance.spec.ts: the delegation-vs-late-switch race (delegate tool flips the caller wider while the creation transaction is pending) and a blocking prompt-submit listener (stamp survives a promptless first turn). Service contract tests renamed to the split API; READMEs and the bilingual Agent Note updated.
This commit is contained in:
@@ -6,7 +6,7 @@ Each request must belong to an open agent turn. The service appends a paired `ap
|
||||
|
||||
Answerers are `approval/request` waterfall listeners. Return an outcome to answer for an owned agent or call `next()` to delegate. Agent-scoped listeners receive only that agent's requests; compose one terminal answerer per deployment because sibling listener order is not a policy priority mechanism. The ACP bridge is the shipped human answerer.
|
||||
|
||||
`ApprovalPolicy` is `'ask'` or `'never'`. The effective value is the last `approval/policy` event, falling back to config; `setApprovalPolicy()` is the write path. `'never'` rejects before interactive dispatch and is the only policy stated in the prompt. Switches produce at most one coalesced notice, attributed to the user when the override follows the last `request/header` and to operator/config otherwise. `ctx.approval.inheritOverride(parent, child)` stamps a parent session's override (never the configured default) onto a child session through that write path — the in-process subagent driver calls it inside the child's first turn so a `'never'` parent cannot mint prompting children ([rationale](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)).
|
||||
`ApprovalPolicy` is `'ask'` or `'never'`. The effective value is the last `approval/policy` event, falling back to config; `setApprovalPolicy()` is the write path. `'never'` rejects before interactive dispatch and is the only policy stated in the prompt. Switches produce at most one coalesced notice, attributed to the user when the override follows the last `request/header` and to operator/config otherwise. `ctx.approval.overrideOf(session)` / `ctx.approval.stampOverride(child, policy)` are the two halves of delegation inheritance — the fold alone (never the configured default), and the write of a captured override through that write path; the in-process subagent driver captures at delegation and stamps inside the child's first turn so a `'never'` parent cannot mint prompting children ([rationale](../../../.agents/notes/implemented/feature/2026-07-25-subagent-policy-inheritance.md)).
|
||||
|
||||
The tools pipeline routes `ask` decisions through this seam and fails closed when it is absent; the sandboxed bash tool also uses it for escalated retries. The ACP bridge is the shipped human answerer for calls it owns. Audit events remain log-only, so the model sees only the asking consumer's result. See the [approval-seam Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-approval-seam.md) and [sandbox Agent Note](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user