@team-agent/installer 0.5.61 → 0.5.63

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 (250) hide show
  1. package/Cargo.lock +1 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/src/cli/adapters.rs +5 -2
  4. package/crates/team-agent/src/cli/attach_app_server_leader.rs +1 -0
  5. package/crates/team-agent/src/cli/diagnose.rs +1 -0
  6. package/crates/team-agent/src/cli/emit.rs +41 -7
  7. package/crates/team-agent/src/cli/helpers.rs +1 -0
  8. package/crates/team-agent/src/cli/leader.rs +6 -1
  9. package/crates/team-agent/src/cli/leaders.rs +2 -0
  10. package/crates/team-agent/src/cli/mod.rs +33 -3
  11. package/crates/team-agent/src/cli/named_address.rs +8 -1
  12. package/crates/team-agent/src/cli/profile.rs +2 -1
  13. package/crates/team-agent/src/cli/send/coordinator.rs +1 -0
  14. package/crates/team-agent/src/cli/send/mailbox.rs +3 -0
  15. package/crates/team-agent/src/cli/send/persist.rs +1 -0
  16. package/crates/team-agent/src/cli/send/presentation.rs +1 -0
  17. package/crates/team-agent/src/cli/send/resolve.rs +206 -1
  18. package/crates/team-agent/src/cli/send.rs +2 -1
  19. package/crates/team-agent/src/cli/spec.rs +1 -0
  20. package/crates/team-agent/src/cli/status.rs +2 -1
  21. package/crates/team-agent/src/cli/status_port/compact.rs +1 -0
  22. package/crates/team-agent/src/cli/status_port/format.rs +1 -0
  23. package/crates/team-agent/src/cli/status_port/inbox.rs +1 -0
  24. package/crates/team-agent/src/cli/tests/verb_profile.rs +38 -0
  25. package/crates/team-agent/src/cli/types.rs +3 -2
  26. package/crates/team-agent/src/communication_mode/mod.rs +1 -0
  27. package/crates/team-agent/src/compiler.rs +1 -0
  28. package/crates/team-agent/src/conpty/backend.rs +1 -0
  29. package/crates/team-agent/src/conpty/mod.rs +1 -0
  30. package/crates/team-agent/src/coordinator/backoff.rs +5 -8
  31. package/crates/team-agent/src/coordinator/conpty_shim.rs +3 -2
  32. package/crates/team-agent/src/coordinator/health.rs +1 -0
  33. package/crates/team-agent/src/coordinator/mod.rs +2 -2
  34. package/crates/team-agent/src/coordinator/orphan.rs +4 -116
  35. package/crates/team-agent/src/coordinator/runtime_detectors.rs +1 -0
  36. package/crates/team-agent/src/coordinator/runtime_observation.rs +1 -0
  37. package/crates/team-agent/src/coordinator/steps/abnormal.rs +15 -866
  38. package/crates/team-agent/src/coordinator/steps/delivery.rs +1 -0
  39. package/crates/team-agent/src/coordinator/steps/health_sync.rs +1 -0
  40. package/crates/team-agent/src/coordinator/steps/mod.rs +2 -0
  41. package/crates/team-agent/src/coordinator/steps/persist.rs +1 -0
  42. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +1 -0
  43. package/crates/team-agent/src/coordinator/steps/session_gate.rs +1 -0
  44. package/crates/team-agent/src/coordinator/tests/abnormal.rs +0 -174
  45. package/crates/team-agent/src/coordinator/tests/api_error_recovery.rs +139 -375
  46. package/crates/team-agent/src/coordinator/tests/basics.rs +0 -184
  47. package/crates/team-agent/src/coordinator/tests/mod.rs +2 -17
  48. package/crates/team-agent/src/coordinator/tests/tick_core.rs +0 -49
  49. package/crates/team-agent/src/coordinator/tick.rs +23 -40
  50. package/crates/team-agent/src/coordinator/types.rs +3 -176
  51. package/crates/team-agent/src/db/agent_health_capture.rs +1 -0
  52. package/crates/team-agent/src/db/message_store.rs +2 -1
  53. package/crates/team-agent/src/db/migration.rs +5 -4
  54. package/crates/team-agent/src/db/mod.rs +1 -0
  55. package/crates/team-agent/src/db/schema.rs +1 -0
  56. package/crates/team-agent/src/diagnose/comms.rs +2 -1
  57. package/crates/team-agent/src/diagnose/mod.rs +1 -0
  58. package/crates/team-agent/src/diagnose/orphans.rs +1 -0
  59. package/crates/team-agent/src/layout/manager.rs +3 -7
  60. package/crates/team-agent/src/layout/mod.rs +2 -2
  61. package/crates/team-agent/src/layout/overlay.rs +6 -1
  62. package/crates/team-agent/src/layout/placement.rs +1 -0
  63. package/crates/team-agent/src/layout/recovery.rs +3 -0
  64. package/crates/team-agent/src/layout/runtime_sessions.rs +8 -3
  65. package/crates/team-agent/src/layout/sessions.rs +8 -1
  66. package/crates/team-agent/src/layout/tmux_endpoint.rs +3 -0
  67. package/crates/team-agent/src/layout/worker_env.rs +3 -0
  68. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  69. package/crates/team-agent/src/leader/helpers.rs +1 -0
  70. package/crates/team-agent/src/leader/incident.rs +1 -0
  71. package/crates/team-agent/src/leader/lease.rs +27 -22
  72. package/crates/team-agent/src/leader/mod.rs +2 -3
  73. package/crates/team-agent/src/leader/owner_bind.rs +13 -3
  74. package/crates/team-agent/src/leader/provider_attribution.rs +1 -0
  75. package/crates/team-agent/src/leader/rediscover.rs +4 -17
  76. package/crates/team-agent/src/leader/registry.rs +3 -15
  77. package/crates/team-agent/src/leader/start.rs +373 -125
  78. package/crates/team-agent/src/leader/takeover.rs +10 -232
  79. package/crates/team-agent/src/leader/tests/claim_leader_mailbox_flush_contract.rs +544 -0
  80. package/crates/team-agent/src/leader/tests/historical_inventory_upgrade_gate_red.rs +624 -0
  81. package/crates/team-agent/src/leader/tests/identity.rs +7 -2
  82. package/crates/team-agent/src/leader/tests/idle.rs +0 -193
  83. package/crates/team-agent/src/leader/tests/lease_api.rs +0 -45
  84. package/crates/team-agent/src/leader/tests/mod.rs +4 -41
  85. package/crates/team-agent/src/leader/tests/rehomed_env.rs +83 -0
  86. package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1273 -0
  87. package/crates/team-agent/src/leader/tests/terminal_and_replay_vs_rerender_invariants_red.rs +417 -0
  88. package/crates/team-agent/src/leader/tests/wake_start_owner.rs +22 -103
  89. package/crates/team-agent/src/leader/types.rs +1 -28
  90. package/crates/team-agent/src/lib.rs +3 -0
  91. package/crates/team-agent/src/lifecycle/display.rs +7 -1
  92. package/crates/team-agent/src/lifecycle/helpers.rs +3 -1
  93. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +2 -2
  94. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +1 -0
  95. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +1 -0
  96. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +1 -0
  97. package/crates/team-agent/src/lifecycle/launch/plan.rs +2 -2
  98. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +4 -26
  99. package/crates/team-agent/src/lifecycle/launch/readiness.rs +0 -27
  100. package/crates/team-agent/src/lifecycle/launch/spawn.rs +1 -27
  101. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +4 -32
  102. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +1 -0
  103. package/crates/team-agent/src/lifecycle/launch.rs +11 -12
  104. package/crates/team-agent/src/lifecycle/mod.rs +2 -1
  105. package/crates/team-agent/src/lifecycle/restart/agent.rs +3 -66
  106. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +2 -2
  107. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +13 -5
  108. package/crates/team-agent/src/lifecycle/restart/remove.rs +1 -1
  109. package/crates/team-agent/src/lifecycle/restart/selection.rs +3 -3
  110. package/crates/team-agent/src/lifecycle/restart.rs +13 -15
  111. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1007 -0
  112. package/crates/team-agent/src/lifecycle/tests/b0_legacy_snapshot_nonauthority_contract.rs +265 -0
  113. package/crates/team-agent/src/lifecycle/tests/b0_reader_hideone_audit_contract.rs +459 -0
  114. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +849 -0
  115. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +323 -0
  116. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +423 -0
  117. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +737 -0
  118. package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +1187 -0
  119. package/crates/team-agent/src/lifecycle/tests/codex_weak_window_attribution_red.rs +683 -0
  120. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +394 -0
  121. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +1856 -0
  122. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +917 -0
  123. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +481 -0
  124. package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +301 -0
  125. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +516 -0
  126. package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +986 -0
  127. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +651 -0
  128. package/crates/team-agent/src/lifecycle/tests/main_preserved.rs +2 -0
  129. package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +332 -0
  130. package/crates/team-agent/src/lifecycle/tests/realmachine_clusters_1_6_red.rs +846 -0
  131. package/crates/team-agent/src/lifecycle/tests/realmachine_residual_g1_g4_red.rs +648 -0
  132. package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +910 -0
  133. package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +630 -0
  134. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +1083 -0
  135. package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +1677 -0
  136. package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +410 -0
  137. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +428 -0
  138. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +1032 -0
  139. package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +869 -0
  140. package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1249 -0
  141. package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +342 -0
  142. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +542 -0
  143. package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1103 -0
  144. package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1276 -0
  145. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_roster_red.rs +145 -0
  146. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +603 -0
  147. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +837 -0
  148. package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +928 -0
  149. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +951 -0
  150. package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +327 -0
  151. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +760 -0
  152. package/crates/team-agent/src/lifecycle/tests.rs +59 -0
  153. package/crates/team-agent/src/lifecycle/types.rs +0 -9
  154. package/crates/team-agent/src/mcp_server/helpers.rs +1 -0
  155. package/crates/team-agent/src/mcp_server/lifecycle_tools/mod.rs +1 -0
  156. package/crates/team-agent/src/mcp_server/lifecycle_tools/state_status.rs +1 -0
  157. package/crates/team-agent/src/mcp_server/mod.rs +1 -0
  158. package/crates/team-agent/src/mcp_server/normalize.rs +4 -3
  159. package/crates/team-agent/src/mcp_server/tools.rs +1 -0
  160. package/crates/team-agent/src/mcp_server/types.rs +1 -18
  161. package/crates/team-agent/src/mcp_server/wire.rs +5 -5
  162. package/crates/team-agent/src/messaging/activity.rs +1 -0
  163. package/crates/team-agent/src/messaging/address.rs +1 -0
  164. package/crates/team-agent/src/messaging/delivery.rs +4 -3
  165. package/crates/team-agent/src/messaging/helpers.rs +2 -1
  166. package/crates/team-agent/src/messaging/leader_channel.rs +1 -0
  167. package/crates/team-agent/src/messaging/leader_receiver.rs +2 -1
  168. package/crates/team-agent/src/messaging/mod.rs +10 -14
  169. package/crates/team-agent/src/messaging/peers.rs +2 -0
  170. package/crates/team-agent/src/messaging/persist.rs +3 -1
  171. package/crates/team-agent/src/messaging/presentation.rs +2 -1
  172. package/crates/team-agent/src/messaging/results.rs +1 -0
  173. package/crates/team-agent/src/messaging/scheduler.rs +1 -0
  174. package/crates/team-agent/src/messaging/selftest.rs +1 -1
  175. package/crates/team-agent/src/messaging/send.rs +41 -8
  176. package/crates/team-agent/src/messaging/tests/mod.rs +5 -0
  177. package/crates/team-agent/src/messaging/types.rs +2 -2
  178. package/crates/team-agent/src/messaging/watchers.rs +19 -13
  179. package/crates/team-agent/src/model/enums.rs +1 -0
  180. package/crates/team-agent/src/model/errors.rs +1 -0
  181. package/crates/team-agent/src/model/ids.rs +1 -0
  182. package/crates/team-agent/src/model/mod.rs +1 -0
  183. package/crates/team-agent/src/model/name_similarity.rs +1 -0
  184. package/crates/team-agent/src/model/pane_authority_refusal.rs +1 -0
  185. package/crates/team-agent/src/model/paths.rs +1 -0
  186. package/crates/team-agent/src/model/permissions.rs +3 -2
  187. package/crates/team-agent/src/model/routing.rs +1 -0
  188. package/crates/team-agent/src/model/spec.rs +1 -0
  189. package/crates/team-agent/src/model/task_graph.rs +1 -0
  190. package/crates/team-agent/src/model/yaml/tests.rs +1 -0
  191. package/crates/team-agent/src/model/yaml.rs +1 -0
  192. package/crates/team-agent/src/packaging/install.rs +9 -147
  193. package/crates/team-agent/src/packaging/migrate.rs +2 -0
  194. package/crates/team-agent/src/packaging/mod.rs +1 -0
  195. package/crates/team-agent/src/packaging/repair.rs +2 -0
  196. package/crates/team-agent/src/packaging/tests.rs +29 -218
  197. package/crates/team-agent/src/packaging/types.rs +8 -15
  198. package/crates/team-agent/src/platform/argv.rs +4 -0
  199. package/crates/team-agent/src/platform/errors.rs +10 -1
  200. package/crates/team-agent/src/platform/file_lock.rs +4 -157
  201. package/crates/team-agent/src/platform/mod.rs +0 -61
  202. package/crates/team-agent/src/platform/process.rs +1 -0
  203. package/crates/team-agent/src/provider/adapter.rs +1 -0
  204. package/crates/team-agent/src/provider/adapters/claude.rs +1 -0
  205. package/crates/team-agent/src/provider/adapters/claude_fork.rs +1 -0
  206. package/crates/team-agent/src/provider/adapters/codex.rs +1 -0
  207. package/crates/team-agent/src/provider/adapters/copilot.rs +1 -0
  208. package/crates/team-agent/src/provider/adapters/copilot_fork.rs +1 -0
  209. package/crates/team-agent/src/provider/adapters/fake.rs +1 -0
  210. package/crates/team-agent/src/provider/adapters/mod.rs +1 -0
  211. package/crates/team-agent/src/provider/approvals/mod.rs +1 -0
  212. package/crates/team-agent/src/provider/approvals/parsing.rs +2 -5
  213. package/crates/team-agent/src/provider/approvals/runtime_prompts.rs +6 -5
  214. package/crates/team-agent/src/provider/classify.rs +1 -0
  215. package/crates/team-agent/src/provider/faults.rs +1 -26
  216. package/crates/team-agent/src/provider/helpers.rs +1 -0
  217. package/crates/team-agent/src/provider/mod.rs +1 -1
  218. package/crates/team-agent/src/provider/session/capture.rs +1 -4
  219. package/crates/team-agent/src/provider/session/context_fork/claude.rs +1 -0
  220. package/crates/team-agent/src/provider/session/context_fork/codex.rs +1 -0
  221. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +1 -0
  222. package/crates/team-agent/src/provider/session/context_fork.rs +1 -0
  223. package/crates/team-agent/src/provider/session/mod.rs +2 -4
  224. package/crates/team-agent/src/provider/session/resume.rs +2 -209
  225. package/crates/team-agent/src/provider/session_scan/claude.rs +1 -0
  226. package/crates/team-agent/src/provider/session_scan/codex.rs +1 -0
  227. package/crates/team-agent/src/provider/session_scan/common.rs +1 -0
  228. package/crates/team-agent/src/provider/session_scan/copilot.rs +1 -0
  229. package/crates/team-agent/src/provider/session_scan.rs +1 -42
  230. package/crates/team-agent/src/provider/startup_prompt.rs +1 -0
  231. package/crates/team-agent/src/provider/types.rs +1 -0
  232. package/crates/team-agent/src/provider/wire.rs +1 -0
  233. package/crates/team-agent/src/state/identity.rs +16 -5
  234. package/crates/team-agent/src/state/identity_keys.rs +1 -0
  235. package/crates/team-agent/src/state/mod.rs +2 -0
  236. package/crates/team-agent/src/state/owner_gate.rs +5 -0
  237. package/crates/team-agent/src/state/ownership.rs +10 -4
  238. package/crates/team-agent/src/state/paths.rs +12 -0
  239. package/crates/team-agent/src/state/persist.rs +9 -3
  240. package/crates/team-agent/src/state/projection.rs +15 -2
  241. package/crates/team-agent/src/state/repository/intent.rs +1 -0
  242. package/crates/team-agent/src/state/repository/tests.rs +1 -0
  243. package/crates/team-agent/src/state/repository.rs +7 -13
  244. package/crates/team-agent/src/state/selector.rs +1 -0
  245. package/crates/team-agent/src/tmux_backend/tests.rs +39 -0
  246. package/crates/team-agent/src/tmux_backend.rs +63 -0
  247. package/crates/team-agent/src/transport.rs +15 -0
  248. package/package.json +4 -4
  249. package/crates/team-agent/src/leader/inject.rs +0 -33
  250. package/crates/team-agent/src/provider/command.rs +0 -80
