@team-agent/installer 0.5.65 → 0.5.68

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 (208) hide show
  1. package/Cargo.lock +8 -1
  2. package/Cargo.toml +1 -1
  3. package/crates/team-agent/Cargo.toml +6 -0
  4. package/crates/team-agent/src/cli/adapters.rs +6 -1
  5. package/crates/team-agent/src/cli/diagnose.rs +82 -0
  6. package/crates/team-agent/src/cli/emit.rs +3 -3
  7. package/crates/team-agent/src/cli/grok_slot.rs +299 -0
  8. package/crates/team-agent/src/cli/leader.rs +21 -7
  9. package/crates/team-agent/src/cli/leaders.rs +125 -1
  10. package/crates/team-agent/src/cli/mod.rs +20 -0
  11. package/crates/team-agent/src/cli/send/presentation.rs +7 -1
  12. package/crates/team-agent/src/cli/spec.rs +2 -0
  13. package/crates/team-agent/src/cli/status_port/compact.rs +28 -0
  14. package/crates/team-agent/src/cli/status_port/snapshot.rs +25 -1
  15. package/crates/team-agent/src/cli/tests/base.rs +26 -3
  16. package/crates/team-agent/src/cli/tests/compile.rs +1 -1
  17. package/crates/team-agent/src/cli/tests/missing_subcommands.rs +129 -19
  18. package/crates/team-agent/src/cli/tests/mod.rs +2 -2
  19. package/crates/team-agent/src/cli/tests/run_delegation.rs +1 -1
  20. package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +387 -6
  21. package/crates/team-agent/src/cli/tests/status_send.rs +79 -10
  22. package/crates/team-agent/src/cli/tests/verb_validate.rs +1 -1
  23. package/crates/team-agent/src/communication_mode/mod.rs +6 -4
  24. package/crates/team-agent/src/compiler/tests.rs +23 -20
  25. package/crates/team-agent/src/compiler.rs +84 -5
  26. package/crates/team-agent/src/conpty/backend.rs +16 -0
  27. package/crates/team-agent/src/coordinator/backoff.rs +55 -0
  28. package/crates/team-agent/src/coordinator/conpty_shim.rs +82 -0
  29. package/crates/team-agent/src/coordinator/health.rs +173 -0
  30. package/crates/team-agent/src/coordinator/mod.rs +31 -0
  31. package/crates/team-agent/src/coordinator/orphan.rs +31 -0
  32. package/crates/team-agent/src/coordinator/runtime_detectors.rs +30 -0
  33. package/crates/team-agent/src/coordinator/runtime_observation.rs +25 -0
  34. package/crates/team-agent/src/coordinator/steps/abnormal.rs +59 -0
  35. package/crates/team-agent/src/coordinator/steps/delivery.rs +10 -0
  36. package/crates/team-agent/src/coordinator/steps/health_sync.rs +10 -0
  37. package/crates/team-agent/src/coordinator/steps/mod.rs +22 -0
  38. package/crates/team-agent/src/coordinator/steps/persist.rs +10 -0
  39. package/crates/team-agent/src/coordinator/steps/runtime_prompts.rs +10 -0
  40. package/crates/team-agent/src/coordinator/steps/session_gate.rs +10 -0
  41. package/crates/team-agent/src/coordinator/tick.rs +133 -22
  42. package/crates/team-agent/src/coordinator/types.rs +49 -0
  43. package/crates/team-agent/src/db/message_store.rs +39 -5
  44. package/crates/team-agent/src/layout/worker_env.rs +20 -3
  45. package/crates/team-agent/src/layout/worker_window_helpers.rs +2 -0
  46. package/crates/team-agent/src/leader/provider_attribution.rs +53 -0
  47. package/crates/team-agent/src/leader/registry.rs +65 -0
  48. package/crates/team-agent/src/leader/start.rs +1080 -58
  49. package/crates/team-agent/src/leader/tests/team_in_team_state_scope_red.rs +1 -1
  50. package/crates/team-agent/src/lifecycle/display.rs +56 -0
  51. package/crates/team-agent/src/lifecycle/helpers.rs +57 -0
  52. package/crates/team-agent/src/lifecycle/launch/add_agent.rs +332 -14
  53. package/crates/team-agent/src/lifecycle/launch/add_agent_state.rs +69 -2
  54. package/crates/team-agent/src/lifecycle/launch/agent_state.rs +196 -2
  55. package/crates/team-agent/src/lifecycle/launch/clone_agent.rs +101 -11
  56. package/crates/team-agent/src/lifecycle/launch/cursor_create_chat.rs +229 -0
  57. package/crates/team-agent/src/lifecycle/launch/cursor_mcp.rs +332 -0
  58. package/crates/team-agent/src/lifecycle/launch/fork_agent.rs +204 -457
  59. package/crates/team-agent/src/lifecycle/launch/fork_entry.rs +24 -0
  60. package/crates/team-agent/src/lifecycle/launch/grok_per_seat.rs +260 -0
  61. package/crates/team-agent/src/lifecycle/launch/identity.rs +146 -0
  62. package/crates/team-agent/src/lifecycle/launch/layout.rs +60 -0
  63. package/crates/team-agent/src/lifecycle/launch/leader_context.rs +112 -0
  64. package/crates/team-agent/src/lifecycle/launch/mcp_config.rs +530 -0
  65. package/crates/team-agent/src/lifecycle/launch/ownership.rs +40 -0
  66. package/crates/team-agent/src/lifecycle/launch/plan.rs +31 -0
  67. package/crates/team-agent/src/lifecycle/launch/quick_start.rs +66 -0
  68. package/crates/team-agent/src/lifecycle/launch/quick_start_transport.rs +78 -0
  69. package/crates/team-agent/src/lifecycle/launch/readiness.rs +85 -38
  70. package/crates/team-agent/src/lifecycle/launch/role_source.rs +44 -44
  71. package/crates/team-agent/src/lifecycle/launch/spawn.rs +101 -4
  72. package/crates/team-agent/src/lifecycle/launch/spec_state.rs +244 -48
  73. package/crates/team-agent/src/lifecycle/launch/state_projection.rs +109 -2
  74. package/crates/team-agent/src/lifecycle/launch/worker_env.rs +214 -1
  75. package/crates/team-agent/src/lifecycle/launch.rs +209 -43
  76. package/crates/team-agent/src/lifecycle/lock.rs +42 -1
  77. package/crates/team-agent/src/lifecycle/mod.rs +11 -0
  78. package/crates/team-agent/src/lifecycle/pane_input_lock.rs +161 -0
  79. package/crates/team-agent/src/lifecycle/profile_launch.rs +98 -0
  80. package/crates/team-agent/src/lifecycle/profile_smoke.rs +51 -1
  81. package/crates/team-agent/src/lifecycle/restart/agent.rs +213 -3
  82. package/crates/team-agent/src/lifecycle/restart/common.rs +373 -18
  83. package/crates/team-agent/src/lifecycle/restart/orchestrator.rs +27 -0
  84. package/crates/team-agent/src/lifecycle/restart/preflight.rs +25 -0
  85. package/crates/team-agent/src/lifecycle/restart/rebuild.rs +165 -15
  86. package/crates/team-agent/src/lifecycle/restart/remove.rs +196 -5
  87. package/crates/team-agent/src/lifecycle/restart/selection.rs +72 -0
  88. package/crates/team-agent/src/lifecycle/restart/team_state.rs +22 -0
  89. package/crates/team-agent/src/lifecycle/restart.rs +29 -0
  90. package/crates/team-agent/src/lifecycle/tests/acceptance_b_batch_red.rs +1 -1
  91. package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +3 -4
  92. package/crates/team-agent/src/lifecycle/tests/behavioral_diff_264_red.rs +1 -1
  93. package/crates/team-agent/src/lifecycle/tests/claude_compatible_config_red.rs +2 -2
  94. package/crates/team-agent/src/lifecycle/tests/claude_profile_launch_red.rs +4 -4
  95. package/crates/team-agent/src/lifecycle/tests/clone_agent_preserves_source_tools.rs +309 -0
  96. package/crates/team-agent/src/lifecycle/tests/clone_fork_copilot_perms_red.rs +159 -174
  97. package/crates/team-agent/src/lifecycle/tests/communication_mode_runtime_contract_red.rs +2 -2
  98. package/crates/team-agent/src/lifecycle/tests/copilot_provider_red.rs +15 -13
  99. package/crates/team-agent/src/lifecycle/tests/core.rs +4 -18
  100. package/crates/team-agent/src/lifecycle/tests/core_034_real_red.rs +1 -1
  101. package/crates/team-agent/src/lifecycle/tests/cursor_mcp_overlay.rs +287 -0
  102. package/crates/team-agent/src/lifecycle/tests/cursor_require_explicit_model_red.rs +229 -0
  103. package/crates/team-agent/src/lifecycle/tests/cursor_restart_resume_red.rs +353 -0
  104. package/crates/team-agent/src/lifecycle/tests/display_adaptive_red.rs +1 -1
  105. package/crates/team-agent/src/lifecycle/tests/f032_startup_prompt_best_effort_red.rs +1 -1
  106. package/crates/team-agent/src/lifecycle/tests/g1_silent_faces.rs +784 -0
  107. package/crates/team-agent/src/lifecycle/tests/gate_fixtures.rs +562 -0
  108. package/crates/team-agent/src/lifecycle/tests/grok_effort_argv_red.rs +239 -0
  109. package/crates/team-agent/src/lifecycle/tests/grok_mcp_overlay_red.rs +498 -0
  110. package/crates/team-agent/src/lifecycle/tests/grok_require_explicit_model_red.rs +250 -0
  111. package/crates/team-agent/src/lifecycle/tests/grok_restart_resume_red.rs +293 -0
  112. package/crates/team-agent/src/lifecycle/tests/harvest2_a_batch_red.rs +3 -0
  113. package/crates/team-agent/src/lifecycle/tests/host_cotenant_death_p0_contract.rs +3 -3
  114. package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +65 -40
  115. package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +20 -32
  116. package/crates/team-agent/src/lifecycle/tests/lifecycle_rollback_red.rs +17 -9
  117. package/crates/team-agent/src/lifecycle/tests/mcp_tool_name_format_red.rs +69 -0
  118. package/crates/team-agent/src/lifecycle/tests/phase_b_contracts.rs +24 -23
  119. package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +98 -62
  120. package/crates/team-agent/src/lifecycle/tests/quick_start_worker_readiness_red.rs +2 -2
  121. package/crates/team-agent/src/lifecycle/tests/restart_build_before_destroy_0540_contract.rs +1 -1
  122. package/crates/team-agent/src/lifecycle/tests/restart_liveness_red.rs +1 -1
  123. package/crates/team-agent/src/lifecycle/tests/restart_rebind_hotfix_252_red.rs +3 -1
  124. package/crates/team-agent/src/lifecycle/tests/restart_session_capture_red.rs +2 -2
  125. package/crates/team-agent/src/lifecycle/tests/resume_recover_red.rs +1 -1
  126. package/crates/team-agent/src/lifecycle/tests/stale_team_saveconflict_contract.rs +1 -1
  127. package/crates/team-agent/src/lifecycle/tests/startup_latency_contract.rs +41 -8
  128. package/crates/team-agent/src/lifecycle/tests/status_credential_redaction_contract.rs +3 -3
  129. package/crates/team-agent/src/lifecycle/tests/subprep_codex_trust_roundtrip_red.rs +1 -1
  130. package/crates/team-agent/src/lifecycle/tests/swallow_batch4_semantics_red.rs +1 -1
  131. package/crates/team-agent/src/lifecycle/tests/team_in_team_identity_scope_red.rs +1 -1
  132. package/crates/team-agent/src/lifecycle/tests/team_in_team_sibling_quick_start_red.rs +1 -1
  133. package/crates/team-agent/src/lifecycle/tests/team_in_team_state_scope_red.rs +1 -1
  134. package/crates/team-agent/src/lifecycle/tests/team_key_retirement_txn_red.rs +1 -1
  135. package/crates/team-agent/src/lifecycle/tests/test_isolation_escape_contract.rs +60 -2
  136. package/crates/team-agent/src/lifecycle/tests/upgrade_compat_0211_red.rs +1 -1
  137. package/crates/team-agent/src/lifecycle/tests/verify_rs031_window_consistency_red.rs +2 -2
  138. package/crates/team-agent/src/lifecycle/tests/worker_spawn_env_red.rs +69 -26
  139. package/crates/team-agent/src/lifecycle/tests.rs +23 -15
  140. package/crates/team-agent/src/lifecycle/types.rs +61 -2
  141. package/crates/team-agent/src/lifecycle/worker_command_context.rs +200 -33
  142. package/crates/team-agent/src/mcp_server/tests/scoped.rs +100 -1
  143. package/crates/team-agent/src/mcp_server/tests.rs +196 -2
  144. package/crates/team-agent/src/messaging/delivery.rs +405 -40
  145. package/crates/team-agent/src/messaging/helpers.rs +2 -0
  146. package/crates/team-agent/src/messaging/leader_receiver.rs +53 -1
  147. package/crates/team-agent/src/messaging/results.rs +4 -0
  148. package/crates/team-agent/src/messaging/send.rs +34 -0
  149. package/crates/team-agent/src/messaging/tests/dup_inject.rs +406 -0
  150. package/crates/team-agent/src/messaging/tests/e23.rs +9 -0
  151. package/crates/team-agent/src/messaging/tests/leader_inject_acceptance.rs +66 -0
  152. package/crates/team-agent/src/messaging/tests/main_preserved.rs +1 -1
  153. package/crates/team-agent/src/messaging/tests/mod.rs +1 -0
  154. package/crates/team-agent/src/messaging/types.rs +4 -1
  155. package/crates/team-agent/src/model/enums.rs +14 -5
  156. package/crates/team-agent/src/model/permissions.rs +3 -0
  157. package/crates/team-agent/src/model/spec.rs +129 -6
  158. package/crates/team-agent/src/model/testdata/spec_invalid_a.yaml +3 -1
  159. package/crates/team-agent/src/model/testdata/team.spec.golden.yaml +3 -1
  160. package/crates/team-agent/src/model/testdata/team.spec.yaml +3 -1
  161. package/crates/team-agent/src/os_probe.rs +73 -2
  162. package/crates/team-agent/src/provider/adapter.rs +231 -4
  163. package/crates/team-agent/src/provider/adapters/claude.rs +5 -2
  164. package/crates/team-agent/src/provider/adapters/codex.rs +5 -2
  165. package/crates/team-agent/src/provider/adapters/copilot.rs +5 -2
  166. package/crates/team-agent/src/provider/adapters/cursor_agent.rs +86 -0
  167. package/crates/team-agent/src/provider/adapters/grok.rs +157 -0
  168. package/crates/team-agent/src/provider/adapters/mod.rs +2 -0
  169. package/crates/team-agent/src/provider/bypass_flags.rs +124 -0
  170. package/crates/team-agent/src/provider/classify.rs +4 -2
  171. package/crates/team-agent/src/provider/faults.rs +2 -1
  172. package/crates/team-agent/src/provider/mod.rs +13 -0
  173. package/crates/team-agent/src/provider/session/capture.rs +158 -20
  174. package/crates/team-agent/src/provider/session/context_fork/claude.rs +38 -1
  175. package/crates/team-agent/src/provider/session/context_fork/codex.rs +72 -1
  176. package/crates/team-agent/src/provider/session/context_fork/outcome.rs +57 -1
  177. package/crates/team-agent/src/provider/session/context_fork.rs +77 -3
  178. package/crates/team-agent/src/provider/session/mod.rs +18 -0
  179. package/crates/team-agent/src/provider/session/resume.rs +57 -0
  180. package/crates/team-agent/src/provider/session_scan/claude.rs +125 -1
  181. package/crates/team-agent/src/provider/session_scan/codex.rs +94 -1
  182. package/crates/team-agent/src/provider/session_scan/common.rs +204 -2
  183. package/crates/team-agent/src/provider/session_scan/copilot.rs +33 -1
  184. package/crates/team-agent/src/provider/session_scan/cursor.rs +538 -0
  185. package/crates/team-agent/src/provider/session_scan/grok.rs +288 -0
  186. package/crates/team-agent/src/provider/session_scan.rs +8 -0
  187. package/crates/team-agent/src/provider/submit_now.rs +94 -0
  188. package/crates/team-agent/src/provider/tests/adapter.rs +304 -0
  189. package/crates/team-agent/src/provider/types.rs +4 -2
  190. package/crates/team-agent/src/provider/wire.rs +23 -1
  191. package/crates/team-agent/src/state/persist.rs +301 -8
  192. package/crates/team-agent/src/state/repository.rs +5 -0
  193. package/crates/team-agent/src/tmux_backend/tests.rs +1737 -42
  194. package/crates/team-agent/src/tmux_backend.rs +1083 -75
  195. package/crates/team-agent/src/transport/test_support.rs +20 -0
  196. package/crates/team-agent/src/transport/tests/wire.rs +28 -2
  197. package/crates/team-agent/src/transport.rs +265 -1
  198. package/npm/install.mjs +129 -73
  199. package/package.json +4 -4
  200. package/skills/team-agent/SKILL.md +33 -238
  201. package/skills/team-agent/command-coverage.json +31 -0
  202. package/crates/team-agent/src/lifecycle/launch/approval.rs +0 -134
  203. package/crates/team-agent/src/lifecycle/launch/fork_agent/completion.rs +0 -59
  204. package/crates/team-agent/src/lifecycle/launch/fork_finalize.rs +0 -483
  205. package/crates/team-agent/src/lifecycle/launch/fork_pending.rs +0 -109
  206. package/crates/team-agent/src/lifecycle/launch/fork_state.rs +0 -447
  207. package/crates/team-agent/src/lifecycle/tests/codex_mcp_approval_inheritance_red.rs +0 -1187
  208. package/crates/team-agent/src/lifecycle/tests/worker_dangerous_bypass_argv_red.rs +0 -327
