fix(acp): gate edit steer preparation

Signed-off-by: Larry <8cf5a83f590ec0955b11647d1c88f796a98e088c30a492c58e0e46c3026ae7a4@buzz.block.builderlab.xyz>
This commit is contained in:
Larry
2026-08-11 11:30:35 -04:00
parent 122acdd8fb
commit 63bbdf6d2a
3 changed files with 45 additions and 1 deletions

View File

@@ -2854,7 +2854,19 @@ async fn tokio_main() -> Result<()> {
// agent.
let native_attempted = if matches!(signal, ControlSignal::Steer)
{
if queue::edit_target_id(&event_for_steer).is_some() {
let is_edit =
queue::edit_target_id(&event_for_steer).is_some();
if queue.has_native_steer_reservations(
buzz_event.channel_id,
) {
tracing::debug!(
channel_id = %buzz_event.channel_id,
"native steer preparation already pending; preserving channel order via cancel+merge"
);
false
} else if is_edit
&& pool.native_steer_available(buzz_event.channel_id)
{
let event_id = event_for_steer.id.to_hex();
let channel_id = buzz_event.channel_id;
match reserve_native_edit_preparation(
@@ -2892,6 +2904,12 @@ async fn tokio_main() -> Result<()> {
false
}
}
} else if is_edit {
tracing::debug!(
channel_id = %buzz_event.channel_id,
"native edit steer unavailable before preparation; falling back to cancel+merge"
);
false
} else {
let prompt_blocks =
pool::format_native_steer_prompt_sync(

View File

@@ -699,6 +699,21 @@ impl AgentPool {
&mut self.task_map
}
/// Return whether the current channel task can accept a native steer now.
///
/// This is a main-loop preflight for edit enrichment: avoid withholding an
/// edit and performing REST work when the task has no steer transport or
/// its capacity-one request slot is already occupied. Availability can
/// still change while enrichment runs, so callers must retain the normal
/// send-time fallback.
pub fn native_steer_available(&self, channel_id: Uuid) -> bool {
self.task_map
.values()
.find(|meta| meta.channel_id == Some(channel_id))
.and_then(|meta| meta.steer_tx.as_ref())
.is_some_and(|tx| !tx.is_closed() && tx.capacity() > 0)
}
/// Try to send a goose-native steer request to the in-flight task for
/// `channel_id`.
///

View File

@@ -751,6 +751,13 @@ impl EventQueue {
true
}
/// Return whether this channel has any native-steer reservation in flight.
pub fn has_native_steer_reservations(&self, channel_id: Uuid) -> bool {
self.withheld_native_steer
.get(&channel_id)
.is_some_and(|entries| !entries.is_empty())
}
/// Return whether this exact event still owns a native-steer reservation.
///
/// Async edit preparation uses this at completion time: deadline recovery,
@@ -4856,6 +4863,8 @@ mod tests {
q.in_flight_deadlines.insert(ch, Instant::now());
q.in_flight_batch_sizes.insert(ch, 1);
assert!(q.mark_native_steer_pending(ch, &event_id));
assert!(q.has_native_steer_reservations(ch));
assert!(q.has_native_steer_reservation(ch, &event_id));
// Force the in-flight deadline to be in the past, simulating the
// steer ack never arriving and the read loop hanging long enough
@@ -4873,6 +4882,8 @@ mod tests {
// The withheld event has been moved back to `queues[ch]`.
assert!(q.withheld_native_steer.is_empty());
assert!(!q.has_native_steer_reservations(ch));
assert!(!q.has_native_steer_reservation(ch, &event_id));
assert_eq!(pending_count(&q), 1);
// Normal dispatch delivers it.