@team-agent/installer 0.5.113 → 0.5.115

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.
Files changed (52) hide show
  1. package/Cargo.lock +252 -84
  2. package/Cargo.toml +3 -1
  3. package/crates/team-agent/Cargo.toml +3 -0
  4. package/crates/team-agent/src/cli/adapters.rs +28 -15
  5. package/crates/team-agent/src/cli/diagnose.rs +36 -13
  6. package/crates/team-agent/src/cli/emit.rs +57 -22
  7. package/crates/team-agent/src/cli/leader.rs +16 -0
  8. package/crates/team-agent/src/cli/leader_prompt.rs +261 -0
  9. package/crates/team-agent/src/cli/mod.rs +157 -8
  10. package/crates/team-agent/src/cli/models.rs +119 -18
  11. package/crates/team-agent/src/cli/spec.rs +7 -1
  12. package/crates/team-agent/src/cli/status_port/brief.rs +268 -101
  13. package/crates/team-agent/src/cli/tests/base.rs +88 -0
  14. package/crates/team-agent/src/cli/tests/status_send.rs +2 -0
  15. package/crates/team-agent/src/compiler.rs +66 -18
  16. package/crates/team-agent/src/contract_runtime/backend.rs +959 -0
  17. package/crates/team-agent/src/contract_runtime/commands.rs +245 -0
  18. package/crates/team-agent/src/contract_runtime/config.rs +340 -0
  19. package/crates/team-agent/src/contract_runtime/config_tests.rs +56 -0
  20. package/crates/team-agent/src/contract_runtime/discovery.rs +383 -0
  21. package/crates/team-agent/src/contract_runtime/forward.rs +229 -0
  22. package/crates/team-agent/src/contract_runtime/framework.rs +294 -0
  23. package/crates/team-agent/src/contract_runtime/mcp.rs +396 -0
  24. package/crates/team-agent/src/contract_runtime/mod.rs +16 -0
  25. package/crates/team-agent/src/contract_runtime/prompt.rs +216 -0
  26. package/crates/team-agent/src/contract_runtime/pump.rs +269 -0
  27. package/crates/team-agent/src/contract_runtime/registry.rs +197 -0
  28. package/crates/team-agent/src/contract_runtime/workspace.rs +160 -0
  29. package/crates/team-agent/src/coordinator/tick.rs +26 -8
  30. package/crates/team-agent/src/leader/mod.rs +1 -0
  31. package/crates/team-agent/src/leader/prompt.rs +906 -0
  32. package/crates/team-agent/src/leader/start.rs +353 -21
  33. package/crates/team-agent/src/leader/tests/mod.rs +2 -0
  34. package/crates/team-agent/src/leader/tests/prompt_contract.rs +268 -0
  35. package/crates/team-agent/src/leader/types.rs +6 -0
  36. package/crates/team-agent/src/lib.rs +4 -0
  37. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +571 -389
  38. package/crates/team-agent/src/lifecycle/launch/spawn.rs +38 -9
  39. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +15 -0
  40. package/crates/team-agent/src/lifecycle/launch.rs +45 -28
  41. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +23 -1
  42. package/crates/team-agent/src/lifecycle/restart/selection.rs +34 -0
  43. package/crates/team-agent/src/lifecycle/role_config.rs +17 -1
  44. package/crates/team-agent/src/lifecycle/types.rs +4 -1
  45. package/crates/team-agent/src/lifecycle/worker_command_context.rs +37 -27
  46. package/crates/team-agent/src/main.rs +6 -0
  47. package/crates/team-agent/src/messaging/delivery.rs +50 -1
  48. package/crates/team-agent/src/messaging/send.rs +10 -0
  49. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +131 -0
  50. package/crates/team-agent/src/model/spec.rs +24 -12
  51. package/crates/team-agent/src/state/persist.rs +73 -0
  52. package/package.json +4 -4
@@ -120,7 +120,12 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
120
120
  }
121
121
 
122
122
  fn tmux_endpoint(&mut self) -> Option<String> {
123
- self.transport.tmux_endpoint()
123
+ // Bind the endpoint we use to observe the caller, not the worker server.
124
+ let caller_transport = caller_read_transport();
125
+ caller_transport
126
+ .as_deref()
127
+ .unwrap_or(self.transport)
128
+ .tmux_endpoint()
124
129
  }
125
130
 
126
131
  fn observe_command(&mut self, pane: &PaneId) -> Option<String> {
@@ -192,7 +197,9 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
192
197
  let (error, applied_grant) = error.into_parts();
193
198
  self.applied_grant = applied_grant.map(|grant| (grant.owner, grant.receiver));
194
199
  self.cas_conflict = match &error {
195
- crate::leader::LeaderError::State(crate::state::StateError::SaveConflict(_)) => true,
200
+ crate::leader::LeaderError::State(crate::state::StateError::SaveConflict(
201
+ _,
202
+ )) => true,
196
203
  _ => false,
197
204
  };
198
205
  self.last_failure_reason = Some(if self.cas_conflict {
@@ -206,7 +213,8 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
206
213
  crate::leader::LeaderError::Io(_)
207
214
  | crate::leader::LeaderError::Json(_)
208
215
  | crate::leader::LeaderError::MessageStore(_)
209
- | crate::leader::LeaderError::Start(_) => "attach_failed",
216
+ | crate::leader::LeaderError::Start(_)
217
+ | crate::leader::LeaderError::Prompt(_) => "attach_failed",
210
218
  crate::leader::LeaderError::EventLog(_) => "attach_event_log_failed",
211
219
  crate::leader::LeaderError::Messaging(_) => "attach_watcher_failed",
212
220
  }
@@ -273,16 +281,13 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
273
281
  });
274
282
  return false;
275
283
  }