@@ -1,3 +1,43 @@
1
+ //! ---
2
+ //! purpose: coordinator daemon 的健康判定、幂等启停与只读观测面——pid/metadata/schema 三合一健康、spawn 与终止、runtime 路径、以及 team-agent watch 的事件渲染
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: coordinator_health
6
+ //! what: 由 pid 文件、coordinator.json 与 message store schema 合成 HealthReport,ok 与 service_available 分开表达
7
+ //! - name: start_coordinator
8
+ //! what: 幂等启动:已健康则 no-op,metadata 不兼容先停再起,schema 不兼容拒启并给修复 hint
9
+ //! - name: start_coordinator_with_team
10
+ //! what: 同上,并把 team_key 以 --team 传给子进程,免得 daemon 自己从 state 推
11
+ //! - name: stop_coordinator
12
+ //! what: 终止 daemon 并清 pid/meta;pid 文件缺失时用 ps 扫描发现流浪 coordinator
13
+ //! - name: collect_watch_lines
14
+ //! what: 从 events.jsonl 与结果表增量取出可渲染行,并推进 WatchCursor
15
+ //! - name: render_event_line
16
+ //! what: 把一条结构化事件渲染成人类可读行,不认识的事件返回 None
17
+ //! - name: run_watch
18
+ //! what: team-agent watch 主循环:反复 collect 后输出并 sleep
19
+ //! - name: coordinator_pid_path
20
+ //! what: coordinator.pid 的位置
21
+ //! - name: coordinator_meta_path
22
+ //! what: coordinator.json 的位置
23
+ //! - name: coordinator_log_path
24
+ //! what: coordinator.log 的位置
25
+ //! depends:
26
+ //! - super::types
27
+ //! - crate::message_store
28
+ //! - crate::db::schema
29
+ //! - crate::event_log
30
+ //! - crate::model::paths
31
+ //! - crate::packaging
32
+ //! - crate::platform::process
33
+ //! - crate::os_probe
34
+ //! boundary:
35
+ //! - 不做 tick 编排,也不投递任何消息
36
+ //! - 不读 provider 凭据、不碰 .env;身份只取自当前可执行文件与已落盘 metadata
37
+ //! - 终止进程限定本 workspace:优先按本次判定拿到的精确 pid;pid 文件缺失时的流浪回收会按 ps 命令行匹配「coordinator --workspace <本 ws>」发现目标,仍不做跨 workspace 的 pkill/killall 泛清
38
+ //! - watch 侧只读:不重放已归档段,rotation 只插一条 marker 并重置 offset
39
+ //! maturity: wired
40
+ //! ---
1
41
  //!
