@team-agent/installer 0.5.42 → 0.5.44
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 +129 -54
- package/crates/team-agent/src/cli/diagnose.rs +1 -2
- package/crates/team-agent/src/cli/emit.rs +1 -7
- package/crates/team-agent/src/cli/helpers.rs +3 -1
- package/crates/team-agent/src/cli/leader.rs +2 -1
- package/crates/team-agent/src/cli/mod.rs +126 -16
- package/crates/team-agent/src/cli/named_address.rs +14 -5
- package/crates/team-agent/src/cli/profile.rs +19 -7
- package/crates/team-agent/src/cli/send.rs +9 -3
- package/crates/team-agent/src/cli/status.rs +8 -30
- package/crates/team-agent/src/cli/status_port.rs +1341 -1272
- package/crates/team-agent/src/cli/tests/base.rs +738 -660
- package/crates/team-agent/src/cli/tests/compile.rs +45 -18
- package/crates/team-agent/src/cli/tests/divergence.rs +462 -444
- package/crates/team-agent/src/cli/tests/lane_c.rs +365 -282
- package/crates/team-agent/src/cli/tests/leader_watch.rs +356 -329
- package/crates/team-agent/src/cli/tests/main_preserved.rs +672 -564
- package/crates/team-agent/src/cli/tests/missing_subcommands.rs +284 -224
- package/crates/team-agent/src/cli/tests/mod.rs +17 -7
- package/crates/team-agent/src/cli/tests/named_address.rs +8 -2
- package/crates/team-agent/src/cli/tests/peer_allow.rs +10 -2
- package/crates/team-agent/src/cli/tests/run_delegation.rs +314 -273
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +26 -15
- package/crates/team-agent/src/cli/tests/status_send.rs +707 -629
- package/crates/team-agent/src/cli/tests/verb_install_skill.rs +20 -4
- package/crates/team-agent/src/cli/tests/verb_profile.rs +46 -17
- package/crates/team-agent/src/cli/tests/verb_validate.rs +15 -3
- package/crates/team-agent/src/codex_app_server.rs +2 -5
- package/crates/team-agent/src/compiler/tests.rs +139 -33
- package/crates/team-agent/src/compiler.rs +55 -22
- package/crates/team-agent/src/conpty/backend.rs +23 -33
- package/crates/team-agent/src/coordinator/backoff.rs +2 -7
- package/crates/team-agent/src/coordinator/conpty_shim.rs +55 -67
- package/crates/team-agent/src/coordinator/health.rs +46 -31
- package/crates/team-agent/src/coordinator/mod.rs +3 -3
- package/crates/team-agent/src/coordinator/orphan.rs +22 -10
- package/crates/team-agent/src/coordinator/steps/abnormal.rs +51 -56
- package/crates/team-agent/src/coordinator/tests/abnormal.rs +55 -19
- package/crates/team-agent/src/coordinator/tests/basics.rs +179 -41
- package/crates/team-agent/src/coordinator/tests/daemon.rs +53 -13
- package/crates/team-agent/src/coordinator/tests/health_sync.rs +78 -19
- package/crates/team-agent/src/coordinator/tests/main_preserved.rs +61 -11
- package/crates/team-agent/src/coordinator/tests/mod.rs +33 -39
- package/crates/team-agent/src/coordinator/tests/spine.rs +52 -12
- package/crates/team-agent/src/coordinator/tests/takeover.rs +73 -15
- package/crates/team-agent/src/coordinator/tests/tick_core.rs +50 -15
- package/crates/team-agent/src/coordinator/tests/watch.rs +74 -20
- package/crates/team-agent/src/db/message_store.rs +138 -30
- package/crates/team-agent/src/db/migration.rs +249 -61
- package/crates/team-agent/src/db/schema.rs +303 -82
- package/crates/team-agent/src/diagnose/comms.rs +9 -2
- package/crates/team-agent/src/diagnose/mod.rs +1 -3
- package/crates/team-agent/src/diagnose/orphans.rs +79 -61
- package/crates/team-agent/src/event_log.rs +70 -16
- package/crates/team-agent/src/layout/manager.rs +15 -4
- package/crates/team-agent/src/layout/mod.rs +4 -4
- package/crates/team-agent/src/layout/overlay.rs +10 -3
- package/crates/team-agent/src/layout/placement.rs +5 -1
- package/crates/team-agent/src/layout/recovery.rs +4 -2
- package/crates/team-agent/src/layout/runtime_sessions.rs +7 -7
- package/crates/team-agent/src/layout/sessions.rs +17 -9
- package/crates/team-agent/src/layout/tmux_endpoint.rs +1 -1
- package/crates/team-agent/src/layout/worker_env.rs +87 -19
- package/crates/team-agent/src/leader/helpers.rs +7 -1
- package/crates/team-agent/src/leader/lease.rs +199 -89
- package/crates/team-agent/src/leader/owner_bind.rs +55 -22
- package/crates/team-agent/src/leader/provider_attribution.rs +25 -6
- package/crates/team-agent/src/leader/rediscover/tests.rs +88 -24
- package/crates/team-agent/src/leader/rediscover.rs +74 -25
- package/crates/team-agent/src/leader/registry.rs +1 -1
- package/crates/team-agent/src/leader/start.rs +75 -54
- package/crates/team-agent/src/leader/takeover.rs +46 -11
- package/crates/team-agent/src/leader/tests/basics.rs +320 -167
- package/crates/team-agent/src/leader/tests/byte_findings.rs +361 -219
- package/crates/team-agent/src/leader/tests/identity.rs +428 -356
- package/crates/team-agent/src/leader/tests/idle.rs +285 -254
- package/crates/team-agent/src/leader/tests/lease_api.rs +338 -274
- package/crates/team-agent/src/leader/tests/lease_claim.rs +643 -593
- package/crates/team-agent/src/leader/tests/mod.rs +115 -99
- package/crates/team-agent/src/leader/tests/rediscover.rs +74 -22
- package/crates/team-agent/src/leader/tests/wake_start_owner.rs +237 -211
- package/crates/team-agent/src/lib.rs +4 -4
- package/crates/team-agent/src/lifecycle/display.rs +7 -3
- package/crates/team-agent/src/lifecycle/launch.rs +55 -15
- package/crates/team-agent/src/lifecycle/mod.rs +9 -1
- package/crates/team-agent/src/lifecycle/profile_launch.rs +77 -34
- package/crates/team-agent/src/lifecycle/profile_smoke.rs +3 -1
- package/crates/team-agent/src/lifecycle/restart/agent.rs +1 -6
- package/crates/team-agent/src/lifecycle/restart/common.rs +6 -2
- package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +1 -4
- package/crates/team-agent/src/lifecycle/restart/preflight.rs +6 -5
- package/crates/team-agent/src/lifecycle/restart/rebuild.rs +26 -22
- package/crates/team-agent/src/lifecycle/restart/remove.rs +45 -35
- package/crates/team-agent/src/lifecycle/restart/team_state.rs +63 -17
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +251 -84
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +198 -48
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +2 -1
- package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +152 -32
- package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +1 -5
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +3 -0
- package/crates/team-agent/src/lifecycle/tests.rs +2 -2
- package/crates/team-agent/src/main.rs +4 -4
- package/crates/team-agent/src/mcp_server/lifecycle_tools/agent_ops.rs +47 -20
- package/crates/team-agent/src/mcp_server/mod.rs +11 -2
- package/crates/team-agent/src/mcp_server/types.rs +14 -3
- package/crates/team-agent/src/mcp_server/wire.rs +230 -68
- package/crates/team-agent/src/messaging/delivery.rs +20 -18
- package/crates/team-agent/src/messaging/helpers.rs +25 -4
- package/crates/team-agent/src/messaging/leader_receiver.rs +4 -5
- package/crates/team-agent/src/messaging/mod.rs +2 -3
- package/crates/team-agent/src/messaging/selftest.rs +46 -26
- package/crates/team-agent/src/messaging/tests/main_preserved.rs +47 -12
- package/crates/team-agent/src/messaging/tests/runtime.rs +57 -22
- package/crates/team-agent/src/messaging/tests/spine.rs +154 -40
- package/crates/team-agent/src/messaging/tests/wave2.rs +31 -32
- package/crates/team-agent/src/messaging/trust.rs +25 -2
- package/crates/team-agent/src/messaging/watchers.rs +37 -9
- package/crates/team-agent/src/model/enums.rs +65 -16
- package/crates/team-agent/src/model/ids.rs +12 -3
- package/crates/team-agent/src/model/paths.rs +28 -7
- package/crates/team-agent/src/model/permissions.rs +176 -33
- package/crates/team-agent/src/model/routing.rs +66 -20
- package/crates/team-agent/src/model/spec.rs +365 -69
- package/crates/team-agent/src/model/task_graph.rs +36 -9
- package/crates/team-agent/src/model/yaml/tests.rs +24 -6
- package/crates/team-agent/src/model/yaml.rs +7 -6
- package/crates/team-agent/src/packaging/install.rs +23 -9
- package/crates/team-agent/src/packaging/migrate.rs +5 -7
- package/crates/team-agent/src/packaging/mod.rs +9 -1
- package/crates/team-agent/src/packaging/repair.rs +13 -6
- package/crates/team-agent/src/packaging/tests.rs +63 -16
- package/crates/team-agent/src/packaging/types.rs +22 -7
- package/crates/team-agent/src/platform/argv.rs +4 -1
- package/crates/team-agent/src/platform/file_lock.rs +22 -8
- package/crates/team-agent/src/platform/process.rs +54 -24
- package/crates/team-agent/src/provider/adapters/claude.rs +1 -3
- package/crates/team-agent/src/provider/approvals/parsing.rs +134 -26
- package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +13 -3
- package/crates/team-agent/src/provider/classify.rs +127 -42
- package/crates/team-agent/src/provider/faults.rs +17 -5
- package/crates/team-agent/src/provider/helpers.rs +6 -5
- package/crates/team-agent/src/provider/startup_prompt.rs +75 -27
- package/crates/team-agent/src/state/persist.rs +28 -0
- package/crates/team-agent/src/state/repository.rs +8 -3
- package/crates/team-agent/src/tmux_backend/tests.rs +1637 -1398
- package/crates/team-agent/src/tmux_backend.rs +80 -44
- package/crates/team-agent/src/topology.rs +40 -20
- package/crates/team-agent/src/transport/test_support.rs +20 -23
- package/crates/team-agent/src/transport/tests/behavior.rs +292 -293
- package/crates/team-agent/src/transport/tests/mod.rs +178 -187
- package/crates/team-agent/src/transport/tests/wire.rs +561 -525
- package/crates/team-agent/src/transport.rs +12 -17
- package/crates/team-agent/src/transport_factory.rs +29 -14
- package/package.json +4 -4
|
@@ -1,125 +1,141 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
2
|
+
use super::*;
|
|
3
|
+
use std::cell::Cell;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
// ── helpers ────────────────────────────────────────────────────────────
|
|
6
|
+
/// derive 一个真 LeaderSessionUuid(骨架无公开裸构造器,仅 `derive`)。
|
|
7
|
+
fn uuid(fp: &str, ws: &str, user: &str, team: &str) -> LeaderSessionUuid {
|
|
8
|
+
LeaderSessionUuid::derive(fp, ws, user, team).unwrap()
|
|
9
|
+
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
/// 注入式 turn-state 分类器:MUST-NOT-13 命门 —— 统计 classify 调用次数,
|
|
12
|
+
/// 据此断言 idle 面经此 trait 分类、绝不直连任何 provider client。
|
|
13
|
+
struct CountingClassifier {
|
|
14
|
+
calls: Cell<usize>,
|
|
15
|
+
result: TurnState,
|
|
16
|
+
}
|
|
17
|
+
impl CountingClassifier {
|
|
18
|
+
fn new(result: TurnState) -> Self {
|
|
19
|
+
Self {
|
|
20
|
+
calls: Cell::new(0),
|
|
21
|
+
result,
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
}
|
|
25
|
+
impl TurnStateClassifier for CountingClassifier {
|
|
26
|
+
fn classify(
|
|
27
|
+
&self,
|
|
28
|
+
_provider: Provider,
|
|
29
|
+
session_log_text: &str,
|
|
30
|
+
) -> Result<TurnClassification, LeaderError> {
|
|
31
|
+
self.calls.set(self.calls.get() + 1);
|
|
32
|
+
// 空 session-log 文本 → unknown(bug-085:None rollout_path 漏穿后读到空串)。
|
|
33
|
+
let state = if session_log_text.is_empty() {
|
|
34
|
+
TurnState::Unknown
|
|
35
|
+
} else {
|
|
36
|
+
self.result
|
|
37
|
+
};
|
|
38
|
+
Ok(TurnClassification {
|
|
39
|
+
state,
|
|
40
|
+
turn_id: None,
|
|
41
|
+
annotations: vec![],
|
|
42
|
+
reason: if state == TurnState::Unknown {
|
|
43
|
+
Some("empty_session_log".into())
|
|
44
|
+
} else {
|
|
45
|
+
None
|
|
46
|
+
},
|
|
47
|
+
})
|
|
38
48
|
}
|
|
49
|
+
}
|
|
39
50
|
|
|
40
|
-
|
|
51
|
+
static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
/// RAII env override: restores prior values on drop (incl. panic unwind), so a
|
|
54
|
+
/// RED assertion-panic cannot leak a dirty env into other tests.
|
|
55
|
+
struct EnvGuard {
|
|
56
|
+
saved: Vec<(String, Option<String>)>,
|
|
57
|
+
}
|
|
58
|
+
impl EnvGuard {
|
|
59
|
+
fn apply(vars: &[(&str, Option<&str>)]) -> Self {
|
|
60
|
+
let saved = vars
|
|
61
|
+
.iter()
|
|
62
|
+
.map(|(k, _)| ((*k).to_string(), std::env::var(k).ok()))
|
|
63
|
+
.collect();
|
|
64
|
+
for (k, v) in vars {
|
|
65
|
+
match v {
|
|
66
|
+
Some(val) => std::env::set_var(k, val),
|
|
67
|
+
None => std::env::remove_var(k),
|
|
55
68
|
}
|
|
56
|
-
Self { saved }
|
|
57
69
|
}
|
|
70
|
+
Self { saved }
|
|
58
71
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
}
|
|
73
|
+
impl Drop for EnvGuard {
|
|
74
|
+
fn drop(&mut self) {
|
|
75
|
+
for (k, v) in &self.saved {
|
|
76
|
+
match v {
|
|
77
|
+
Some(val) => std::env::set_var(k, val),
|
|
78
|
+
None => std::env::remove_var(k),
|
|
66
79
|
}
|
|
67
80
|
}
|
|
68
81
|
}
|
|
82
|
+
}
|
|
69
83
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
fn p2_temp_ws(tag: &str) -> PathBuf {
|
|
85
|
+
let ws = std::env::temp_dir().join(format!("ta_rs_p2leader_{}_{}", tag, std::process::id()));
|
|
86
|
+
std::fs::create_dir_all(&ws).unwrap();
|
|
87
|
+
ws
|
|
88
|
+
}
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
90
|
+
// P1 — state-supplied leader_session_uuid → source 'derived' (NOT 'env'); Python's
|
|
91
|
+
// source is binary override-vs-derived (leader/__init__.py:206).
|
|
92
|
+
struct SeededLiveness {
|
|
93
|
+
live_panes: std::collections::BTreeSet<String>,
|
|
94
|
+
}
|
|
95
|
+
impl crate::state::owner_gate::PaneLivenessProbe for SeededLiveness {
|
|
96
|
+
fn liveness(&self, pane_id: &str) -> crate::model::enums::PaneLiveness {
|
|
97
|
+
if self.live_panes.contains(pane_id) {
|
|
98
|
+
crate::model::enums::PaneLiveness::Live
|
|
99
|
+
} else {
|
|
100
|
+
crate::model::enums::PaneLiveness::Dead
|
|
88
101
|
}
|
|
89
102
|
}
|
|
103
|
+
}
|
|
90
104
|
|
|
91
|
-
|
|
92
|
-
|
|
105
|
+
fn seeded_liveness(panes: &[&str]) -> SeededLiveness {
|
|
106
|
+
SeededLiveness {
|
|
107
|
+
live_panes: panes.iter().map(|p| (*p).to_string()).collect(),
|
|
93
108
|
}
|
|
109
|
+
}
|
|
94
110
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
// RED — VACANT ACQUIRE: empty state + eligible caller → status=Claimed,
|
|
112
|
+
// reason=vacant_acquired, owner_epoch 0→1, owner+receiver bound to caller,
|
|
113
|
+
// claimed_via=claim-leader, BOTH state files written (dual-state).
|
|
114
|
+
// golden /tmp/probe_claimed.py: epoch 1, claimed_via "claim-leader",
|
|
115
|
+
// discovery "claim_leader", reason "vacant_acquired".
|
|
116
|
+
/// Event names from the workspace event log (events.jsonl), in write order.
|
|
117
|
+
fn event_names(ws: &std::path::Path) -> Vec<String> {
|
|
118
|
+
let path = crate::model::paths::logs_dir(ws).join("events.jsonl");
|
|
119
|
+
std::fs::read_to_string(&path)
|
|
120
|
+
.map(|t| {
|
|
121
|
+
t.lines()
|
|
122
|
+
.filter_map(|l| serde_json::from_str::<serde_json::Value>(l).ok())
|
|
123
|
+
.filter_map(|e| e.get("event").and_then(|v| v.as_str()).map(String::from))
|
|
124
|
+
.collect()
|
|
125
|
+
})
|
|
126
|
+
.unwrap_or_default()
|
|
127
|
+
}
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
// D1 [BLOCK] — claim-path team_owner is EXACTLY golden's 7 keys (NO os_user). Golden new_owner
|
|
130
|
+
// (__init__.py:686-694) = pane_id,provider,machine_fingerprint,leader_session_uuid,owner_epoch,
|
|
131
|
+
// claimed_at,claimed_via; only Family-A leader_binding writes os_user, NEVER the claim path. Rust
|
|
132
|
+
// make_owner sets os_user:Some(..) + TeamOwner has no skip_serializing_if -> 8 keys. RED.
|
|
117
133
|
|
|
118
134
|
mod basics;
|
|
119
|
-
mod
|
|
120
|
-
mod lease_api;
|
|
121
|
-
mod idle;
|
|
135
|
+
mod byte_findings;
|
|
122
136
|
mod identity;
|
|
137
|
+
mod idle;
|
|
138
|
+
mod lease_api;
|
|
123
139
|
mod lease_claim;
|
|
124
|
-
mod byte_findings;
|
|
125
140
|
mod rediscover;
|
|
141
|
+
mod wake_start_owner;
|
|
@@ -8,7 +8,10 @@ fn r12_ws(tag: &str) -> std::path::PathBuf {
|
|
|
8
8
|
"ta-r12-{}-{}-{}",
|
|
9
9
|
tag,
|
|
10
10
|
std::process::id(),
|
|
11
|
-
std::time::SystemTime::now()
|
|
11
|
+
std::time::SystemTime::now()
|
|
12
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
13
|
+
.unwrap()
|
|
14
|
+
.as_nanos()
|
|
12
15
|
));
|
|
13
16
|
std::fs::create_dir_all(&ws).unwrap();
|
|
14
17
|
ws
|
|
@@ -31,14 +34,23 @@ fn usable_target(pane: &str, cmd: &str) -> crate::transport::PaneInfo {
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
fn r12_events(ws: &std::path::Path) -> Vec<serde_json::Value> {
|
|
34
|
-
crate::event_log::EventLog::new(ws)
|
|
37
|
+
crate::event_log::EventLog::new(ws)
|
|
38
|
+
.tail(0)
|
|
39
|
+
.unwrap_or_default()
|
|
35
40
|
}
|
|
36
41
|
fn find_ev<'a>(evs: &'a [serde_json::Value], name: &str) -> Option<&'a serde_json::Value> {
|
|
37
|
-
evs.iter()
|
|
42
|
+
evs.iter()
|
|
43
|
+
.rev()
|
|
44
|
+
.find(|e| e.get("event").and_then(|v| v.as_str()) == Some(name))
|
|
38
45
|
}
|
|
39
46
|
fn r12_keys(e: &serde_json::Value) -> std::collections::BTreeSet<String> {
|
|
40
47
|
e.as_object()
|
|
41
|
-
.map(|o|
|
|
48
|
+
.map(|o| {
|
|
49
|
+
o.keys()
|
|
50
|
+
.filter(|k| *k != "ts" && *k != "event")
|
|
51
|
+
.cloned()
|
|
52
|
+
.collect()
|
|
53
|
+
})
|
|
42
54
|
.unwrap_or_default()
|
|
43
55
|
}
|
|
44
56
|
|
|
@@ -46,12 +58,16 @@ fn r12_keys(e: &serde_json::Value) -> std::collections::BTreeSet<String> {
|
|
|
46
58
|
// path D3: golden _rediscover_leader_receiver:133-145, owner present + >1 owner_candidates → broadcast).
|
|
47
59
|
fn owner_matching_target(pane: &str, cmd: &str, uuid: &str) -> crate::transport::PaneInfo {
|
|
48
60
|
let mut t = usable_target(pane, cmd);
|
|
49
|
-
t.leader_env
|
|
50
|
-
|
|
61
|
+
t.leader_env.insert(
|
|
62
|
+
"TEAM_AGENT_LEADER_SESSION_UUID".to_string(),
|
|
63
|
+
uuid.to_string(),
|
|
64
|
+
);
|
|
51
65
|
t
|
|
52
66
|
}
|
|
53
67
|
fn count_ev(evs: &[serde_json::Value], name: &str) -> usize {
|
|
54
|
-
evs.iter()
|
|
68
|
+
evs.iter()
|
|
69
|
+
.filter(|e| e.get("event").and_then(|v| v.as_str()) == Some(name))
|
|
70
|
+
.count()
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
// R12-0 + R12-3: NO owner_identity + 2 command-usable targets -> golden two-tier AMBIGUOUS (command-usable
|
|
@@ -61,10 +77,16 @@ fn count_ev(evs: &[serde_json::Value], name: &str) -> usize {
|
|
|
61
77
|
fn r12_no_owner_two_usable_targets_is_ambiguous_not_missing() {
|
|
62
78
|
let ws = r12_ws("noownerambig");
|
|
63
79
|
let log = crate::event_log::EventLog::new(&ws);
|
|
64
|
-
let mut state =
|
|
80
|
+
let mut state =
|
|
81
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
65
82
|
let targets = vec![usable_target("%a", "codex"), usable_target("%b", "codex")];
|
|
66
83
|
let out = crate::leader::rediscover_leader_receiver_from_targets_with_owner_identity(
|
|
67
|
-
&ws,
|
|
84
|
+
&ws,
|
|
85
|
+
&mut state,
|
|
86
|
+
&targets,
|
|
87
|
+
&log,
|
|
88
|
+
&serde_json::json!({}),
|
|
89
|
+
None,
|
|
68
90
|
)
|
|
69
91
|
.unwrap();
|
|
70
92
|
assert_eq!(
|
|
@@ -86,10 +108,16 @@ fn r12_no_owner_two_usable_targets_is_ambiguous_not_missing() {
|
|
|
86
108
|
fn r12_no_owner_zero_usable_missing_is_lean_payload() {
|
|
87
109
|
let ws = r12_ws("noownermiss");
|
|
88
110
|
let log = crate::event_log::EventLog::new(&ws);
|
|
89
|
-
let mut state =
|
|
111
|
+
let mut state =
|
|
112
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
90
113
|
let targets: Vec<crate::transport::PaneInfo> = vec![];
|
|
91
114
|
let out = crate::leader::rediscover_leader_receiver_from_targets_with_owner_identity(
|
|
92
|
-
&ws,
|
|
115
|
+
&ws,
|
|
116
|
+
&mut state,
|
|
117
|
+
&targets,
|
|
118
|
+
&log,
|
|
119
|
+
&serde_json::json!({}),
|
|
120
|
+
None,
|
|
93
121
|
)
|
|
94
122
|
.unwrap();
|
|
95
123
|
assert_eq!(out.get("status").and_then(|v| v.as_str()), Some("missing"));
|
|
@@ -108,7 +136,10 @@ fn r12_no_owner_zero_usable_missing_is_lean_payload() {
|
|
|
108
136
|
"R12-1: no-owner D7 rebind_required (golden leader_panes.py:186) has rediscovery_status only, NO \
|
|
109
137
|
recovery_action/owner_identity; got {rk:?}"
|
|
110
138
|
);
|
|
111
|
-
assert_eq!(
|
|
139
|
+
assert_eq!(
|
|
140
|
+
rebind.get("rediscovery_status").and_then(|v| v.as_str()),
|
|
141
|
+
Some("missing")
|
|
142
|
+
);
|
|
112
143
|
}
|
|
113
144
|
|
|
114
145
|
// R12-1/R12-2: owner_identity PRESENT + non-matching + 2 command-usable -> golden owner-MISSING (D4):
|
|
@@ -119,7 +150,8 @@ fn r12_no_owner_zero_usable_missing_is_lean_payload() {
|
|
|
119
150
|
fn r12_owner_missing_candidate_count_is_command_usable_len_and_rebind_shape() {
|
|
120
151
|
let ws = r12_ws("ownermiss");
|
|
121
152
|
let log = crate::event_log::EventLog::new(&ws);
|
|
122
|
-
let mut state =
|
|
153
|
+
let mut state =
|
|
154
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
123
155
|
let owner = serde_json::json!({
|
|
124
156
|
"pane_id": "%owner", "leader_session_uuid": "U-abcdef01",
|
|
125
157
|
"machine_fingerprint": "F", "provider": "codex", "team_id": "team-a"
|
|
@@ -161,7 +193,8 @@ fn r12_owner_missing_candidate_count_is_command_usable_len_and_rebind_shape() {
|
|
|
161
193
|
fn r12_5_ambiguous_candidates_event_is_full_golden_candidates_key() {
|
|
162
194
|
let ws = r12_ws("ambigbroadcast");
|
|
163
195
|
let log = crate::event_log::EventLog::new(&ws);
|
|
164
|
-
let mut state =
|
|
196
|
+
let mut state =
|
|
197
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
165
198
|
let owner = serde_json::json!({
|
|
166
199
|
"pane_id": "%owner", "leader_session_uuid": "U-abcdef01",
|
|
167
200
|
"machine_fingerprint": "F", "provider": "codex", "team_id": "team-a"
|
|
@@ -174,7 +207,10 @@ fn r12_5_ambiguous_candidates_event_is_full_golden_candidates_key() {
|
|
|
174
207
|
&ws, &mut state, &targets, &log, &owner, None,
|
|
175
208
|
)
|
|
176
209
|
.unwrap();
|
|
177
|
-
assert_eq!(
|
|
210
|
+
assert_eq!(
|
|
211
|
+
out.get("status").and_then(|v| v.as_str()),
|
|
212
|
+
Some("ambiguous")
|
|
213
|
+
);
|
|
178
214
|
let evs = r12_events(&ws);
|
|
179
215
|
let bc = find_ev(&evs, "leader_receiver.ambiguous_candidates")
|
|
180
216
|
.expect("OWNER-ambiguous must broadcast leader_receiver.ambiguous_candidates");
|
|
@@ -193,7 +229,10 @@ fn r12_5_ambiguous_candidates_event_is_full_golden_candidates_key() {
|
|
|
193
229
|
Some(serde_json::json!(["%a", "%b"])),
|
|
194
230
|
"R12-5: candidates == sorted pane_ids (golden candidate_ids = sorted); bc={bc:?}"
|
|
195
231
|
);
|
|
196
|
-
assert_eq!(
|
|
232
|
+
assert_eq!(
|
|
233
|
+
bc.get("reason").and_then(|v| v.as_str()),
|
|
234
|
+
Some("force_confirm_required")
|
|
235
|
+
);
|
|
197
236
|
}
|
|
198
237
|
|
|
199
238
|
// R12-5 dedup: golden _broadcast_ambiguous_candidates:263 skips re-broadcast when a prior
|
|
@@ -204,7 +243,8 @@ fn r12_5_ambiguous_candidates_event_is_full_golden_candidates_key() {
|
|
|
204
243
|
fn r12_5_ambiguous_candidates_dedups_on_repeat_incident() {
|
|
205
244
|
let ws = r12_ws("ambigdedup");
|
|
206
245
|
let log = crate::event_log::EventLog::new(&ws);
|
|
207
|
-
let mut state =
|
|
246
|
+
let mut state =
|
|
247
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
208
248
|
let owner = serde_json::json!({
|
|
209
249
|
"pane_id": "%owner", "leader_session_uuid": "U-abcdef01",
|
|
210
250
|
"machine_fingerprint": "F", "provider": "codex", "team_id": "team-a"
|
|
@@ -240,7 +280,8 @@ fn r12_5_ambiguous_candidates_dedups_on_repeat_incident() {
|
|
|
240
280
|
fn r12_6_per_candidate_emits_separate_ambiguous_candidate_queued_events() {
|
|
241
281
|
let ws = r12_ws("percand");
|
|
242
282
|
let log = crate::event_log::EventLog::new(&ws);
|
|
243
|
-
let mut state =
|
|
283
|
+
let mut state =
|
|
284
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
244
285
|
let owner = serde_json::json!({
|
|
245
286
|
"pane_id": "%owner", "leader_session_uuid": "U-abcdef01",
|
|
246
287
|
"machine_fingerprint": "F", "provider": "codex", "team_id": "team-a"
|
|
@@ -263,8 +304,15 @@ fn r12_6_per_candidate_emits_separate_ambiguous_candidate_queued_events() {
|
|
|
263
304
|
);
|
|
264
305
|
let qpanes: std::collections::BTreeSet<String> = evs
|
|
265
306
|
.iter()
|
|
266
|
-
.filter(|e|
|
|
267
|
-
|
|
307
|
+
.filter(|e| {
|
|
308
|
+
e.get("event").and_then(|v| v.as_str())
|
|
309
|
+
== Some("leader_receiver.ambiguous_candidate_queued")
|
|
310
|
+
})
|
|
311
|
+
.filter_map(|e| {
|
|
312
|
+
e.get("pane_id")
|
|
313
|
+
.and_then(|v| v.as_str())
|
|
314
|
+
.map(str::to_string)
|
|
315
|
+
})
|
|
268
316
|
.collect();
|
|
269
317
|
assert_eq!(
|
|
270
318
|
qpanes,
|
|
@@ -296,7 +344,8 @@ fn r12_return_candidates(out: &serde_json::Value) -> &Vec<serde_json::Value> {
|
|
|
296
344
|
fn r12_7_candidate_raw_uses_golden_pane_current_spelling() {
|
|
297
345
|
let ws = r12_ws("rawkeys");
|
|
298
346
|
let log = crate::event_log::EventLog::new(&ws);
|
|
299
|
-
let mut state =
|
|
347
|
+
let mut state =
|
|
348
|
+
serde_json::json!({"leader_receiver": {"pane_id": "%old", "provider": "codex"}});
|
|
300
349
|
let owner = serde_json::json!({
|
|
301
350
|
"pane_id": "%owner", "leader_session_uuid": "U-abcdef01",
|
|
302
351
|
"machine_fingerprint": "F", "provider": "codex", "team_id": "team-a"
|
|
@@ -339,7 +388,10 @@ fn r12_7_event_provider_defaults_to_codex_when_absent() {
|
|
|
339
388
|
&ws, &mut state, &targets, &log, &owner, None,
|
|
340
389
|
)
|
|
341
390
|
.unwrap();
|
|
342
|
-
assert_eq!(
|
|
391
|
+
assert_eq!(
|
|
392
|
+
out.get("status").and_then(|v| v.as_str()),
|
|
393
|
+
Some("ambiguous")
|
|
394
|
+
);
|
|
343
395
|
let evs = r12_events(&ws);
|
|
344
396
|
let amb = find_ev(&evs, "leader_receiver.rediscover_ambiguous").expect("rediscover_ambiguous");
|
|
345
397
|
assert_eq!(
|