Skip to content

fix(senpi-task): wake parent on task_send revival by promoting the revived epoch to background - #7249

Open
AceRothstein71 wants to merge 1 commit into
code-yeongyu:devfrom
AceRothstein71:issue/6532-task-send-parent-wake
Open

fix(senpi-task): wake parent on task_send revival by promoting the revived epoch to background#7249
AceRothstein71 wants to merge 1 commit into
code-yeongyu:devfrom
AceRothstein71:issue/6532-task-send-parent-wake

Conversation

@AceRothstein71

@AceRothstein71 AceRothstein71 commented Aug 25, 2026

Copy link
Copy Markdown

What

Reviving a terminal resident child via task_send now promotes the revived epoch to background before the follow-up prompt starts, so its completion wakes the idle parent. Concretely:

  • SteeringPort gains promoteToBackground(taskId), wired to the manager's existing public promotion (persisted notify_on_terminal + background_mode).
  • reviveTerminal() promotes BEFORE handle.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.
  • Steering test fixture mirrors the manager's promotion semantics; two inline engine-test ports gain a no-op member.

Why

Issue #6532: a synchronous task completes, task_send revives 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() passed notify_on_terminal through untouched, so wasBackground() stayed false and notifier.ts skipped with { kind: "skipped", reason: "sync-task" } before idle wake routing was reached. The result only surfaced after a later user message plus task_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

  • Failing-first regression at both seams (red observed before the fix, green after):
    • 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 keep background_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 (failed bun install prepare step means plugin artifacts were never built); none touch the task component.
  • tsgo --noEmit clean for both senpi-task and omo-senpi.
  • Live harness A/B with scripts/qa/task-e2e.mjs (real senpi binary, isolated agent dirs): results byte-identical between base and patch - same PASS set including unconditional_wake and sync_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_terminal is false - exactly the population the issue reports. Originally-background tasks take a no-op promotion path (guard in promoteToBackground), 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.

  • Add promoteToBackground(taskId) to SteeringPort and wire it to the manager’s existing promotion (persisted notify_on_terminal and background_mode). Implementers of SteeringPort must add this method (tests and fakes updated).
  • Promote before followUp(); roll back if follow-up start fails; rebuild the revived record from fresh store state to preserve the promotion.
  • Resulting behavior: parents receive exactly one wake per revived epoch; originally background tasks are unchanged.

Written for commit a8d8072. Summary will update on new commits.

Review in cubic

…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
@github-actions github-actions Bot added omo-senpi Changes under packages/omo-senpi senpi-task Changes under packages/senpi-task labels Aug 25, 2026
@gitguardian

gitguardian Bot commented Aug 25, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
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
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. 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


🦉 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

omo-senpi Changes under packages/omo-senpi senpi-task Changes under packages/senpi-task

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(senpi-task): task_send revival of completed foreground task never wakes idle parent

1 participant