Skip to content

fix(subagent,core): reap panicked sub-agents via join_handle, scrub PII in sub-agent debug dumps#6414

Merged
bug-ops merged 5 commits into
mainfrom
fix/6408-subagent-reap-pii-scrub
Jul 17, 2026
Merged

fix(subagent,core): reap panicked sub-agents via join_handle, scrub PII in sub-agent debug dumps#6414
bug-ops merged 5 commits into
mainfrom
fix/6408-subagent-reap-pii-scrub

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Two P3 bug follow-ups discovered during impl-critic review of PR #6406, bundled together since both are small, independent defense-in-depth fixes from the same review cycle.

  • collect_finished_subagents() (crates/zeph-core/src/agent/scheduler_loop.rs) determined reapability purely from status_rx's terminal state, so a sub-agent task that exited via a panic — without ever publishing a terminal SubAgentStatus — left its handle frozen in the last observed Working state forever, reproducing the TUI agents sidebar shows sub-agent as WORKING forever after LLM-call timeout (zombie entry, elapsed counter climbs indefinitely) #6381 zombie-sidebar-entry symptom through a path fix(subagent): publish terminal status on LLM timeout and capture debug dumps #6406 did not close. Added join_handle.is_finished() as an independent terminal signal (BlockingHandle::is_finished in zeph-common, SubAgentManager::is_task_finished in zeph-subagent). Also fixed a related bug in SubAgentManager::collect(), which early-returned via ? on a panicked join_handle, skipping the fleet mark_terminal call and the final TranscriptMeta write for panicked tasks.
  • Sub-agent-executed LLM-call debug dumps (wired in fix(subagent): publish terminal status on LLM timeout and capture debug dumps #6406 via DebugDumpSink) received baseline scrub_content/redact_binary_blobs scrubbing but skipped the optional extra PiiFilter.scrub() layer that top-level dumps get when PII filtering is enabled — an inconsistent PII-redaction posture between top-level and sub-agent-executed dumps. Added PiiScrubbingDumpSink, wrapping DebugDumper with the same PiiFilter handle used by top-level dump construction, wired into build_spawn_context for both fresh spawn and /agent resume.

Closes #6408
Closes #6407

Test plan

  • New regression tests: reap-on-panic-via-backstop, keep-alive negative path (still-running handle not reaped), PII-scrub-when-enabled, skip-when-disabled
  • cargo +nightly fmt --check
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins (14161 passed)
  • RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler"
  • cargo test --doc --workspace --features "desktop,ide,server,chat,pdf,scheduler" (34 doc-test suites)
  • gitleaks detect on the branch diff
  • Adversarial critique (rust-critic) and code review (2 rounds) both passed

@github-actions github-actions Bot added documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate bug Something isn't working size/XL Extra large PR (500+ lines) labels Jul 17, 2026
bug-ops added 5 commits July 17, 2026 22:12
…just status_rx

collect_finished_subagents() previously determined reapability purely from
status_rx terminal state, so a panicking sub-agent task left its handle
frozen in the last observed Working state and never got reaped, reproducing
the zombie-sidebar-entry symptom via a path #6406 did not close. Add
join_handle.is_finished() as an independent terminal signal.

collect() also early-returned via `?` on a panicked join_handle, skipping
fleet mark_terminal and the final TranscriptMeta write; flattened the
double-Result so both still run for panicked tasks.

Closes #6408
Sub-agent LLM-call debug dumps wired in #6406 received the baseline
scrub_content/redact_binary_blobs pass but skipped the optional extra
PiiFilter.scrub() layer that top-level dumps get when [classifiers]/PII
filtering is enabled, giving sub-agent dumps a weaker PII-redaction
posture than top-level dumps.

Add PiiScrubbingDumpSink, wrapping DebugDumper with the same PiiFilter
handle used by top-level dump construction, and wire it into
build_spawn_context's debug_dump_sink for both fresh spawn and
/agent resume. PiiFilter now derives Clone (cheap, Regex is Arc-backed).

Closes #6407
collect_finished_subagents_reaps_handle_whose_task_finished_without_terminal_status
covers the reap side of the join_handle.is_finished() backstop but nothing
guarded against over-eager reaping. Add a test asserting a handle whose
task is genuinely still running (status_rx == Working, is_finished() ==
false) survives collect_finished_subagents().
Replace redundant closure with a bare function reference in the
negative-path regression test (clippy::redundant_closure under -D
warnings), and add the missing CHANGELOG.md entry for the #6408 fix.
DebugState::write_chat_debug_dump is private (agent::state is
pub(crate)), so linking to it from a pub item trips
rustdoc::private_intra_doc_links under -D warnings. Drop the link
markup, keep the reference as plain inline code text.
@bug-ops
bug-ops enabled auto-merge (squash) July 17, 2026 20:12
@bug-ops
bug-ops force-pushed the fix/6408-subagent-reap-pii-scrub branch from 15d301c to 3381c8d Compare July 17, 2026 20:12
@bug-ops
bug-ops merged commit 57b0600 into main Jul 17, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6408-subagent-reap-pii-scrub branch July 17, 2026 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working core zeph-core crate documentation Improvements or additions to documentation rust Rust code changes size/XL Extra large PR (500+ lines)

Projects

None yet

1 participant