Skip to content

fix(core,acp): reset owner_key/is_guest_context staleness, thread ACP identity into cross-thread store#6428

Merged
bug-ops merged 1 commit into
mainfrom
fix/6418-owner-key-stale-dispatch
Jul 17, 2026
Merged

fix(core,acp): reset owner_key/is_guest_context staleness, thread ACP identity into cross-thread store#6428
bug-ops merged 1 commit into
mainfrom
fix/6418-owner-key-stale-dispatch

Conversation

@bug-ops

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

Copy link
Copy Markdown
Owner

Summary

Two follow-ups from the cross-thread store owner_key work (spec-080, #6389 / PR #6416):

  • session.owner_key/is_guest_context were set only in the LoopEvent::Message arm of the agent loop and reset only at Agent::end_turn. A fast-path slash-command dispatch that exits the loop iteration via DispatchFlow::Continue/Break before reaching end_turn could leave a stale value in place for the next LoopEvent (a scheduled task, autonomous tick, or a different sender's fast-path message). Both scalars are now reset unconditionally at the top of every Agent::run loop iteration, closing the gap uniformly across CLI/TUI/Telegram/gateway/A2A/ACP. end_turn's existing reset is kept as defense-in-depth.
  • ACP dispatch never threaded its already-authenticated per-connection identity into the cross-thread store, collapsing every ACP session to the shared "local" bucket like the single-user CLI/TUI/Telegram paths, despite ACP having the strongest per-caller identity of any dispatch path. All three ChannelMessage construction sites in the ACP agent (do_prompt, /clear, /review) now carry that identity as owner_key.

Review notes

  • impl-critic verified the reset placement is provably correct (nothing reads session.owner_key/is_guest_context between the reset and the point where they're set for the current iteration) and traced all ACP entry points to confirm the three ChannelMessage sites cover every path that reaches the cross-thread store.
  • A related, narrower gap was found and confirmed out of scope: QueuedMessage has no owner_key/is_guest_context fields, so a ChannelMessage queued mid-turn silently loses its owner_key at drain_channel. Confirmed unreachable today (every channel that can carry a real owner_key routes through recv(), not try_recv()) and fail-safe in direction (falls back to the shared default bucket, never misattributes to another tenant). Worth a follow-up issue, not a blocker here.
  • Reviewer independently ran the full CI-matching check suite (fmt, clippy --profile ci, nextest, rustdoc gate) after rebase — all green.

Test plan

  • New regression test proving the fast-path staleness bug (verified load-bearing by reverting the fix and confirming the test fails)
  • Two-turn Agent integration test asserting owner_key set/reset through a real turn
  • scheduler_loop.rs test proving persist_handoff_update/append_shared_state_block are load-bearing on owner_key
  • ACP owner_key-threading tests for /clear and /review
  • cargo +nightly fmt --check
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings
  • cargo nextest run --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins (14222 passed)
  • rustdoc gate (RUSTFLAGS=-D warnings, --deny rustdoc::broken_intra_doc_links)

Closes #6418
Closes #6419

@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/L Large PR (201-500 lines) labels Jul 17, 2026
…on, thread ACP identity into cross-thread store

Reset session.owner_key and is_guest_context unconditionally at the top
of every Agent::run loop iteration instead of relying solely on
end_turn, so a fast-path slash-command dispatch that bypasses
process_user_message cannot leak a stale value into the next
LoopEvent regardless of its origin (#6418).

Thread ACP's already-authenticated per-connection identity into all
three ChannelMessage construction sites (do_prompt, /clear, /review)
so ACP sessions get cross-thread store isolation consistent with
gateway/A2A instead of collapsing to the shared local bucket (#6419).

Closes #6418
Closes #6419
@bug-ops
bug-ops force-pushed the fix/6418-owner-key-stale-dispatch branch from c935f38 to 2572e2c Compare July 17, 2026 22:15
@bug-ops
bug-ops enabled auto-merge (squash) July 17, 2026 22:15
@bug-ops
bug-ops merged commit b5d17c6 into main Jul 17, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6418-owner-key-stale-dispatch branch July 17, 2026 22:24
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