@@ -1,4 +1,5 @@
1
- //! unit-5 (Stage 2) — resume preflight + closed `ResumeRefusalReason` enum.
1
+ //!
2
+ //! unit-5 (Stage 2) — closed `ResumeRefusalReason` enum and recovery hints.
2
3
  //!
3
4
  //! Today the restart resume gate flattens every refusal into one of two
4
5
  //! opaque strings:
@@ -159,110 +160,6 @@ impl ResumeRefusalReason {
159
160
  }
160
161
  }
161
162
 
162
- /// Outcome of `ResumePreflight::check`.
163
- #[derive(Debug, Clone, PartialEq, Eq)]
164
- pub enum ResumePreflightOutcome {
165
- /// Worker can resume from the named session.
166
- Resume { session_id: String },
167
- /// `--allow-fresh` was set; worker will start fresh.
168
- FreshStart,
169
- /// Resume refused. Caller MUST NOT proceed with teardown/spawn.
170
- Refuse { reason: ResumeRefusalReason },
171
- }
172
-
173
- /// Information about whether a provider backing file is present on disk.
174
- #[derive(Debug, Clone, PartialEq, Eq)]
175
- pub struct ProviderBackingCheck {
176
- pub paths: Vec<PathBuf>,
177
- pub exists: bool,
178
- }
179
-
180
- /// Per-decision detail emitted to events / JSON.
181
- #[derive(Debug, Clone, PartialEq, Eq)]
182
- pub struct ResumeDecisionDetail {
183
- pub agent_id: String,
184
- pub session_id: Option<String>,
185
- pub provider: String,
186
- pub backing: Option<ProviderBackingCheck>,
187
- pub outcome: ResumePreflightOutcome,
188
- }
189
-
190
- /// Pure resume preflight evaluator. No I/O — callers pass facts in.
191
- pub struct ResumePreflight;
192
-
193
- impl ResumePreflight {
194
- /// Decide a single worker's resume outcome from the facts the
195
- /// restart code already collected. Mirrors the existing
196
- /// `classify_restart_plan_with_resume_validation` decision tree:
197
- ///
198
- /// * session_id present + provider can resume + backing exists -> Resume
199
- /// * session_id present + (no resume OR no backing) + allow_fresh -> FreshStart
200
- /// * session_id present + (no resume OR no backing) + !allow_fresh -> Refuse
201
- /// * session_id absent + allow_fresh -> FreshStart
202
- /// * session_id absent + !allow_fresh -> Refuse(NoSessionId)
203
- pub fn check(
204
- session_id: Option<&str>,
205
- provider_can_resume: bool,
206
- backing: Option<&ProviderBackingCheck>,
207
- provider_name: &str,
208
- allow_fresh: bool,
209
- ) -> ResumePreflightOutcome {
210
- Self::check_with_hint(
211
- session_id,
212
- provider_can_resume,
213
- backing,
214
- provider_name,
215
- allow_fresh,
216
- None,
217
- )
218
- }
219
-
220
- /// Layer 2 self-healing variant: same decision tree as
221
- /// [`Self::check`], but propagates an optional `RecoveryHint` into
222
- /// the `SessionBackingStoreMissing` refusal so the CLI / event log
223
- /// can surface a "look for session named X under cwd Y" pointer to
224
- /// the operator. The hint is for HUMAN consumption only — no
225
- /// auto-resume happens off it (Layer 3 follow-up).
226
- pub fn check_with_hint(
227
- session_id: Option<&str>,
228
- provider_can_resume: bool,
229
- backing: Option<&ProviderBackingCheck>,
230
- provider_name: &str,
231
- allow_fresh: bool,
232
- recovery_hint: Option<RecoveryHint>,
233
- ) -> ResumePreflightOutcome {
234
- match session_id {
235
- Some(sid) if provider_can_resume => {
236
- let backing_present = backing.map(|b| b.exists).unwrap_or(true);
237
- if backing_present {
238
- ResumePreflightOutcome::Resume {
239
- session_id: sid.to_string(),
240
- }
241
- } else if allow_fresh {
242
- ResumePreflightOutcome::FreshStart
243
- } else {
244
- ResumePreflightOutcome::Refuse {
245
- reason: ResumeRefusalReason::SessionBackingStoreMissing {
246
- checked_paths: backing.map(|b| b.paths.clone()).unwrap_or_default(),
247
- recovery_hint,
248
- },
249
- }
250
- }
251
- }
252
- Some(_) if allow_fresh => ResumePreflightOutcome::FreshStart,
253
- Some(_) => ResumePreflightOutcome::Refuse {
254
- reason: ResumeRefusalReason::ProviderResumeUnsupported {
255
- provider: provider_name.to_string(),
256
- },
257
- },
258
- None if allow_fresh => ResumePreflightOutcome::FreshStart,
259
- None => ResumePreflightOutcome::Refuse {
260
- reason: ResumeRefusalReason::NoSessionId,
261
- },
262
- }
263
- }
264
- }
265
-
266
163
  #[cfg(test)]