2
42
  //! coordinator 健康/身份 & 只读可观测面:metadata 身份原语 + coordinator 路径 + watch 实时流。
3
43
 
@@ -27,6 +67,12 @@ use super::types::{
27
67
  // ===========================================================================
28
68
 
29
69
  /// `coordinator_health`(`lifecycle.py:38-46`):`running ∧ metadata_ok ∧ schema_ok` → typed report.
70
+ /// ---
71
+ /// purpose: 一次性判定本 workspace 的 coordinator daemon 是否健康
72
+ /// params:
73
+ /// workspace: workspace 根;pid/metadata 路径与 message store 都由它派生
74
+ /// returns: HealthReport。ok = 进程在跑 ∧ metadata 三元全等 ∧ 二进制身份一致 ∧ schema 兼容;service_available 刻意排除二进制身份,表示「这个 daemon 还能处理本队队列」;status 区分 Missing / InvalidPid / Running / Stale
75
+ /// ---
30
76
  pub fn coordinator_health(workspace: &WorkspacePath) -> HealthReport {
31
77
  let schema = message_store_schema_health(workspace);
32
78
  let current_binary_identity = current_coordinator_binary_identity();
@@ -73,6 +119,13 @@ pub fn coordinator_health(workspace: &WorkspacePath) -> HealthReport {
73
119
 
74
120
  /// `start_coordinator`(`lifecycle.py:49-121`):幂等 — 已健康 no-op(AlreadyRunning);metadata 不兼容
75
121
  /// 先 stop 再起;schema 不兼容拒启 + hint;否则 spawn `team-agent coordinator --workspace <ws>`。
122
+ /// ---
123
+ /// purpose: 不带 team_key 的幂等启动入口
124
+ /// params:
125
+ /// workspace: workspace 根
126
+ /// returns: 与 start_coordinator_with_team(workspace, None) 完全一致
127
+ /// errors: 同 start_coordinator_with_team
128
+ /// ---
76
129
  pub fn start_coordinator(workspace: &WorkspacePath) -> Result<StartReport, StartError> {
77
130
  start_coordinator_with_team(workspace, None)
78
131
  }
@@ -85,6 +138,14 @@ pub fn start_coordinator(workspace: &WorkspacePath) -> Result<StartReport, Start
85
138
  ///
86
139
  /// Callers that CAN pass team_key (Batch 9 quick-start Windows path)
87
140
  /// SHOULD — that avoids Batch 8's F8 seed-state trap.
141
+ /// ---
142
+ /// purpose: 幂等启动 coordinator daemon 子进程,并把不兼容/需轮换的情形分成互不折叠的结局
143
+ /// params:
144
+ /// workspace: workspace 根
145
+ /// team_key: 传给子进程的 --team;None 或空串时子进程回落到 state.active_team_key
146
+ /// returns: StartReport。已健康 → AlreadyRunning(含「daemon 比调用方新,保留不动」这一支,rotation_reason=daemon_newer_than_caller);schema 不兼容 → SchemaIncompatible 且 ok=false 并带修复 hint;在跑但 wire metadata 不兼容、或 metadata 指向调用方自身、或先停失败 → RestartIncompatibleStopFailed;成功 spawn → Started,因身份轮换而重起则为 StartedAfterRotation
147
+ /// errors: 建目录、开日志、spawn、写 pid/metadata 或写事件失败时返回 StartError;「拒启」不是 Err,而是 ok=false 的报告
148
+ /// ---
88
149
  pub fn start_coordinator_with_team(
89
150
  workspace: &WorkspacePath,
90
151
  team_key: Option<&str>,
@@ -322,6 +383,13 @@ fn detach_daemon_child(command: &mut Command) {
322
383
  fn detach_daemon_child(_command: &mut Command) {}
323
384
 
324
385
  /// `stop_coordinator`(`lifecycle.py:228-247`):SIGTERM pid + 清 pid/meta → typed report。
386
+ /// ---
387
+ /// purpose: 停掉本 workspace 的 coordinator daemon 并清掉 pid/meta 文件
388
+ /// params:
389
+ /// workspace: workspace 根
390
+ /// returns: StopReport。pid 文件不存在时先尝试按 ps 发现流浪 coordinator,仍没有则 Missing;pid 文件内容非法 → 清文件并报 InvalidPidRemoved;终止成功 → Stopped;信号发不出去 → KillFailed
391
+ /// errors: 删 pid/meta 文件失败时返回 StopError;本函数不写事件(EventLog 变体在此路径无产生点)
392
+ /// ---
325
393
  pub fn stop_coordinator(workspace: &WorkspacePath) -> Result<StopReport, StopError> {
326
394
  let pid_path = coordinator_pid_path(workspace);
327
395
  if !pid_path.exists() {
@@ -498,6 +566,12 @@ fn terminate_pid(pid: Pid) -> bool {
498
566
 
499
567
  /// Public wrapper for diagnostic cleanup paths that must reuse coordinator
500
568
  /// shutdown's SIGTERM-then-SIGKILL semantics.
569
+ /// ---
570
+ /// purpose: 把 coordinator 停机用的「先温和后强制」终止语义暴露给诊断清理路径复用
571
+ /// params:
572
+ /// pid: 要终止的进程;只终止这棵进程树,不做名字匹配的批量清理
573
+ /// returns: 超时窗口内整棵树都不再存活为 true
574
+ /// ---
501
575
  pub fn terminate_pid_tree(pid: Pid) -> bool {
502
576
  terminate_pid(pid)
503
577
  }
@@ -607,6 +681,14 @@ fn wait_until_not_running(pid: Pid, timeout: Duration) -> bool {
607
681
  /// `ps stat=` step has no analogue). This preserves the coordinator's
608
682
  /// "am I the owner" check without silently reporting stale pids as
609
683
  /// alive.
684
+ /// ---
685
+ /// purpose: 判断某 pid 是不是本 coordinator 还能拥有的活进程(Unix 实现)
686
+ /// params:
687
+ /// pid: 待判定进程号
688
+ /// returns: 存活且非僵尸为 true。语义与通用存活探针不同:signal 返回 EPERM 一律判 false,因为 coordinator 只认自己能发信号的进程;另用 ps 的 stat 排掉僵尸
689
+ /// errors: 除 EPERM/ESRCH 外的 signal 错误、以及 ps 探测失败时返回 io::Error
690
+ /// cfg: unix
691
+ /// ---
610
692
  #[cfg(unix)]
611
693
  pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
612
694
  let Ok(pid_t) = libc::pid_t::try_from(pid.get()) else {
@@ -640,6 +722,14 @@ pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
640
722
  /// treats as `Live`; so on Windows the coordinator sees a process
641
723
  /// it can't query as still-running (safer than pretending it's gone
642
724
  /// and losing the ownership handle).
725
+ /// ---
726
+ /// purpose: 判断某 pid 是不是本 coordinator 还能拥有的活进程(非 Unix 实现)
727
+ /// params:
728
+ /// pid: 待判定进程号
729
+ /// returns: 平台层报 Live 为 true,Dead 或 Unknown 均为 false。Windows 没有僵尸态,故不做 ps stat 那一步;平台层把拒绝访问算作 Live,于是查不动的进程仍被视为在跑
730
+ /// errors: 平台层存活查询失败时返回 io::Error
731
+ /// cfg: not(unix)
732
+ /// ---
643
733
  #[cfg(not(unix))]
644
734
  pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
645
735
  match crate::platform::process::pid_liveness(pid.get())? {
@@ -650,11 +740,21 @@ pub fn pid_is_running(pid: Pid) -> Result<bool, std::io::Error> {
650
740
  }
651
741
 
652
742
  /// `read_coordinator_metadata`(`metadata.py:28-34`)。读 `coordinator.json`;损坏/缺失/非 dict → `None`。
743
+ /// ---
744
+ /// purpose: 读出已落盘的 coordinator.json
745
+ /// params:
746
+ /// workspace: workspace 根
747
+ /// returns: 解析成功才有值;文件缺失、读不动或 JSON 形状不符一律为 None,绝不返回半份 metadata
748
+ /// ---
653
749
  pub fn read_coordinator_metadata(workspace: &WorkspacePath) -> Option<CoordinatorMetadata> {
654
750
  let text = std::fs::read_to_string(coordinator_meta_path(workspace)).ok()?;
655
751
  serde_json::from_str(&text).ok()
656
752
  }
657
753
 
754
+ /// ---
755
+ /// purpose: 给出「当前这个 CLI 二进制」的身份,用于和 daemon 已记录的身份比对
756
+ /// returns: 路径取自当前可执行文件(尽量 canonicalize)而非 PATH 查找,版本取自编译进来的包版本;路径取不到时退化成 <unknown>。测试可用 TEAM_AGENT_TEST_CALLER_BINARY_IDENTITY 覆盖,且只有两字段都非空才采信
757
+ /// ---
658
758
  pub fn current_coordinator_binary_identity() -> CoordinatorBinaryIdentity {
659
759
  if let Ok(raw) = std::env::var("TEAM_AGENT_TEST_CALLER_BINARY_IDENTITY") {
660
760
  if let Ok(identity) = serde_json::from_str::<CoordinatorBinaryIdentity>(&raw) {
@@ -675,10 +775,24 @@ pub fn current_coordinator_binary_identity() -> CoordinatorBinaryIdentity {
675
775
 
676
776
  /// `coordinator_metadata_ok` now includes daemon binary identity in addition
677
777
  /// to the original pid/protocol/schema tuple.
778
+ /// ---
779
+ /// purpose: 判断已落盘 metadata 是否与当前事实完全一致
780
+ /// params:
781
+ /// metadata: 已读出的 coordinator.json;None 视为不一致
782
+ /// pid: 实际观测到的 daemon pid
783
+ /// returns: pid、协议版本、message store schema 版本、以及 daemon 二进制身份四者全对才为 true
784
+ /// ---
678
785
  pub fn coordinator_metadata_ok(metadata: Option<&CoordinatorMetadata>, pid: Pid) -> bool {
679
786
  coordinator_metadata_mismatch_reason(metadata, pid).is_none()
680
787
  }
681
788
 
789
+ /// ---
790
+ /// purpose: 给出 metadata 不一致的机器可读原因,而不是只给一个布尔
791
+ /// params:
792
+ /// metadata: 已读出的 coordinator.json;None 时原因为 MetadataMissing
793
+ /// pid: 实际观测到的 daemon pid
794
+ /// returns: 第一个不匹配项对应的原因;全部一致时为 None。先判 pid/协议/schema 这组线协议字段,再判二进制身份
795
+ /// ---
682
796
  pub fn coordinator_metadata_mismatch_reason(
683
797
  metadata: Option<&CoordinatorMetadata>,
684
798
  pid: Pid,
@@ -833,6 +947,15 @@ fn path_matches(metadata_path: &str, path: &Path) -> bool {
833
947
 
834
948
  /// `write_coordinator_metadata`(`metadata.py:46-61`)。写 `coordinator.json`(pretty indent=2),
835
949
  /// `updated_at = now(utc).isoformat()`。
950
+ /// ---
951
+ /// purpose: 落盘 coordinator.json,把当前 daemon 的身份三元与二进制身份记下来
952
+ /// params:
953
+ /// workspace: workspace 根
954
+ /// pid: 本次要记录的 daemon pid
955
+ /// source: 这份 metadata 是 daemon 自举时写的还是 CLI start 时写的
956
+ /// returns: 写成功返回 ()。协议版本与 schema 版本取自当前构建常量,updated_at 是写入时刻的 UTC
957
+ /// errors: 建目录、序列化或写文件失败时返回 io::Error
958
+ /// ---
836
959
  pub fn write_coordinator_metadata(
837
960
  workspace: &WorkspacePath,
838
961
  pid: Pid,
@@ -856,6 +979,12 @@ pub fn write_coordinator_metadata(
856
979
  std::fs::write(path, text)
857
980
  }
858
981
 
982
+ /// ---
983
+ /// purpose: 用「能不能真的打开本队 message store」来判 schema 兼容门
984
+ /// params:
985
+ /// workspace: workspace 根
986
+ /// returns: 打开成功则 ok=true 且 error/action 为空;失败则 ok=false,带 InitFailed 原文与修复 hint。schema_version 恒为当前构建的版本号
987
+ /// ---
859
988
  pub(crate) fn message_store_schema_health(workspace: &WorkspacePath) -> SchemaHealth {
860
989
  match MessageStore::open(workspace.as_path()) {
861
990
  Ok(_) => SchemaHealth {
@@ -894,16 +1023,34 @@ fn remove_file_if_exists(path: &Path) -> Result<(), std::io::Error> {
894
1023
  // ===========================================================================
895
1024
 
896
1025
  /// `coordinator.pid` 路径(`paths.py:8`)= `runtime_dir(workspace)/coordinator.pid`。
1026
+ /// ---
1027
+ /// purpose: 给出 coordinator.pid 的位置
1028
+ /// params:
1029
+ /// workspace: workspace 根
1030
+ /// returns: runtime 目录下的 coordinator.pid;只算路径,不保证文件存在
1031
+ /// ---
897
1032
  pub fn coordinator_pid_path(workspace: &WorkspacePath) -> PathBuf {
898
1033
  crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.pid")
899
1034
  }
900
1035
 
901
1036
  /// `coordinator.json` 路径(`paths.py:12`)。
1037
+ /// ---
1038
+ /// purpose: 给出 coordinator.json 的位置
1039
+ /// params:
1040
+ /// workspace: workspace 根
1041
+ /// returns: runtime 目录下的 coordinator.json;只算路径,不保证文件存在
1042
+ /// ---
902
1043
  pub fn coordinator_meta_path(workspace: &WorkspacePath) -> PathBuf {
903
1044
  crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.json")
904
1045
  }
905
1046
 
906
1047
  /// `coordinator.log` 路径(`paths.py:16`)。
1048
+ /// ---
1049
+ /// purpose: 给出 coordinator.log 的位置
1050
+ /// params:
1051
+ /// workspace: workspace 根
1052
+ /// returns: runtime 目录下的 coordinator.log;daemon 子进程的 stdout/stderr 都追加到这里
1053
+ /// ---
907
1054
  pub fn coordinator_log_path(workspace: &WorkspacePath) -> PathBuf {
908
1055
  crate::model::paths::runtime_dir(workspace.as_path()).join("coordinator.log")
909
1056
  }
@@ -915,6 +1062,16 @@ pub fn coordinator_log_path(workspace: &WorkspacePath) -> PathBuf {
915
1062
  /// `collect_watch_lines`(`watch.py:40`)。tail events.jsonl(过滤 team)+ latest_results,
916
1063
  /// 渲染人类可读行;处理 log rotation(ROTATION_MARKER + offset 重置,不重放历史段)。
917
1064
  /// 推进 `cursor`。
1065
+ /// ---
1066
+ /// purpose: 增量取出自上次游标以来的可渲染 watch 行(事件 + 结果两路)
1067
+ /// params:
1068
+ /// workspace: workspace 根
1069
+ /// cursor: 可变游标,函数会推进 offset、已见结果 id 集合与归档签名
1070
+ /// store: 已打开的 message store,用于取结果行
1071
+ /// team: 只看这个 team 的事件;None 表示不过滤
1072
+ /// returns: 本次新增的渲染行,事件行在前、结果行在后;无新内容时为空 Vec
1073
+ /// errors: 读事件文件或查库失败时返回 WatchError
1074
+ /// ---
918
1075
  pub fn collect_watch_lines(
919
1076
  workspace: &WorkspacePath,
920
1077
  cursor: &mut WatchCursor,
@@ -1031,6 +1188,12 @@ fn collect_result_lines(
1031
1188
  /// `render_event_line`(`watch.py:46-63`)。把一条 step 4 事件渲染成人类可读行;非可渲染事件 → `None`。
1032
1189
  /// 消费的事件类型:`result_received` / `leader_receiver.{injected,submitted}` / `send.failed` /
1033
1190
  /// `leader_receiver.rebind_required` / `leader.api_error`(card 表)。
1191
+ /// ---
1192
+ /// purpose: 把一条结构化事件渲染成一行人类可读文本
1193
+ /// params:
1194
+ /// event: 事件 JSON 对象;靠其中的 event 字段分派
1195
+ /// returns: 已知事件类型返回渲染行,其余一律 None(不猜、不打印原始 JSON)。摘要字段做长度截断
1196
+ /// ---
1034
1197
  pub fn render_event_line(event: &Value) -> Option<String> {
1035
1198
  let event_name = event.get("event").and_then(Value::as_str)?;
1036
1199
  match event_name {
@@ -1087,6 +1250,16 @@ pub fn render_event_line(event: &Value) -> Option<String> {
1087
1250
 
1088
1251
  /// `run_watch`(`watch.py:25`)。`team-agent watch` 主循环:反复 `collect_watch_lines` + 输出 + sleep。
1089
1252
  /// `output`/`sleep` 注入便于测试。§10 返 Result。
1253
+ /// ---
1254
+ /// purpose: team-agent watch 的主循环:反复增量收集、输出、休眠
1255
+ /// params:
1256
+ /// workspace: workspace 根
1257
+ /// team: 只看这个 team;None 表示不过滤
1258
+ /// interval_sec: 轮询间隔;非有限值或非正数时回落到内置默认
1259
+ /// output: 输出回调,注入以便测试;本函数自己不写 stdout
1260
+ /// returns: 循环结束时为 Ok。这是个长跑循环,正常运行期间不返回
1261
+ /// errors: 打开 message store 或某轮收集失败时返回 WatchError
1262
+ /// ---
1090
1263
  pub fn run_watch(
1091
1264
  workspace: &WorkspacePath,
1092
1265
  team: Option<&str>,
@@ -1,3 +1,34 @@
1
+ //! ---
2
+ //! purpose: coordinator 子系统装配面——声明各子模块并把它们的公开面重导出到 crate::coordinator
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: run_daemon
6
+ //! what: per-workspace daemon 进程入口(主循环 + 退避)
7
+ //! - name: coordinator_health
8
+ //! what: pid/metadata/schema 三合一健康判定
9
+ //! - name: start_coordinator
10
+ //! what: 幂等启动 daemon 子进程
11
+ //! - name: stop_coordinator
12
+ //! what: 停 daemon 并清 pid/meta
13
+ //! - name: run_watch
14
+ //! what: team-agent watch 的只读事件流主循环
15
+ //! - name: detect_whole_team_gone
16
+ //! what: 不依赖 coordinator 存活的整队消失判定
17
+ //! depends:
18
+ //! - crate::state
19
+ //! - crate::message_store
20
+ //! - crate::messaging
21
+ //! - crate::transport
22
+ //! - crate::provider
23
+ //! - crate::leader
24
+ //! - crate::event_log
25
+ //! boundary:
26
+ //! - 不实现消息投递与结果回收本体(在 crate::messaging,本模块只按固定顺序调用)
27
+ //! - 不直接依赖任何 provider client crate,provider 一律经 ProviderAdapter trait
28
+ //! - 不做物理注入/键盘写入,注入归 crate::transport
29
+ //! - 无 pending obligation 时不注入任何探索性 prompt
30
+ //! maturity: wired
31
+ //! ---
1
32
  //!
2
33
  //! step 12 · coordinator — daemon lifecycle / single-tick orchestration SKELETON (ROUND-0).
3
34
  //!
@@ -1,3 +1,19 @@
1
+ //! ---
2
+ //! purpose: 两个纯判定——daemon 自己是不是该自杀的孤儿,以及整个队是不是已经全没了
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: should_orphan_self_terminate
6
+ //! what: ppid 变更 + 被 init 收养 + workspace 已消失,三者同时成立才判孤儿
7
+ //! - name: detect_whole_team_gone
8
+ //! what: 由存活快照判整队消失,并区分 clean/restart(静默)与 unexpected(写 marker + 延迟升报)
9
+ //! depends:
10
+ //! - super::types
11
+ //! boundary:
12
+ //! - 不杀任何进程,也不发信号;只给判定结果,动作归调用方
13
+ //! - 不读屏、不命名 provider;只消费结构化存活快照
14
+ //! - 不直接升报用户,unexpected 只落 durable marker,等下一条 leader 命令再升
15
+ //! maturity: wired
16
+ //! ---
1
17
  //!
2
18
  //! 孤儿自终止判定(Gap 37b)+ provider-neutral 整队消失检测。
3
19
 
@@ -9,6 +25,14 @@ use super::types::{
9
25
  /// 孤儿自终止判定(`__main__.py:51-59`,Gap 37b)。仅当
10
26
  /// `current_ppid != initial_ppid ∧ current_ppid == 1 ∧ !workspace.exists()` 三者**同时**成立 → true。
11
27
  /// 少一个条件都不能误杀正常 daemon(card §91)。
28
+ /// ---
29
+ /// purpose: 判断本 daemon 是否已成为应当自我终止的孤儿
30
+ /// params:
31
+ /// initial_ppid: 进程启动那一刻记下的父 pid
32
+ /// current_ppid: 当前父 pid;被 init/launchd 收养后为 1
33
+ /// workspace: 本 daemon 服务的 workspace 根,用其存在性作第三个条件
34
+ /// returns: 三个条件同时成立才为 true;少一个都返回 false,宁可不自杀
35
+ /// ---
12
36
  pub fn should_orphan_self_terminate(
13
37
  initial_ppid: u32,
14
38
  current_ppid: u32,
@@ -25,6 +49,13 @@ pub fn should_orphan_self_terminate(
25
49
  /// `detect_whole_team_gone`(`abnormal_track.py:91`,C10/C13)。coordinator-independent 整队消失检测:
26
50
  /// 全死(coordinator + leader + 所有 worker + 所有 session)且非 clean_shutdown/restart →
27
51
  /// 写 durable marker + 延迟到下条 leader 命令再 escalate。clean/restart 静默。
52
+ /// ---
53
+ /// purpose: 由整队存活快照判定「整队消失」并给出分类与后续处置标志
54
+ /// params:
55
+ /// snapshot: coordinator/leader/各 worker 进程/transport 会话的存活位,以及 clean_shutdown、restart_in_progress 两个意图位
56
+ /// marker_store: durable marker 写入口;仅 unexpected_exit 分支会被调用
57
+ /// returns: 任一成员存活则 Alive 且全部标志为 false;全死时按 clean_shutdown、restart_in_progress、unexpected_exit 依次分类,只有 unexpected 才置 notify/escalate 并写 marker
58
+ /// ---
28
59
  pub fn detect_whole_team_gone(
29
60
  snapshot: &TeamPresenceSnapshot,
30
61
  marker_store: &mut dyn MarkerStore,
@@ -1,3 +1,22 @@
1
+ //! ---
2
+ //! purpose: 三个只读运行时探测——上下文压缩、Codex session 漂移、leader 端 API 错误——全部值变才发事件
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: observe_runtime
6
+ //! what: 对本 tick 的每条捕获事实跑三个探测,收集结果并写变化驱动的事件
7
+ //! depends:
8
+ //! - super::runtime_observation
9
+ //! - super::types
10
+ //! - crate::event_log
11
+ //! - crate::state::projection
12
+ //! - crate::state::ownership
13
+ //! - crate::model::enums
14
+ //! boundary:
15
+ //! - 只分类不动作:不重启 agent、不清 session、不投递任何消息,只给 recommendation 文案
16
+ //! - 事件是 change-driven:计数/指纹不变的那一 tick 不重发,去重键存在 state 里
17
+ //! - 只读 scrollback 尾与已存 session id,不与 provider 进程交互
18
+ //! maturity: wired
19
+ //! ---
1
20
  //!
2
21
  use std::collections::BTreeMap;
3
22
  use std::path::Path;
@@ -15,6 +34,15 @@ use super::types::{CompactionResult, LeaderApiError, SessionDriftResult};
15
34
 
16
35
  const COMPACTION_RESET_THRESHOLD_DEFAULT: i64 = 3;
17
36
 
37
+ /// ---
38
+ /// purpose: 对本 tick 的全部捕获事实依次跑 compaction / session-drift / leader-api-error 三个探测
39
+ /// params:
40
+ /// workspace: workspace 根,用于打开事件日志
41
+ /// state: 可变运行时状态;探测在其中读写压缩计数、漂移标记与 api-error 指纹这些跨 tick 去重键
42
+ /// captures_by_agent: 本 tick 的 per-agent 捕获事实,按 agent_id 有序
43
+ /// leader_capture: leader 侧捕获;为 None 时 api-error 结果为空,且不清除既有指纹
44
+ /// returns: 捕获事实原样带回,附三组探测结果;未命中的探测对应空 Vec
45
+ /// ---
18
46
  pub fn observe_runtime(
19
47
  workspace: &Path,
20
48
  state: &mut Value,
@@ -554,6 +582,8 @@ fn runtime_event_provider_name(provider: Provider) -> &'static str {
554
582
  Provider::Codex => "codex",
555
583
  Provider::Copilot => "copilot",
556
584
  Provider::GeminiCli => "gemini_cli",
585
+ Provider::Grok => "grok",
586
+ Provider::CursorAgent => "cursor_agent",
557
587
  Provider::Fake => "fake",
558
588
  }
559
589
  }
@@ -1,3 +1,19 @@
1
+ //! ---
2
+ //! purpose: 运行时观测的类型缝——定义「一次 tick 捕到的事实」与「探测结果集合」两个形状,并把探测转交 runtime_detectors
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: observe
6
+ //! what: 把本 tick 的 per-agent 捕获事实与 leader 捕获事实交给探测器,返回结果集合
7
+ //! depends:
8
+ //! - super::runtime_detectors
9
+ //! - super::types
10
+ //! - crate::provider
11
+ //! - crate::transport
12
+ //! boundary:
13
+ //! - 不做捕获本身(scrollback/pane 快照由 tick 侧采集后传入)
14
+ //! - 不做任何判定,判定全在 runtime_detectors
15
+ //! maturity: wired
16
+ //! ---
1
17
  //!
2
18
  //! Shared coordinator runtime observation seam.
3
19
  //!
@@ -49,6 +65,15 @@ pub struct RuntimeObservationResults {
49
65
  pub api_errors: Vec<LeaderApiError>,
50
66
  }
51
67
 
68
+ /// ---
69
+ /// purpose: 本 tick 观测的统一入口,把捕获事实转交 runtime_detectors 并原样带回结果
70
+ /// params:
71
+ /// workspace: workspace 根,探测器据此写事件日志
72
+ /// state: 可变运行时状态;探测器在其中保存跨 tick 的去重/计数键
73
+ /// captures_by_agent: 本 tick 每个 agent 的捕获事实(scrollback 尾、pane 信息、已存 session id 等)
74
+ /// leader_capture: leader 侧捕获事实;缺失表示本 tick 没拿到 leader 屏幕,api-error 探测随之为空
75
+ /// returns: 捕获事实原样回传,外加 compaction / session_drift / leader api-error 三组探测结果
76
+ /// ---
52
77
  pub fn observe(
53
78
  workspace: &Path,
54
79
  state: &mut Value,
@@ -1,3 +1,31 @@
1
+ //! ---
2
+ //! purpose: tick 的异常退出检测步骤——按 agent 读有界 rollout 尾,判「最新一条显式 provider 错误是否属于当前 worker 世代」,据此决定通知还是只留审计
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: detect_abnormal_exits
6
+ //! what: 遍历受监视 agent,产出 worker.abnormal_exit 通知或 dead_only 审计事件,并把本轮观测写回 state 的 abnormal_exit_watch
7
+ //! - name: explicit_process_liveness
8
+ //! what: 从 agent JSON 的显式存活字段解析进程存活态,不做任何探测
9
+ //! - name: read_tail_text
10
+ //! what: 有界读文件尾部文本,超长时从尾部 max_bytes 处起读
11
+ //! - name: metadata_mtime_ns
12
+ //! what: 把文件 metadata 的 mtime 归一成纳秒整数,供跨 tick 变化比较
13
+ //! depends:
14
+ //! - super::super::health
15
+ //! - super::super::tick
16
+ //! - super::super::types
17
+ //! - crate::event_log
18
+ //! - crate::messaging
19
+ //! - crate::provider
20
+ //! - crate::transport
21
+ //! - crate::state::projection
22
+ //! boundary:
23
+ //! - 不重启、不清理、不做物理注入:写事件与 state 观测记录之外,异常通知会经 crate::messaging 的 leader funnel 入库为 accepted 消息(物理注入由后续 deliver_pending 完成)
24
+ //! - 进程已死但没有显式错误时不通知,只落 dead_only 审计
25
+ //! - 通知事件里的 queued 只表示消息入库,不表示已送达
26
+ //! - rollout 尾读是有界的(首行可能被截断,消费方只解析最后一条完整 JSONL 记录)
27
+ //! maturity: wired
28
+ //! ---
1
29
  //!
2
30
  //! unit-11 (Stage 4) — coordinator tick `abnormal` step group.
3
31
  //!
@@ -23,6 +51,17 @@ use super::super::types::Pid;
23
51
  /// provider error that is fresh for the current worker cohort. A dead process
24
52
  /// without an explicit error remains a suppressed `dead_only` audit event; process
25
53
  /// liveness is otherwise diagnostic data for this path.
54
+ /// ---
55
+ /// purpose: 跑一轮异常退出检测,把结论落成事件与 state 里的 abnormal_exit_watch 记录
56
+ /// params:
57
+ /// workspace: workspace 根,用于解析 rollout 相对路径
58
+ /// transport: pane 存活探测通道;只读探测,不注入
59
+ /// state: 可变运行时状态;本轮观测(size/mtime/世代/去重键)写回 coordinator.abnormal_exit_watch
60
+ /// event_log: 事件出口
61
+ /// targets: 本 tick 已采到的 pane 快照,避免每 agent 重新列一遍
62
+ /// returns: 检测跑完即 Ok;「有没有异常」不由返回值表达,只体现在事件与 state 里
63
+ /// errors: 事件写入等不可恢复失败时返回 TickError;单个 agent 的 rollout metadata 读不到不算错误,记为 unverifiable 继续
64
+ /// ---
26
65
  pub(crate) fn detect_abnormal_exits(
27
66
  workspace: &Path,
28
67
  transport: &dyn crate::transport::Transport,
@@ -476,6 +515,12 @@ fn agent_pid(agent: &Value) -> Option<Pid> {
476
515
  .find_map(|key| json_u32(agent.get(key)).map(Pid::new))
477
516
  }
478
517
 
518
+ /// ---
519
+ /// purpose: 只从 agent JSON 里已写明的存活字段读出进程存活态,不做任何主动探测
520
+ /// params:
521
+ /// agent: agent 状态对象;先下钻 provider_process / process 子对象,再看本层的 *_liveness 串字段
522
+ /// returns: 命中显式字段时给出 Alive/Dead/Unverifiable;没有任何显式字段时为 None,交调用方走探测路径
523
+ /// ---
479
524
  pub(crate) fn explicit_process_liveness(agent: &Value) -> Option<ProcessLiveness> {
480
525
  if let Some(process) = agent
481
526
  .get("provider_process")
@@ -836,6 +881,12 @@ fn process_liveness_wire(state: ProcessLiveness) -> &'static str {
836
881
  }
837
882
  }
838
883
 
884
+ /// ---
885
+ /// purpose: 把文件修改时间归一成自 UNIX 纪元起的纳秒整数,供跨 tick 比较「rollout 有没有变过」
886
+ /// params:
887
+ /// metadata: 目标文件的 metadata
888
+ /// returns: 纳秒时间戳;取不到 mtime 或早于纪元时为 None。乘加均为 saturating,不会回绕
889
+ /// ---
839
890
  pub(crate) fn metadata_mtime_ns(metadata: &std::fs::Metadata) -> Option<u64> {
840
891
  let duration = metadata
841
892
  .modified()
@@ -977,6 +1028,14 @@ const ABNORMAL_TAIL_BYTES: u64 = 131_072;
977
1028
  ///
978
1029
  /// P1: bounded tail read; a partial first line is harmless (the consumer only parses
979
1030
  /// the latest complete JSONL record) and lossy UTF-8 keeps a mid-codepoint seek safe.
1031
+ /// ---
1032
+ /// purpose: 有界读取文件尾部文本,避免整份 rollout 进内存
1033
+ /// params:
1034
+ /// path: 目标文件
1035
+ /// max_bytes: 最多回读的字节数;文件更短时整份读出
1036
+ /// returns: 尾部文本。按字节 seek,首行可能被截断,且用有损 UTF-8 解码,切在码点中间也安全
1037
+ /// errors: 打开、取长度或读取失败时返回底层 io::Error
1038
+ /// ---
980
1039
  pub(crate) fn read_tail_text(path: &Path, max_bytes: u64) -> std::io::Result<String> {
981
1040
  use std::io::{Read, Seek, SeekFrom};
982
1041
  let mut file = std::fs::File::open(path)?;
@@ -1,3 +1,13 @@
1
+ //! ---
2
+ //! purpose: coordinator tick delivery 步骤组的占位命名空间——实现仍在 tick.rs
3
+ //! contract:
4
+ //! provides: []
5
+ //! depends: []
6
+ //! boundary:
7
+ //! - 本文件当前不含任何 item:消息投递 FSM 的 tick 步骤未来迁入处
8
+ //! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
9
+ //! maturity: signature_only
10
+ //! ---
1
11
  //!
2
12
  //! unit-11 (Stage 4) — coordinator tick `delivery` step group.
3
13
  //!
@@ -1,3 +1,13 @@
1
+ //! ---
2
+ //! purpose: coordinator tick health_sync 步骤组的占位命名空间——实现仍在 tick.rs
3
+ //! contract:
4
+ //! provides: []
5
+ //! depends: []
6
+ //! boundary:
7
+ //! - 本文件当前不含任何 item:worker 存活对账步骤未来迁入处
8
+ //! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
9
+ //! maturity: signature_only
10
+ //! ---
1
11
  //!
2
12
  //! unit-11 (Stage 4) — coordinator tick `health_sync` step group.
3
13
  //!
@@ -1,3 +1,17 @@
1
+ //! ---
2
+ //! purpose: tick 步骤组的命名空间与规范顺序——给每个步骤组一个稳定标签与固定次序,供编排器与事件日志共用
3
+ //! contract:
4
+ //! provides:
5
+ //! - name: ordered
6
+ //! what: 步骤组的规范顺序(穷尽枚举),编排器必须按此序调用
7
+ //! - name: as_str
8
+ //! what: 步骤组的稳定标签(tick.<group>),进事件与指标字段
9
+ //! depends: []
10
+ //! boundary:
11
+ //! - 不含任何步骤的实现,只定义分组身份与顺序
12
+ //! - persist 必须排最后、session_gate 必须排最前,这是顺序本身承载的约束
13
+ //! maturity: wired
14
+ //! ---
1
15
  //!
2
16
  //! unit-11 (Stage 4) — coordinator tick steps namespace.
3
17
  //!
@@ -37,6 +51,10 @@ pub enum TickStepGroup {
37
51
 
38
52
  impl TickStepGroup {
39
53
  /// Stable label used in event-log and metric fields.
54
+ /// ---
55
+ /// purpose: 给步骤组一个稳定标签,供事件日志与指标字段使用
56
+ /// returns: 形如 tick.<group> 的稳定串;已发布的取值不可改写,只可新增
57
+ /// ---
40
58
  pub fn as_str(self) -> &'static str {
41
59
  match self {
42
60
  Self::SessionGate => "tick.session_gate",
@@ -50,6 +68,10 @@ impl TickStepGroup {
50
68
 
51
69
  ///
52
70
  /// Canonical ordering as a const slice — exhaustive over the enum.
71
+ /// ---
72
+ /// purpose: 给出步骤组的规范调用顺序
73
+ /// returns: 穷尽覆盖本 enum 全部变体的静态切片,session_gate 在首、persist 在尾;编排器按此序调用,持久化才能反映之前每一步的结果
74
+ /// ---
53
75
  pub fn ordered() -> &'static [TickStepGroup] {
54
76
  &[
55
77
  TickStepGroup::SessionGate,
@@ -1,3 +1,13 @@
1
+ //! ---
2
+ //! purpose: coordinator tick persist 步骤组的占位命名空间——实现仍在 tick.rs
3
+ //! contract:
4
+ //! provides: []
5
+ //! depends: []
6
+ //! boundary:
7
+ //! - 本文件当前不含任何 item:tick 末尾的持久化步骤未来迁入处
8
+ //! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
9
+ //! maturity: signature_only
10
+ //! ---
1
11
  //!
2
12
  //! unit-11 (Stage 4) — coordinator tick `persist` step group.
3
13
  //!
@@ -1,3 +1,13 @@
1
+ //! ---
2
+ //! purpose: coordinator tick runtime_prompts 步骤组的占位命名空间——实现仍在 tick.rs
3
+ //! contract:
4
+ //! provides: []
5
+ //! depends: []
6
+ //! boundary:
7
+ //! - 本文件当前不含任何 item:startup / approval / abnormal-exit 提示步骤未来迁入处
8
+ //! - 迁移落地前不要在此新增逻辑,否则步骤顺序会分裂成两处
9
+ //! maturity: signature_only
10
+ //! ---
1
11
  //!
2
12
  //! unit-11 (Stage 4) — coordinator tick `runtime_prompts` step group.
3
13
  //!