@team-agent/installer 0.5.61 → 0.5.62

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 +6 -5
  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 +0 -9
  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 -42
  49. package/crates/team-agent/src/coordinator/tick.rs +24 -28
  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 -3
  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 -11
  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 -0
  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,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `delivery` step group.
2
3
  //!
3
4
  //! Future home for the message-delivery FSM ticks from
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `health_sync` step group.
2
3
  //!
3
4
  //! Future home for worker-liveness reconciliation steps from
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick steps namespace.
2
3
  //!
3
4
  //! The 3083 LOC `coordinator/tick.rs` orchestrator runs an ordered
@@ -47,6 +48,7 @@ impl TickStepGroup {
47
48
  }
48
49
  }
49
50
 
51
+ ///
50
52
  /// Canonical ordering as a const slice — exhaustive over the enum.
51
53
  pub fn ordered() -> &'static [TickStepGroup] {
52
54
  &[
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `persist` step group.
2
3
  //!
3
4
  //! Future home for the durable state-persistence step at the end of each
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `runtime_prompts` step group.
2
3
  //!
3
4
  //! Future home for the startup / approval / abnormal-exit prompt steps
@@ -1,3 +1,4 @@
1
+ //!
1
2
  //! unit-11 (Stage 4) — coordinator tick `session_gate` step group.
2
3
  //!
3
4
  //! Future home for the provider session-capture + readiness-gate steps
@@ -1,179 +1,5 @@
1
1
  use super::*;
2
2
 
3
- // ═════════════════════════════════════════════════════════════════════════
4
- // GROUP E — abnormal_track classify / dedup (abnormal_track.py) — RED
5
- // provider-neutral:断言 ZERO adapter_for 调用(MUST-NOT-13)。
6
- // ASSUMPTION:传入 `records` 是 provider reader 已产出的结构化 fault facts
7
- // ({signature, turn_id?, kind?, raw}),即 read_fault_facts 的输出形;abnormal_track
8
- // 只对它做 catch-bias + (signature, turn_id|fingerprint) 去重(error_lists 来自注入
9
- // registry,绝不经 adapter_for 触碰 provider client)。
10
- // ═════════════════════════════════════════════════════════════════════════
11
-
12
- #[test]
13
- fn abnormal_default_notify_for_structured_fault() {
14
- // abnormal_track.py:204 — C9 catch-bias: 无黑白名单命中 → notify_default.
15
- let reg = MockRegistry::new(&[], &[]);
16
- let records = vec![serde_json::json!({"raw": "session line"})];
17
- let out = process_abnormal_records(
18
- &records,
19
- &reg,
20
- Provider::Codex,
21
- &AbnormalNotificationState::default(),
22
- )
23
- .unwrap();
24
- assert_eq!(out.notifications.len(), 1);
25
- assert_eq!(
26
- out.notifications[0].decision,
27
- AbnormalDecision::NotifyDefault
28
- );
29
- // §84:绝不触碰 provider adapter client。
30
- assert_eq!(
31
- reg.adapter_calls.get(),
32
- 0,
33
- "MUST NOT call adapter_for (provider client)"
34
- );
35
- }
36
-
37
- #[test]
38
- fn abnormal_blacklist_hit_yields_notify_blacklist() {
39
- // abnormal_track.py:203 — blacklist 命中 → notify_blacklist.
40
- let reg = MockRegistry::new(&[], &["boom"]);
41
- let records = vec![serde_json::json!({"raw": "kaboom: boom happened"})];
42
- let out = process_abnormal_records(
43
- &records,
44
- &reg,
45
- Provider::Codex,
46
- &AbnormalNotificationState::default(),
47
- )
48
- .unwrap();
49
- assert_eq!(out.notifications.len(), 1);
50
- assert_eq!(
51
- out.notifications[0].decision,
52
- AbnormalDecision::NotifyBlacklist
53
- );
54
- assert_eq!(reg.adapter_calls.get(), 0);
55
- }
56
-
57
- #[test]
58
- fn abnormal_whitelist_beats_blacklist_and_skips() {
59
- // abnormal_track.py:200-201 — whitelist > blacklist > default. 同命中 → skip, 0 notify.
60
- let reg = MockRegistry::new(&["boom"], &["boom"]);
61
- let records = vec![serde_json::json!({"raw": "boom transient"})];
62
- let out = process_abnormal_records(
63
- &records,
64
- &reg,
65
- Provider::Codex,
66
- &AbnormalNotificationState::default(),
67
- )
68
- .unwrap();
69
- assert_eq!(
70
- out.notifications.len(),
71
- 0,
72
- "whitelist wins → skip (probe confirmed)"
73
- );
74
- assert_eq!(reg.adapter_calls.get(), 0);
75
- }
76
-
77
- #[test]
78
- fn abnormal_approval_kind_maps_to_blocked_on_human() {
79
- // abnormal_track.py:74 — kind=="approval" → state blocked_on_human, else abnormal.
80
- let reg = MockRegistry::new(&[], &[]);
81
- let records = vec![serde_json::json!({"raw": "approve?", "kind": "approval"})];
82
- let out = process_abnormal_records(
83
- &records,
84
- &reg,
85
- Provider::Codex,
86
- &AbnormalNotificationState::default(),
87
- )
88
- .unwrap();
89
- assert_eq!(out.notifications.len(), 1);
90
- assert_eq!(out.notifications[0].state, TurnState::BlockedOnHuman);
91
- }
92
-
93
- #[test]
94
- fn abnormal_same_turn_id_folds_to_one_notification() {
95
- // abnormal_track.py:60-68 — C8 dedup: same (signature, turn_id) → one notify.
96
- let reg = MockRegistry::new(&[], &[]);
97
- let records = vec![
98
- serde_json::json!({"signature": "sig_a", "turn_id": "t1", "raw": "boom"}),
99
- serde_json::json!({"signature": "sig_a", "turn_id": "t1", "raw": "boom"}),
100
- ];
101
- let out = process_abnormal_records(
102
- &records,
103
- &reg,
104
- Provider::Codex,
105
- &AbnormalNotificationState::default(),
106
- )
107
- .unwrap();
108
- assert_eq!(
109
- out.notifications.len(),
110
- 1,
111
- "retry-loop in SAME turn folds (probe: 1)"
112
- );
113
- // seen 状态回存,key = "sig_a\0t1"。
114
- assert!(out.notification_state.seen.contains("sig_a\u{0}t1"));
115
- }
116
-
117
- #[test]
118
- fn abnormal_missing_turn_id_distinct_faults_each_notify() {
119
- // abnormal_track.py:64 — turn_id None → per-record content fingerprint bucket:
120
- // 不同 fault 各自 notify(绝不折叠进全局桶,probe: 2)。
121
- let reg = MockRegistry::new(&[], &[]);
122
- let records = vec![
123
- serde_json::json!({"signature": "sig_b", "raw": "alpha"}),
124
- serde_json::json!({"signature": "sig_b", "raw": "beta"}),
125
- ];
126
- let out = process_abnormal_records(
127
- &records,
128
- &reg,
129
- Provider::Codex,
130
- &AbnormalNotificationState::default(),
131
- )
132
- .unwrap();
133
- assert_eq!(
134
- out.notifications.len(),
135
- 2,
136
- "distinct raw → 2 notifies (probe)"
137
- );
138
- }
139
-
140
- #[test]
141
- fn abnormal_missing_turn_id_identical_faults_fold() {
142
- // abnormal_track.py:64-68 — identical raw + missing turn_id → same fingerprint → fold (probe: 1).
143
- let reg = MockRegistry::new(&[], &[]);
144
- let records = vec![
145
- serde_json::json!({"signature": "sig_c", "raw": "same"}),
146
- serde_json::json!({"signature": "sig_c", "raw": "same"}),
147
- ];
148
- let out = process_abnormal_records(
149
- &records,
150
- &reg,
151
- Provider::Codex,
152
- &AbnormalNotificationState::default(),
153
- )
154
- .unwrap();
155
- assert_eq!(
156
- out.notifications.len(),
157
- 1,
158
- "identical raw folds even w/o turn_id (probe)"
159
- );
160
- }
161
-
162
- #[test]
163
- fn abnormal_preseeded_seen_suppresses_duplicate_across_calls() {
164
- // abnormal_track.py:67 — key already in seen → skip notification (cross-tick dedup).
165
- let reg = MockRegistry::new(&[], &[]);
166
- let mut state = AbnormalNotificationState::default();
167
- state.seen.insert("sig_a\u{0}t1".to_string());
168
- let records = vec![serde_json::json!({"signature": "sig_a", "turn_id": "t1", "raw": "boom"})];
169
- let out = process_abnormal_records(&records, &reg, Provider::Codex, &state).unwrap();
170
- assert_eq!(
171
- out.notifications.len(),
172
- 0,
173
- "pre-seeded seen suppresses (probe: 0)"
174
- );
175
- }
176
-
177
3
  #[test]
178
4
  fn abnormal_explicit_error_classifier_boundaries_stay_stable() {
179
5
  let claude_api = line(serde_json::json!({
@@ -447,7 +447,6 @@ impl Drop for RecoveryCase {
447
447
  #[derive(Clone)]
448
448
  struct CounterState {
449
449
  adapter_calls: Arc<AtomicU32>,
450
- error_list_calls: Arc<AtomicU32>,
451
450
  }
452
451
 
453
452
  struct CountingRegistry {
@@ -459,7 +458,6 @@ impl CountingRegistry {
459
458
  Self {
460
459
  counters: CounterState {
461
460
  adapter_calls: Arc::new(AtomicU32::new(0)),
462
- error_list_calls: Arc::new(AtomicU32::new(0)),
463
461
  },
464
462
  }
465
463
  }
@@ -474,13 +472,6 @@ impl ProviderRegistry for CountingRegistry {
474
472
  self.counters.adapter_calls.fetch_add(1, Ordering::SeqCst);
475
473
  crate::provider::get_adapter(provider)
476
474
  }
477
-
478
- fn error_lists(&self, _provider: Provider) -> ErrorLists {
479
- self.counters
480
- .error_list_calls
481
- .fetch_add(1, Ordering::SeqCst);
482
- ErrorLists::default()
483
- }
484
475
  }
485
476
 
486
477
  fn claude_api_error_line(uuid: &str, status: i64, error: &str) -> String {
@@ -98,18 +98,6 @@ fn status_enums_serialize_to_exact_python_strings() {
98
98
  serde_json::to_string(&MetadataSource::Start).unwrap(),
99
99
  "\"start\"",
100
100
  ),
101
- (
102
- serde_json::to_string(&AbnormalDecision::Skip).unwrap(),
103
- "\"skip\"",
104
- ),
105
- (
106
- serde_json::to_string(&AbnormalDecision::NotifyBlacklist).unwrap(),
107
- "\"notify_blacklist\"",
108
- ),
109
- (
110
- serde_json::to_string(&AbnormalDecision::NotifyDefault).unwrap(),
111
- "\"notify_default\"",
112
- ),
113
101
  (
114
102
  serde_json::to_string(&WholeTeamGoneClass::Alive).unwrap(),
115
103
  "\"alive\"",
@@ -132,178 +120,6 @@ fn status_enums_serialize_to_exact_python_strings() {
132
120
  }
133
121
  }
134
122
 
135
- #[test]
136
- fn coordinator_event_tags_are_byte_stable() {
137
- // 逐一钉 events.jsonl tag(events.py 稳定契约)。
138
- let pid = Pid(4242);
139
- let cases: Vec<(CoordinatorEvent, &str)> = vec![
140
- (
141
- CoordinatorEvent::Boot {
142
- workspace: "/w".into(),
143
- once: true,
144
- },
145
- "coordinator.boot",
146
- ),
147
- (
148
- CoordinatorEvent::Started {
149
- pid,
150
- log: "/l".into(),
151
- },
152
- "coordinator.started",
153
- ),
154
- (CoordinatorEvent::Stopped { pid }, "coordinator.stopped"),
155
- (CoordinatorEvent::Exit { stop: true }, "coordinator.exit"),
156
- (
157
- CoordinatorEvent::SessionMissing {
158
- session: "s".into(),
159
- },
160
- "coordinator.session_missing",
161
- ),
162
- (
163
- CoordinatorEvent::OrphanSelfTerminate {
164
- initial_ppid: 9,
165
- current_ppid: 1,
166
- workspace: "/w".into(),
167
- },
168
- "coordinator.orphan_self_terminate",
169
- ),
170
- (
171
- CoordinatorEvent::TickError {
172
- error: "boom".into(),
173
- exc_type: "OSError".into(),
174
- consecutive_failures: 1,
175
- next_sleep_sec: 5.0,
176
- },
177
- "coordinator.tick_error",
178
- ),
179
- (
180
- CoordinatorEvent::TickErrorSuppressed {
181
- consecutive_failures: 2,
182
- next_sleep_sec: 10.0,
183
- },
184
- "coordinator.tick_error.suppressed",
185
- ),
186
- (
187
- CoordinatorEvent::TickRecovered {
188
- consecutive_failures: 3,
189
- },
190
- "coordinator.tick_recovered",
191
- ),
192
- (
193
- CoordinatorEvent::RestartIncompatible {
194
- pid: Some(pid),
195
- expected_protocol: 2,
196
- expected_schema: 3,
197
- },
198
- "coordinator.restart_incompatible",
199
- ),
200
- (
201
- CoordinatorEvent::RestartIncompatibleStopFailed { pid: Some(pid) },
202
- "coordinator.restart_incompatible_stop_failed",
203
- ),
204
- (
205
- CoordinatorEvent::SchemaIncompatible {
206
- table: Some("messages".into()),
207
- missing_columns: vec!["owner_team_id".into()],
208
- },
209
- "coordinator.schema_incompatible",
210
- ),
211
- (
212
- CoordinatorEvent::IdleTakeoverUnknownPersistent {
213
- node_id: "w1".into(),
214
- provider: Some(Provider::Codex),
215
- auth_mode: None,
216
- consecutive_ticks: 60,
217
- rollout_path: None,
218
- },
219
- "idle_takeover.unknown_persistent",
220
- ),
221
- (
222
- CoordinatorEvent::AbnormalNotify {
223
- signature: "sig".into(),
224
- turn_id: None,
225
- decision: AbnormalDecision::NotifyDefault,
226
- },
227
- "abnormal.notify",
228
- ),
229
- (
230
- CoordinatorEvent::AbnormalWholeTeamGone {
231
- classification: WholeTeamGoneClass::UnexpectedExit,
232
- },
233
- "abnormal.whole_team_gone",
234
- ),
235
- (
236
- CoordinatorEvent::LeaderNotificationLogPruned { removed: 7 },
237
- "leader_notification.log_pruned",
238
- ),
239
- (
240
- CoordinatorEvent::LeaderNotificationPruneFailed { error: "io".into() },
241
- "leader_notification.prune_failed",
242
- ),
243
- (
244
- CoordinatorEvent::RuntimeStateSaveFailed {
245
- phase: "tick_end".into(),
246
- error: "replace".into(),
247
- exc_type: "OSError".into(),
248
- },
249
- "runtime.state.save_failed",
250
- ),
251
- ];
252
- for (evt, want_tag) in &cases {
253
- let json = serde_json::to_value(evt).unwrap();
254
- assert_eq!(json["event"], *want_tag, "tag mismatch for {want_tag}");
255
- }
256
- }
257
-
258
- #[test]
259
- fn tick_error_event_carries_exact_python_fields() {
260
- // __main__.py:69-74 — error / exc_type / consecutive_failures / next_sleep_sec.
261
- let evt = CoordinatorEvent::TickError {
262
- error: "os.replace failed".into(),
263
- exc_type: "OSError".into(),
264
- consecutive_failures: 4,
265
- next_sleep_sec: 40.0,
266
- };
267
- let json = serde_json::to_value(&evt).unwrap();
268
- assert_eq!(json["event"], "coordinator.tick_error");
269
- assert_eq!(json["error"], "os.replace failed");
270
- assert_eq!(json["exc_type"], "OSError");
271
- assert_eq!(json["consecutive_failures"], 4);
272
- assert_eq!(json["next_sleep_sec"], 40.0);
273
- }
274
-
275
- #[test]
276
- fn unknown_persistent_event_provider_none_is_null_not_missing() {
277
- // lifecycle.py:407 rollout_path=node.get(...) — None 漏穿堵死(bug-085):
278
- // provider/rollout_path 缺失序列化为 JSON null,绝不省略键。
279
- let evt = CoordinatorEvent::IdleTakeoverUnknownPersistent {
280
- node_id: "w7".into(),
281
- provider: None,
282
- auth_mode: None,
283
- consecutive_ticks: 72,
284
- rollout_path: None,
285
- };
286
- let json = serde_json::to_value(&evt).unwrap();
287
- assert_eq!(json["event"], "idle_takeover.unknown_persistent");
288
- assert_eq!(json["node_id"], "w7");
289
- assert!(
290
- json.get("provider").is_some(),
291
- "provider key MUST be present (None→null)"
292
- );
293
- assert!(json["provider"].is_null(), "provider None → JSON null");
294
- assert!(
295
- json.get("auth_mode").is_some(),
296
- "auth_mode key MUST be present"
297
- );
298
- assert!(json["auth_mode"].is_null(), "auth_mode None → JSON null");
299
- assert!(
300
- json.get("rollout_path").is_some(),
301
- "rollout_path key MUST be present"
302
- );
303
- assert!(json["rollout_path"].is_null());
304
- assert_eq!(json["consecutive_ticks"], 72);
305
- }
306
-
307
123
  #[test]
308
124
  fn coordinator_metadata_json_field_names_are_stable() {
309
125
  // metadata.py:50-57 — 稳定 coordinator.json 契约。
@@ -25,23 +25,15 @@ fn meta(pid: u32, proto: u32, schema: i64) -> CoordinatorMetadata {
25
25
  }
26
26
  }
27
27
 
28
- /// `ProviderRegistry` mock — 断言**零** provider-client 调用 (MUST-NOT-13 / §84).
29
- /// `adapter_for`/`error_lists` 各记一次调用计数;abnormal-track 只允许触碰 `error_lists`,
30
- /// 绝不触碰 `adapter_for`(那会走真实 provider client crate)。
28
+ /// `ProviderRegistry` mock — 记录 provider-client adapter 调用 (MUST-NOT-13 / §84).
31
29
  struct MockRegistry {
32
- whitelist: Vec<String>,
33
- blacklist: Vec<String>,
34
30
  adapter_calls: std::cell::Cell<u32>,
35
- error_list_calls: std::cell::Cell<u32>,
36
31
  }
37
32
 
38
33
  impl MockRegistry {
39
- fn new(whitelist: &[&str], blacklist: &[&str]) -> Self {
34
+ fn new(_whitelist: &[&str], _blacklist: &[&str]) -> Self {
40
35
  Self {
41
- whitelist: whitelist.iter().map(|s| s.to_string()).collect(),
42
- blacklist: blacklist.iter().map(|s| s.to_string()).collect(),
43
36
  adapter_calls: std::cell::Cell::new(0),
44
- error_list_calls: std::cell::Cell::new(0),
45
37
  }
46
38
  }
47
39
  }
@@ -52,13 +44,6 @@ impl ProviderRegistry for MockRegistry {
52
44
  self.adapter_calls.set(self.adapter_calls.get() + 1);
53
45
  crate::provider::get_adapter(_provider)
54
46
  }
55
- fn error_lists(&self, _provider: Provider) -> ErrorLists {
56
- self.error_list_calls.set(self.error_list_calls.get() + 1);
57
- ErrorLists {
58
- whitelist: self.whitelist.clone(),
59
- blacklist: self.blacklist.clone(),
60
- }
61
- }
62
47
  }
63
48
 
64
49
  /// in-memory `MarkerStore` —— durable marker 落盘探针。
@@ -260,45 +260,3 @@ fn p2_render_result_received_truncates_summary_to_80_chars() {
260
260
  "summary must be truncated to 80 chars"
261
261
  );
262
262
  }
263
-
264
- // P1 — idle_takeover.unknown_persistent must carry the auth_mode field (null when absent)
265
- // (lifecycle.py:401-408). NOTE: the variant currently lacks the field; the porter adds
266
- // `auth_mode` between provider and consecutive_ticks and updates this construction.
267
- #[test]
268
- fn p2_unknown_persistent_event_serializes_auth_mode_key() {
269
- let evt = CoordinatorEvent::IdleTakeoverUnknownPersistent {
270
- node_id: "w7".into(),
271
- provider: None,
272
- auth_mode: None,
273
- consecutive_ticks: 72,
274
- rollout_path: None,
275
- };
276
- let json = serde_json::to_value(&evt).unwrap();
277
- assert!(
278
- json.get("auth_mode").is_some(),
279
- "idle_takeover.unknown_persistent must serialize an auth_mode key (null when absent)"
280
- );
281
- }
282
-
283
- // P1 — process_abnormal_records matches a LOWERCASED signature too (abnormal_track.py:49,198):
284
- // raw has no needle but signature 'TimeoutError' matches blacklist 'timeout'. Current is
285
- // case-sensitive on `raw` only and ignores the signature → NotifyDefault.
286
- #[test]
287
- fn p2_abnormal_matches_lowercased_signature_too() {
288
- let reg = MockRegistry::new(&[], &["timeout"]);
289
- let records =
290
- vec![serde_json::json!({"raw":"nothing here","signature":"TimeoutError","kind":"error"})];
291
- let out = process_abnormal_records(
292
- &records,
293
- &reg,
294
- Provider::Codex,
295
- &AbnormalNotificationState::default(),
296
- )
297
- .unwrap();
298
- assert_eq!(out.notifications.len(), 1);
299
- assert_eq!(
300
- out.notifications[0].decision,
301
- AbnormalDecision::NotifyBlacklist,
302
- "blacklist 'timeout' must match the lowercased signature 'TimeoutError'"
303
- );
304
- }