267
164
  mod tests {
268
165
  use super::*;
@@ -287,58 +184,6 @@ mod tests {
287
184
  assert!(matches!(r, ResumeRefusalReason::Other { .. }));
288
185
  }
289
186
 
290
- #[test]
291
- fn preflight_resume_when_session_and_backing_present() {
292
- let backing = ProviderBackingCheck {
293
- paths: vec![PathBuf::from("/tmp/x.jsonl")],
294
- exists: true,
295
- };
296
- let out = ResumePreflight::check(Some("sess-1"), true, Some(&backing), "codex", false);
297
- assert!(matches!(out, ResumePreflightOutcome::Resume { .. }));
298
- }
299
-
300
- #[test]
301
- fn preflight_refuses_when_session_id_missing_without_allow_fresh() {
302
- let out = ResumePreflight::check(None, true, None, "codex", false);
303
- assert_eq!(
304
- out,
305
- ResumePreflightOutcome::Refuse {
306
- reason: ResumeRefusalReason::NoSessionId
307
- }
308
- );
309
- }
310
-
311
- #[test]
312
- fn preflight_distinguishes_backing_missing_from_no_session_id() {
313
- let backing = ProviderBackingCheck {
314
- paths: vec![PathBuf::from("/missing.jsonl")],
315
- exists: false,
316
- };
317
- let out = ResumePreflight::check(Some("sess-x"), true, Some(&backing), "codex", false);
318
- match out {
319
- ResumePreflightOutcome::Refuse { reason } => {
320
- assert_eq!(reason.wire(), "session_backing_store_missing");
321
- }
322
- other => panic!("expected backing-missing refusal; got {other:?}"),
323
- }
324
- }
325
-
326
- #[test]
327
- fn preflight_allow_fresh_converts_refusals_to_fresh() {
328
- let backing = ProviderBackingCheck {
329
- paths: vec![PathBuf::from("/missing.jsonl")],
330
- exists: false,
331
- };
332
- assert_eq!(
333
- ResumePreflight::check(None, true, None, "codex", true),
334
- ResumePreflightOutcome::FreshStart
335
- );
336
- assert_eq!(
337
- ResumePreflight::check(Some("sess-x"), true, Some(&backing), "codex", true),
338
- ResumePreflightOutcome::FreshStart
339
- );
340
- }
341
-
342
187
  // Layer 2 self-healing tests ────────────────────────────────────────────
343
188
 
344
189
  #[test]
@@ -364,56 +209,4 @@ mod tests {
364
209
  };
365
210
  assert_eq!(hint.picker_hint(), "codex session");
366
211
  }
