refactor(subprocess): the dispose ladder moves to its one consumer
SubprocessHandle loses dispose(graces) and SubprocessDisposeGraces: the stdin-EOF→SIGTERM→SIGKILL sequence is teardown POLICY encoding one consumer's cooperation shape, not process vocabulary — the seam keeps kill/terminate/waitForExit, and waitForExit(signal?) is the quiescence probe a consumer ladder needs. dsh-subagent-acp owns disposeAcpChild() over those public verbs (tier tests move into its suite; a never-exits stub pins the fail-loud path); dsh-subprocess-local sheds the ladder, its deadline import, and the dsh-timeout dependency. Every future backend now owes four verbs and no teardown policy. New bilingual ladder-ownership Agent Note records the decision; catalogs regenerated.
This commit is contained in:
@@ -132,7 +132,7 @@ interface SubprocessSpawnSpec {
|
||||
|
||||
## Handles: streams, readers, and tree-scoped termination
|
||||
|
||||
A spawn returns a live handle immediately. Collect-mode readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; piped streams belong to the caller. Termination is tree-scoped on every platform: `kill(signal)` sends one signal Node-style, `terminate()` escalates SIGTERM→grace→SIGKILL, `waitForExit()` observes the whole tree, and `dispose(graces)` runs the cooperative stdin-EOF→SIGTERM→SIGKILL ladder out-of-process children need.
|
||||
A spawn returns a live handle immediately. Collect-mode readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; piped streams belong to the caller. Termination is tree-scoped on every platform: `kill(signal)` sends one signal Node-style, `terminate()` escalates SIGTERM→grace→SIGKILL, and `waitForExit()` observes the whole tree — enough for a consumer to build its own teardown ladder (the ACP backend's stdin-EOF-first `disposeAcpChild` is the template).
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
@@ -177,15 +177,6 @@ interface SubprocessHandle {
|
||||
* @returns `true` when the tree exited, `false` when the signal aborted first.
|
||||
*/
|
||||
waitForExit(signal?: AbortSignal): Promise<boolean>
|
||||
/**
|
||||
* Tear the child down to quiescence, resolving only after exit: close stdin
|
||||
* (when this handle owns a piped one) and allow cooperative flush for
|
||||
* `eofGraceMs`, then SIGTERM with a `graceMs` window (POSIX), then forced
|
||||
* tree termination with a final bounded `graceMs` wait.
|
||||
* @param graces - the ladder's two windows, from the consumer's Config.
|
||||
* @throws when the child still has not exited `graceMs` after the forced tier.
|
||||
*/
|
||||
dispose(graces: SubprocessDisposeGraces): Promise<void>
|
||||
}
|
||||
```
|
||||
|
||||
@@ -233,31 +224,6 @@ interface SubprocessCollectedOutputs {
|
||||
}
|
||||
```
|
||||
|
||||
```ts type-equiv
|
||||
/**
|
||||
* The two grace periods of the cooperative dispose ladder
|
||||
* ({@link SubprocessHandle.dispose}). Consumers carry them as defaulted,
|
||||
* validated Config fields, so teardown timing is deployment-tunable and this
|
||||
* seam hardcodes nothing.
|
||||
*/
|
||||
interface SubprocessDisposeGraces {
|
||||
/**
|
||||
* Tier-1 window (ms): after stdin EOF, how long the child gets to quiesce
|
||||
* ON ITS OWN — flush durable state, tear down its own descendants — before
|
||||
* escalation to platform termination. Usually WIDER than
|
||||
* {@link SubprocessDisposeGraces.graceMs}: a cooperative child's EOF-driven
|
||||
* teardown may itself wait on a signal-trapping grandchild plus a final
|
||||
* flush.
|
||||
*/
|
||||
eofGraceMs: number
|
||||
/**
|
||||
* Termination confirmation window (ms): POSIX applies it after `SIGTERM`
|
||||
* and again after `SIGKILL`; Windows applies it after the forced tree
|
||||
* termination.
|
||||
*/
|
||||
graceMs: number
|
||||
}
|
||||
```
|
||||
|
||||
## Outcomes carry exit facts only
|
||||
|
||||
|
||||
Reference in New Issue
Block a user