Skip to content

fix(core): parallelize apply_tier_results hooks and align WATCHED_SPANS names#6137

Merged
bug-ops merged 1 commit into
mainfrom
fix/6128-tier-loop-apply-tier-results-s
Jul 12, 2026
Merged

fix(core): parallelize apply_tier_results hooks and align WATCHED_SPANS names#6137
bug-ops merged 1 commit into
mainfrom
fix/6128-tier-loop-apply-tier-results-s

Conversation

@bug-ops

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

Copy link
Copy Markdown
Owner

Summary

  • apply_tier_results (crates/zeph-core/src/agent/tool_execution/tier_loop.rs) processed each tool result's RuntimeLayer::after_tool chain and PostToolUse hook firing sequentially, one index at a time, even though the tier's own tool execution already runs bounded-parallel. A tier with many PostToolUse-matching calls paid N sequential subprocess spawns after already paying for parallel tool execution. The layer/hook phase now runs concurrently across a tier's indices via futures::future::join_all, bounded by the same max_parallel semaphore the tier's tool execution uses.
  • MetricsBridge::WATCHED_SPANS (crates/zeph-core/src/metrics_bridge.rs, profiling feature) named three spans (agent.prepare_context, agent.tool_loop, agent.persist_message) that never matched any real tracing span, silently making their on_close handling dead code — only llm.chat was ever observed. Renamed the first two to their real span names (core.context.prepare_context, core.tool.native_loop). agent.persist_message is intentionally left unwatched: its real span fires many times per turn, so bridging it would report the wrong call's duration instead of the first user-message persist that TurnTimings::persist_message_ms is meant to measure — that field stays manually-timed only.

Closes #6128
Closes #6111

Test plan

  • cargo +nightly fmt --check
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing,profiling" -- -D warnings
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins — 13075 passed, 35 skipped, 0 failed
  • cargo nextest run -p zeph-core --features profiling -E 'test(metrics_bridge) or test(apply_tier_results)' — 6/6 passed
  • New concurrency test (after_tool_hooks_run_concurrently_across_tier_indices) verified non-flaky over 20 runs
  • Rustdoc gate (RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler")
  • Independent adversarial critique of state-mutation safety, error/panic isolation under concurrency, and semaphore bound correctness — verdict: minor, non-blocking
  • Independent code review — approved
  • CHANGELOG.md updated under [Unreleased]
  • .local/testing/playbooks/tier-apply-results-concurrency.md and .local/testing/playbooks/metrics-bridge-watched-spans.md added (main repo)
  • .local/testing/coverage-status.md updated in place (main repo)
  • Live session verification — not required (no config/user-facing surface changed beyond latency and metric accuracy); scenarios documented in the playbooks above for the next CI cycle

Follow-up (non-blocking, noted by reviewer): a dedicated test for hook/layer failure isolation across concurrent indices would strengthen coverage; current isolation is structurally guaranteed (catch_unwind + fail-open hooks, join_all never short-circuits) and independently verified by two reviewers reading the code, but untested directly.

…NS names

apply_tier_results processed each tool result's RuntimeLayer::after_tool
chain and PostToolUse hook firing sequentially, one index at a time, even
though the tier's own tool execution already runs bounded-parallel. Layer
and hook firing now run concurrently across a tier's indices via
futures::future::join_all, bounded by the same max_parallel semaphore the
tier's tool execution uses.

MetricsBridge::WATCHED_SPANS named three spans that never matched a real
tracing span, silently making their on_close handling dead code. Renamed
agent.prepare_context and agent.tool_loop to their real span names, and
removed agent.persist_message entirely — its real span fires many times
per turn, so bridging it would report the wrong call's duration; that
field stays manually-timed only.

Closes #6128
Closes #6111
@github-actions github-actions Bot added bug Something isn't working size/L Large PR (201-500 lines) documentation Improvements or additions to documentation rust Rust code changes core zeph-core crate labels Jul 12, 2026
@bug-ops
bug-ops enabled auto-merge (squash) July 12, 2026 14:49
@bug-ops
bug-ops merged commit c5758e8 into main Jul 12, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6128-tier-loop-apply-tier-results-s branch July 12, 2026 14:55
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/L Large PR (201-500 lines)

Projects

None yet

1 participant