fix(senpi-task): wake parent on task_send revival by promoting the revived epoch to background - #7249
Conversation
…vived epoch to background reviveTerminal() re-armed a terminal resident child without promoting it to background, so an originally sync spawn kept notify_on_terminal=false after revival and notifyTerminal() skipped with 'sync-task' - the idle parent never learned the revived subagent finished. Promote through a new SteeringPort seam before the follow-up starts (so even a fast-settling turn notifies), roll back if the follow-up fails to start, and build the revived record from the fresh persisted state so the promotion is not reverted by the replace. Fixes code-yeongyu#6532
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| - | - | Generic High Entropy Secret | a8d8072 | .omo/evidence/20260824-6532-task-send-wake/live-task-e2e-base.json | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
What
Reviving a terminal resident child via
task_sendnow promotes the revived epoch to background before the follow-up prompt starts, so its completion wakes the idle parent. Concretely:SteeringPortgainspromoteToBackground(taskId), wired to the manager's existing public promotion (persistednotify_on_terminal+background_mode).reviveTerminal()promotes BEFOREhandle.followUp()(so even a fast-settling revived turn notifies), rolls the promotion back if starting the follow-up fails, and builds the revived record from the freshly persisted state so the replace does not revert the promotion.Why
Issue #6532: a synchronous task completes,
task_sendrevives the terminal resident child, the revived run finishes - and the idle parent never wakes. Root cause chain:reviveTerminal()never promoted the revived epoch (packages/senpi-task/src/steering/engine.ts),buildRevived()passednotify_on_terminalthrough untouched, sowasBackground()stayed false andnotifier.tsskipped with{ kind: "skipped", reason: "sync-task" }before idle wake routing was reached. The result only surfaced after a later user message plustask_output.Once revived, the run is asynchronous from the parent's perspective regardless of how it was spawned, so notification intent must flip at revival time.
Verified
packages/senpi-task/src/steering/engine.test.ts: promote-before-followUp ordering (snapshot of persisted state taken inside the handle), rollback on failed follow-up start (promotion undone, error propagates, reservation released not committed), originally-background children keepbackground_mode: "background".packages/omo-senpi/src/components/task/completion-bridge.test.ts: full sync spawn -> terminal -> revive -> completion chain delivers exactly ONE wake per run_epoch; repeated revivals notify once per epoch; originally-background spawns keep notifying exactly once per epoch across revival.bun test packages/senpi-task: 1748 pass / 0 fail (includes the 200-iteration chaos bench pinning exactly-once per(task_id, run_epoch)).bun test packages/omo-senpi: 11 failures, all pre-existing artifact/skill-sync tests that fail identically on the base commit in this sandbox (failedbun installprepare step means plugin artifacts were never built); none touch the task component.tsgo --noEmitclean for bothsenpi-taskandomo-senpi.scripts/qa/task-e2e.mjs(real senpi binary, isolated agent dirs): results byte-identical between base and patch - same PASS set includingunconditional_wakeandsync_inline_no_notification, same pre-existing FAIL set on both sides;real_senpi_untouched: true. Evidence under.omo/evidence/20260824-6532-task-send-wake/.Risk
Low. Behavior changes only for tasks that are revived while
notify_on_terminalis false - exactly the population the issue reports. Originally-background tasks take a no-op promotion path (guard inpromoteToBackground), failed revives roll back to their exact prior record fields (guarded mutate never clobbers concurrent writers), and the concurrency/outcome epoch machinery is untouched. Residual risk: hosts that relied on revived sync children staying silent will now receive one wake per revived epoch, which is the requested behavior.Fixes #6532
Summary by cubic
Reviving a terminal resident child via task_send now promotes the revived epoch to background before the follow-up, so its completion wakes the idle parent. Previously, revival left notify_on_terminal=false and the notifier skipped with "sync-task", so the parent never woke. Fixes #6532.
SteeringPortand wire it to the manager’s existing promotion (persisted notify_on_terminal and background_mode). Implementers ofSteeringPortmust add this method (tests and fakes updated).Written for commit a8d8072. Summary will update on new commits.