DMs are private channels, not a separate scoping model. Pin that
contract with four tests in dispatch_scope_tests:
- scope derivation is channel-type-agnostic: identical tag shapes
derive identical root components on DM and stream channels in both
modes
- thread mode: two top-level DM messages are distinct concurrent
roots on distinct workers (context registers the channel as a DM)
- thread mode: a threaded DM reply joins its outermost root's batch
- channel mode: DM events collapse to (channel, None) and serialize,
second worker idle
Test-only; no production code touched.
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Mari's re-review: after a rollback/reconciliation pass, a failed
stopAgent leaves a process running under the wrong scope and a failed
startAgent leaves it stopped — committing a normal UI scope in either
case claims a convergence that does not exist. All process rollbacks
are still attempted, but any failure now surfaces onUnrecoverable
(card disables the toggle) instead of setUi.
Tests: the one-rollback-restart-fails case now asserts hard recovery
and no UI claim; new rollback-stop-failure case asserts the same.
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Two review findings from the PR #1981 session-scope setting:
Legacy materialization (Mari, MAJOR 1): hydration read the legacy
acp_top_level_sessions override but never persisted the translation, so
removing the compatibility reader would silently flip explicit channel
users to the thread default. hydrate_scope now atomically materializes
an explicit legacy value into acp_session_scope during hydration —
false→channel, true→thread — while the bare no-field default stays
unwritten (unset remains distinguishable from an override) and an
explicit new-field value is never rewritten. DesktopSettings gains a
#[serde(flatten)] passthrough so any save preserves JSON fields owned
by other features. A failed materialization write keeps the translated
scope in memory and the legacy field on disk for retry — no divergence.
Rollback convergence (Mari, MAJOR 2): on apply failure with a failed
rollback write, the old path restarted processes and forced the UI to
'previous' while the authoritative backend still held the new value —
false convergence. applyAcpSessionScopeSetting now establishes the
authoritative scope first (confirmed rollback write, else re-read via
getBackend), reconciles processes and UI to that actual value, and if
the authority is unreadable fires onUnrecoverable — the card surfaces a
hard recovery state and disables the toggle instead of claiming a scope.
Tests: 7 new Tauri hydration/materialization tests (incl. read-only-dir
write-failure injection) and 2 new rollback-matrix tests (authority
re-read reconciliation; double-failure hard recovery).
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Reviewer-authored deterministic coverage for the pool-affinity edges Eva
flagged unwritten at eca05aa25 (LRU-eviction-under-load, worker
death/respawn). All test-only, in the pool.rs test module — no production
changes.
- quinn_lru_evict_stale_reservation_does_not_beat_real_session_holder:
a stale session_owners[key]->slot reservation must not win over a
different slot that actually holds the session. Proven non-vacuous:
fails (claims stale slot 0 vs correct slot 1) when
prune_session_owners is neutered, so prune is load-bearing for
affinity correctness (prevents a forked provider session).
- quinn_bare_stale_reservation_is_pruned: bare stale reservation is
dropped by prune -> clean Pass 2 claim, no phantom session.
- quinn_busy_owner_does_not_block_unrelated_root: a busy retained root
returns ClaimOutcome::BusyOwner (never migrates, never Exhausted)
while an unrelated root claims another idle slot concurrently.
- quinn_respawn_clears_stale_reservation: a respawned fresh-state agent
at the same index does not inherit the dead session via a stale
reservation.
cargo test -p buzz-acp: 561 passed. clippy -D warnings clean, fmt clean.
Co-authored-by: Tyler Longwell <tlongwell@block.xyz>
Signed-off-by: Tyler Longwell <tlongwell@block.xyz>
Three fixes for PR CI:
- fmt: apply rustfmt to the rebased command_env helper in
managed_agents/runtime/tests.rs (Rust Lint failure).
- lib.rs over the 1000-line limit: move the window/haptic tauri
commands (perform_sidebar_default_haptic, title_bar_double_click,
fill_window, toggle_maximize) into commands/window_actions.rs where
they belong with the other frontend-forwarded commands
(1012 -> 901 lines, back under the default limit).
- app_state.rs over its ratchet: drop the AppState field for the
experiment entirely. The experiment flag now lives in
commands/experiments.rs as a process-local atomic, lazily hydrated
from the Rust-owned store on first read. The hydrate-before-restore
ordering invariant now holds by construction (the spawn boundary is
the first reader) instead of by an app-setup ordering requirement,
and app_state.rs is byte-identical to main — one less shared surface
the experiment touches.
desktop src-tauri: cargo test 1483 passed, clippy and fmt clean, and
node scripts/check-file-sizes.mjs passes.
Co-authored-by: npub1zurdm6fx3kksz8f8d8y4js3mvjyu3rshlpqejr8wa8hta5tsqqeshmes7w <1706dde9268dad011d2769c959423b6489c88e17f841990ceee9eebed1700033@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1zurdm6fx3kksz8f8d8y4js3mvjyu3rshlpqejr8wa8hta5tsqqeshmes7w <1706dde9268dad011d2769c959423b6489c88e17f841990ceee9eebed1700033@sprout-oss.stage.blox.sqprod.co>
Reduce the ongoing cost of the top-level-sessions experiment by
collapsing its scattered maintenance surfaces without changing behavior:
- pool: replace eager session_owners reconciliation (5 lifecycle call
sites + retains in return_agent / invalidate_channel_sessions /
model-switch paths) with a single lazy prune_session_owners() at the
one read site in try_claim. Future slot-lifecycle paths can no longer
forget the purge; the invariant converges at one choke point.
- queue: extract pop_cancelled() / dispatch_cancelled() helpers so the
three copy-pasted cancelled-batch blocks in flush_next become
one-liners.
- session key: drop the top_level_sessions bool param and dead
thread-tag fallback from conversation_session_key; remove the
redundant PromptContext.top_level_sessions field. The key is now
purely data-driven from batch.conversation_root, which is only
populated at queue-push when the experiment is enabled.
Net -59 lines. cargo test -p buzz-acp: 530 passed; clippy and fmt
clean. Disabled-mode paths degenerate identically (root=None
everywhere).
Co-authored-by: npub1zurdm6fx3kksz8f8d8y4js3mvjyu3rshlpqejr8wa8hta5tsqqeshmes7w <1706dde9268dad011d2769c959423b6489c88e17f841990ceee9eebed1700033@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1zurdm6fx3kksz8f8d8y4js3mvjyu3rshlpqejr8wa8hta5tsqqeshmes7w <1706dde9268dad011d2769c959423b6489c88e17f841990ceee9eebed1700033@sprout-oss.stage.blox.sqprod.co>