@team-agent/installer 0.5.64 → 0.5.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +5 -0
- package/crates/team-agent/src/cli/emit.rs +15 -0
- package/crates/team-agent/src/cli/mod.rs +9 -8
- package/crates/team-agent/src/cli/send/presentation.rs +1 -0
- package/crates/team-agent/src/cli/spec.rs +3 -0
- package/crates/team-agent/src/cli/tests/mod.rs +31 -0
- package/crates/team-agent/src/cli/tests/status_send.rs +13 -3
- package/crates/team-agent/src/cli/types.rs +7 -0
- package/crates/team-agent/src/coordinator/health.rs +17 -0
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +55 -2
- package/crates/team-agent/src/db/migration.rs +2 -1
- package/crates/team-agent/src/db/schema.rs +16 -8
- package/crates/team-agent/src/leader/lease.rs +1 -2
- package/crates/team-agent/src/leader/start.rs +8 -8
- package/crates/team-agent/src/lifecycle/restart/common.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -3
- package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +10 -6
- package/crates/team-agent/src/lifecycle/tests.rs +11 -5
- package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
- package/crates/team-agent/src/messaging/delivery.rs +29 -0
- package/crates/team-agent/src/messaging/helpers.rs +2 -0
- package/crates/team-agent/src/messaging/leader_receiver.rs +12 -0
- package/crates/team-agent/src/messaging/mod.rs +2 -0
- package/crates/team-agent/src/messaging/results.rs +5 -0
- package/crates/team-agent/src/messaging/send.rs +9 -0
- package/crates/team-agent/src/messaging/tests/runtime.rs +32 -0
- package/crates/team-agent/src/messaging/types.rs +2 -0
- package/crates/team-agent/src/messaging/wait.rs +366 -0
- package/crates/team-agent/src/messaging/watchers.rs +153 -6
- package/crates/team-agent/src/tmux_backend.rs +16 -12
- package/crates/team-agent/src/transport.rs +11 -11
- package/package.json +4 -4
|
@@ -74,6 +74,7 @@ pub fn deliver_stored_message(
|
|
|
74
74
|
stage: None,
|
|
75
75
|
reason: None,
|
|
76
76
|
channel: None,
|
|
77
|
+
ack_forced_off: false,
|
|
77
78
|
})
|
|
78
79
|
}
|
|
79
80
|
|
|
@@ -181,6 +182,7 @@ pub fn deliver_pending_message(
|
|
|
181
182
|
stage: None,
|
|
182
183
|
reason: None,
|
|
183
184
|
channel: None,
|
|
185
|
+
ack_forced_off: false,
|
|
184
186
|
});
|
|
185
187
|
}
|
|
186
188
|
let message = message_for_delivery(store, message_id)?;
|
|
@@ -194,6 +196,7 @@ pub fn deliver_pending_message(
|
|
|
194
196
|
stage: None,
|
|
195
197
|
reason: Some(DeliveryRefusal::UnknownRecipient),
|
|
196
198
|
channel: None,
|
|
199
|
+
ack_forced_off: false,
|
|
197
200
|
});
|
|
198
201
|
};
|
|
199
202
|
let mut canonical_owner_team_id = message.owner_team_id.clone();
|
|
@@ -281,6 +284,7 @@ pub fn deliver_pending_message(
|
|
|
281
284
|
stage: None,
|
|
282
285
|
reason: Some(DeliveryRefusal::MessageAlreadyClaimed),
|
|
283
286
|
channel: None,
|
|
287
|
+
ack_forced_off: false,
|
|
284
288
|
});
|
|
285
289
|
};
|
|
286
290
|
if message.recipient == "leader" {
|
|
@@ -310,6 +314,7 @@ pub fn deliver_pending_message(
|
|
|
310
314
|
stage: None,
|
|
311
315
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
312
316
|
channel: Some("rebind_required".to_string()),
|
|
317
|
+
ack_forced_off: false,
|
|
313
318
|
});
|
|
314
319
|
};
|
|
315
320
|
if let Some(outcome) = leader_receiver_transport_conflict_outcome(
|
|
@@ -340,6 +345,7 @@ pub fn deliver_pending_message(
|
|
|
340
345
|
stage: None,
|
|
341
346
|
reason: None,
|
|
342
347
|
channel: Some("rebind_required".to_string()),
|
|
348
|
+
ack_forced_off: false,
|
|
343
349
|
});
|
|
344
350
|
}
|
|
345
351
|
crate::messaging::LeaderChannelResolution::Unbound(reason) => {
|
|
@@ -378,6 +384,7 @@ pub fn deliver_pending_message(
|
|
|
378
384
|
stage: None,
|
|
379
385
|
reason: Some(refusal),
|
|
380
386
|
channel: Some("rebind_required".to_string()),
|
|
387
|
+
ack_forced_off: false,
|
|
381
388
|
});
|
|
382
389
|
}
|
|
383
390
|
}
|
|
@@ -424,6 +431,7 @@ pub fn deliver_pending_message(
|
|
|
424
431
|
stage: None,
|
|
425
432
|
reason: None,
|
|
426
433
|
channel: None,
|
|
434
|
+
ack_forced_off: false,
|
|
427
435
|
});
|
|
428
436
|
}
|
|
429
437
|
};
|
|
@@ -471,6 +479,7 @@ pub fn deliver_pending_message(
|
|
|
471
479
|
stage: Some(DeliveryStage::TrustAutoAnswerDismissalWait),
|
|
472
480
|
reason: None,
|
|
473
481
|
channel: None,
|
|
482
|
+
ack_forced_off: false,
|
|
474
483
|
});
|
|
475
484
|
}
|
|
476
485
|
let rendered = render_message(
|
|
@@ -528,6 +537,7 @@ pub fn deliver_pending_message(
|
|
|
528
537
|
stage: None,
|
|
529
538
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
530
539
|
channel: Some("rebind_required".to_string()),
|
|
540
|
+
ack_forced_off: false,
|
|
531
541
|
});
|
|
532
542
|
}
|
|
533
543
|
if transport_error_is_target_missing(&error) {
|
|
@@ -571,6 +581,7 @@ pub fn deliver_pending_message(
|
|
|
571
581
|
stage: Some(DeliveryStage::Inject),
|
|
572
582
|
reason: None,
|
|
573
583
|
channel: None,
|
|
584
|
+
ack_forced_off: false,
|
|
574
585
|
});
|
|
575
586
|
}
|
|
576
587
|
store.mark(message_id, "target_resolved", Some(&reason))?;
|
|
@@ -583,6 +594,7 @@ pub fn deliver_pending_message(
|
|
|
583
594
|
stage: Some(DeliveryStage::Inject),
|
|
584
595
|
reason: None,
|
|
585
596
|
channel: None,
|
|
597
|
+
ack_forced_off: false,
|
|
586
598
|
});
|
|
587
599
|
}
|
|
588
600
|
};
|
|
@@ -642,6 +654,7 @@ pub fn deliver_pending_message(
|
|
|
642
654
|
stage: Some(DeliveryStage::Submit),
|
|
643
655
|
reason: None,
|
|
644
656
|
channel: None,
|
|
657
|
+
ack_forced_off: false,
|
|
645
658
|
});
|
|
646
659
|
}
|
|
647
660
|
store.mark(message_id, "submitted_unverified", Some(&reason))?;
|
|
@@ -654,6 +667,7 @@ pub fn deliver_pending_message(
|
|
|
654
667
|
stage: Some(DeliveryStage::Submit),
|
|
655
668
|
reason: None,
|
|
656
669
|
channel: None,
|
|
670
|
+
ack_forced_off: false,
|
|
657
671
|
});
|
|
658
672
|
}
|
|
659
673
|
// S1-CAPTURE-001 (0.4.8, CR M4 Claude phase-1): for Claude/ClaudeCode
|
|
@@ -718,6 +732,7 @@ pub fn deliver_pending_message(
|
|
|
718
732
|
stage: Some(DeliveryStage::Submit),
|
|
719
733
|
reason: None,
|
|
720
734
|
channel: None,
|
|
735
|
+
ack_forced_off: false,
|
|
721
736
|
});
|
|
722
737
|
}
|
|
723
738
|
}
|
|
@@ -766,6 +781,7 @@ pub fn deliver_pending_message(
|
|
|
766
781
|
stage: None,
|
|
767
782
|
reason: None,
|
|
768
783
|
channel: None,
|
|
784
|
+
ack_forced_off: false,
|
|
769
785
|
};
|
|
770
786
|
stamp_first_send_at_if_leader_to_worker_scoped(
|
|
771
787
|
workspace,
|
|
@@ -847,6 +863,7 @@ pub(crate) fn mark_worker_target_missing(
|
|
|
847
863
|
stage: Some(DeliveryStage::Inject),
|
|
848
864
|
reason: Some(DeliveryRefusal::TmuxTargetMissing),
|
|
849
865
|
channel: Some("delivery_blocked".to_string()),
|
|
866
|
+
ack_forced_off: false,
|
|
850
867
|
})
|
|
851
868
|
}
|
|
852
869
|
|
|
@@ -1000,6 +1017,7 @@ fn deliver_leader_via_app_server(
|
|
|
1000
1017
|
stage: None,
|
|
1001
1018
|
reason: None,
|
|
1002
1019
|
channel: Some("codex_app_server".to_string()),
|
|
1020
|
+
ack_forced_off: false,
|
|
1003
1021
|
})
|
|
1004
1022
|
}
|
|
1005
1023
|
Err(error) => app_server_delivery_failure(
|
|
@@ -1045,6 +1063,7 @@ fn app_server_delivery_failure(
|
|
|
1045
1063
|
stage: None,
|
|
1046
1064
|
reason: Some(DeliveryRefusal::RecipientBusy),
|
|
1047
1065
|
channel: Some("leader_busy".to_string()),
|
|
1066
|
+
ack_forced_off: false,
|
|
1048
1067
|
})
|
|
1049
1068
|
}
|
|
1050
1069
|
crate::codex_app_server::AppServerError::ThreadStale { expected, actual } => {
|
|
@@ -1083,6 +1102,7 @@ fn app_server_delivery_failure(
|
|
|
1083
1102
|
stage: None,
|
|
1084
1103
|
reason: Some(DeliveryRefusal::MissingPermissions),
|
|
1085
1104
|
channel: Some("codex_app_server".to_string()),
|
|
1105
|
+
ack_forced_off: false,
|
|
1086
1106
|
})
|
|
1087
1107
|
}
|
|
1088
1108
|
crate::codex_app_server::AppServerError::ProtocolMismatch(_)
|
|
@@ -1134,6 +1154,7 @@ fn rebind_required_outcome(message_id: &str, action: &str) -> DeliveryOutcome {
|
|
|
1134
1154
|
stage: None,
|
|
1135
1155
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
1136
1156
|
channel: Some("rebind_required".to_string()),
|
|
1157
|
+
ack_forced_off: false,
|
|
1137
1158
|
}
|
|
1138
1159
|
}
|
|
1139
1160
|
|
|
@@ -1536,6 +1557,7 @@ fn leader_receiver_transport_conflict_outcome(
|
|
|
1536
1557
|
stage: None,
|
|
1537
1558
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
1538
1559
|
channel: Some("rebind_required".to_string()),
|
|
1560
|
+
ack_forced_off: false,
|
|
1539
1561
|
}));
|
|
1540
1562
|
}
|
|
1541
1563
|
}
|
|
@@ -2106,6 +2128,7 @@ fn leader_acceptance_pending_outcome(message_id: &str, status: &str) -> Delivery
|
|
|
2106
2128
|
stage: Some(DeliveryStage::Submit),
|
|
2107
2129
|
reason: None,
|
|
2108
2130
|
channel: Some("leader_acceptance_pending".to_string()),
|
|
2131
|
+
ack_forced_off: false,
|
|
2109
2132
|
}
|
|
2110
2133
|
}
|
|
2111
2134
|
|
|
@@ -2119,6 +2142,7 @@ pub(crate) fn leader_receipt_source_unavailable_outcome(message_id: &str) -> Del
|
|
|
2119
2142
|
stage: Some(DeliveryStage::Submit),
|
|
2120
2143
|
reason: None,
|
|
2121
2144
|
channel: Some("leader_receipt_source_unavailable".to_string()),
|
|
2145
|
+
ack_forced_off: false,
|
|
2122
2146
|
}
|
|
2123
2147
|
}
|
|
2124
2148
|
|
|
@@ -2159,6 +2183,7 @@ fn observe_pending_leader_acceptance(
|
|
|
2159
2183
|
stage: None,
|
|
2160
2184
|
reason: None,
|
|
2161
2185
|
channel: Some("leader_receiver".to_string()),
|
|
2186
|
+
ack_forced_off: false,
|
|
2162
2187
|
})
|
|
2163
2188
|
}
|
|
2164
2189
|
|
|
@@ -2188,6 +2213,7 @@ pub fn handle_trust_retry_needed(
|
|
|
2188
2213
|
stage: Some(DeliveryStage::TrustAutoAnswerDismissalWait),
|
|
2189
2214
|
reason: None,
|
|
2190
2215
|
channel: None,
|
|
2216
|
+
ack_forced_off: false,
|
|
2191
2217
|
});
|
|
2192
2218
|
}
|
|
2193
2219
|
let next_attempt = payload.attempt.saturating_add(1);
|
|
@@ -2227,6 +2253,7 @@ pub fn handle_trust_retry_needed(
|
|
|
2227
2253
|
stage: Some(DeliveryStage::TrustAutoAnswerDismissalWait),
|
|
2228
2254
|
reason: None,
|
|
2229
2255
|
channel: None,
|
|
2256
|
+
ack_forced_off: false,
|
|
2230
2257
|
})
|
|
2231
2258
|
}
|
|
2232
2259
|
|
|
@@ -2723,6 +2750,7 @@ fn refuse_owner_team_resolution(
|
|
|
2723
2750
|
stage: None,
|
|
2724
2751
|
reason: Some(refusal),
|
|
2725
2752
|
channel: Some("owner_team_resolution".to_string()),
|
|
2753
|
+
ack_forced_off: false,
|
|
2726
2754
|
})
|
|
2727
2755
|
}
|
|
2728
2756
|
|
|
@@ -2779,6 +2807,7 @@ pub fn retry_injection_after_trust_auto_answer(
|
|
|
2779
2807
|
stage: Some(DeliveryStage::TrustAutoAnswerDismissalWait),
|
|
2780
2808
|
reason: None,
|
|
2781
2809
|
channel: None,
|
|
2810
|
+
ack_forced_off: false,
|
|
2782
2811
|
})
|
|
2783
2812
|
}
|
|
2784
2813
|
|
|
@@ -294,6 +294,7 @@ pub(crate) fn fail_leader_delivery(
|
|
|
294
294
|
stage: None,
|
|
295
295
|
reason: Some(reason),
|
|
296
296
|
channel: Some("fallback_log".to_string()),
|
|
297
|
+
ack_forced_off: false,
|
|
297
298
|
});
|
|
298
299
|
};
|
|
299
300
|
store.mark(&message_id, "failed", error)?;
|
|
@@ -310,6 +311,7 @@ pub(crate) fn fail_leader_delivery(
|
|
|
310
311
|
stage: None,
|
|
311
312
|
reason: Some(reason),
|
|
312
313
|
channel: Some("fallback_inbox".to_string()),
|
|
314
|
+
ack_forced_off: false,
|
|
313
315
|
})
|
|
314
316
|
}
|
|
315
317
|
|
|
@@ -133,6 +133,7 @@ pub fn send_to_leader_receiver_with_presentation(
|
|
|
133
133
|
stage: None,
|
|
134
134
|
reason: Some(DeliveryRefusal::Duplicate),
|
|
135
135
|
channel: Some("leader_receiver".to_string()),
|
|
136
|
+
ack_forced_off: requires_ack,
|
|
136
137
|
});
|
|
137
138
|
}
|
|
138
139
|
PersistResolution::Persisted(persisted) => persisted.message_id,
|
|
@@ -174,6 +175,7 @@ pub fn send_to_leader_receiver_with_presentation(
|
|
|
174
175
|
stage: None,
|
|
175
176
|
reason: None,
|
|
176
177
|
channel: Some("leader_receiver".to_string()),
|
|
178
|
+
ack_forced_off: requires_ack,
|
|
177
179
|
});
|
|
178
180
|
}
|
|
179
181
|
}
|
|
@@ -210,6 +212,7 @@ pub fn send_to_leader_receiver_with_presentation(
|
|
|
210
212
|
stage: None,
|
|
211
213
|
reason: None,
|
|
212
214
|
channel: Some("leader_receiver".to_string()),
|
|
215
|
+
ack_forced_off: requires_ack,
|
|
213
216
|
})
|
|
214
217
|
}
|
|
215
218
|
|
|
@@ -255,6 +258,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
255
258
|
stage: None,
|
|
256
259
|
reason: None,
|
|
257
260
|
channel: Some("leader_receiver".to_string()),
|
|
261
|
+
ack_forced_off: false,
|
|
258
262
|
});
|
|
259
263
|
}
|
|
260
264
|
|
|
@@ -269,6 +273,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
269
273
|
stage: None,
|
|
270
274
|
reason: None,
|
|
271
275
|
channel: Some("leader_receiver".to_string()),
|
|
276
|
+
ack_forced_off: false,
|
|
272
277
|
});
|
|
273
278
|
}
|
|
274
279
|
|
|
@@ -310,6 +315,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
310
315
|
stage: None,
|
|
311
316
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
312
317
|
channel: Some("fallback_pane".to_string()),
|
|
318
|
+
ack_forced_off: false,
|
|
313
319
|
});
|
|
314
320
|
};
|
|
315
321
|
|
|
@@ -383,6 +389,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
383
389
|
stage: None,
|
|
384
390
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
385
391
|
channel: Some("rebind_required".to_string()),
|
|
392
|
+
ack_forced_off: false,
|
|
386
393
|
});
|
|
387
394
|
};
|
|
388
395
|
let target = Target::Pane(PaneId::new(channel.pane_id));
|
|
@@ -435,6 +442,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
435
442
|
stage: Some(DeliveryStage::Submit),
|
|
436
443
|
reason: None,
|
|
437
444
|
channel: Some("leader_acceptance_pending".to_string()),
|
|
445
|
+
ack_forced_off: false,
|
|
438
446
|
});
|
|
439
447
|
}
|
|
440
448
|
super::delivery::LeaderReceiptObservation::TokenObserved => {}
|
|
@@ -461,6 +469,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
461
469
|
stage: None,
|
|
462
470
|
reason: None,
|
|
463
471
|
channel: Some("fallback_pane".to_string()),
|
|
472
|
+
ack_forced_off: false,
|
|
464
473
|
})
|
|
465
474
|
} else {
|
|
466
475
|
let reason = format!(
|
|
@@ -486,6 +495,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
486
495
|
stage: Some(DeliveryStage::Submit),
|
|
487
496
|
reason: None,
|
|
488
497
|
channel: Some("fallback_pane".to_string()),
|
|
498
|
+
ack_forced_off: false,
|
|
489
499
|
})
|
|
490
500
|
}
|
|
491
501
|
}
|
|
@@ -527,6 +537,7 @@ pub fn deliver_to_leader_fallback_pane(
|
|
|
527
537
|
stage: None,
|
|
528
538
|
reason: Some(DeliveryRefusal::TmuxTargetMissing),
|
|
529
539
|
channel: Some(channel),
|
|
540
|
+
ack_forced_off: false,
|
|
530
541
|
})
|
|
531
542
|
}
|
|
532
543
|
}
|
|
@@ -718,5 +729,6 @@ pub fn enqueue_leader_mailbox_until_attach(
|
|
|
718
729
|
stage: None,
|
|
719
730
|
reason: None,
|
|
720
731
|
channel: Some("leader_mailbox".to_string()),
|
|
732
|
+
ack_forced_off: false,
|
|
721
733
|
})
|
|
722
734
|
}
|
|
@@ -76,6 +76,7 @@ pub mod selftest;
|
|
|
76
76
|
pub mod send;
|
|
77
77
|
pub mod trust;
|
|
78
78
|
pub mod types;
|
|
79
|
+
pub mod wait;
|
|
79
80
|
pub mod watchers;
|
|
80
81
|
|
|
81
82
|
// ── re-export: 保持 `crate::messaging::X` 与 test `super::X` 解析不变 ──────────
|
|
@@ -118,6 +119,7 @@ pub use types::{
|
|
|
118
119
|
TrustRetryPayload, WatcherNotice, WorkerRuntimeState, RESULT_DELIVERY_MAX_ATTEMPTS,
|
|
119
120
|
SEND_RETRY_MAX_ATTEMPTS, TRUST_RETRY_BACKOFF_SECONDS, TRUST_RETRY_MAX_ATTEMPTS,
|
|
120
121
|
};
|
|
122
|
+
pub use wait::{wait_for_result, WaitResult};
|
|
121
123
|
pub use watchers::{
|
|
122
124
|
format_result_watcher_notification, requeue_after_claim_leader,
|
|
123
125
|
requeue_delivery_exhausted_watchers, result_id_from_text, retry_result_deliveries,
|
|
@@ -842,6 +842,7 @@ fn report_result_for_owner_team_inner(
|
|
|
842
842
|
return Ok(serde_json::Value::Object(out));
|
|
843
843
|
}
|
|
844
844
|
let event_log = EventLog::new(workspace);
|
|
845
|
+
super::watchers::notify_fifo_result_watchers(&conn, &event_log, task_id, &result_id)?;
|
|
845
846
|
if presentation.effective_sink != super::presentation::PresentationSink::Leader {
|
|
846
847
|
event_log.write(
|
|
847
848
|
"presentation.stored_without_live_inject",
|
|
@@ -938,6 +939,7 @@ fn report_result_for_owner_team_inner(
|
|
|
938
939
|
stage: None,
|
|
939
940
|
reason: Some(crate::messaging::DeliveryRefusal::LeaderNotAttached),
|
|
940
941
|
channel: Some("codex_app_server".to_string()),
|
|
942
|
+
ack_forced_off: false,
|
|
941
943
|
}
|
|
942
944
|
}
|
|
943
945
|
Err(error) => {
|
|
@@ -1002,6 +1004,7 @@ fn report_result_for_owner_team_inner(
|
|
|
1002
1004
|
stage: None,
|
|
1003
1005
|
reason: None,
|
|
1004
1006
|
channel: Some("leader_receiver".to_string()),
|
|
1007
|
+
ack_forced_off: false,
|
|
1005
1008
|
};
|
|
1006
1009
|
break;
|
|
1007
1010
|
}
|
|
@@ -1031,6 +1034,7 @@ fn report_result_for_owner_team_inner(
|
|
|
1031
1034
|
stage: None,
|
|
1032
1035
|
reason: None,
|
|
1033
1036
|
channel: Some("leader_receiver".to_string()),
|
|
1037
|
+
ack_forced_off: false,
|
|
1034
1038
|
};
|
|
1035
1039
|
break;
|
|
1036
1040
|
}
|
|
@@ -1046,6 +1050,7 @@ fn report_result_for_owner_team_inner(
|
|
|
1046
1050
|
stage: None,
|
|
1047
1051
|
reason: None,
|
|
1048
1052
|
channel: Some("leader_receiver".to_string()),
|
|
1053
|
+
ack_forced_off: false,
|
|
1049
1054
|
};
|
|
1050
1055
|
break;
|
|
1051
1056
|
}
|
|
@@ -214,6 +214,7 @@ pub fn send_message(
|
|
|
214
214
|
stage: None,
|
|
215
215
|
reason: Some(crate::messaging::DeliveryRefusal::EmptyTargetList),
|
|
216
216
|
channel: None,
|
|
217
|
+
ack_forced_off: false,
|
|
217
218
|
});
|
|
218
219
|
}
|
|
219
220
|
MessageTarget::Fanout(recipients) => {
|
|
@@ -351,6 +352,7 @@ pub fn send_message(
|
|
|
351
352
|
stage: None,
|
|
352
353
|
reason: None,
|
|
353
354
|
channel: None,
|
|
355
|
+
ack_forced_off: false,
|
|
354
356
|
})
|
|
355
357
|
}
|
|
356
358
|
|
|
@@ -404,6 +406,7 @@ fn persist_stored_only_send(
|
|
|
404
406
|
stage: None,
|
|
405
407
|
reason: None,
|
|
406
408
|
channel: Some(presentation.effective_sink.as_str().to_string()),
|
|
409
|
+
ack_forced_off: false,
|
|
407
410
|
})
|
|
408
411
|
}
|
|
409
412
|
|
|
@@ -451,6 +454,7 @@ fn refused_outcome_with_id(reason: DeliveryRefusal, message_id: Option<String>)
|
|
|
451
454
|
stage: None,
|
|
452
455
|
reason: Some(reason),
|
|
453
456
|
channel: None,
|
|
457
|
+
ack_forced_off: false,
|
|
454
458
|
}
|
|
455
459
|
}
|
|
456
460
|
|
|
@@ -467,6 +471,7 @@ fn refused_outcome_with_verification(
|
|
|
467
471
|
stage: None,
|
|
468
472
|
reason: Some(reason),
|
|
469
473
|
channel: None,
|
|
474
|
+
ack_forced_off: false,
|
|
470
475
|
}
|
|
471
476
|
}
|
|
472
477
|
|
|
@@ -549,6 +554,7 @@ fn coordinator_unavailable_outcome(
|
|
|
549
554
|
stage: None,
|
|
550
555
|
reason: Some(DeliveryRefusal::CoordinatorUnavailable),
|
|
551
556
|
channel: Some("coordinator_unavailable".to_string()),
|
|
557
|
+
ack_forced_off: false,
|
|
552
558
|
},
|
|
553
559
|
}))
|
|
554
560
|
}
|
|
@@ -573,6 +579,7 @@ fn rebind_required_outcome_with_verification(
|
|
|
573
579
|
stage: None,
|
|
574
580
|
reason: Some(DeliveryRefusal::LeaderNotAttached),
|
|
575
581
|
channel: Some("rebind_required".to_string()),
|
|
582
|
+
ack_forced_off: false,
|
|
576
583
|
}
|
|
577
584
|
}
|
|
578
585
|
|
|
@@ -804,6 +811,7 @@ pub(crate) fn session_drift_refusal(
|
|
|
804
811
|
stage: None,
|
|
805
812
|
reason: Some(DeliveryRefusal::SessionDrift),
|
|
806
813
|
channel: None,
|
|
814
|
+
ack_forced_off: false,
|
|
807
815
|
}))
|
|
808
816
|
}
|
|
809
817
|
|
|
@@ -924,5 +932,6 @@ fn fanout_send(
|
|
|
924
932
|
} else {
|
|
925
933
|
channel_label.to_string()
|
|
926
934
|
}),
|
|
935
|
+
ack_forced_off: false,
|
|
927
936
|
})
|
|
928
937
|
}
|
|
@@ -709,6 +709,38 @@ fn report_result_invalid_envelope_errors_validation() {
|
|
|
709
709
|
);
|
|
710
710
|
}
|
|
711
711
|
|
|
712
|
+
#[test]
|
|
713
|
+
fn leader_receiver_reports_requires_ack_forced_off() {
|
|
714
|
+
let ws = tmp_ws("ack-forced-off");
|
|
715
|
+
let log = EventLog::new(&ws);
|
|
716
|
+
let state = json(serde_json::json!({
|
|
717
|
+
"active_team_key": "team-a",
|
|
718
|
+
"teams": {"team-a": {}}
|
|
719
|
+
}));
|
|
720
|
+
|
|
721
|
+
let outcome = send_to_leader_receiver(
|
|
722
|
+
&ws,
|
|
723
|
+
&state,
|
|
724
|
+
"leader",
|
|
725
|
+
"ack contract probe",
|
|
726
|
+
None,
|
|
727
|
+
"worker",
|
|
728
|
+
true,
|
|
729
|
+
None,
|
|
730
|
+
&log,
|
|
731
|
+
)
|
|
732
|
+
.unwrap();
|
|
733
|
+
|
|
734
|
+
let value = crate::mcp_server::helpers::delivery_outcome_value(&outcome);
|
|
735
|
+
assert_eq!(
|
|
736
|
+
value
|
|
737
|
+
.get("ack_forced_off")
|
|
738
|
+
.and_then(serde_json::Value::as_bool),
|
|
739
|
+
Some(true),
|
|
740
|
+
"requires_ack=true must report that the unavailable ack guarantee was forced off"
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
|
|
712
744
|
// ════════════════════════════════════════════════════════════════════════
|
|
713
745
|
// GROUP N — notify_result_watchers dedupe (exactly-once, Gap 32/38).
|
|
714
746
|
// result_delivery.py:38-132. superseded for duplicate watchers same result.
|
|
@@ -295,6 +295,8 @@ pub enum PaneWidthQuery {
|
|
|
295
295
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
296
296
|
pub struct DeliveryOutcome {
|
|
297
297
|
pub ok: bool,
|
|
298
|
+
/// Whether a caller-requested ack guarantee was unavailable and forced off.
|
|
299
|
+
pub ack_forced_off: bool,
|
|
298
300
|
/// 投递层结果态 (≠ 行态)。
|
|
299
301
|
pub status: DeliveryStatus,
|
|
300
302
|
/// step 7 `messages.status` 行态原文 (shadow;leader 集成时收口为 step 7 enum)。
|