367
-
368
- #[test]
369
- fn preflight_with_hint_attaches_to_backing_missing_refusal() {
370
- let backing = ProviderBackingCheck {
371
- paths: vec![PathBuf::from("/missing.jsonl")],
372
- exists: false,
373
- };
374
- let hint = RecoveryHint {
375
- provider_session_name_hint: Some("coder".to_string()),
376
- spawn_cwd: Some(PathBuf::from("/repo")),
377
- provider: "claude".to_string(),
378
- };
379
- let out = ResumePreflight::check_with_hint(
380
- Some("sess-1"),
381
- true,
382
- Some(&backing),
383
- "claude",
384
- false,
385
- Some(hint.clone()),
386
- );
387
- match out {
388
- ResumePreflightOutcome::Refuse {
389
- reason:
390
- ResumeRefusalReason::SessionBackingStoreMissing {
391
- recovery_hint: Some(h),
392
- ..
393
- },
394
- } => {
395
- assert_eq!(h, hint);
396
- }
397
- other => panic!("expected SessionBackingStoreMissing with hint; got {other:?}"),
398
- }
399
- }
400
-
401
- #[test]
402
- fn preflight_no_hint_legacy_behavior_unchanged() {
403
- // Default check() (no hint) still produces None recovery_hint —
404
- // wire-string-compatible with pre-Layer-2 callers.
405
- let backing = ProviderBackingCheck {
406
- paths: vec![PathBuf::from("/missing.jsonl")],
407
- exists: false,
408
- };
409
- let out = ResumePreflight::check(Some("sess-x"), true, Some(&backing), "codex", false);
410
- match out {
411
- ResumePreflightOutcome::Refuse {
412
- reason: ResumeRefusalReason::SessionBackingStoreMissing { recovery_hint, .. },
413
- } => {
414
- assert!(recovery_hint.is_none());
415
- }
416
- other => panic!("expected backing-missing refusal; got {other:?}"),
417
- }
418
- }
419
212
  }