276
- let Ok(resolved) = crate::state::projection::resolve_runtime_team_scope(
277
- workspace,
278
- Some(team_key),
279
- ) else {
284
+ let Ok(resolved) =
285
+ crate::state::projection::resolve_runtime_team_scope(workspace, Some(team_key))
286
+ else {
280
287
  self.last_failure_reason = Some("receiver_scope_unavailable");
281
288
  return false;
282
289
  };
283
- let Some(receiver) =
284
- super::selected_team_leader_receiver(&resolved.state, team_key)
285
- else {
290
+ let Some(receiver) = super::selected_team_leader_receiver(&resolved.state, team_key) else {
286
291
  self.last_failure_reason = Some("receiver_missing");
287
292
  return false;
288
293
  };
@@ -291,9 +296,8 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
291
296
  .and_then(serde_json::Value::as_str)
292
297
  .filter(|endpoint| !endpoint.is_empty())
293
298
  .map(crate::transport_factory::leader_endpoint_transport);
294
- let live_channel_transport: &dyn Transport = leader_transport
295
- .as_deref()
296
- .unwrap_or(self.transport);
299
+ let live_channel_transport: &dyn Transport =
300
+ leader_transport.as_deref().unwrap_or(self.transport);
297
301
  if !matches!(
298
302
  crate::messaging::resolve_live_leader_channel(
299
303
  workspace,
@@ -314,9 +318,7 @@ impl FreshQuickStartLeaderBindingOps for RuntimeFreshQuickStartLeaderBindingOps<
314
318
  }
315
319
 
316
320
  fn frozen_seed_receipt(&self) -> Option<(serde_json::Value, serde_json::Value)> {
317
- self.frozen_owner
318
- .clone()
319
- .zip(self.frozen_receiver.clone())
321
+ self.frozen_owner.clone().zip(self.frozen_receiver.clone())
320
322
  }
321
323
  }
322
324
 
@@ -376,7 +378,6 @@ impl BindingFileSnapshot {
376
378
  let bytes = std::fs::read(&path).ok();
377
379
  Self { path, bytes }
378
380
  }
379
-
380
381
  }
381
382
 
382
383
  fn binding_snapshots(workspace: &Path, team_key: &str) -> Vec<BindingFileSnapshot> {
@@ -434,7 +435,10 @@ fn persisted_binding_matches_verified_pane(
434
435
  {
435
436
  return false;
436
437
  }
437
- let Some(owner) = state.get("team_owner").and_then(serde_json::Value::as_object) else {
438
+ let Some(owner) = state
439
+ .get("team_owner")
440
+ .and_then(serde_json::Value::as_object)
441
+ else {
438
442
  return false;
439
443
  };
440
444
  let Some(receiver) = state
@@ -488,10 +492,9 @@ fn bind_fresh_quick_start_leader_with<O: FreshQuickStartLeaderBindingOps>(
488
492
  seeded_owner: Option<&serde_json::Value>,
489
493
  ops: &mut O,
490
494
  ) -> Result<bool, LifecycleError> {
491
- let Ok(resolved) = crate::state::projection::resolve_runtime_team_scope(
492
- workspace,
493
- Some(team_key),
494
- ) else {
495
+ let Ok(resolved) =
496
+ crate::state::projection::resolve_runtime_team_scope(workspace, Some(team_key))
497
+ else {
495
498
  return refuse_fresh_bind(workspace, team_key, "scope", "scope_unresolved");
496
499
  };
497
500
  if resolved.canonical_team_key != team_key {
@@ -550,27 +553,27 @@ fn bind_fresh_quick_start_leader_with<O: FreshQuickStartLeaderBindingOps>(
550
553
  // projected state still contains that seed.
551
554
  let current_receiver = state.get("leader_receiver");
552
555
  let frozen_receipt = ops.frozen_seed_receipt();
553
- let fresh_seeded_binding = if let Some((frozen_owner, frozen_receiver)) = frozen_receipt.as_ref()
554
- {
555
- state
556
- .get("team_owner")
557
- .is_some_and(|current| current == frozen_owner)
558
- && current_receiver.is_some_and(|current| current == frozen_receiver)
559
- } else {
560
- let pending_seed_receiver = current_receiver.is_some_and(|receiver| {
561
- receiver.get("status").and_then(serde_json::Value::as_str) == Some("pending")
562
- && receiver
563
- .get("discovery")
564
- .and_then(serde_json::Value::as_str)
565
- == Some("quick_start_seed")
566
- });
567
- seeded_owner.is_some_and(|seed| {
556
+ let fresh_seeded_binding =
557
+ if let Some((frozen_owner, frozen_receiver)) = frozen_receipt.as_ref() {
568
558
  state
569
559
  .get("team_owner")
570
- .is_some_and(|current| current == seed)
571
- && pending_seed_receiver
572
- })
573
- };
560
+ .is_some_and(|current| current == frozen_owner)
561
+ && current_receiver.is_some_and(|current| current == frozen_receiver)
562
+ } else {
563
+ let pending_seed_receiver = current_receiver.is_some_and(|receiver| {
564
+ receiver.get("status").and_then(serde_json::Value::as_str) == Some("pending")
565
+ && receiver
566
+ .get("discovery")
567
+ .and_then(serde_json::Value::as_str)
568
+ == Some("quick_start_seed")
569
+ });
570
+ seeded_owner.is_some_and(|seed| {
571
+ state
572
+ .get("team_owner")
573
+ .is_some_and(|current| current == seed)
574
+ && pending_seed_receiver
575
+ })
576
+ };
574
577
  let seeded_receiver = frozen_receipt
575
578
  .as_ref()
576
579
  .map(|(_, receiver)| receiver.clone())
@@ -721,9 +724,9 @@ fn combine_rollback_errors(
721
724
  match (state, registry) {
722
725
  (None, None) => None,
723
726
  (Some(error), None) | (None, Some(error)) => Some(error),
724
- (Some(state), Some(registry)) => Some(LifecycleError::StatePersist(format!(
725
- "{state}; {registry}"
726
- ))),
727
+ (Some(state), Some(registry)) => {
728
+ Some(LifecycleError::StatePersist(format!("{state}; {registry}")))
729
+ }
727
730
  }
728
731
  }
729
732
 
@@ -757,9 +760,11 @@ fn restore_this_attempt_state(
757
760
  });
758
761
  };
759
762
  let previous = match snapshot.map(|snapshot| snapshot.bytes.as_deref()) {
760
- Some(Some(bytes)) => serde_json::from_slice::<serde_json::Value>(bytes).map_err(|error| {
761
- LifecycleError::StatePersist(format!("quick-start binding cleanup failed: {error}"))
762
- })?,
763
+ Some(Some(bytes)) => {
764
+ serde_json::from_slice::<serde_json::Value>(bytes).map_err(|error| {
765
+ LifecycleError::StatePersist(format!("quick-start binding cleanup failed: {error}"))
766
+ })?
767
+ }
763
768
  Some(None) | None => serde_json::Value::Null,
764
769
  };
765
770
  let previous_owner = previous
@@ -879,9 +884,9 @@ fn clear_fresh_binding_on_refusal(
879
884
  };
880
885
  crate::state::repository::StateRepository::new(workspace)
881
886
  .save(intent, state)
882
- .map_err(|error| LifecycleError::StatePersist(format!(
883
- "quick-start binding cleanup failed: {error}"
884
- )))
887
+ .map_err(|error| {
888
+ LifecycleError::StatePersist(format!("quick-start binding cleanup failed: {error}"))
889
+ })
885
890
  }
886
891
 
887
892
  fn existing_runtime_identity_view(
@@ -907,16 +912,14 @@ fn caller_read_transport() -> Option<Box<dyn Transport>> {
907
912
  if !Path::new(&endpoint).exists() {
908
913
  return None;
909
914
  }
910
- Some(Box::new(crate::tmux_backend::TmuxBackend::for_tmux_endpoint(
911
- &endpoint,
912
- )))
915
+ Some(Box::new(
916
+ crate::tmux_backend::TmuxBackend::for_tmux_endpoint(&endpoint),
917
+ ))
913
918
  }
914
919
 
915
920
  fn query_caller_pane_command(transport: &dyn Transport, pane: &PaneId) -> Option<String> {
916
921
  let caller_transport = caller_read_transport();
917
- let query_transport: &dyn Transport = caller_transport
918
- .as_deref()
919
- .unwrap_or(transport);
922
+ let query_transport: &dyn Transport = caller_transport.as_deref().unwrap_or(transport);
920
923
  query_transport
921
924
  .query(&Target::Pane(pane.clone()), PaneField::PaneCurrentCommand)
922
925
  .ok()
@@ -959,8 +962,8 @@ fn preflight_fresh_leader_identity(
959
962
  let Some(pane) = pane else {
960
963
  return None;
961
964
  };
962
- let command = query_caller_pane_command(transport, &PaneId::new(pane))
963
- .unwrap_or_default();
965
+ let command =
966
+ query_caller_pane_command(transport, &PaneId::new(pane)).unwrap_or_default();
964
967
  let explicit = std::env::var("TEAM_AGENT_LEADER_PROVIDER")
965
968
  .ok()
966
969
  .filter(|provider| !provider.is_empty());
@@ -968,16 +971,11 @@ fn preflight_fresh_leader_identity(
968
971
  return Some((
969
972
  "quick-start refused before spawn: command unobservable".to_string(),
970
973
  vec!["stage=command_observation reason=command_unobservable".to_string()],
971
- vec![
972
- "run from a live provider pane; do not run claim-leader".to_string(),
973
- ],
974
+ vec!["run from a live provider pane; do not run claim-leader".to_string()],
974
975
  ));
975
976
  }
976
- if crate::leader::owner_bind::strict_owner_bind_provider(
977
- explicit.as_deref(),
978
- &command,
979
- )
980
- .is_some()
977
+ if crate::leader::owner_bind::strict_owner_bind_provider(explicit.as_deref(), &command)
978
+ .is_some()
981
979
  {
982
980
  None
983
981
  } else {
@@ -1097,12 +1095,7 @@ pub fn quick_start_in_workspace_with_backend(
1097
1095
  if is_tmux_or_default {
1098
1096
  let transport = quick_start_tmux_backend(&workspace);
1099
1097
  return quick_start_with_transport_in_workspace(
1100
- &workspace,
1101
- agents_dir,
1102
- name,
1103
- yes,
1104
- team_id,
1105
- &transport,
1098
+ &workspace, agents_dir, name, yes, team_id, &transport,
1106
1099
  );
1107
1100
  }
1108
1101
  // Explicit non-tmux backend: route through the factory. Parse the
@@ -1275,6 +1268,32 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1275
1268
  )));
1276
1269
  }
1277
1270
  crate::lifecycle::launch::run_pi_catalog_preflight(agents_dir, discover)?;
1271
+ #[cfg(unix)]
1272
+ {
1273
+ let input = crate::cli::QuickStartArgs {
1274
+ workspace: workspace.into(),
1275
+ agents_dir: agents_dir.into(),
1276
+ name: name.map(str::to_owned),
1277
+ team_id: team_id.map(str::to_owned),
1278
+ yes: false,
1279
+ json: false,
1280
+ detail: false,
1281
+ backend: Some(
1282
+ if matches!(transport.kind(), crate::transport::BackendKind::Tmux) {
1283
+ "tmux"
1284
+ } else {
1285
+ "conpty"
1286
+ }
1287
+ .into(),
1288
+ ),
1289
+ };
1290
+ if let Some(config) = crate::contract_runtime::config::read_team(&input)
1291
+ .map_err(|error| LifecycleError::Compile(error.to_string()))?
1292
+ {
1293
+ crate::contract_runtime::backend::preflight(&config)
1294
+ .map_err(|error| LifecycleError::Provider(error.to_string()))?;
1295
+ }
1296
+ }
1278
1297
  let workspace = workspace.to_path_buf();
1279
1298
  let mut spec = crate::compiler::compile_team(agents_dir)
1280
1299
  .map_err(|e| LifecycleError::Compile(e.to_string()))?;
@@ -1328,7 +1347,9 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1328
1347
  .get("tmux_endpoint")
1329
1348
  .and_then(serde_json::Value::as_str)
1330
1349
  .or_else(|| {
1331
- identity.get("tmux_socket").and_then(serde_json::Value::as_str)
1350
+ identity
1351
+ .get("tmux_socket")
1352
+ .and_then(serde_json::Value::as_str)
1332
1353
  })
1333
1354
  .or_else(|| {
1334
1355
  state
@@ -1450,10 +1471,7 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1450
1471
  .and_then(|teams| teams.get(&state_team_key))
1451
1472
  .and_then(|team| team.get("team_owner"))
1452
1473
  .filter(|owner| {
1453
- owner
1454
- .get("claimed_via")
1455
- .and_then(serde_json::Value::as_str)
1456
- == Some("quick-start")
1474
+ owner.get("claimed_via").and_then(serde_json::Value::as_str) == Some("quick-start")
1457
1475
  })
1458
1476
  .cloned();
1459
1477
  let seeded_receiver = state
@@ -1517,12 +1535,18 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1517
1535
  quick_start_session_capture_incomplete_agents(&workspace, &state_team_key);
1518
1536
  let coordinator_workspace = crate::coordinator::WorkspacePath::new(workspace.clone());
1519
1537
  let coordinator_report = crate::coordinator::start_coordinator(&coordinator_workspace)
1520
- .map_err(|error| LifecycleError::StatePersist(format!(
1521
- "coordinator start failed for {}: {error}; inspect {} before retrying",
1522
- workspace.display(),
1523
- crate::coordinator::coordinator_log_path(&coordinator_workspace).display()
1524
- )))?;
1525
- quick_start_phase_timer.emit(&workspace, "launch.phase", crate::lifecycle::restart::LifecyclePhase::CoordinatorStart);
1538
+ .map_err(|error| {
1539
+ LifecycleError::StatePersist(format!(
1540
+ "coordinator start failed for {}: {error}; inspect {} before retrying",
1541
+ workspace.display(),
1542
+ crate::coordinator::coordinator_log_path(&coordinator_workspace).display()
1543
+ ))
1544
+ })?;
1545
+ quick_start_phase_timer.emit(
1546
+ &workspace,
1547
+ "launch.phase",
1548
+ crate::lifecycle::restart::LifecyclePhase::CoordinatorStart,
1549
+ );
1526
1550
  require_quick_start_coordinator_started(&coordinator_report, &workspace)?;
1527
1551
  let coordinator_action = "coordinator started";
1528
1552
  // BUG-7: build an honest readiness verdict from the post-spawn runtime state.
@@ -1532,7 +1556,11 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1532
1556
  // loaded successfully (provider-side codex/claude schema rejections happen
1533
1557
  // asynchronously after spawn), so the verdict is PendingToolLoad — never
1534
1558
  // bare Ready.
1535
- quick_start_phase_timer.emit(&workspace, "launch.phase", crate::lifecycle::restart::LifecyclePhase::ReadinessWait);
1559
+ quick_start_phase_timer.emit(
1560
+ &workspace,
1561
+ "launch.phase",
1562
+ crate::lifecycle::restart::LifecyclePhase::ReadinessWait,
1563
+ );
1536
1564
  let worker_readiness = quick_start_worker_readiness(&workspace, &state_team_key);
1537
1565
  let attach_windows = load_runtime_state(&workspace)
1538
1566
  .ok()
@@ -1572,7 +1600,11 @@ pub(crate) fn quick_start_with_transport_in_workspace_pi_preflight(
1572
1600
  ));
1573
1601
  }
1574
1602
  next_actions.extend(attach_commands.iter().cloned());
1575
- quick_start_phase_timer.emit(&workspace, "launch.phase", crate::lifecycle::restart::LifecyclePhase::Completed);
1603
+ quick_start_phase_timer.emit(
1604
+ &workspace,
1605
+ "launch.phase",
1606
+ crate::lifecycle::restart::LifecyclePhase::Completed,
1607
+ );
1576
1608
  Ok(QuickStartReport::Ready {
1577
1609
  session_name,
1578
1610
  launch: Box::new(launch),
@@ -1595,8 +1627,15 @@ fn preserve_quick_start_bootstrap_binding(
1595
1627
  if let Some(receiver) = bootstrap.get("leader_receiver") {
1596
1628
  binding = binding.with_leader_receiver(receiver.clone());
1597
1629
  }
1598
- if let Some(epoch) = bootstrap.get("owner_epoch").and_then(serde_json::Value::as_u64)
1599
- .or_else(|| bootstrap.get("team_owner").and_then(|owner| owner.get("owner_epoch")).and_then(serde_json::Value::as_u64))
1630
+ if let Some(epoch) = bootstrap
1631
+ .get("owner_epoch")
1632
+ .and_then(serde_json::Value::as_u64)
1633
+ .or_else(|| {
1634
+ bootstrap
1635
+ .get("team_owner")
1636
+ .and_then(|owner| owner.get("owner_epoch"))
1637
+ .and_then(serde_json::Value::as_u64)
1638
+ })
1600
1639
  {
1601
1640
  binding = binding.with_owner_epoch(epoch);
1602
1641
  }
@@ -1682,13 +1721,19 @@ mod fresh_quick_start_leader_binding_tests {
1682
1721
  assert_eq!(launched.get(key), bootstrap.get(key));
1683
1722
  assert_eq!(launched["teams"]["current"].get(key), bootstrap.get(key));
1684
1723
  }
1685
- assert_eq!(launched.get("leader_client"), bootstrap.get("leader_client"));
1724
+ assert_eq!(
1725
+ launched.get("leader_client"),
1726
+ bootstrap.get("leader_client")
1727
+ );
1686
1728
  assert_eq!(launched.get("is_external_leader"), Some(&json!(true)));
1687
1729
  assert_eq!(launched["agents"], json!({"worker": {}}));
1688
1730
  let merged = super::super::state_projection::merge_workspace_team_state_with_key(
1689
1731
  &bootstrap, &launched, "current",
1690
1732
  );
1691
- assert_eq!(merged["teams"]["current"]["team_owner"], bootstrap["team_owner"]);
1733
+ assert_eq!(
1734
+ merged["teams"]["current"]["team_owner"],
1735
+ bootstrap["team_owner"]
1736
+ );
1692
1737
  assert_eq!(merged["teams"]["current"]["owner_epoch"], json!(7));
1693
1738
  }
1694
1739
 
@@ -1702,20 +1747,34 @@ mod fresh_quick_start_leader_binding_tests {
1702
1747
  binary_path: Some("/tmp/candidate/team-agent".to_string()),
1703
1748
  binary_version: Some("0.5.112".to_string()),
1704
1749
  rotation_reason: Some("original rotation reason".to_string()),
1705
- binary_identity_relation: crate::coordinator::CoordinatorBinaryIdentityRelation::Unknown,
1750
+ binary_identity_relation:
1751
+ crate::coordinator::CoordinatorBinaryIdentityRelation::Unknown,
1706
1752
  log: Some(PathBuf::from("/tmp/current/.team/runtime/coordinator.log")),
1707
- schema_error: Some(crate::coordinator::SchemaError::InitFailed { message: "original database permission denied".to_string() }),
1753
+ schema_error: Some(crate::coordinator::SchemaError::InitFailed {
1754
+ message: "original database permission denied".to_string(),
1755
+ }),
1708
1756
  action: Some("repair the exact database permissions".to_string()),
1709
1757
  };
1710
1758
  let error = require_quick_start_coordinator_started(&report, Path::new("/tmp/current"))
1711
- .unwrap_err().to_string();
1712
- for detail in ["schema_incompatible", "original database permission denied", "repair the exact database permissions", "/tmp/candidate/team-agent", "/tmp/current/.team/runtime/coordinator.log", "workers may already be started"] {
1759
+ .unwrap_err()
1760
+ .to_string();
1761
+ for detail in [
1762
+ "schema_incompatible",
1763
+ "original database permission denied",
1764
+ "repair the exact database permissions",
1765
+ "/tmp/candidate/team-agent",
1766
+ "/tmp/current/.team/runtime/coordinator.log",
1767
+ "workers may already be started",
1768
+ ] {
1713
1769
  assert!(error.contains(detail), "lost {detail}: {error}");
1714
1770
  }
1715
1771
  report.ok = true;
1716
1772
  report.status = crate::coordinator::StartOutcome::AlreadyRunning;
1717
- report.binary_identity_relation = crate::coordinator::CoordinatorBinaryIdentityRelation::DaemonNewerThanCaller;
1718
- assert!(require_quick_start_coordinator_started(&report, Path::new("/tmp/current")).is_ok());
1773
+ report.binary_identity_relation =
1774
+ crate::coordinator::CoordinatorBinaryIdentityRelation::DaemonNewerThanCaller;
1775
+ assert!(
1776
+ require_quick_start_coordinator_started(&report, Path::new("/tmp/current")).is_ok()
1777
+ );
1719
1778
  }
1720
1779
 
1721
1780
  #[test]
@@ -1725,11 +1784,17 @@ mod fresh_quick_start_leader_binding_tests {
1725
1784
  env.scrub_tmux();
1726
1785
  env.assert_no_real_tmux();
1727
1786
  let workspace = std::env::temp_dir().join(format!(
1728
- "ta-current-bootstrap-{}-{}", std::process::id(), SEQUENCE.fetch_add(1, Ordering::Relaxed)
1787
+ "ta-current-bootstrap-{}-{}",
1788
+ std::process::id(),
1789
+ SEQUENCE.fetch_add(1, Ordering::Relaxed)
1729
1790
  ));
1730
1791
  let team = workspace.join(".team/current");
1731
1792
  std::fs::create_dir_all(team.join("agents")).unwrap();
1732
- std::fs::write(team.join("TEAM.md"), "---\nname: current\nobjective: Bootstrap fixture.\n---\n").unwrap();
1793
+ std::fs::write(
1794
+ team.join("TEAM.md"),
1795
+ "---\nname: current\nobjective: Bootstrap fixture.\n---\n",
1796
+ )
1797
+ .unwrap();
1733
1798
  std::fs::write(team.join("agents/worker.md"), "---\nname: worker\nrole: Worker\nprovider: codex\nauth_mode: subscription\ndangerously_skip_permissions: false\n---\nBounded fixture.\n").unwrap();
1734
1799
  let state_path = crate::state::persist::runtime_state_path(&workspace);
1735
1800
  std::fs::create_dir_all(state_path.parent().unwrap()).unwrap();
@@ -1749,10 +1814,20 @@ mod fresh_quick_start_leader_binding_tests {
1749
1814
  std::env::set_var("TMUX_PANE", "%0");
1750
1815
  std::env::set_var(CALLER_PANE_ENV, "%0");
1751
1816
  std::env::set_var(CALLER_PROVIDER_ENV, "pi");
1752
- std::env::set_var(CALLER_ENDPOINT_ENV, "/private/tmp/different-bootstrap/default");
1753
- let transport = OfflineTransport::new().with_tmux_endpoint("/private/tmp/bootstrap-test/default");
1754
- let result = quick_start_with_transport_in_workspace(&workspace, &team, None, true, None, &transport).unwrap();
1755
- assert!(matches!(result, QuickStartReport::PreflightBlocked { .. }), "unexpected outcome: {result:?}");
1817
+ std::env::set_var(
1818
+ CALLER_ENDPOINT_ENV,
1819
+ "/private/tmp/different-bootstrap/default",
1820
+ );
1821
+ let transport =
1822
+ OfflineTransport::new().with_tmux_endpoint("/private/tmp/bootstrap-test/default");
1823
+ let result = quick_start_with_transport_in_workspace(
1824
+ &workspace, &team, None, true, None, &transport,
1825
+ )
1826
+ .unwrap();
1827
+ assert!(
1828
+ matches!(result, QuickStartReport::PreflightBlocked { .. }),
1829
+ "unexpected outcome: {result:?}"
1830
+ );
1756
1831
  assert_eq!(std::fs::read(&state_path).unwrap(), before);
1757
1832
  assert!(!workspace.join(".team/team.db").exists());
1758
1833
  assert!(!crate::model::paths::runtime_spec_path(&workspace, "current").exists());
@@ -1922,10 +1997,7 @@ mod fresh_quick_start_leader_binding_tests {
1922
1997
  )
1923
1998
  }
1924
1999
  _ => crate::state::persist::save_runtime_state_with_receiver_authority(
1925
- workspace,
1926
- state,
1927
- &team_key,
1928
- None,
2000
+ workspace, state, &team_key, None,
1929
2001
  ),
1930
2002
  };
1931
2003
  if saved.is_ok() {
@@ -1941,9 +2013,7 @@ mod fresh_quick_start_leader_binding_tests {
1941
2013
  }
1942
2014
 
1943
2015
  fn frozen_seed_receipt(&self) -> Option<(serde_json::Value, serde_json::Value)> {
1944
- self.frozen_owner
1945
- .clone()
1946
- .zip(self.frozen_receiver.clone())
2016
+ self.frozen_owner.clone().zip(self.frozen_receiver.clone())
1947
2017
  }
1948
2018
 
1949
2019
  fn this_attempt_extra_state_keys(&self) -> Vec<&'static str> {
@@ -1990,12 +2060,15 @@ mod fresh_quick_start_leader_binding_tests {
1990
2060
  }
1991
2061
 
1992
2062
  #[test]
1993
- fn fresh_binding_persists_then_registers_then_requires_canonical_readback_provider_independent() {
2063
+ fn fresh_binding_persists_then_registers_then_requires_canonical_readback_provider_independent()
2064
+ {
1994
2065
  let workspace = workspace("positive");
1995
2066
  let mut ops = MockOps::default();
1996
- assert!(bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
1997
- .unwrap());
1998
- assert_eq!(ops.attached_provider, Some(crate::provider::Provider::Codex));
2067
+ assert!(bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap());
2068
+ assert_eq!(
2069
+ ops.attached_provider,
2070
+ Some(crate::provider::Provider::Codex)
2071
+ );
1999
2072
  assert_eq!(ops.attach_calls, 1);
2000
2073
  assert_eq!(ops.register_calls, 1);
2001
2074
  assert_eq!(ops.readback_calls, 1);
@@ -2030,11 +2103,13 @@ mod fresh_quick_start_leader_binding_tests {
2030
2103
  leader_session_uuid: "uuid-fresh".to_string(),
2031
2104
  leader_session_uuid_source: "env".to_string(),
2032
2105
  };
2033
- assert!(super::spec_state::seed_launched_owner_from_caller_with_provider_lookup(
2034
- &mut state,
2035
- caller,
2036
- |_| None
2037
- ));
2106
+ assert!(
2107
+ super::spec_state::seed_launched_owner_from_caller_with_provider_lookup(
2108
+ &mut state,
2109
+ caller,
2110
+ |_| None
2111
+ )
2112
+ );
2038
2113
  let owner = state
2039
2114
  .pointer("/teams/fresh/team_owner")
2040
2115
  .cloned()
@@ -2061,13 +2136,10 @@ mod fresh_quick_start_leader_binding_tests {
2061
2136
  frozen_receiver: Some(frozen_receiver.clone()),
2062
2137
  ..MockOps::default()
2063
2138
  };
2064
- assert!(bind_fresh_quick_start_leader_with(
2065
- &workspace,
2066
- "fresh",
2067
- Some(&owner),
2068
- &mut ops
2069
- )
2070
- .unwrap());
2139
+ assert!(
2140
+ bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&owner), &mut ops)
2141
+ .unwrap()
2142
+ );
2071
2143
  assert_eq!(ops.attach_calls, 1);
2072
2144
  assert_eq!(ops.last_expected_receiver, Some(frozen_receiver));
2073
2145
  let _ = std::fs::remove_dir_all(&workspace);
@@ -2084,10 +2156,7 @@ mod fresh_quick_start_leader_binding_tests {
2084
2156
  state["leader_receiver"] = newer.clone();
2085
2157
  state["teams"]["fresh"]["leader_receiver"] = newer.clone();
2086
2158
  crate::state::persist::save_runtime_state_with_receiver_authority(
2087
- &workspace,
2088
- &state,
2089
- "fresh",
2090
- None,
2159
+ &workspace, &state, "fresh", None,
2091
2160
  )
2092
2161
  .unwrap();
2093
2162
  let on_disk = crate::state::persist::load_runtime_state(&workspace).unwrap();
@@ -2104,13 +2173,10 @@ mod fresh_quick_start_leader_binding_tests {
2104
2173
  frozen_receiver: Some(frozen_receiver),
2105
2174
  ..MockOps::default()
2106
2175
  };
2107
- assert!(!bind_fresh_quick_start_leader_with(
2108
- &workspace,
2109
- "fresh",
2110
- Some(&owner),
2111
- &mut ops
2112
- )
2113
- .unwrap());
2176
+ assert!(
2177
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&owner), &mut ops)
2178
+ .unwrap()
2179
+ );
2114
2180
  assert_eq!(ops.attach_calls, 0);
2115
2181
  assert_eq!(ops.last_expected_receiver, None);
2116
2182
  let _ = std::fs::remove_dir_all(&workspace);
@@ -2127,10 +2193,7 @@ mod fresh_quick_start_leader_binding_tests {
2127
2193
  state["leader_receiver"] = winner.clone();
2128
2194
  state["teams"]["fresh"]["leader_receiver"] = winner.clone();
2129
2195
  crate::state::persist::save_runtime_state_with_receiver_authority(
2130
- &workspace,
2131
- &state,
2132
- "fresh",
2133
- None,
2196
+ &workspace, &state, "fresh", None,
2134
2197
  )
2135
2198
  .unwrap();
2136
2199
  let on_disk = crate::state::persist::load_runtime_state(&workspace).unwrap();
@@ -2147,13 +2210,10 @@ mod fresh_quick_start_leader_binding_tests {
2147
2210
  frozen_receiver: Some(frozen_receiver),
2148
2211
  ..MockOps::default()
2149
2212
  };
2150
- assert!(!bind_fresh_quick_start_leader_with(
2151
- &workspace,
2152
- "fresh",
2153
- Some(&owner),
2154
- &mut ops
2155
- )
2156
- .unwrap());
2213
+ assert!(
2214
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&owner), &mut ops)
2215
+ .unwrap()
2216
+ );
2157
2217
  assert_eq!(ops.attach_calls, 0);
2158
2218
  assert_eq!(ops.last_expected_receiver, None);
2159
2219
  let _ = std::fs::remove_dir_all(&workspace);
@@ -2163,7 +2223,11 @@ mod fresh_quick_start_leader_binding_tests {
2163
2223
  fn fresh_bind_refusal_event_keeps_first_safe_stage_and_reason() {
2164
2224
  for (case, expected_stage, expected_reason) in [
2165
2225
  ("missing_pane", "caller_pane", "caller_pane_missing"),
2166
- ("empty_command", "command_observation", "command_unobservable"),
2226
+ (
2227
+ "empty_command",
2228
+ "command_observation",
2229
+ "command_unobservable",
2230
+ ),
2167
2231
  ("unknown_provider", "strict_provider", "provider_unresolved"),
2168
2232
  (
2169
2233
  "existing_owner",
@@ -2200,12 +2264,16 @@ mod fresh_quick_start_leader_binding_tests {
2200
2264
  }
2201
2265
  crate::state::persist::save_runtime_state(&workspace, &state).unwrap();
2202
2266
 
2203
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
2204
- .unwrap());
2267
+ assert!(
2268
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap()
2269
+ );
2205
2270
  let events = crate::event_log::EventLog::new(&workspace).tail(0).unwrap();
2206
2271
  assert_eq!(events.len(), 1, "{case} must emit one first-refusal event");
2207
2272
  assert_eq!(events[0]["event"], json!(FRESH_BIND_REFUSAL_EVENT));
2208
- assert_eq!(events[0]["operation"], json!("fresh_quick_start_leader_bind"));
2273
+ assert_eq!(
2274
+ events[0]["operation"],
2275
+ json!("fresh_quick_start_leader_bind")
2276
+ );
2209
2277
  assert_eq!(events[0]["team_key"], json!("fresh"));
2210
2278
  assert_eq!(events[0]["stage"], json!(expected_stage));
2211
2279
  assert_eq!(events[0]["reason"], json!(expected_reason));
@@ -2223,9 +2291,12 @@ mod fresh_quick_start_leader_binding_tests {
2223
2291
  ));
2224
2292
  std::fs::create_dir_all(&empty_workspace).unwrap();
2225
2293
  let mut ops = MockOps::default();
2226
- assert!(!bind_fresh_quick_start_leader_with(&empty_workspace, "fresh", None, &mut ops)
2227
- .unwrap());
2228
- let events = crate::event_log::EventLog::new(&empty_workspace).tail(0).unwrap();
2294
+ assert!(
2295
+ !bind_fresh_quick_start_leader_with(&empty_workspace, "fresh", None, &mut ops).unwrap()
2296
+ );
2297
+ let events = crate::event_log::EventLog::new(&empty_workspace)
2298
+ .tail(0)
2299
+ .unwrap();
2229
2300
  assert_eq!(events.len(), 1);
2230
2301
  assert_eq!(events[0]["stage"], json!("scope"));
2231
2302
  assert_eq!(events[0]["reason"], json!("scope_unresolved"));
@@ -2240,8 +2311,9 @@ mod fresh_quick_start_leader_binding_tests {
2240
2311
  state["teams"] = json!({"fresh": {"team_key": "fresh", "agents": {}}});
2241
2312
  crate::state::persist::save_runtime_state(&workspace, &state).unwrap();
2242
2313
  let mut ops = MockOps::default();
2243
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "current", None, &mut ops)
2244
- .unwrap());
2314
+ assert!(
2315
+ !bind_fresh_quick_start_leader_with(&workspace, "current", None, &mut ops).unwrap()
2316
+ );
2245
2317
  let events = crate::event_log::EventLog::new(&workspace).tail(0).unwrap();
2246
2318
  assert_eq!(events.len(), 1);
2247
2319
  assert_eq!(events[0]["stage"], json!("scope"));
@@ -2285,10 +2357,10 @@ mod fresh_quick_start_leader_binding_tests {
2285
2357
  ops.command = Some("codex".to_string());
2286
2358
  }
2287
2359
  "existing_owner" => state["team_owner"] = json!({"pane_id": "%old"}),
2288
- "existing_receiver" => {
2289
- state["leader_receiver"] = json!({"pane_id": "%old"})
2290
- }
2291
- "provider_mismatch" | "socket_mismatch" | "workspace_mismatch"
2360
+ "existing_receiver" => state["leader_receiver"] = json!({"pane_id": "%old"}),
2361
+ "provider_mismatch"
2362
+ | "socket_mismatch"
2363
+ | "workspace_mismatch"
2292
2364
  | "dual_state_mismatch" => {
2293
2365
  state["workspace"] = json!(workspace);
2294
2366
  state["team_owner"] = json!({
@@ -2303,8 +2375,10 @@ mod fresh_quick_start_leader_binding_tests {
2303
2375
  match case {
2304
2376
  "provider_mismatch" => {
2305
2377
  state["leader_receiver"]["provider"] = json!("claude")
2306
- },
2307
- "socket_mismatch" => state["leader_receiver"]["tmux_socket"] = json!("/tmp/other"),
2378
+ }
2379
+ "socket_mismatch" => {
2380
+ state["leader_receiver"]["tmux_socket"] = json!("/tmp/other")
2381
+ }
2308
2382
  "workspace_mismatch" => state["workspace"] = json!(workspace.join("other")),
2309
2383
  "dual_state_mismatch" => state["team_owner"]["owner_epoch"] = json!(2),
2310
2384
  _ => unreachable!(),
@@ -2314,11 +2388,10 @@ mod fresh_quick_start_leader_binding_tests {
2314
2388
  _ => unreachable!(),
2315
2389
  }
2316
2390
  crate::state::persist::save_runtime_state(&workspace, &state).unwrap();
2317
- let before = std::fs::read(crate::state::persist::runtime_state_path(&workspace))
2318
- .unwrap();
2391
+ let before =
2392
+ std::fs::read(crate::state::persist::runtime_state_path(&workspace)).unwrap();
2319
2393
  assert!(
2320
- !bind_fresh_quick_start_leader_with(&workspace, team_key, None, &mut ops)
2321
- .unwrap(),
2394
+ !bind_fresh_quick_start_leader_with(&workspace, team_key, None, &mut ops).unwrap(),
2322
2395
  "{case} must refuse"
2323
2396
  );
2324
2397
  assert_eq!(
@@ -2490,15 +2563,23 @@ mod fresh_quick_start_leader_binding_tests {
2490
2563
  || bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
2491
2564
  )
2492
2565
  .unwrap());
2493
- assert_eq!(ops.attach_calls, 0, "preseeded dual state must not reattach");
2494
- let path = crate::leader::registry::registry_dir().unwrap().join(format!(
2495
- "{}__fresh.json",
2496
- crate::leader::registry::workspace_hash(&workspace)
2497
- ));
2566
+ assert_eq!(
2567
+ ops.attach_calls, 0,
2568
+ "preseeded dual state must not reattach"
2569
+ );
2570
+ let path = crate::leader::registry::registry_dir()
2571
+ .unwrap()
2572
+ .join(format!(
2573
+ "{}__fresh.json",
2574
+ crate::leader::registry::workspace_hash(&workspace)
2575
+ ));
2498
2576
  let entry: crate::leader::registry::LeaderRegistryEntry =
2499
2577
  serde_json::from_slice(&std::fs::read(path).unwrap()).unwrap();
2500
2578
  assert_eq!(
2501
- entry.channel.get("tmux_socket").and_then(serde_json::Value::as_str),
2579
+ entry
2580
+ .channel
2581
+ .get("tmux_socket")
2582
+ .and_then(serde_json::Value::as_str),
2502
2583
  Some("/private/tmp/tmux-test/default")
2503
2584
  );
2504
2585
  }
@@ -2528,8 +2609,7 @@ mod fresh_quick_start_leader_binding_tests {
2528
2609
  let before = std::fs::read(crate::state::persist::runtime_state_path(&workspace)).unwrap();
2529
2610
  let mut ops = MockOps::default();
2530
2611
 
2531
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
2532
- .unwrap());
2612
+ assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap());
2533
2613
  assert_eq!(
2534
2614
  before,
2535
2615
  std::fs::read(crate::state::persist::runtime_state_path(&workspace)).unwrap(),
@@ -2709,10 +2789,7 @@ mod fresh_quick_start_leader_binding_tests {
2709
2789
  persisted["teams"][team_key]["leader_receiver"] = takeover.receiver.clone();
2710
2790
  persisted["teams"][team_key]["owner_epoch"] = json!(takeover.epoch);
2711
2791
  crate::state::persist::save_runtime_state_with_receiver_authority(
2712
- workspace,
2713
- &persisted,
2714
- team_key,
2715
- None,
2792
+ workspace, &persisted, team_key, None,
2716
2793
  )
2717
2794
  .unwrap();
2718
2795
  assert_fresh_binding_kept(
@@ -2744,18 +2821,13 @@ mod fresh_quick_start_leader_binding_tests {
2744
2821
  }
2745
2822
  }
2746
2823
 
2747
- fn assert_fresh_binding_kept(
2748
- persisted: &serde_json::Value,
2749
- takeover: &ConcurrentTakeover,
2750
- ) {
2824
+ fn assert_fresh_binding_kept(persisted: &serde_json::Value, takeover: &ConcurrentTakeover) {
2751
2825
  assert_eq!(
2752
- persisted["teams"]["fresh"]["team_owner"],
2753
- takeover.owner,
2826
+ persisted["teams"]["fresh"]["team_owner"], takeover.owner,
2754
2827
  "concurrent team_owner must survive seeded cleanup"
2755
2828
  );
2756
2829
  assert_eq!(
2757
- persisted["teams"]["fresh"]["leader_receiver"],
2758
- takeover.receiver,
2830
+ persisted["teams"]["fresh"]["leader_receiver"], takeover.receiver,
2759
2831
  "concurrent leader_receiver must survive seeded cleanup"
2760
2832
  );
2761
2833
  assert_eq!(
@@ -2769,13 +2841,10 @@ mod fresh_quick_start_leader_binding_tests {
2769
2841
  fn seeded_cleanup_clears_exact_seed_through_bind_repository_entry() {
2770
2842
  let (workspace, seed) = workspace_with_fresh_seed("seed-cleanup-success");
2771
2843
  let mut ops = failed_register_ops(None, false);
2772
- assert!(!bind_fresh_quick_start_leader_with(
2773
- &workspace,
2774
- "fresh",
2775
- Some(&seed),
2776
- &mut ops
2777
- )
2778
- .unwrap());
2844
+ assert!(
2845
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
2846
+ .unwrap()
2847
+ );
2779
2848
  assert_eq!(ops.inner.attach_calls, 1);
2780
2849
  assert_eq!(ops.inner.register_calls, 1);
2781
2850
  assert!(ops
@@ -2794,11 +2863,9 @@ mod fresh_quick_start_leader_binding_tests {
2794
2863
  "matching seed must be cleared via bind/repository; got {}",
2795
2864
  persisted["teams"]["fresh"]["team_owner"]
2796
2865
  );
2797
- assert!(
2798
- persisted
2799
- .pointer("/teams/fresh/leader_receiver")
2800
- .is_some_and(serde_json::Value::is_null)
2801
- );
2866
+ assert!(persisted
2867
+ .pointer("/teams/fresh/leader_receiver")
2868
+ .is_some_and(serde_json::Value::is_null));
2802
2869
  assert_eq!(
2803
2870
  persisted["teams"]["fresh"]["owner_epoch"],
2804
2871
  json!(1),
@@ -2811,13 +2878,10 @@ mod fresh_quick_start_leader_binding_tests {
2811
2878
  let (workspace, seed) = workspace_with_matching_seed("seed-cleanup-concurrent");
2812
2879
  let takeover = takeover_binding(1);
2813
2880
  let mut ops = failed_register_ops(Some(takeover_binding(1)), false);
2814
- assert!(!bind_fresh_quick_start_leader_with(
2815
- &workspace,
2816
- "fresh",
2817
- Some(&seed),
2818
- &mut ops
2819
- )
2820
- .unwrap());
2881
+ assert!(
2882
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
2883
+ .unwrap()
2884
+ );
2821
2885
  assert_fresh_binding_kept(
2822
2886
  &crate::state::persist::load_runtime_state(&workspace).unwrap(),
2823
2887
  &takeover,
@@ -2829,13 +2893,10 @@ mod fresh_quick_start_leader_binding_tests {
2829
2893
  let (workspace, seed) = workspace_with_matching_seed("seed-cleanup-epoch2");
2830
2894
  let takeover = takeover_binding(2);
2831
2895
  let mut ops = failed_register_ops(Some(takeover_binding(2)), false);
2832
- assert!(!bind_fresh_quick_start_leader_with(
2833
- &workspace,
2834
- "fresh",
2835
- Some(&seed),
2836
- &mut ops
2837
- )
2838
- .unwrap());
2896
+ assert!(
2897
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
2898
+ .unwrap()
2899
+ );
2839
2900
  assert_fresh_binding_kept(
2840
2901
  &crate::state::persist::load_runtime_state(&workspace).unwrap(),
2841
2902
  &takeover,
@@ -2846,13 +2907,8 @@ mod fresh_quick_start_leader_binding_tests {
2846
2907
  fn seeded_cleanup_propagates_persist_error() {
2847
2908
  let (workspace, seed) = workspace_with_fresh_seed("seed-cleanup-persist-err");
2848
2909
  let mut ops = failed_register_ops(None, true);
2849
- let error = bind_fresh_quick_start_leader_with(
2850
- &workspace,
2851
- "fresh",
2852
- Some(&seed),
2853
- &mut ops,
2854
- )
2855
- .expect_err("poisoned state.json must surface cleanup persist failure");
2910
+ let error = bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
2911
+ .expect_err("poisoned state.json must surface cleanup persist failure");
2856
2912
  assert_eq!(ops.inner.attach_calls, 1);
2857
2913
  assert_eq!(ops.inner.register_calls, 1);
2858
2914
  assert!(ops
@@ -2932,7 +2988,9 @@ mod fresh_quick_start_leader_binding_tests {
2932
2988
  "owner_epoch": 1
2933
2989
  }
2934
2990
  });
2935
- serde_json::to_string_pretty(&expected).unwrap().into_bytes()
2991
+ serde_json::to_string_pretty(&expected)
2992
+ .unwrap()
2993
+ .into_bytes()
2936
2994
  }
2937
2995
 
2938
2996
  fn assert_failure_rolls_back_this_attempt(
@@ -3031,8 +3089,7 @@ mod fresh_quick_start_leader_binding_tests {
3031
3089
  attach_ok: false,
3032
3090
  ..MockOps::default()
3033
3091
  };
3034
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
3035
- .unwrap());
3092
+ assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap());
3036
3093
  let after = crate::state::persist::load_runtime_state(&workspace).unwrap();
3037
3094
  assert_eq!(after.get("tasks"), Some(&json!({"keep": true})));
3038
3095
  assert!(after.get("failed_attach_mutation").is_none());
@@ -3076,6 +3133,99 @@ mod fresh_quick_start_leader_binding_tests {
3076
3133
  })
3077
3134
  }
3078
3135
 
3136
+ #[cfg(unix)]
3137
+ #[test]
3138
+ #[serial_test::serial(env)]
3139
+ fn runtime_binding_endpoint_matches_caller_socket_without_redirecting_workers() {
3140
+ let hermetic = HermeticTestEnv::enter("runtime-caller-endpoint");
3141
+ let workspace = hermetic.root();
3142
+ let caller_socket = workspace.join("leader.sock");
3143
+ // Select the real caller-read backend without depending on a host tmux
3144
+ // server. This marker is not evidence of pane liveness.
3145
+ std::fs::write(&caller_socket, "fixture endpoint; no tmux server").unwrap();
3146
+ let caller_endpoint = caller_socket.to_str().unwrap();
3147
+ let tmux = hermetic.with_env("TMUX", &format!("{caller_endpoint},1,0"));
3148
+ let _pane = hermetic.with_env("TMUX_PANE", "%0");
3149
+ let worker_endpoint = "ta-fixture-workers";
3150
+ let transport = OfflineTransport::new()
3151
+ .with_tmux_endpoint(worker_endpoint)
3152
+ .with_pane_current_command("%0", "pi");
3153
+ let mut ops = RuntimeFreshQuickStartLeaderBindingOps {
3154
+ transport: &transport,
3155
+ last_failure_reason: None,
3156
+ cas_conflict: false,
3157
+ applied_grant: None,
3158
+ registry_receipt: None,
3159
+ frozen_owner: None,
3160
+ frozen_receiver: None,
3161
+ nonce_writer: None,
3162
+ };
3163
+ let endpoint = ops.tmux_endpoint().unwrap();
3164
+ assert_eq!(endpoint, caller_endpoint);
3165
+ assert_eq!(
3166
+ caller_read_transport().unwrap().tmux_endpoint().as_deref(),
3167
+ Some(endpoint.as_str())
3168
+ );
3169
+ assert_eq!(transport.tmux_endpoint().as_deref(), Some(worker_endpoint));
3170
+ let state = native_persisted_binding(workspace, caller_endpoint);
3171
+ let before = state.clone();
3172
+ assert!(persisted_binding_matches_verified_pane(
3173
+ &state,
3174
+ workspace,
3175
+ &PaneId::new("%0"),
3176
+ Provider::Pi,
3177
+ Some(&endpoint),
3178
+ ));
3179
+ assert_eq!(state, before);
3180
+ drop(tmux);
3181
+ assert!(caller_read_transport().is_none());
3182
+ assert_eq!(ops.tmux_endpoint().as_deref(), Some(worker_endpoint));
3183
+ }
3184
+
3185
+ #[cfg(unix)]
3186
+ #[test]
3187
+ #[serial_test::serial(env)]
3188
+ fn runtime_binding_endpoint_rejects_foreign_socket_with_same_pane_identity() {
3189
+ let hermetic = HermeticTestEnv::enter("runtime-foreign-endpoint");
3190
+ let workspace = hermetic.root();
3191
+ let caller_socket = workspace.join("leader.sock");
3192
+ std::fs::write(&caller_socket, "fixture endpoint; no tmux server").unwrap();
3193
+ let caller_endpoint = caller_socket.to_str().unwrap();
3194
+ let _tmux = hermetic.with_env("TMUX", &format!("{caller_endpoint},1,0"));
3195
+ let _pane = hermetic.with_env("TMUX_PANE", "%0");
3196
+ let worker_endpoint = "ta-fixture-workers";
3197
+ let transport = OfflineTransport::new()
3198
+ .with_tmux_endpoint(worker_endpoint)
3199
+ .with_pane_current_command("%0", "pi");
3200
+ let mut ops = RuntimeFreshQuickStartLeaderBindingOps {
3201
+ transport: &transport,
3202
+ last_failure_reason: None,
3203
+ cas_conflict: false,
3204
+ applied_grant: None,
3205
+ registry_receipt: None,
3206
+ frozen_owner: None,
3207
+ frozen_receiver: None,
3208
+ nonce_writer: None,
3209
+ };
3210
+ let endpoint = ops.tmux_endpoint().unwrap();
3211
+ assert_eq!(endpoint, caller_endpoint);
3212
+ let foreign_socket = workspace.join("foreign").join("leader.sock");
3213
+ for socket in [worker_endpoint, foreign_socket.to_str().unwrap()] {
3214
+ let state = native_persisted_binding(workspace, socket);
3215
+ let before = state.clone();
3216
+ // Both servers may have %0; the shared owner/provider/UUID/epoch
3217
+ // cannot make a foreign endpoint authoritative.
3218
+ assert!(!persisted_binding_matches_verified_pane(
3219
+ &state,
3220
+ workspace,
3221
+ &PaneId::new("%0"),
3222
+ Provider::Pi,
3223
+ Some(&endpoint),
3224
+ ));
3225
+ assert_eq!(state, before);
3226
+ }
3227
+ }
3228
+
3079
3229
  #[cfg(unix)]
3080
3230
  #[test]
3081
3231
  #[serial_test::serial(env)]
@@ -3090,18 +3240,34 @@ mod fresh_quick_start_leader_binding_tests {
3090
3240
  let pane = PaneId::new("%0");
3091
3241
  assert_ne!(socket.to_str(), Some(endpoint.as_str()));
3092
3242
  assert!(persisted_binding_matches_verified_pane(
3093
- &state, workspace, &pane, Provider::Pi, Some(&endpoint),
3243
+ &state,
3244
+ workspace,
3245
+ &pane,
3246
+ Provider::Pi,
3247
+ Some(&endpoint),
3094
3248
  ));
3095
3249
  assert_eq!(state, before);
3096
3250
  assert!(!persisted_binding_matches_verified_pane(
3097
- &state, workspace, &PaneId::new("%1"), Provider::Pi, Some(&endpoint),
3251
+ &state,
3252
+ workspace,
3253
+ &PaneId::new("%1"),
3254
+ Provider::Pi,
3255
+ Some(&endpoint),
3098
3256
  ));
3099
3257
  assert!(!persisted_binding_matches_verified_pane(
3100
- &state, workspace, &pane, Provider::Codex, Some(&endpoint),
3258
+ &state,
3259
+ workspace,
3260
+ &pane,
3261
+ Provider::Codex,
3262
+ Some(&endpoint),
3101
3263
  ));
3102
3264
  for endpoint in [None, Some("")] {
3103
3265
  assert!(!persisted_binding_matches_verified_pane(
3104
- &state, workspace, &pane, Provider::Pi, endpoint,
3266
+ &state,
3267
+ workspace,
3268
+ &pane,
3269
+ Provider::Pi,
3270
+ endpoint,
3105
3271
  ));
3106
3272
  }
3107
3273
  for (field, value) in [
@@ -3121,15 +3287,26 @@ mod fresh_quick_start_leader_binding_tests {
3121
3287
  ] {
3122
3288
  let mut conflict = state.clone();
3123
3289
  *conflict.pointer_mut(field).unwrap() = value;
3124
- assert!(!persisted_binding_matches_verified_pane(
3125
- &conflict, workspace, &pane, Provider::Pi, Some(&endpoint),
3126
- ), "conflicting {field} must refuse");
3290
+ assert!(
3291
+ !persisted_binding_matches_verified_pane(
3292
+ &conflict,
3293
+ workspace,
3294
+ &pane,
3295
+ Provider::Pi,
3296
+ Some(&endpoint),
3297
+ ),
3298
+ "conflicting {field} must refuse"
3299
+ );
3127
3300
  }
3128
3301
  let mut unauthorized = state.clone();
3129
3302
  unauthorized["leader_receiver"]["authorized_team_workspace"] =
3130
3303
  json!(workspace.join("foreign"));
3131
3304
  assert!(!persisted_binding_matches_verified_pane(
3132
- &unauthorized, workspace, &pane, Provider::Pi, Some(&endpoint),
3305
+ &unauthorized,
3306
+ workspace,
3307
+ &pane,
3308
+ Provider::Pi,
3309
+ Some(&endpoint),
3133
3310
  ));
3134
3311
  }
3135
3312
 
@@ -3143,15 +3320,24 @@ mod fresh_quick_start_leader_binding_tests {
3143
3320
  let endpoint = transport.tmux_endpoint().unwrap();
3144
3321
  let foreign_socket = workspace.join("foreign-socket-root").join(&endpoint);
3145
3322
  let state = native_persisted_binding(workspace, foreign_socket.to_str().unwrap());
3146
- assert_eq!(foreign_socket.file_name().unwrap().to_str(), Some(endpoint.as_str()));
3323
+ assert_eq!(
3324
+ foreign_socket.file_name().unwrap().to_str(),
3325
+ Some(endpoint.as_str())
3326
+ );
3147
3327
  assert!(!persisted_binding_matches_verified_pane(
3148
- &state, workspace, &PaneId::new("%0"), Provider::Pi, Some(&endpoint),
3328
+ &state,
3329
+ workspace,
3330
+ &PaneId::new("%0"),
3331
+ Provider::Pi,
3332
+ Some(&endpoint),
3149
3333
  ));
3150
3334
  assert!(!quick_start_tmux_endpoints_match(
3151
- foreign_socket.to_str().unwrap(), "default",
3335
+ foreign_socket.to_str().unwrap(),
3336
+ "default",
3152
3337
  ));
3153
3338
  assert!(!quick_start_tmux_endpoints_match(
3154
- foreign_socket.to_str().unwrap(), "",
3339
+ foreign_socket.to_str().unwrap(),
3340
+ "",
3155
3341
  ));
3156
3342
  }
3157
3343
 
@@ -3169,7 +3355,10 @@ mod fresh_quick_start_leader_binding_tests {
3169
3355
  std::fs::write(&socket, "fixture endpoint; no tmux server").unwrap();
3170
3356
  let state = native_persisted_binding(workspace, socket.to_str().unwrap());
3171
3357
  assert!(persisted_binding_matches_verified_pane(
3172
- &state, workspace, &PaneId::new("%0"), Provider::Pi,
3358
+ &state,
3359
+ workspace,
3360
+ &PaneId::new("%0"),
3361
+ Provider::Pi,
3173
3362
  alias.join("ta-native.sock").to_str(),
3174
3363
  ));
3175
3364
  }
@@ -3185,10 +3374,7 @@ mod fresh_quick_start_leader_binding_tests {
3185
3374
  state["teams"]["fresh"]["leader_receiver"] = receiver.clone();
3186
3375
  state["teams"]["fresh"]["owner_epoch"] = json!(epoch);
3187
3376
  crate::state::persist::save_runtime_state_with_receiver_authority(
3188
- workspace,
3189
- &state,
3190
- "fresh",
3191
- None,
3377
+ workspace, &state, "fresh", None,
3192
3378
  )
3193
3379
  .unwrap();
3194
3380
  let raw = std::fs::read(crate::state::persist::runtime_state_path(workspace)).unwrap();
@@ -3248,7 +3434,10 @@ mod fresh_quick_start_leader_binding_tests {
3248
3434
  .unwrap();
3249
3435
  let after = crate::state::persist::load_runtime_state(&workspace).unwrap();
3250
3436
  assert_eq!(after["teams"]["fresh"]["team_owner"], previous_owner);
3251
- assert_eq!(after["teams"]["fresh"]["leader_receiver"], previous_receiver);
3437
+ assert_eq!(
3438
+ after["teams"]["fresh"]["leader_receiver"],
3439
+ previous_receiver
3440
+ );
3252
3441
  assert_eq!(after["teams"]["fresh"]["owner_epoch"], json!(1));
3253
3442
  assert_eq!(after.get("tasks"), Some(&json!({"keep": true})));
3254
3443
  let _ = std::fs::remove_dir_all(&workspace);
@@ -3298,7 +3487,10 @@ mod fresh_quick_start_leader_binding_tests {
3298
3487
  assert_eq!(after["teams"]["fresh"]["leader_receiver"], winner_receiver);
3299
3488
  assert_eq!(after["teams"]["fresh"]["owner_epoch"], json!(2));
3300
3489
  assert_ne!(after["teams"]["fresh"]["team_owner"], previous_owner);
3301
- assert_ne!(after["teams"]["fresh"]["leader_receiver"], previous_receiver);
3490
+ assert_ne!(
3491
+ after["teams"]["fresh"]["leader_receiver"],
3492
+ previous_receiver
3493
+ );
3302
3494
  let _ = std::fs::remove_dir_all(&workspace);
3303
3495
  }
3304
3496
 
@@ -3343,19 +3535,23 @@ mod fresh_quick_start_leader_binding_tests {
3343
3535
  let _home = HomeGuard::set(&home);
3344
3536
  let state_path = crate::state::persist::runtime_state_path(&workspace);
3345
3537
  let before = std::fs::read(&state_path).unwrap();
3346
- let registry_path = crate::leader::registry::registry_dir().unwrap().join(format!(
3347
- "{}__fresh.json",
3348
- crate::leader::registry::workspace_hash(&workspace)
3349
- ));
3538
+ let registry_path = crate::leader::registry::registry_dir()
3539
+ .unwrap()
3540
+ .join(format!(
3541
+ "{}__fresh.json",
3542
+ crate::leader::registry::workspace_hash(&workspace)
3543
+ ));
3350
3544
  let mut ops = AmbientRegistryOps {
3351
3545
  readback_ok: false,
3352
3546
  attach_calls: 0,
3353
3547
  registry_receipt: None,
3354
3548
  };
3355
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
3356
- .unwrap());
3549
+ assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap());
3357
3550
  assert_eq!(std::fs::read(state_path).unwrap(), before);
3358
- assert!(!registry_path.exists(), "failed readback left registry bytes");
3551
+ assert!(
3552
+ !registry_path.exists(),
3553
+ "failed readback left registry bytes"
3554
+ );
3359
3555
  }
3360
3556
 
3361
3557
  struct RecordingRuntimeOps<'a> {
@@ -3563,7 +3759,10 @@ mod fresh_quick_start_leader_binding_tests {
3563
3759
  let mut focused = caller_target(parent.clone(), Some("shared-live-nonce"));
3564
3760
  focused.active = true;
3565
3761
  let (active_ok, active_reason) = bind_seeded_caller(focused, "runtime-focus-active");
3566
- assert!(active_ok, "focused live caller must bind: {active_reason:?}");
3762
+ assert!(
3763
+ active_ok,
3764
+ "focused live caller must bind: {active_reason:?}"
3765
+ );
3567
3766
 
3568
3767
  let mut background = caller_target(parent, Some("shared-live-nonce"));
3569
3768
  background.active = false;
@@ -3599,8 +3798,10 @@ mod fresh_quick_start_leader_binding_tests {
3599
3798
  frozen_receiver: None,
3600
3799
  nonce_writer: None,
3601
3800
  };
3602
- assert!(!bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
3603
- .unwrap());
3801
+ assert!(
3802
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
3803
+ .unwrap()
3804
+ );
3604
3805
  assert_eq!(ops.last_failure_reason, Some("caller_pane_not_live"));
3605
3806
  }
3606
3807
 
@@ -3647,7 +3848,10 @@ mod fresh_quick_start_leader_binding_tests {
3647
3848
  .map(|agents| agents.keys().cloned().collect::<Vec<_>>())
3648
3849
  .unwrap_or_default();
3649
3850
  assert_eq!(ids, vec!["bob".to_string()]);
3650
- assert_eq!(view.get("session_name").and_then(serde_json::Value::as_str), Some("team-bob"));
3851
+ assert_eq!(
3852
+ view.get("session_name").and_then(serde_json::Value::as_str),
3853
+ Some("team-bob")
3854
+ );
3651
3855
  }
3652
3856
 
3653
3857
  #[test]
@@ -3750,11 +3954,7 @@ mod fresh_quick_start_leader_binding_tests {
3750
3954
  .with_tmux_endpoint("/tmp/tmux.sock")
3751
3955
  .with_targets(vec![stale_target]);
3752
3956
  assert!(matches!(
3753
- crate::messaging::resolve_live_leader_channel(
3754
- &workspace,
3755
- &receiver,
3756
- &stale_transport
3757
- ),
3957
+ crate::messaging::resolve_live_leader_channel(&workspace, &receiver, &stale_transport),
3758
3958
  crate::messaging::LeaderChannelResolution::Unbound(
3759
3959
  crate::messaging::LeaderChannelUnbound::PaneWorkspaceMismatch(_)
3760
3960
  )
@@ -3792,10 +3992,17 @@ mod fresh_quick_start_leader_binding_tests {
3792
3992
  ));
3793
3993
 
3794
3994
  let mut foreign_receiver = receiver.clone();
3795
- foreign_receiver["authorized_team_workspace"] =
3796
- json!(hermetic.root().join("foreign").to_string_lossy().to_string());
3995
+ foreign_receiver["authorized_team_workspace"] = json!(hermetic
3996
+ .root()
3997
+ .join("foreign")
3998
+ .to_string_lossy()
3999
+ .to_string());
3797
4000
  assert!(matches!(
3798
- crate::messaging::resolve_live_leader_channel(&workspace, &foreign_receiver, &transport),
4001
+ crate::messaging::resolve_live_leader_channel(
4002
+ &workspace,
4003
+ &foreign_receiver,
4004
+ &transport
4005
+ ),
3799
4006
  crate::messaging::LeaderChannelResolution::Unbound(
3800
4007
  crate::messaging::LeaderChannelUnbound::PaneWorkspaceMismatch(_)
3801
4008
  )
@@ -3998,10 +4205,7 @@ mod fresh_quick_start_leader_binding_tests {
3998
4205
  let mut winner = crate::state::persist::load_runtime_state(workspace).unwrap();
3999
4206
  winner["teams"][team_key]["leader_receiver"]["pane_id"] = json!("%winner");
4000
4207
  crate::state::persist::save_runtime_state_with_receiver_authority(
4001
- workspace,
4002
- &winner,
4003
- team_key,
4004
- None,
4208
+ workspace, &winner, team_key, None,
4005
4209
  )
4006
4210
  .unwrap();
4007
4211
  let _ = crate::leader::registry::register_binding_from_state_best_effort(
@@ -4037,10 +4241,7 @@ mod fresh_quick_start_leader_binding_tests {
4037
4241
  .with_tmux_endpoint("/tmp/tmux.sock")
4038
4242
  .with_pane_current_command("%1", "bash")
4039
4243
  .with_targets(vec![target_with_nonce.clone()])
4040
- .with_target_snapshots(vec![
4041
- vec![target_without_nonce],
4042
- vec![target_with_nonce],
4043
- ]);
4244
+ .with_target_snapshots(vec![vec![target_without_nonce], vec![target_with_nonce]]);
4044
4245
  let mut ops = RuntimeCommitFailureOps {
4045
4246
  inner: RuntimeFreshQuickStartLeaderBindingOps {
4046
4247
  transport: &transport,
@@ -4059,13 +4260,10 @@ mod fresh_quick_start_leader_binding_tests {
4059
4260
  break_registry_lock: false,
4060
4261
  break_registry_read: false,
4061
4262
  };
4062
- assert!(!bind_fresh_quick_start_leader_with(
4063
- &workspace,
4064
- "fresh",
4065
- Some(&seed),
4066
- &mut ops
4067
- )
4068
- .unwrap());
4263
+ assert!(
4264
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
4265
+ .unwrap()
4266
+ );
4069
4267
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4070
4268
  assert!(persisted
4071
4269
  .pointer("/teams/fresh/team_owner")
@@ -4080,7 +4278,10 @@ mod fresh_quick_start_leader_binding_tests {
4080
4278
  "{}__fresh.json",
4081
4279
  crate::leader::registry::workspace_hash(&workspace)
4082
4280
  ));
4083
- assert!(!registry_path.exists(), "failed child grant left registry row");
4281
+ assert!(
4282
+ !registry_path.exists(),
4283
+ "failed child grant left registry row"
4284
+ );
4084
4285
  let observed = transport.list_targets().unwrap();
4085
4286
  assert_eq!(
4086
4287
  observed[0]
@@ -4128,14 +4329,14 @@ mod fresh_quick_start_leader_binding_tests {
4128
4329
  break_registry_lock: false,
4129
4330
  break_registry_read: false,
4130
4331
  };
4131
- assert!(!bind_fresh_quick_start_leader_with(
4132
- &workspace,
4133
- "fresh",
4134
- Some(&seed),
4135
- &mut ops,
4136
- )
4137
- .unwrap());
4138
- assert_eq!(ops.inner.last_failure_reason, Some("attach_event_log_failed"));
4332
+ assert!(
4333
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops,)
4334
+ .unwrap()
4335
+ );
4336
+ assert_eq!(
4337
+ ops.inner.last_failure_reason,
4338
+ Some("attach_event_log_failed")
4339
+ );
4139
4340
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4140
4341
  assert!(persisted
4141
4342
  .pointer("/teams/fresh/team_owner")
@@ -4192,7 +4393,10 @@ mod fresh_quick_start_leader_binding_tests {
4192
4393
  || bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
4193
4394
  )
4194
4395
  .unwrap());
4195
- assert_eq!(ops.last_failure_reason, Some("receiver_live_channel_unavailable"));
4396
+ assert_eq!(
4397
+ ops.last_failure_reason,
4398
+ Some("receiver_live_channel_unavailable")
4399
+ );
4196
4400
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4197
4401
  assert!(persisted
4198
4402
  .pointer("/teams/fresh/team_owner")
@@ -4245,13 +4449,10 @@ mod fresh_quick_start_leader_binding_tests {
4245
4449
  break_registry_lock: false,
4246
4450
  break_registry_read: false,
4247
4451
  };
4248
- assert!(!bind_fresh_quick_start_leader_with(
4249
- &workspace,
4250
- "fresh",
4251
- Some(&seed),
4252
- &mut ops
4253
- )
4254
- .unwrap());
4452
+ assert!(
4453
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
4454
+ .unwrap()
4455
+ );
4255
4456
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4256
4457
  assert!(persisted
4257
4458
  .pointer("/teams/fresh/team_owner")
@@ -4265,7 +4466,10 @@ mod fresh_quick_start_leader_binding_tests {
4265
4466
  "{}__fresh.json",
4266
4467
  crate::leader::registry::workspace_hash(&workspace)
4267
4468
  ));
4268
- assert!(!registry_path.exists(), "readback failure left registry row");
4469
+ assert!(
4470
+ !registry_path.exists(),
4471
+ "readback failure left registry row"
4472
+ );
4269
4473
  }
4270
4474
 
4271
4475
  #[test]
@@ -4304,13 +4508,10 @@ mod fresh_quick_start_leader_binding_tests {
4304
4508
  break_registry_lock: false,
4305
4509
  break_registry_read: false,
4306
4510
  };
4307
- assert!(!bind_fresh_quick_start_leader_with(
4308
- &workspace,
4309
- "fresh",
4310
- Some(&seed),
4311
- &mut ops,
4312
- )
4313
- .unwrap());
4511
+ assert!(
4512
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops,)
4513
+ .unwrap()
4514
+ );
4314
4515
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4315
4516
  assert_eq!(
4316
4517
  persisted
@@ -4348,13 +4549,11 @@ mod fresh_quick_start_leader_binding_tests {
4348
4549
  #[test]
4349
4550
  #[serial_test::serial(env)]
4350
4551
  fn seeded_runtime_registry_rollback_errors_are_visible_after_state_cleanup() {
4351
- for (tag, break_registry_lock, break_registry_read) in [
4352
- ("lock", true, false),
4353
- ("read", false, true),
4354
- ] {
4355
- let hermetic = HermeticTestEnv::enter(&format!(
4356
- "runtime-seeded-registry-rollback-{tag}"
4357
- ));
4552
+ for (tag, break_registry_lock, break_registry_read) in
4553
+ [("lock", true, false), ("read", false, true)]
4554
+ {
4555
+ let hermetic =
4556
+ HermeticTestEnv::enter(&format!("runtime-seeded-registry-rollback-{tag}"));
4358
4557
  let workspace = runtime_workspace(&hermetic, "fresh");
4359
4558
  let parent = hermetic.root().join("parent");
4360
4559
  std::fs::create_dir_all(&parent).unwrap();
@@ -4387,13 +4586,9 @@ mod fresh_quick_start_leader_binding_tests {
4387
4586
  break_registry_lock,
4388
4587
  break_registry_read,
4389
4588
  };
4390
- let error = bind_fresh_quick_start_leader_with(
4391
- &workspace,
4392
- "fresh",
4393
- Some(&seed),
4394
- &mut ops,
4395
- )
4396
- .expect_err("registry rollback failure must be visible");
4589
+ let error =
4590
+ bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
4591
+ .expect_err("registry rollback failure must be visible");
4397
4592
  assert!(error
4398
4593
  .to_string()
4399
4594
  .contains("quick-start registry rollback failed"));
@@ -4477,7 +4672,10 @@ mod fresh_quick_start_leader_binding_tests {
4477
4672
  )
4478
4673
  .unwrap());
4479
4674
  assert_eq!(ops.last_failure_reason, Some(expected_reason));
4480
- assert_eq!(refusal_reason(&workspace).map(|(_, reason)| reason), Some(expected_reason.to_string()));
4675
+ assert_eq!(
4676
+ refusal_reason(&workspace).map(|(_, reason)| reason),
4677
+ Some(expected_reason.to_string())
4678
+ );
4481
4679
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4482
4680
  assert!(persisted
4483
4681
  .pointer("/teams/fresh/team_owner")
@@ -4501,12 +4699,10 @@ mod fresh_quick_start_leader_binding_tests {
4501
4699
  let _caller_pane = hermetic.with_env(CALLER_PANE_ENV, "%1");
4502
4700
  let _caller_endpoint = hermetic.with_env(CALLER_ENDPOINT_ENV, "/tmp/tmux.sock");
4503
4701
  let seed = seeded_runtime_owner(&workspace);
4504
- let mut state = crate::state::projection::resolve_runtime_team_scope(
4505
- &workspace,
4506
- Some("fresh"),
4507
- )
4508
- .unwrap()
4509
- .state;
4702
+ let mut state =
4703
+ crate::state::projection::resolve_runtime_team_scope(&workspace, Some("fresh"))
4704
+ .unwrap()
4705
+ .state;
4510
4706
  let expected_owner = state["team_owner"].clone();
4511
4707
  let expected_receiver = state["leader_receiver"].clone();
4512
4708
  let target = caller_target(parent.clone(), None);
@@ -4538,12 +4734,10 @@ mod fresh_quick_start_leader_binding_tests {
4538
4734
 
4539
4735
  let workspace = runtime_workspace(&hermetic, "writer-failure");
4540
4736
  let seed = seeded_runtime_owner(&workspace);
4541
- let mut state = crate::state::projection::resolve_runtime_team_scope(
4542
- &workspace,
4543
- Some("fresh"),
4544
- )
4545
- .unwrap()
4546
- .state;
4737
+ let mut state =
4738
+ crate::state::projection::resolve_runtime_team_scope(&workspace, Some("fresh"))
4739
+ .unwrap()
4740
+ .state;
4547
4741
  let expected_owner = state["team_owner"].clone();
4548
4742
  let expected_receiver = state["leader_receiver"].clone();
4549
4743
  let target = caller_target(hermetic.root().join("parent"), None);
@@ -4583,27 +4777,22 @@ mod fresh_quick_start_leader_binding_tests {
4583
4777
  let _caller_pane = hermetic.with_env(CALLER_PANE_ENV, "%1");
4584
4778
  let _caller_endpoint = hermetic.with_env(CALLER_ENDPOINT_ENV, "/tmp/tmux.sock");
4585
4779
  let seed = seeded_runtime_owner(&workspace);
4586
- let concurrent_writer = |_: &str,
4587
- _: &PaneId,
4588
- _: &str|
4589
- -> Result<String, crate::leader::LeaderError> {
4590
- let mut winner = crate::state::persist::load_runtime_state(&workspace)
4780
+ let concurrent_writer =
4781
+ |_: &str, _: &PaneId, _: &str| -> Result<String, crate::leader::LeaderError> {
4782
+ let mut winner = crate::state::persist::load_runtime_state(&workspace)
4783
+ .map_err(crate::leader::LeaderError::State)?;
4784
+ winner["teams"]["fresh"]["leader_receiver"]["pane_id"] = json!("%winner");
4785
+ crate::state::persist::save_runtime_state_with_receiver_authority(
4786
+ &workspace, &winner, "fresh", None,
4787
+ )
4591
4788
  .map_err(crate::leader::LeaderError::State)?;
4592
- winner["teams"]["fresh"]["leader_receiver"]["pane_id"] = json!("%winner");
4593
- crate::state::persist::save_runtime_state_with_receiver_authority(
4594
- &workspace,
4595
- &winner,
4596
- "fresh",
4597
- None,
4598
- )
4599
- .map_err(crate::leader::LeaderError::State)?;
4600
- let _ = crate::leader::registry::register_binding_from_state_best_effort(
4601
- &workspace,
4602
- Some("fresh"),
4603
- "concurrent",
4604
- );
4605
- Ok("writer-winner".to_string())
4606
- };
4789
+ let _ = crate::leader::registry::register_binding_from_state_best_effort(
4790
+ &workspace,
4791
+ Some("fresh"),
4792
+ "concurrent",
4793
+ );
4794
+ Ok("writer-winner".to_string())
4795
+ };
4607
4796
  let target = caller_target(parent, None);
4608
4797
  let transport = OfflineTransport::new()
4609
4798
  .with_tmux_endpoint("/tmp/tmux.sock")
@@ -4619,30 +4808,35 @@ mod fresh_quick_start_leader_binding_tests {
4619
4808
  frozen_receiver: None,
4620
4809
  nonce_writer: Some(&concurrent_writer),
4621
4810
  };
4622
- assert!(!bind_fresh_quick_start_leader_with(
4623
- &workspace,
4624
- "fresh",
4625
- Some(&seed),
4626
- &mut ops
4627
- )
4628
- .unwrap());
4811
+ assert!(
4812
+ !bind_fresh_quick_start_leader_with(&workspace, "fresh", Some(&seed), &mut ops)
4813
+ .unwrap()
4814
+ );
4629
4815
  assert!(ops.cas_conflict);
4630
4816
  assert_eq!(ops.last_failure_reason, Some("attach_cas_conflict"));
4631
4817
  let persisted = crate::state::persist::load_runtime_state(&workspace).unwrap();
4632
4818
  assert_eq!(
4633
- persisted.pointer("/teams/fresh/team_owner/pane_id").and_then(serde_json::Value::as_str),
4819
+ persisted
4820
+ .pointer("/teams/fresh/team_owner/pane_id")
4821
+ .and_then(serde_json::Value::as_str),
4634
4822
  Some("%1")
4635
4823
  );
4636
4824
  assert_eq!(
4637
- persisted.pointer("/teams/fresh/leader_receiver/pane_id").and_then(serde_json::Value::as_str),
4825
+ persisted
4826
+ .pointer("/teams/fresh/leader_receiver/pane_id")
4827
+ .and_then(serde_json::Value::as_str),
4638
4828
  Some("%winner")
4639
4829
  );
4640
4830
  assert_eq!(
4641
- persisted.pointer("/teams/fresh/team_owner/owner_epoch").and_then(serde_json::Value::as_u64),
4831
+ persisted
4832
+ .pointer("/teams/fresh/team_owner/owner_epoch")
4833
+ .and_then(serde_json::Value::as_u64),
4642
4834
  Some(1)
4643
4835
  );
4644
4836
  assert_eq!(
4645
- persisted.pointer("/teams/fresh/leader_receiver/owner_epoch").and_then(serde_json::Value::as_u64),
4837
+ persisted
4838
+ .pointer("/teams/fresh/leader_receiver/owner_epoch")
4839
+ .and_then(serde_json::Value::as_u64),
4646
4840
  Some(1)
4647
4841
  );
4648
4842
  let registry_path = crate::leader::registry::registry_dir()
@@ -4651,7 +4845,10 @@ mod fresh_quick_start_leader_binding_tests {
4651
4845
  "{}__fresh.json",
4652
4846
  crate::leader::registry::workspace_hash(&workspace)
4653
4847
  ));
4654
- assert!(registry_path.exists(), "concurrent winner registry was removed");
4848
+ assert!(
4849
+ registry_path.exists(),
4850
+ "concurrent winner registry was removed"
4851
+ );
4655
4852
  let winner_entry: crate::leader::registry::LeaderRegistryEntry =
4656
4853
  serde_json::from_slice(&std::fs::read(registry_path).unwrap()).unwrap();
4657
4854
  assert_eq!(winner_entry.channel["pane_id"], json!("%winner"));
@@ -4661,18 +4858,8 @@ mod fresh_quick_start_leader_binding_tests {
4661
4858
  #[serial_test::serial(env)]
4662
4859
  fn runtime_socket_and_explicit_conflicts_refuse_without_command_fallback() {
4663
4860
  for (tag, endpoint, leader, scoped) in [
4664
- (
4665
- "socket",
4666
- "/tmp/other.sock",
4667
- None,
4668
- "/tmp/tmux.sock",
4669
- ),
4670
- (
4671
- "scoped",
4672
- "/tmp/tmux.sock",
4673
- None,
4674
- "/tmp/product.sock",
4675
- ),
4861
+ ("socket", "/tmp/other.sock", None, "/tmp/tmux.sock"),
4862
+ ("scoped", "/tmp/tmux.sock", None, "/tmp/product.sock"),
4676
4863
  (
4677
4864
  // The explicit leader provider intentionally conflicts with the
4678
4865
  // caller provider; worker_env must reject this before command fallback.
@@ -4689,7 +4876,8 @@ mod fresh_quick_start_leader_binding_tests {
4689
4876
  let _provider = hermetic.with_env(CALLER_PROVIDER_ENV, "codex");
4690
4877
  let _caller_pane = hermetic.with_env(CALLER_PANE_ENV, "%1");
4691
4878
  let _caller_endpoint = hermetic.with_env(CALLER_ENDPOINT_ENV, endpoint);
4692
- let _leader = leader.map(|value| hermetic.with_env("TEAM_AGENT_LEADER_PROVIDER", value));
4879
+ let _leader =
4880
+ leader.map(|value| hermetic.with_env("TEAM_AGENT_LEADER_PROVIDER", value));
4693
4881
  let transport = OfflineTransport::new()
4694
4882
  .with_tmux_endpoint(scoped)
4695
4883
  .with_pane_current_command("%1", "codex");
@@ -4702,7 +4890,6 @@ mod fresh_quick_start_leader_binding_tests {
4702
4890
  }
4703
4891
  }
4704
4892
 
4705
-
4706
4893
  #[test]
4707
4894
  fn pi_tool_category_is_transparently_accepted_by_compiler() {
4708
4895
  let root = std::env::temp_dir().join(format!(
@@ -4729,9 +4916,9 @@ mod fresh_quick_start_leader_binding_tests {
4729
4916
  .get("agents")
4730
4917
  .and_then(Value::as_list)
4731
4918
  .and_then(|agents| {
4732
- agents.iter().find(|agent| {
4733
- agent.get("id").and_then(Value::as_str) == Some("worker")
4734
- })
4919
+ agents
4920
+ .iter()
4921
+ .find(|agent| agent.get("id").and_then(Value::as_str) == Some("worker"))
4735
4922
  })
4736
4923
  .expect("compiled spec must retain the worker role");
4737
4924
  assert!(
@@ -4745,8 +4932,7 @@ mod fresh_quick_start_leader_binding_tests {
4745
4932
  fn fresh_binding_persists_then_registers_then_requires_canonical_readback() {
4746
4933
  let workspace = workspace_with_provider("positive-pi", "pi");
4747
4934
  let mut ops = MockOps::with_provider("pi");
4748
- assert!(bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops)
4749
- .unwrap());
4935
+ assert!(bind_fresh_quick_start_leader_with(&workspace, "fresh", None, &mut ops).unwrap());
4750
4936
  assert_eq!(ops.attached_provider, Some(crate::provider::Provider::Pi));
4751
4937
  assert_eq!(ops.attach_calls, 1);
4752
4938
  assert_eq!(ops.register_calls, 1);
@@ -4803,12 +4989,10 @@ mod fresh_quick_start_leader_binding_tests {
4803
4989
  let _caller_pane = hermetic.with_env(CALLER_PANE_ENV, "%1");
4804
4990
  let _caller_endpoint = hermetic.with_env(CALLER_ENDPOINT_ENV, "/tmp/tmux.sock");
4805
4991
  let seed = seeded_runtime_owner(&workspace);
4806
- let mut state = crate::state::projection::resolve_runtime_team_scope(
4807
- &workspace,
4808
- Some("fresh"),
4809
- )
4810
- .unwrap()
4811
- .state;
4992
+ let mut state =
4993
+ crate::state::projection::resolve_runtime_team_scope(&workspace, Some("fresh"))
4994
+ .unwrap()
4995
+ .state;
4812
4996
  let expected_owner = state["team_owner"].clone();
4813
4997
  let expected_receiver = state["leader_receiver"].clone();
4814
4998
  let target = caller_target(parent.clone(), None);
@@ -4840,12 +5024,10 @@ mod fresh_quick_start_leader_binding_tests {
4840
5024
 
4841
5025
  let workspace = runtime_workspace_with_provider(&hermetic, "writer-failure", "pi");
4842
5026
  let seed = seeded_runtime_owner(&workspace);
4843
- let mut state = crate::state::projection::resolve_runtime_team_scope(
4844
- &workspace,
4845
- Some("fresh"),
4846
- )
4847
- .unwrap()
4848
- .state;
5027
+ let mut state =
5028
+ crate::state::projection::resolve_runtime_team_scope(&workspace, Some("fresh"))
5029
+ .unwrap()
5030
+ .state;
4849
5031
  let expected_owner = state["team_owner"].clone();
4850
5032
  let expected_receiver = state["leader_receiver"].clone();
4851
5033
  let target = caller_target(hermetic.root().join("parent"), None);