fix(omo-senpi): report child results waiting in the wake queue (#10782)
Part of code-yeongyu/oh-my-openagent#10782 (item 2: child results waiting in the wake queue).
What changed
Between a child finishing and its result reaching the parent, the result waits in the idle-injection batch window (or in an async delivery). Nothing told the engine about it, so senpi's lifecycle (code-yeongyu/senpi#3864) could read the parent as done in that gap.
idle-injection-coordinator.ts: an optionalonChildWorkChange(count)is called with each new count of child results that are queued or still in delivery. Child sources aretask-completion,workpool-aggregate,team-messageanddag-run; continuations and kibitzer nudges are the parent's own and do not count. A result leaves the count when its delivery succeeds or fails, or when the coordinator retires.wake-queue-source.ts(new): publishes the count aswake_source_state { source: "omo-wake-queue", kind: "children", activeCount }.compose.ts: wires the publisher into the shared coordinator.
Not covered here: when a delivery fails, the producer owns the result again (senpi-task redelivers it at the next session_start), so the queue stops counting it at the failure receipt.
Bundle car: source and tests only; the batch regenerates plugin/ and adds the [Unreleased] line.
Tests
idle-injection-child-work.test.ts(new): queued -> delivered (1, 0), async delivery keeps the child counted until it resolves, a rejected delivery clears it, continuations and passive nudges never count, distinct counts are reported once, retire clears it, and the publisher's exact event. Without the coordinator change 5 fail / 2 pass; with it 7/7.src/extension+src/components/task: 1006 pass, 0 fail.tsgo --noEmit -p packages/omo-senpi/tsconfig.json: clean.
Live QA (senpi-qa)
Real senpi (the pinned engine), plugin built from this branch, the task-rpc-e2e scenario A (a background process child; the parent waits for the child's terminal record, so its completion lands while the parent is alive), a probe extension recording every wake_source_state.
- the child's completion was delivered;
omo-wake-queuewent1then0, both withkind: "children" - senpi exit 0; real
~/.senpisettings untouched; no QA process left behind - evidence:
.omo/evidence/omo-senpi-adapter/20261024-wake-queue-count/, sha256:- checks.json 5bcdaf2d44fba591a6d002d01fde5201b73834d0f3df5bee6257956184d8655c
- wake-source-events.json 79eb8a14aa8ab6e1643079af488d76518ae1cef72f80275b0dd9ed995d8811e8
- run.log 60b38f9903506c41a3beac7929fa0dd4843aead540b65446474d889e82db2187
- wake-queue-rpc-qa.mjs b295c85959e8c48f1095ac6a0f487e876a0a40d57a5e298378ce51c6a7504636
(A first live attempt in print mode never delivered a completion: the parent ended its turn and senpi exited before the child finished, so the RPC scenario's wait-for-child step is what exercises this path.)
Summary by cubic
Fixes the lifecycle gap where the engine could read a parent as done between a child finishing and its result reaching the parent. The idle-injection coordinator now counts child results that are queued or still in delivery and publishes the count as an omo-wake-queue wake source of kind children, so senpi's lifecycle keeps the session open until the result lands.
- Counts task completions, workpool aggregates, team messages, and dag runs; continuations and kibitzer nudges are the parent's own and don't count.
- A result leaves the count when its delivery succeeds or fails, or when the coordinator retires. After a failed delivery the producer owns the result again, so the queue stops counting it at the failure receipt.