@@ -1,3 +1,4 @@
1
+ //!
1
2
  use std::path::{Path, PathBuf};
2
3
 
3
4
  use crate::provider::helpers::find_session_id;
@@ -1,3 +1,4 @@
1
+ //!
1
2
  pub(super) fn parse_spawned_at(raw: &str) -> Option<std::time::SystemTime> {
2
3
  chrono::DateTime::parse_from_rfc3339(raw)
3
4
  .ok()
@@ -1,3 +1,4 @@
1
+ //!
1
2
  use std::path::{Path, PathBuf};
2
3
 
3
4
  use crate::provider::helpers::{find_session_id, parse_jsonl_records};
@@ -1,3 +1,4 @@
1
+ //!
1
2
  use std::path::Path;
2
3
 
3
4
  use crate::provider::types::{CaptureVia, CapturedSession, Confidence, RolloutPath, SessionId};
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Provider session-scan boundary.
2
3
  //!
3
4
  //! `ProviderAdapter` keeps the public polling facade in `adapter.rs`; this
@@ -14,27 +15,6 @@ pub(crate) mod codex;
14
15
  pub(crate) mod common;
15
16
  pub(crate) mod copilot;
16
17
 
17
- /// Marker label for which scan strategy a provider uses.
18
- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
19
- pub enum SessionScanStrategy {
20
- CodexJsonl,
21
- ClaudeTranscript,
22
- CopilotHome,
23
- NotRequired,
24
- }
25
-
26
- impl SessionScanStrategy {
27
- pub fn for_provider(provider: Provider) -> Self {
28
- match provider {
29
- Provider::Codex => Self::CodexJsonl,
30
- Provider::Claude | Provider::ClaudeCode => Self::ClaudeTranscript,
31
- Provider::Copilot => Self::CopilotHome,
32
- Provider::GeminiCli => Self::NotRequired,
33
- Provider::Fake => Self::NotRequired,
34
- }
35
- }
36
- }
37
-
38
18
  #[derive(Debug, Clone, PartialEq, Eq)]
39
19
  pub struct CaptureSessionContext {
40
20
  pub agent_id: String,
@@ -87,24 +67,3 @@ pub(crate) fn scan_session_candidates_once(
87
67
  }
88
68
 
89
69
  pub(crate) use claude::rollout_path_has_leader_marker as rollout_path_has_claude_leader_marker;
90
-
91
- #[cfg(test)]
92
- mod tests {
93
- use super::*;
94
-
95
- #[test]
96
- fn strategy_per_provider() {
97
- assert_eq!(
98
- SessionScanStrategy::for_provider(Provider::Codex),
99
- SessionScanStrategy::CodexJsonl
100
- );
101
- assert_eq!(
102
- SessionScanStrategy::for_provider(Provider::Claude),
103
- SessionScanStrategy::ClaudeTranscript
104
- );
105
- assert_eq!(
106
- SessionScanStrategy::for_provider(Provider::Fake),
107
- SessionScanStrategy::NotRequired
108
- );
109
- }
110
- }
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! codex startup-prompt recognizer — workspace-trust + update-skip screen detection.
2
3
  //!
3
4
  //! Golden (READ-ONLY truth `team-agent-public` v0.2.11): `provider_cli/codex.py`
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! provider 共享类型:enums / newtypes / ProviderCaps / ProviderError / 捕获+classify payload / 占位结构。
2
3
 
3
4
  use std::collections::{BTreeMap, BTreeSet};
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Provider wire-format helpers — the single source of truth for converting
2
3
  //! `Provider` ↔ string forms used across state JSON, CLI args, log fields,
3
4
  //! and the workers we shell out to.
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! identity:leader receiver identity 派生 / 迁移 / first-time binding(真相源 `state.py`)。
2
3
  //!
3
4
  //! Python 直接读 `os.environ`/`os.getcwd()`/`Path.resolve()`;此处把**环境变量**经
@@ -44,8 +45,9 @@ fn path_str(p: &Path) -> String {
44
45
  p.to_string_lossy().into_owned()
45
46
  }
46
47
 
48
+ ///
47
49
  /// `_identity_os_user`(`state.py:275`):`USER` or `USERNAME` or `""`。
48
- pub fn identity_os_user(env: &dyn IdentityEnv) -> String {
50
+ fn identity_os_user(env: &dyn IdentityEnv) -> String {
49
51
  let user = env_str(env, "USER");
50
52
  if !user.is_empty() {
51
53
  return user;
@@ -57,9 +59,10 @@ pub fn identity_os_user(env: &dyn IdentityEnv) -> String {
57
59
  String::new()
58
60
  }
59
61
 
62
+ ///
60
63
  /// `_identity_machine_fingerprint`(`state.py:279`):team_owner/leader_receiver 的非空
61
64
  /// machine_fingerprint 优先,否则 env `TEAM_AGENT_MACHINE_FINGERPRINT` or `""`。
62
- pub fn identity_machine_fingerprint(state: &Value, env: &dyn IdentityEnv) -> String {
65
+ fn identity_machine_fingerprint(state: &Value, env: &dyn IdentityEnv) -> String {
63
66
  for key in ["team_owner", "leader_receiver"] {
64
67
  if let Some(fp) = state
65
68
  .get(key)
@@ -74,9 +77,10 @@ pub fn identity_machine_fingerprint(state: &Value, env: &dyn IdentityEnv) -> Str
74
77
  env_str(env, "TEAM_AGENT_MACHINE_FINGERPRINT")
75
78
  }
76
79
 
80
+ ///
77
81
  /// `_identity_workspace_abspath`(`state.py:264`):按 workspace→team_dir→spec_path→fallback
78
82
  /// 顺序派生 workspace 绝对路径(各分支先 `resolve()` 再做 parent 导航)。
79
- pub fn identity_workspace_abspath(
83
+ fn identity_workspace_abspath(
80
84
  state: &Value,
81
85
  env: &dyn IdentityEnv,
82
86
  workspace: Option<&Path>,
@@ -157,9 +161,10 @@ fn leader_session_uuid_for_state(
157
161
  Ok(uuid.as_str().to_string())
158
162
  }
159
163
 
164
+ ///
160
165
  /// `_migrate_team_identity`(`state.py:295`):为缺 `leader_session_uuid` 的 team_owner /
161
166
  /// leader_receiver 填入派生 uuid。返回是否有改动。
162
- pub fn migrate_team_identity(
167
+ fn migrate_team_identity(
163
168
  state: &mut Value,
164
169
  env: &dyn IdentityEnv,
165
170
  workspace: Option<&Path>,
@@ -189,6 +194,7 @@ pub fn migrate_team_identity(
189
194
  Ok(changed)
190
195
  }
191
196
 
197
+ ///
192
198
  /// `_migrate_state_identity`(`state.py:306`):顶层(有 session_name 时)+ 每个 team 子状态迁移。
193
199
  pub fn migrate_state_identity(
194
200
  state: &mut Value,
@@ -220,6 +226,7 @@ pub fn migrate_state_identity(
220
226
  Ok(changed)
221
227
  }
222
228
 
229
+ ///
223
230
  /// `_caller_identity_from_env`(`state.py:316`):env override/env/derived → 5 字段 caller 身份。
224
231
  pub fn caller_identity_from_env(
225
232
  state: Option<&Value>,
@@ -282,9 +289,10 @@ pub fn caller_identity_from_env(
282
289
  })
283
290
  }
284
291
 
292
+ ///
285
293
  /// `populate_team_owner_from_env`(`state.py:414`):已有 team_owner → 仅补迁移 uuid 后返回;
286
294
  /// 否则从 env caller 身份 seed team_owner(无 pane_id → `None`)。`now_iso` = claimed_at。
287
- pub fn populate_team_owner_from_env(
295
+ fn populate_team_owner_from_env(
288
296
  state: &mut Value,
289
297
  source: &str,
290
298
  env: &dyn IdentityEnv,
@@ -320,6 +328,7 @@ pub fn populate_team_owner_from_env(
320
328
  Ok(Some(owner))
321
329
  }
322
330
 
331
+ ///
323
332
  /// `apply_first_time_leader_binding`(`state.py:434`):命令 + workspace realpath 双门后,
324
333
  /// 写入 team_owner / leader_receiver(owner_epoch=0)。拒绝 dict 字节对齐 Python(含 `pane` +
325
334
  /// `repr()` 错误串)。`command_looks_usable`(`_leader_command_looks_usable`,step 11)经闭包注入。
@@ -411,6 +420,7 @@ pub fn apply_first_time_leader_binding(
411
420
  json!({ "ok": true, "pane": pane_info, "warning": null, "first_time": true })
412
421
  }
413
422
 
423
+ ///
414
424
  /// `leader_env_exports`(`state.py:469`):receiver + identity → 6 个 leader env 导出(插入序)。
415
425
  pub fn leader_env_exports(receiver: &Value, identity: &Value) -> Vec<(String, String)> {
416
426
  vec![
@@ -441,6 +451,7 @@ pub fn leader_env_exports(receiver: &Value, identity: &Value) -> Vec<(String, St
441
451
  ]
442
452
  }
443
453
 
454
+ ///
444
455
  /// `validate_leader_uuid_from_targets`(`state.py:480`):fake provider 直过;否则核对 targets
445
456
  /// 扫描成功 + receiver.pane_id 在 targets 中存在。
446
457
  pub fn validate_leader_uuid_from_targets(receiver: &Value, targets: &Value) -> Value {
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Stage 0 of the identity-boundary unified plan (architect direction
2
3
  //! 2026-06-23): `SessionAttributionKey`.
3
4
  //!
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! step 5 · state — state.json 持久化 / identity / owner-gate / projection(真相源 `state.py`)。
2
3
  //!
3
4
  //! §6 step 5:原子写/锁/self-heal(**bug-084** 血泪)/ team projection / leader receiver identity /
@@ -32,6 +33,7 @@ pub mod selector;
32
33
  use serde_json::Value;
33
34
  use thiserror::Error;
34
35
 
36
+ ///
35
37
  /// Python 真值语义(`null`/`false`/`0`/`""`/`[]`/`{}` → false),`state` 模块共用。
36
38
  pub(crate) fn json_truthy(v: &Value) -> bool {
37
39
  match v {
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! owner-gate:trust own-vs-foreign(§11 / bug-064 / bug-082 血泪;真相源 `state.py`)。
2
3
  //!
3
4
  //! 三核心纯判定(集成 send_message/MCP 是 step 11/14):
@@ -37,6 +38,7 @@ pub struct CallerIdentity {
37
38
  pub leader_session_uuid_source: String,
38
39
  }
39
40
 
41
+ ///
40
42
  /// `check_team_owner`(`state.py:366`)的纯判定版:caller 身份 + 是否有 TEAM_AGENT_ID + liveness 注入。
41
43
  /// 返回 `None`=允许(own / 无 owner / 死 owner pane 可接管);`Some(dict)`=拒绝(team_owner_mismatch)。
42
44
  ///
@@ -123,6 +125,7 @@ fn caller_to_value(c: &CallerIdentity) -> Value {
123
125
  })
124
126
  }
125
127
 
128
+ ///
126
129
  /// `worker_sender_bypasses_owner_gate`(`state.py:400`):worker peer-send 绕过 owner 门。
127
130
  /// 返回 `Some(agent_id)`=绕过;`None`=不绕过(走 owner 门)。
128
131
  pub fn worker_sender_bypasses_owner_gate(
@@ -160,6 +163,7 @@ pub fn worker_sender_bypasses_owner_gate(
160
163
  Some(sender.to_string())
161
164
  }
162
165
 
166
+ ///
163
167
  /// §11 realpath own-vs-foreign(`state.py:449`):**两边 canonicalize** 后全等才判 own。
164
168
  /// macOS `/tmp → /private/tmp` 软链不对称由「两边 canonicalize」消除。canonicalize 失败(路径不存在)
165
169
  /// → 退化为词法绝对比较(此时无软链可解,等价)。**禁 basename/startswith/子串/反推**。
@@ -187,6 +191,7 @@ fn lexical_abs(p: &Path) -> std::path::PathBuf {
187
191
  }
188
192
  }
189
193
 
194
+ ///
190
195
  /// `os.path.realpath` 等价(对抗 P0-B):全路径存在 → `canonicalize`;否则对**最长存在前缀**
191
196
  /// canonicalize(解析其软链)再拼回缺失末段(规范化 `..`/`.`)。这复刻 Python「解析存在部分的
192
197
  /// 软链 + 保留不存在末段」,修掉「父目录是软链 + 末段不存在 → 漏判 own」的 §11 血泪。
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Stage 2 of identity-boundary unified plan (architect direction 2026-06-23):
2
3
  //! `state::ownership` — single read entry point for `team_owner` lookups.
3
4
  //!
@@ -41,7 +42,7 @@ use crate::state::projection::{read_owner as projection_read_owner, team_state_k
41
42
  /// owner value. CLI status / diagnose use it to surface legacy duplicate
42
43
  /// warnings.
43
44
  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
44
- pub enum OwnershipSource {
45
+ enum OwnershipSource {
45
46
  /// Stage 5 canonical path: `.team/runtime/<team_key>/state.json` (not
46
47
  /// yet emitted — placeholder for forward compatibility).
47
48
  CanonicalPerTeamState,
@@ -57,11 +58,12 @@ pub enum OwnershipSource {
57
58
  /// caller consumes (same shape as `state.get("team_owner")` returned today);
58
59
  /// the `source` is diagnostic.
59
60
  #[derive(Debug, Clone)]
60
- pub struct OwnershipRead<'a> {
61
+ struct OwnershipRead<'a> {
61
62
  pub value: &'a Value,
62
63
  pub source: OwnershipSource,
63
64
  }
64
65
 
66
+ ///
65
67
  /// Stage 2 entry point: read the team owner for the given `team_key` from an
66
68
  /// in-memory state value, honouring the legacy precedence. Returns `None` if
67
69
  /// no source carries a non-empty, valid owner record.
@@ -73,7 +75,7 @@ pub struct OwnershipRead<'a> {
73
75
  /// This deliberately reuses `projection::read_owner` so the pane-id validity
74
76
  /// check (`%N` or all-digits) stays in one place. The repository's value-add
75
77
  /// is the precedence ordering and the `OwnershipSource` tag.
76
- pub fn read_owner_for_team<'a>(state: &'a Value, team_key: &str) -> Option<OwnershipRead<'a>> {
78
+ fn read_owner_for_team<'a>(state: &'a Value, team_key: &str) -> Option<OwnershipRead<'a>> {
77
79
  // Step 1 (Stage 5): canonical per-team state. Stage 2 does not consult
78
80
  // a separate file yet — owner truth still lives in the in-memory state.
79
81
  // Once Stage 5 wires `.team/runtime/<team_key>/state.json` as canonical,
@@ -109,6 +111,7 @@ pub fn read_owner_for_team<'a>(state: &'a Value, team_key: &str) -> Option<Owner
109
111
  None
110
112
  }
111
113
 
114
+ ///
112
115
  /// Convenience: just the JSON value, no diagnostic source. Returns `None`
113
116
  /// when no owner is found. Stable across Stage 5 — only the lookup
114
117
  /// implementation will move.
@@ -116,6 +119,7 @@ pub fn read_owner_value<'a>(state: &'a Value, team_key: &str) -> Option<&'a Valu
116
119
  read_owner_for_team(state, team_key).map(|read| read.value)
117
120
  }
118
121
 
122
+ ///
119
123
  /// Stage 3 (identity-boundary unified plan, architect direction 2026-06-23):
120
124
  /// single write entry point for owner mutations. Pre-Stage-3, owner writes
121
125
  /// were spread across 13 sites (claim/attach/readopt/managed-leader/quick-
@@ -187,6 +191,7 @@ pub fn write_owner(state: &mut Value, team_key: &str, record: OwnershipWrite) {
187
191
  }
188
192
  }
189
193
 
194
+ ///
190
195
  /// Stage 3 top-level cleanup (architect direction 2026-06-24,
191
196
  /// .team/artifacts/stage3-toplevel-cleanup-fix.md): strip the legacy
192
197
  /// top-level `team_owner / leader_receiver / owner_epoch` fields from a
@@ -202,12 +207,13 @@ pub fn write_owner(state: &mut Value, team_key: &str, record: OwnershipWrite) {
202
207
  /// load-time path — legacy single-team states may still have only
203
208
  /// top-level owner and no canonical `teams.<key>` owner, and a blind load
204
209
  /// strip would lose ownership before migration.
205
- pub fn strip_top_level_ownership(root: &mut serde_json::Map<String, Value>) {
210
+ fn strip_top_level_ownership(root: &mut serde_json::Map<String, Value>) {
206
211
  for key in ["team_owner", "leader_receiver", "owner_epoch"] {
207
212
  root.remove(key);
208
213
  }
209
214
  }
210
215
 
216
+ ///
211
217
  /// Stage 3 save-output canonical-aware strip (architect direction
212
218
  /// 2026-06-24, .team/artifacts/stage3-save-strip-fix.md): conditional
213
219
  /// version of `strip_top_level_ownership` used by `state::persist`'s
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! Stage 0 of the identity-boundary unified plan (architect direction
2
3
  //! 2026-06-23): `TeamScope` + `TeamRuntimePaths` foundation.
3
4
  //!
@@ -42,6 +43,7 @@ pub struct TeamScope {
42
43
  }
43
44
 
44
45
  impl TeamScope {
46
+ ///
45
47
  /// Construct a TeamScope from an already-resolved workspace + team_key.
46
48
  /// Callers that have a display name must resolve it through the existing
47
49
  /// `state::selector` machinery first; this constructor refuses an empty
@@ -66,6 +68,7 @@ impl TeamScope {
66
68
  &self.team_key
67
69
  }
68
70
 
71
+ ///
69
72
  /// Convenience: derive the path helper from this scope.
70
73
  pub fn paths(&self) -> TeamRuntimePaths {
71
74
  TeamRuntimePaths::for_scope(self)
@@ -110,6 +113,7 @@ impl TeamRuntimePaths {
110
113
  &self.team_key
111
114
  }
112
115
 
116
+ ///
113
117
  /// `.team/runtime/teams/<team_key>/` — the team's future B3 runtime
114
118
  /// directory. It is not used as product authority until the B3 migration;
115
119
  /// current callers must keep using `runtime_state_path`.
@@ -119,6 +123,7 @@ impl TeamRuntimePaths {
119
123
  .join(&self.team_key)
120
124
  }
121
125
 
126
+ ///
122
127
  /// Transitional runtime spec path. Mirrors the existing
123
128
  /// `runtime_spec_path` helper while specs remain at
124
129
  /// `.team/runtime/<team_key>/team.spec.yaml`.
@@ -126,6 +131,7 @@ impl TeamRuntimePaths {
126
131
  runtime_spec_path(&self.workspace, &self.team_key)
127
132
  }
128
133
 
134
+ ///
129
135
  /// `.team/runtime/teams/<team_key>/state.json` — the canonical per-team
130
136
  /// state path that B3 will start writing. Not used by current product
131
137
  /// code; callers must continue using `runtime_state_path` until B3
@@ -134,11 +140,13 @@ impl TeamRuntimePaths {
134
140
  self.team_dir().join("state.json")
135
141
  }
136
142
 
143
+ ///
137
144
  /// `.team/runtime/teams/<team_key>/coordinator.pid` — future sidecar location.
138
145
  pub fn coordinator_pid_path(&self) -> PathBuf {
139
146
  self.team_dir().join("coordinator.pid")
140
147
  }
141
148
 
149
+ ///
142
150
  /// `.team/runtime/teams/<team_key>/coordinator.log` — future sidecar location.
143
151
  pub fn coordinator_log_path(&self) -> PathBuf {
144
152
  self.team_dir().join("coordinator.log")
@@ -180,6 +188,7 @@ pub enum CommandScope {
180
188
  }
181
189
 
182
190
  impl CommandScope {
191
+ ///
183
192
  /// Resolve the CLI's `--team` argument against the workspace state.
184
193
  /// On any I/O error the empty case is returned — destructive commands
185
194
  /// will run their own selector and surface the real error.
@@ -202,6 +211,7 @@ impl CommandScope {
202
211
  }
203
212
  }
204
213
 
214
+ ///
205
215
  /// Convert to an `Option<String>` for backward compatibility with
206
216
  /// existing `args.team.as_deref()` call sites.
207
217
  pub fn team_key(&self) -> Option<&str> {
@@ -211,11 +221,13 @@ impl CommandScope {
211
221
  }
212
222
  }
213
223
 
224
+ ///
214
225
  /// True iff there are 2+ alive teams and no explicit `--team`.
215
226
  pub fn is_ambiguous(&self) -> bool {
216
227
  matches!(self, Self::Ambiguous(_))
217
228
  }
218
229
 
230
+ ///
219
231
  /// The candidate list when ambiguous; empty otherwise.
220
232
  pub fn candidates(&self) -> &[String] {
221
233
  match self {