code-coordinator 0.5.576__tar.gz → 0.5.578__tar.gz

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 (932) hide show
  1. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/PKG-INFO +1 -1
  2. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/PKG-INFO +1 -1
  3. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_version.json +2 -2
  4. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_github.py +10 -4
  5. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/server.py +50 -1
  6. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_queue.py +101 -0
  7. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/github_ops.py +103 -33
  8. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/github_throttle.py +199 -0
  9. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/merge_queue.py +51 -0
  10. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notify.py +115 -0
  11. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/conftest.py +27 -0
  12. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard.py +156 -0
  13. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue.py +151 -0
  14. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_github_ops.py +209 -0
  15. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_github_throttle.py +144 -0
  16. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_merge_queue.py +31 -0
  17. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stalled_pipeline.py +94 -0
  18. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/board.md +0 -0
  19. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/complete-session.md +0 -0
  20. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/coordinator.md +0 -0
  21. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/_lib.sh +0 -0
  22. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-checkout +0 -0
  23. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-commit +0 -0
  24. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-merge +0 -0
  25. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  26. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/coord-ci-acceptance.yml +0 -0
  27. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/auto-release.yml +0 -0
  28. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/publish.yml +0 -0
  29. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/test.yml +0 -0
  30. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.gitignore +0 -0
  31. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/CLAUDE.md +0 -0
  32. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/GOAL.md +0 -0
  33. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/LICENSE +0 -0
  34. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/MANIFEST.in +0 -0
  35. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/README.md +0 -0
  36. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/SOURCES.txt +0 -0
  37. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/dependency_links.txt +0 -0
  38. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/entry_points.txt +0 -0
  39. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/requires.txt +0 -0
  40. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_file_list.json +0 -0
  41. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/top_level.txt +0 -0
  42. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/__init__.py +0 -0
  43. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/_board_mapping.py +0 -0
  44. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/acceptance.py +0 -0
  45. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/acceptance_drivers.py +0 -0
  46. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent.py +0 -0
  47. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent_app.py +0 -0
  48. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent_update.py +0 -0
  49. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/.gitignore +0 -0
  50. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/agents/work.md +0 -0
  51. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/routing.jsonc +0 -0
  52. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/approved_work.py +0 -0
  53. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/audit.py +0 -0
  54. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/auto_loop.py +0 -0
  55. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/backup.py +0 -0
  56. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/block_log.py +0 -0
  57. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_schema.py +0 -0
  58. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_service.py +0 -0
  59. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_wire.py +0 -0
  60. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/brain.py +0 -0
  61. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/branch_model.py +0 -0
  62. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/bug_intake.py +0 -0
  63. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/bugbash.py +0 -0
  64. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/cargo_cache.py +0 -0
  65. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_fix.py +0 -0
  66. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_gitlab.py +0 -0
  67. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_store.py +0 -0
  68. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/claim.py +0 -0
  69. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/claude_setup_token.py +0 -0
  70. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/cli.py +0 -0
  71. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/client.py +0 -0
  72. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/codegen.py +0 -0
  73. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/__init__.py +0 -0
  74. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/_common.py +0 -0
  75. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/acceptance.py +0 -0
  76. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/agent_ops.py +0 -0
  77. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/audit.py +0 -0
  78. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/backup.py +0 -0
  79. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/bugbash.py +0 -0
  80. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/chat.py +0 -0
  81. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/ci.py +0 -0
  82. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/codegen.py +0 -0
  83. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dispatch.py +0 -0
  84. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dispatch_workers.py +0 -0
  85. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dr.py +0 -0
  86. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/drive.py +0 -0
  87. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/drive_queue.py +0 -0
  88. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/gate_a.py +0 -0
  89. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/gates.py +0 -0
  90. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/issues.py +0 -0
  91. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/lifecycle.py +0 -0
  92. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/machine.py +0 -0
  93. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/merge.py +0 -0
  94. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/milestone.py +0 -0
  95. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/plan_followup.py +0 -0
  96. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/plans.py +0 -0
  97. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/portal.py +0 -0
  98. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/pr.py +0 -0
  99. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/release.py +0 -0
  100. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/repo.py +0 -0
  101. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/report.py +0 -0
  102. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/review.py +0 -0
  103. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/scorecard.py +0 -0
  104. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/sessions.py +0 -0
  105. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/setup.py +0 -0
  106. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/status.py +0 -0
  107. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/store_migrate.py +0 -0
  108. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/terminal.py +0 -0
  109. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/test_gate.py +0 -0
  110. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/tui.py +0 -0
  111. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/comments.py +0 -0
  112. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/config.py +0 -0
  113. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/config_reload.py +0 -0
  114. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/confirm_test.py +0 -0
  115. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/conflict_fix.py +0 -0
  116. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dao.py +0 -0
  117. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/__init__.py +0 -0
  118. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/fixture.py +0 -0
  119. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/index.html +0 -0
  120. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/reports.html +0 -0
  121. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/terminal.py +0 -0
  122. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/db.py +0 -0
  123. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dead_end.py +0 -0
  124. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/decomposition_chat.py +0 -0
  125. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/README.md +0 -0
  126. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-agent.service +0 -0
  127. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-backup.service +0 -0
  128. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-backup.timer +0 -0
  129. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.service +0 -0
  130. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.sh +0 -0
  131. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.timer +0 -0
  132. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.service +0 -0
  133. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.timer +0 -0
  134. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.service +0 -0
  135. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.timer +0 -0
  136. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-failure-notify.service +0 -0
  137. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.service +0 -0
  138. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.timer +0 -0
  139. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-notify.service +0 -0
  140. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-notify.timer +0 -0
  141. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.service +0 -0
  142. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.timer +0 -0
  143. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.service +0 -0
  144. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.timer +0 -0
  145. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-serve.service +0 -0
  146. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.service +0 -0
  147. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.timer +0 -0
  148. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web.service +0 -0
  149. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy_manifest.py +0 -0
  150. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy_units.py +0 -0
  151. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deprecation_telemetry.py +0 -0
  152. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deps.py +0 -0
  153. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/diagnose.py +0 -0
  154. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dispatch.py +0 -0
  155. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dispatch_liveness.py +0 -0
  156. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dist_name.py +0 -0
  157. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dr_promote.py +0 -0
  158. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dr_verify.py +0 -0
  159. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive.py +0 -0
  160. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_sessions_snapshot.py +0 -0
  161. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_state.py +0 -0
  162. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/events.py +0 -0
  163. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/failure_class.py +0 -0
  164. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/failure_classifier.py +0 -0
  165. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/filelock.py +0 -0
  166. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/fleet_config_health.py +0 -0
  167. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/forge_availability.py +0 -0
  168. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/freshness.py +0 -0
  169. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_a.py +0 -0
  170. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_b.py +0 -0
  171. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_snapshot.py +0 -0
  172. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gates.py +0 -0
  173. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gen_board_fixture.py +0 -0
  174. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/goal.py +0 -0
  175. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/graph_health.py +0 -0
  176. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gtk_native_driver.py +0 -0
  177. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/__init__.py +0 -0
  178. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/aggregate.py +0 -0
  179. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/__init__.py +0 -0
  180. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/_ci_pin.py +0 -0
  181. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/agent_install.py +0 -0
  182. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/cargo_targets.py +0 -0
  183. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/claude_binary.py +0 -0
  184. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/config_drift.py +0 -0
  185. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/coord_tui_ci_pin.py +0 -0
  186. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/coord_web_ci_pin.py +0 -0
  187. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/deploy_lane_facts.py +0 -0
  188. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/disk.py +0 -0
  189. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_board.py +0 -0
  190. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_deploy_lanes.py +0 -0
  191. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_phantom.py +0 -0
  192. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_unit_drift.py +0 -0
  193. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/graph.py +0 -0
  194. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/graphify_cli.py +0 -0
  195. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/index_lock.py +0 -0
  196. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/issues_sync_staleness.py +0 -0
  197. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/local_machine_identity.py +0 -0
  198. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/plan_usage.py +0 -0
  199. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/pr_churn.py +0 -0
  200. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/release_cordon.py +0 -0
  201. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/repo_state.py +0 -0
  202. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/spawned_coord.py +0 -0
  203. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/stalled_pipeline.py +0 -0
  204. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/timer_active.py +0 -0
  205. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/toolchain.py +0 -0
  206. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/unit_drift.py +0 -0
  207. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/unit_enablement.py +0 -0
  208. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/wedged_drive_queue.py +0 -0
  209. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/worktrees.py +0 -0
  210. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/cli.py +0 -0
  211. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/context.py +0 -0
  212. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/fleet_snapshot.py +0 -0
  213. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/models.py +0 -0
  214. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/pypi.py +0 -0
  215. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/registry.py +0 -0
  216. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/render.py +0 -0
  217. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/units.py +0 -0
  218. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/hooks.py +0 -0
  219. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/housekeeping.py +0 -0
  220. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/interactive.py +0 -0
  221. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/invariant_alarms.py +0 -0
  222. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/issue_store.py +0 -0
  223. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/issues_sync_status.py +0 -0
  224. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/liveness_auditor.py +0 -0
  225. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/mac_native_driver.py +0 -0
  226. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_fault.py +0 -0
  227. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_metrics.py +0 -0
  228. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_onboard.py +0 -0
  229. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_pause.py +0 -0
  230. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_stats.py +0 -0
  231. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_chat.py +0 -0
  232. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_dispatch.py +0 -0
  233. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_gate.py +0 -0
  234. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_order.py +0 -0
  235. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/mock_author.py +0 -0
  236. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/models.py +0 -0
  237. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/network.py +0 -0
  238. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/new_issue_chat.py +0 -0
  239. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/__init__.py +0 -0
  240. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/baseline.py +0 -0
  241. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/cli.py +0 -0
  242. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/collect.py +0 -0
  243. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/digest.py +0 -0
  244. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/models.py +0 -0
  245. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/predicate.py +0 -0
  246. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/service.py +0 -0
  247. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/store.py +0 -0
  248. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/transport.py +0 -0
  249. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/openapi.py +0 -0
  250. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/overlap_fence.py +0 -0
  251. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/overlap_predict.py +0 -0
  252. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/parentage.py +0 -0
  253. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/parentage_github.py +0 -0
  254. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/pipeline.py +0 -0
  255. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/plan_parser.py +0 -0
  256. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/plans.py +0 -0
  257. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/platform_paths.py +0 -0
  258. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_bridge.py +0 -0
  259. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_store.py +0 -0
  260. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_sync.py +0 -0
  261. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/pr_body_lint.py +0 -0
  262. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/prereqs.py +0 -0
  263. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/progress.py +0 -0
  264. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/__init__.py +0 -0
  265. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/base.py +0 -0
  266. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/claude.py +0 -0
  267. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/claude_pty.py +0 -0
  268. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/opencode.py +0 -0
  269. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/queue_diagnose.py +0 -0
  270. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reconcile.py +0 -0
  271. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reconcile_tick.py +0 -0
  272. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/refine_chat.py +0 -0
  273. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_cordon.py +0 -0
  274. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_gate.py +0 -0
  275. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_propagate.py +0 -0
  276. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_verify.py +0 -0
  277. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_window.py +0 -0
  278. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_dormancy.py +0 -0
  279. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_edit.py +0 -0
  280. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_onboard.py +0 -0
  281. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reports.py +0 -0
  282. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/rest_schema.py +0 -0
  283. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/restart_cmd.py +0 -0
  284. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/revalidate.py +0 -0
  285. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/review.py +0 -0
  286. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/scorecard.py +0 -0
  287. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/self_health.py +0 -0
  288. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/serve_app.py +0 -0
  289. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/coord-dispatch-verbs/SKILL.md +0 -0
  290. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/drive-queue-preflight/SKILL.md +0 -0
  291. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/fleet-restart-safety/SKILL.md +0 -0
  292. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/merge-stuck-triage/SKILL.md +0 -0
  293. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/pipeline-limbo-triage/SKILL.md +0 -0
  294. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/portal-followup/SKILL.md +0 -0
  295. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/release-now/SKILL.md +0 -0
  296. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/review-verdict-recovery/SKILL.md +0 -0
  297. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/tui-quadraui-workflow/SKILL.md +0 -0
  298. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/update-issue/SKILL.md +0 -0
  299. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/smoke.py +0 -0
  300. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/smoke_tags.py +0 -0
  301. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/spend_ceiling.py +0 -0
  302. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/split_work.py +0 -0
  303. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/sql.py +0 -0
  304. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/stage_projection.py +0 -0
  305. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/state.py +0 -0
  306. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/store_migrate.py +0 -0
  307. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/store_parity.py +0 -0
  308. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/templates/deploy-cloudflare.node.yml +0 -0
  309. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_author.py +0 -0
  310. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_chat.py +0 -0
  311. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_orchestrator.py +0 -0
  312. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_report.py +0 -0
  313. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/tui_pty_driver.py +0 -0
  314. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/tui_release.py +0 -0
  315. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/uat_checks.py +0 -0
  316. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage.py +0 -0
  317. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage_limits.py +0 -0
  318. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage_rollup.py +0 -0
  319. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/win_native_bridge.py +0 -0
  320. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/win_native_driver.py +0 -0
  321. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/worker_events.py +0 -0
  322. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coordinator.example.yml +0 -0
  323. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-agent.service +0 -0
  324. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-backup.service +0 -0
  325. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-backup.timer +0 -0
  326. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.service +0 -0
  327. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.sh +0 -0
  328. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.timer +0 -0
  329. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-dr-verify.service +0 -0
  330. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-dr-verify.timer +0 -0
  331. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-drive-queue.service +0 -0
  332. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-drive-queue.timer +0 -0
  333. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-failure-notify.service +0 -0
  334. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-failure-notify.sh +0 -0
  335. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.service +0 -0
  336. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.timer +0 -0
  337. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-notify.service +0 -0
  338. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-notify.timer +0 -0
  339. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-propagate.service +0 -0
  340. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-propagate.timer +0 -0
  341. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-window.service +0 -0
  342. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-window.timer +0 -0
  343. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-serve.service +0 -0
  344. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.service +0 -0
  345. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.sh +0 -0
  346. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.timer +0 -0
  347. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-rollback.sh +0 -0
  348. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web.service +0 -0
  349. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/node-shim.sh +0 -0
  350. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_TUI_CI.md +0 -0
  351. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_ACCEPTANCE_SUITE.md +0 -0
  352. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_CI.md +0 -0
  353. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_DIST.md +0 -0
  354. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_PY_RUST_MIRRORS.md +0 -0
  355. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/AGENT_OPERATIONS.md +0 -0
  356. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ARCHITECTURE.md +0 -0
  357. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ARCH_SECURITY_GATES.md +0 -0
  358. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/COCKPIT.md +0 -0
  359. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CONTROL_CENTER.md +0 -0
  360. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/COST_DISCIPLINE.md +0 -0
  361. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CROSS_PLATFORM.md +0 -0
  362. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CUSTOMER_FACING_APPS.md +0 -0
  363. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CUSTOMER_PORTAL.md +0 -0
  364. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DATA_STORE_SELECTION.md +0 -0
  365. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DISASTER_RECOVERY.md +0 -0
  366. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DRIVE_QUEUE.md +0 -0
  367. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/EPHEMERAL_WORKERS.md +0 -0
  368. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/FORGE_MIGRATION.md +0 -0
  369. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/GRAPHIFY_SETUP.md +0 -0
  370. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ISSUE_GUIDANCE.md +0 -0
  371. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/MAC_MINI.md +0 -0
  372. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/MERGE_AUTO_DRAIN_TRUST_BAR.md +0 -0
  373. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/NOTIFIER.md +0 -0
  374. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPENCODE_VERIFICATION.md +0 -0
  375. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPERATING_GOTCHAS.md +0 -0
  376. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPERATOR_GUIDES.md +0 -0
  377. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ORACLE_LOOP.md +0 -0
  378. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PHONE_WEBAPP.md +0 -0
  379. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PIPELINE_V2.md +0 -0
  380. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PLATFORM_EVOLUTION.md +0 -0
  381. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/SECOND_BACKEND.md +0 -0
  382. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/STORE_SERVICE.md +0 -0
  383. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/TEST_FIRST_BUG_LANE.md +0 -0
  384. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/WEB_CONTROL_CENTER.md +0 -0
  385. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/WSL_WINDOWS_WORKER.md +0 -0
  386. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/README.md +0 -0
  387. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/_tokens.css +0 -0
  388. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/issue-detail.html +0 -0
  389. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-narrow.html +0 -0
  390. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-wide.html +0 -0
  391. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/graphify-out/.gitignore +0 -0
  392. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/install-agent.sh +0 -0
  393. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/pyproject.toml +0 -0
  394. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/audit_review_verdict_overrides.py +0 -0
  395. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/bootstrap-shared.sh +0 -0
  396. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/build-worker-image.sh +0 -0
  397. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/coordinator-machine.py +0 -0
  398. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/dr-down.sh +0 -0
  399. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/dr-up.sh +0 -0
  400. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/epic-down.sh +0 -0
  401. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/epic-up.sh +0 -0
  402. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/preflight.sh +0 -0
  403. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/provision-server.sh +0 -0
  404. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/provision-worker.sh +0 -0
  405. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/scrub-and-generalize.sh +0 -0
  406. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/tailnet-acl.hujson +0 -0
  407. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/throwaway-vm.sh +0 -0
  408. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/verify-github-token.sh +0 -0
  409. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/check_gh_argv_containment.py +0 -0
  410. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/codegen.py +0 -0
  411. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-test-runner.sh +0 -0
  412. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/coord-ci-acceptance.yml +0 -0
  413. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/cargo-test.yml +0 -0
  414. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/codegen-drift.yml +0 -0
  415. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/CLAUDE.md +0 -0
  416. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-venv-rollback.sh +0 -0
  417. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/drive-batch.sh +0 -0
  418. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/extract-coord-tui.sh +0 -0
  419. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/fleet_watchdog.py +0 -0
  420. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/gen_board_fixture.py +0 -0
  421. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/gen_mock_index.py +0 -0
  422. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/lib/provision-core.sh +0 -0
  423. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/next_release_tag.py +0 -0
  424. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/provision-machine.sh +0 -0
  425. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/run_tests_in_populated_home.sh +0 -0
  426. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/run_tests_without_gh.sh +0 -0
  427. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/setup-macmini.sh +0 -0
  428. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/smoke_437_interactive.py +0 -0
  429. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify-provision-noble.sh +0 -0
  430. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_878_review_capture.py +0 -0
  431. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_release_published.py +0 -0
  432. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_release_wheel.py +0 -0
  433. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/setup.cfg +0 -0
  434. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/SMOKE_SET.md +0 -0
  435. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/__init__.py +0 -0
  436. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/conftest.py +0 -0
  437. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/contract.md +0 -0
  438. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/manifest.yml +0 -0
  439. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_cli_1115.py +0 -0
  440. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_core_1118.py +0 -0
  441. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/contract.md +0 -0
  442. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active-extended.spec.ts +0 -0
  443. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active.spec.ts +0 -0
  444. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/manifest.yml +0 -0
  445. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/mocks/home-active.html +0 -0
  446. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/tsconfig.json +0 -0
  447. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-example/mocks/home-active.html +0 -0
  448. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/backends.py +0 -0
  449. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-basic.json +0 -0
  450. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-terminal-gates.json +0 -0
  451. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_failure_sample.jsonl +0 -0
  452. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_length_sample.jsonl +0 -0
  453. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_sample.jsonl +0 -0
  454. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/all_pass.json +0 -0
  455. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/global_setup_crash.json +0 -0
  456. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/mixed_fail.json +0 -0
  457. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.json +0 -0
  458. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.junit.xml +0 -0
  459. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/skip.json +0 -0
  460. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/truncated.json +0 -0
  461. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_compile_error.txt +0 -0
  462. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_multi_target_failures.txt +0 -0
  463. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_no_parseable_failures.txt +0 -0
  464. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_collection_error.txt +0 -0
  465. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_log_record.txt +0 -0
  466. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_string_in_body.txt +0 -0
  467. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_internal_error.txt +0 -0
  468. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_mixed_failures.txt +0 -0
  469. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_no_parseable_failures.txt +0 -0
  470. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_acceptance.py +0 -0
  471. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_acceptance_drivers.py +0 -0
  472. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent.py +0 -0
  473. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_api_error.py +0 -0
  474. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_app.py +0 -0
  475. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_branch_base.py +0 -0
  476. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_branch_capture.py +0 -0
  477. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_config_free_1712.py +0 -0
  478. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_deploy_units_endpoint.py +0 -0
  479. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_dirty_worktree.py +0 -0
  480. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_drive_queue_reconcile_2373.py +0 -0
  481. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_graph_self_heal.py +0 -0
  482. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_health_h3.py +0 -0
  483. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_idle_restart.py +0 -0
  484. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_push_failure.py +0 -0
  485. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_reap.py +0 -0
  486. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_repos_and_pull.py +0 -0
  487. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_restart_services_endpoint.py +0 -0
  488. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_skills_self_heal.py +0 -0
  489. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_startup_diagnostics.py +0 -0
  490. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_update.py +0 -0
  491. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_update_bluegreen.py +0 -0
  492. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_usage_limit.py +0 -0
  493. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_zero_commit.py +0 -0
  494. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ambient_home_isolation.py +0 -0
  495. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_capability_reroute_3241.py +0 -0
  496. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_dependency_busy_2804.py +0 -0
  497. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_reject_plan.py +0 -0
  498. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_usage_gate.py +0 -0
  499. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approved_work_2532.py +0 -0
  500. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approved_work_2996.py +0 -0
  501. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_assignment_already_recorded_daemon.py +0 -0
  502. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_log.py +0 -0
  503. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_outcome.py +0 -0
  504. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_query.py +0 -0
  505. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_auto_loop.py +0 -0
  506. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_auto_release_publish_2035.py +0 -0
  507. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_backend_selection.py +0 -0
  508. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_backup.py +0 -0
  509. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_base_checkout_restore.py +0 -0
  510. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_block_log.py +0 -0
  511. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_cap_762.py +0 -0
  512. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_fixture.py +0 -0
  513. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_read_path.py +0 -0
  514. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_schema.py +0 -0
  515. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_service.py +0 -0
  516. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_state.py +0 -0
  517. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_wire.py +0 -0
  518. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_brain.py +0 -0
  519. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_branch_model.py +0 -0
  520. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_bug_intake.py +0 -0
  521. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_bugbash.py +0 -0
  522. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_build_worker_image_env_update.py +0 -0
  523. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cargo_cache.py +0 -0
  524. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_check_gh_argv_containment.py +0 -0
  525. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_acceptance_gate_1950.py +0 -0
  526. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_fix.py +0 -0
  527. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_github.py +0 -0
  528. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_gitlab.py +0 -0
  529. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_parity_2091.py +0 -0
  530. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_store.py +0 -0
  531. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claim.py +0 -0
  532. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claude_md_budget.py +0 -0
  533. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claude_setup_token.py +0 -0
  534. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_acceptance.py +0 -0
  535. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign.py +0 -0
  536. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_oracle_gate.py +0 -0
  537. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_remote.py +0 -0
  538. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_provider.py +0 -0
  539. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_repo_drift_2219.py +0 -0
  540. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_audit.py +0 -0
  541. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_chat_continue.py +0 -0
  542. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_ci.py +0 -0
  543. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_codegen.py +0 -0
  544. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_decide.py +0 -0
  545. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_capability_rules.py +0 -0
  546. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_config_provenance.py +0 -0
  547. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_forge_availability.py +0 -0
  548. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_graph.py +0 -0
  549. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_self.py +0 -0
  550. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_test_coverage.py +0 -0
  551. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor.py +0 -0
  552. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_free_1801.py +0 -0
  553. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_mismatch_1712.py +0 -0
  554. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_store_backend_3084.py +0 -0
  555. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_drive.py +0 -0
  556. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_drive_queue.py +0 -0
  557. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_escalate.py +0 -0
  558. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_fix_headless_review.py +0 -0
  559. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_gate_a.py +0 -0
  560. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_install_drift.py +0 -0
  561. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_install_skills.py +0 -0
  562. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_comment.py +0 -0
  563. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_create_label.py +0 -0
  564. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_reopen.py +0 -0
  565. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_view_list.py +0 -0
  566. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issues.py +0 -0
  567. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_merge.py +0 -0
  568. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_assign.py +0 -0
  569. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_capture.py +0 -0
  570. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_chat_add_child.py +0 -0
  571. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_dispatch.py +0 -0
  572. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_b.py +0 -0
  573. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_c.py +0 -0
  574. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_order.py +0 -0
  575. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_remove_and_issue_close.py +0 -0
  576. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_ship.py +0 -0
  577. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_network.py +0 -0
  578. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_new_issue_chat.py +0 -0
  579. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_plans.py +0 -0
  580. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_portal.py +0 -0
  581. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_pr.py +0 -0
  582. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_pull_artifact.py +0 -0
  583. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_queue.py +0 -0
  584. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_reattach_sessions.py +0 -0
  585. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_refine_board.py +0 -0
  586. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_preflight.py +0 -0
  587. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_propagate.py +0 -0
  588. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_window.py +0 -0
  589. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_repo_2220.py +0 -0
  590. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_review_test_author_tracking_epic_2639.py +0 -0
  591. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_scorecard.py +0 -0
  592. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_serve_store_backend_3084.py +0 -0
  593. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_set_review_findings.py +0 -0
  594. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_advisory_terminal.py +0 -0
  595. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_contested_tag.py +0 -0
  596. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_invariant_alarms.py +0 -0
  597. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_machine_fault.py +0 -0
  598. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_merge_queue.py +0 -0
  599. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_provider.py +0 -0
  600. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_retried_3340.py +0 -0
  601. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_review_finalizing.py +0 -0
  602. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_supervisor_3366.py +0 -0
  603. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_test_failed_tag.py +0 -0
  604. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_usage_limit.py +0 -0
  605. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_sync_comments_873.py +0 -0
  606. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_test_plan.py +0 -0
  607. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_track.py +0 -0
  608. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_tui_update.py +0 -0
  609. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_wait.py +0 -0
  610. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client.py +0 -0
  611. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_base_install.py +0 -0
  612. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_config_cache_atomic_3052.py +0 -0
  613. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_resource_migration_1946.py +0 -0
  614. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_commands_common.py +0 -0
  615. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_comments.py +0 -0
  616. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_completion_summary.py +0 -0
  617. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config.py +0 -0
  618. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_acceptance.py +0 -0
  619. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_audit.py +0 -0
  620. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_drift_check.py +0 -0
  621. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_effective.py +0 -0
  622. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_pricing.py +0 -0
  623. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_snapshot_noncanonical_2208.py +0 -0
  624. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_usage_gate.py +0 -0
  625. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_confirm_test.py +0 -0
  626. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_conflict_fix.py +0 -0
  627. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_conflict_fix_semantic.py +0 -0
  628. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_log_daemon_fallback_2547.py +0 -0
  629. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test.py +0 -0
  630. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_acceptance_toolchain_2936.py +0 -0
  631. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_baseline.py +0 -0
  632. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_populated_home.py +0 -0
  633. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_routing.py +0 -0
  634. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_toolchain.py +0 -0
  635. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_uat.py +0 -0
  636. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_web_sse_restart_live.py +0 -0
  637. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coordinator_machine.py +0 -0
  638. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cross_platform_imports.py +0 -0
  639. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dao.py +0 -0
  640. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_api.py +0 -0
  641. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_fixture.py +0 -0
  642. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_reports.py +0 -0
  643. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_server.py +0 -0
  644. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_terminal.py +0 -0
  645. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_terminal_live.py +0 -0
  646. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_db.py +0 -0
  647. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dead_end.py +0 -0
  648. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_decomposition_chat.py +0 -0
  649. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_db_backup.py +0 -0
  650. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_dist.py +0 -0
  651. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_rollback.py +0 -0
  652. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_db_backup_unit.py +0 -0
  653. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_drive_queue_unit.py +0 -0
  654. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_failure_notify_unit.py +0 -0
  655. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_manifest.py +0 -0
  656. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_notify_unit.py +0 -0
  657. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_units_lane.py +0 -0
  658. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_web_unit.py +0 -0
  659. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deprecation_telemetry.py +0 -0
  660. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deps.py +0 -0
  661. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_diagnose.py +0 -0
  662. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch.py +0 -0
  663. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_liveness.py +0 -0
  664. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_target_validation.py +0 -0
  665. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_workers.py +0 -0
  666. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dist_name.py +0 -0
  667. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_done_housekeeping.py +0 -0
  668. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_azure_scripts.py +0 -0
  669. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_promote.py +0 -0
  670. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_verify.py +0 -0
  671. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive.py +0 -0
  672. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_machine_fault.py +0 -0
  673. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_blocked_rendering.py +0 -0
  674. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_launch_argv.py +0 -0
  675. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_config.py +0 -0
  676. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_per_repo_config.py +0 -0
  677. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_roll_pending.py +0 -0
  678. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_self_cordon_escalation.py +0 -0
  679. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_sessions_snapshot.py +0 -0
  680. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_state.py +0 -0
  681. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_tmux.py +0 -0
  682. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_capability_detection.py +0 -0
  683. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_down_symlinked_config_1887.py +0 -0
  684. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_image_provenance.py +0 -0
  685. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_errors.py +0 -0
  686. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_events.py +0 -0
  687. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_failure_class.py +0 -0
  688. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_failure_classifier.py +0 -0
  689. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_filelock.py +0 -0
  690. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_finalize_interactive_exit_test_verdict.py +0 -0
  691. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fix_escalation_classifier.py +0 -0
  692. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fix_of_force_override.py +0 -0
  693. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_config_health.py +0 -0
  694. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_health_probes.py +0 -0
  695. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_health_snapshot.py +0 -0
  696. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_watchdog.py +0 -0
  697. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_forge_availability.py +0 -0
  698. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_freshness.py +0 -0
  699. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_a.py +0 -0
  700. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_b.py +0 -0
  701. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_snapshot_staleness.py +0 -0
  702. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gates.py +0 -0
  703. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gather_fleet_tmux_sessions.py +0 -0
  704. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gen_mock_index.py +0 -0
  705. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_rust_fixture.py +0 -0
  706. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_rust_requests.py +0 -0
  707. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_types_fixture.py +0 -0
  708. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_goal.py +0 -0
  709. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_graph_health.py +0 -0
  710. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_graph_selfheal_absent_2237.py +0 -0
  711. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gtk_native_driver.py +0 -0
  712. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_handoff.py +0 -0
  713. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_checks.py +0 -0
  714. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_cli.py +0 -0
  715. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_cli_graph.py +0 -0
  716. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_config.py +0 -0
  717. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_context.py +0 -0
  718. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_coord_tui_ci_pin.py +0 -0
  719. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_coord_web_ci_pin.py +0 -0
  720. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_deploy_lane_facts.py +0 -0
  721. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_fix.py +0 -0
  722. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_incident_regression.py +0 -0
  723. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_issues_sync_staleness.py +0 -0
  724. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_pr_churn.py +0 -0
  725. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_pypi.py +0 -0
  726. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_registry.py +0 -0
  727. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_release_cordon_probe.py +0 -0
  728. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_timer_active.py +0 -0
  729. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_toolchain.py +0 -0
  730. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_unit_drift.py +0 -0
  731. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_unit_enablement.py +0 -0
  732. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_wedged_drive_queue.py +0 -0
  733. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_hooks.py +0 -0
  734. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_housekeeping.py +0 -0
  735. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_human_attended_437.py +0 -0
  736. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_init.py +0 -0
  737. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_capabilities_3515.py +0 -0
  738. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_venv_2911.py +0 -0
  739. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_wsl_bridge_3515.py +0 -0
  740. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_integration.py +0 -0
  741. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive.py +0 -0
  742. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_briefing_echo.py +0 -0
  743. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_pane_log_2541.py +0 -0
  744. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_prefill_state.py +0 -0
  745. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_session_relaunch.py +0 -0
  746. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_test_verdict_backstop.py +0 -0
  747. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_token_attribution.py +0 -0
  748. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_worktree.py +0 -0
  749. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_invariant_alarms.py +0 -0
  750. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_issue_store_seam.py +0 -0
  751. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_issues_sync_status.py +0 -0
  752. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_liveness_auditor.py +0 -0
  753. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_liveness_notify.py +0 -0
  754. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_lock_contention_ratchet.py +0 -0
  755. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_mac_native_driver.py +0 -0
  756. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_fault.py +0 -0
  757. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_metrics.py +0 -0
  758. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_onboard.py +0 -0
  759. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_pause.py +0 -0
  760. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_stats.py +0 -0
  761. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_merge_verify.py +0 -0
  762. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_chat.py +0 -0
  763. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_dispatch.py +0 -0
  764. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_gate.py +0 -0
  765. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_order.py +0 -0
  766. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_seam.py +0 -0
  767. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_mock_author.py +0 -0
  768. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_model_tiering.py +0 -0
  769. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_models.py +0 -0
  770. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_models_config_labels.py +0 -0
  771. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_needs_attention.py +0 -0
  772. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_network.py +0 -0
  773. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_new_issue_chat.py +0 -0
  774. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_next_release_tag.py +0 -0
  775. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_node_shim.py +0 -0
  776. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_baseline.py +0 -0
  777. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_cli.py +0 -0
  778. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_collect.py +0 -0
  779. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_config.py +0 -0
  780. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_drive_seam.py +0 -0
  781. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_isolation.py +0 -0
  782. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_predicate.py +0 -0
  783. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_quiet_hours.py +0 -0
  784. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_service.py +0 -0
  785. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notify.py +0 -0
  786. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notify_drain.py +0 -0
  787. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_openapi.py +0 -0
  788. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_operational_defaults.py +0 -0
  789. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_overlap_fence.py +0 -0
  790. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_overlap_predict.py +0 -0
  791. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_packaged_deploy_units.py +0 -0
  792. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_parentage.py +0 -0
  793. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_paste_landed.py +0 -0
  794. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_phantom_heal_venv_independence_2570.py +0 -0
  795. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_pipeline.py +0 -0
  796. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_approve_plan_command.py +0 -0
  797. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_pr_command.py +0 -0
  798. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_review_command.py +0 -0
  799. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_only.py +0 -0
  800. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_parser.py +0 -0
  801. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_platform_paths.py +0 -0
  802. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_bridge.py +0 -0
  803. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_config.py +0 -0
  804. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_store.py +0 -0
  805. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_sync.py +0 -0
  806. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_pr_body_lint.py +0 -0
  807. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_prereqs.py +0 -0
  808. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_production_db_guard.py +0 -0
  809. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_progress.py +0 -0
  810. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provider_seam.py +0 -0
  811. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers.py +0 -0
  812. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers_config_labels.py +0 -0
  813. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers_pty.py +0 -0
  814. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provision_core.py +0 -0
  815. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provision_machine.py +0 -0
  816. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_py_rust_mirror_inventory.py +0 -0
  817. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_quiet_hours.py +0 -0
  818. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_quiet_hours_store_2146.py +0 -0
  819. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reap_merged_sessions.py +0 -0
  820. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reap_stale_interactive_tick.py +0 -0
  821. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile.py +0 -0
  822. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_branch.py +0 -0
  823. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_completions.py +0 -0
  824. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_late_agent_reports_2547.py +0 -0
  825. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_merges.py +0 -0
  826. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_no_agent_record.py +0 -0
  827. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_tick.py +0 -0
  828. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_usage_limit_done.py +0 -0
  829. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_refine_chat.py +0 -0
  830. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_2101.py +0 -0
  831. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_daemon_leads_2176.py +0 -0
  832. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_deadlock_2240.py +0 -0
  833. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_drain_stall_3336.py +0 -0
  834. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_stuck_2490.py +0 -0
  835. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_gate.py +0 -0
  836. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_propagate.py +0 -0
  837. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_propagate_threshold.py +0 -0
  838. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_roll_between_legs_2854.py +0 -0
  839. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_roll_window_handoff.py +0 -0
  840. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_unified_1242.py +0 -0
  841. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_verify.py +0 -0
  842. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_window.py +0 -0
  843. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_remote_auto_prune.py +0 -0
  844. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_remote_interactive_reaper.py +0 -0
  845. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_add.py +0 -0
  846. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_dormancy.py +0 -0
  847. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_edit_2220.py +0 -0
  848. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_graph_fleet_2237.py +0 -0
  849. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_max_parallel_3423.py +0 -0
  850. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_onboard_2220.py +0 -0
  851. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_report_public_export.py +0 -0
  852. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_report_result_push.py +0 -0
  853. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reports.py +0 -0
  854. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_restart_cmd.py +0 -0
  855. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry.py +0 -0
  856. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_advisory_1606.py +0 -0
  857. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_escalation_classify_3360.py +0 -0
  858. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_type_1636.py +0 -0
  859. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_revalidate.py +0 -0
  860. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review.py +0 -0
  861. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_end_review_without_verdict.py +0 -0
  862. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_parse_failure_diagnostic.py +0 -0
  863. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_reaffirm.py +0 -0
  864. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_state.py +0 -0
  865. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_backstop.py +0 -0
  866. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_override_audit.py +0 -0
  867. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_relay.py +0 -0
  868. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_zero_commits.py +0 -0
  869. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_scoped_review_wiring.py +0 -0
  870. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_scorecard.py +0 -0
  871. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_self_health.py +0 -0
  872. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve.py +0 -0
  873. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_app.py +0 -0
  874. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_app_board_trim.py +0 -0
  875. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_rest_routes.py +0 -0
  876. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_session.py +0 -0
  877. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_slice_issue_attribution.py +0 -0
  878. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke.py +0 -0
  879. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_fanout_manifest_3333.py +0 -0
  880. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_live_checkout_restore.py +0 -0
  881. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_workflow.py +0 -0
  882. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_spend_ceiling.py +0 -0
  883. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_spend_ceiling_coordinator.py +0 -0
  884. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_split.py +0 -0
  885. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_split_work.py +0 -0
  886. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_sql_dialect.py +0 -0
  887. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_sqlite_connect_ratchet.py +0 -0
  888. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stage_projection.py +0 -0
  889. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stale_busy_reviewer_697.py +0 -0
  890. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_state.py +0 -0
  891. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_state_review_findings_daemon.py +0 -0
  892. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_status_fleet_footer.py +0 -0
  893. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stop_1567.py +0 -0
  894. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_store_contract.py +0 -0
  895. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_store_migrate.py +0 -0
  896. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stuck.py +0 -0
  897. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stuck_test_state_watchdog_2803.py +0 -0
  898. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_terminal_command.py +0 -0
  899. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_author.py +0 -0
  900. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_chat.py +0 -0
  901. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_orchestrator.py +0 -0
  902. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_report.py +0 -0
  903. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_verdict_parsing.py +0 -0
  904. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_verdict_transcript_floor.py +0 -0
  905. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_text_io_encoding_audit.py +0 -0
  906. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_board_audit.py +0 -0
  907. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_config_load_1080.py +0 -0
  908. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_daemon_routing_906.py +0 -0
  909. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_throwaway_vm.py +0 -0
  910. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tmux_host.py +0 -0
  911. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tmux_session.py +0 -0
  912. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_transcript_floor.py +0 -0
  913. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tui_pty_driver.py +0 -0
  914. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_uat_checks.py +0 -0
  915. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage.py +0 -0
  916. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage_limits.py +0 -0
  917. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage_rollup.py +0 -0
  918. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_venv_live_install_2121.py +0 -0
  919. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_version_single_source.py +0 -0
  920. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_watch.py +0 -0
  921. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_win_native_bridge.py +0 -0
  922. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_win_native_driver.py +0 -0
  923. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_windows_job_is_a_real_gate_2000.py +0 -0
  924. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_env_venv_isolation.py +0 -0
  925. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_events.py +0 -0
  926. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_image_pin_sync.py +0 -0
  927. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_safety.py +0 -0
  928. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_test_scoping.py +0 -0
  929. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worktree.py +0 -0
  930. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worktree_rmtree_chokepoint.py +0 -0
  931. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_write_parity.py +0 -0
  932. {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/write_parity.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-coordinator
3
- Version: 0.5.576
3
+ Version: 0.5.578
4
4
  Summary: Coordinate Claude Code workers across multiple machines and repos.
5
5
  Author-email: John Donaghy <johnfdonaghy@gmail.com>
6
6
  License-Expression: LicenseRef-FSL-1.1-MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-coordinator
3
- Version: 0.5.576
3
+ Version: 0.5.578
4
4
  Summary: Coordinate Claude Code workers across multiple machines and repos.
5
5
  Author-email: John Donaghy <johnfdonaghy@gmail.com>
6
6
  License-Expression: LicenseRef-FSL-1.1-MIT
@@ -1,7 +1,7 @@
1
1
  {
2
- "tag": "0.5.576",
2
+ "tag": "0.5.578",
3
3
  "distance": 0,
4
- "node": "g3da50042b74f92cdac51303b6f3672b6568b1a02",
4
+ "node": "g27497ebf63627571d2a865a710e3c9c502a8053d",
5
5
  "dirty": false,
6
6
  "branch": "HEAD",
7
7
  "node_date": "2026-10-03"
@@ -797,10 +797,16 @@ class GitHubCi:
797
797
  # out to `gh pr checks` directly (a non-zero exit there can still
798
798
  # carry usable JSON on stdout, which `_gh()`'s raise-on-nonzero
799
799
  # contract can't express, see `get_pr_checks`'s own docstring) — so
800
- # this call is the *only* forge-availability observation this read
801
- # produces. It stands alone, not "layered on top" of anything.
802
- # Only fires on a real cache miss — a cached `list_checks_for_pr`
803
- # hit never reaches here, so this costs nothing extra either.
800
+ # the `record_ci_check_fetch` call below is the only *CI-outcome*
801
+ # observation this read produces: the distribution of pass/fail/
802
+ # pending per check. (#3536 review follow-up: `get_pr_checks` itself
803
+ # now also feeds the generic, caller-attributed `record_gh_call` seam
804
+ # and the shared `github_throttle` pacing/backoff — same as every
805
+ # `_gh()`-backed call — so this is no longer the *only*
806
+ # forge-availability signal the read produces, just the only
807
+ # CI-specific one.) Only fires on a real cache miss — a cached
808
+ # `list_checks_for_pr` hit never reaches here, so this costs nothing
809
+ # extra either.
804
810
  _t0 = time.monotonic()
805
811
  try:
806
812
  raw = github_ops.get_pr_checks(repo, number)
@@ -634,6 +634,29 @@ _SESSIONS_SLOW_THRESHOLD = 3.0 # seconds; a healthy sweep is normally <1s
634
634
  # on every ~4s dashboard poll.
635
635
  _SESSIONS_COOLDOWN = 20.0 # seconds before a down machine is re-probed
636
636
 
637
+ # #1228: belt-and-suspenders hard cap on each per-machine sweep *future*,
638
+ # applied by api_sessions itself via `asyncio.wait_for` rather than trusted
639
+ # to `list_coord_tmux_sessions`'s internal `subprocess.run(timeout=5.0)`.
640
+ # #1217 iteration 2 assumed that internal timeout bounded every sweep to
641
+ # ~5-6s worst case, but a live smoke test measured a >60s (12x) overrun
642
+ # against a real offline machine and the root cause was never confirmed —
643
+ # a same-night diagnostic session could only reproduce fast (<1s) ssh
644
+ # rejections, not a genuine hang, against that machine. A deterministic
645
+ # repro against a TEST-NET-1 (192.0.2.0/24, RFC 5737) address — guaranteed
646
+ # non-routable, no DNS/auth involved — shows `ssh -o BatchMode=yes -o
647
+ # ConnectTimeout=4` (with or without this codebase's `_SSH_MUX_OPTS`
648
+ # ControlMaster options) and Python's own `subprocess.run(timeout=5.0)`
649
+ # wrapping it BOTH bound correctly to ~4s against a genuinely packet-dropped
650
+ # host (see TestSessionsHardTimeout / the ssh timing note in
651
+ # tests/test_dashboard.py) — so neither hypothesis in the issue reproduces
652
+ # here. Since the real overrun's cause is still unconfirmed, this endpoint
653
+ # no longer trusts any upstream timeout at all: whatever the per-machine
654
+ # sweep future does, `api_sessions` itself gives up on it after this many
655
+ # seconds and reports that machine as empty for this poll (and starts its
656
+ # offline cooldown), so one bad host can never stall the response past this
657
+ # bound regardless of what's actually slow underneath.
658
+ _SESSIONS_HARD_TIMEOUT = 6.0 # seconds; event-loop-side cap per machine
659
+
637
660
  # #2066: PipelineView.current_stage values that represent genuinely finished
638
661
  # work with no pending action — safe for api_pipeline's recency cutoff to age
639
662
  # out. Every other current_stage ("coding", "review_running", "review_done",
@@ -3343,6 +3366,17 @@ def build_app(
3343
3366
  (see the comment above ``_sessions_executor``'s definition for why:
3344
3367
  #1217 iteration 1 fixed a dashboard-wide hang caused by exactly this
3345
3368
  fan-out saturating the process's shared default executor).
3369
+
3370
+ #1228: ``list_coord_tmux_sessions``'s internal 5s ``subprocess.run``
3371
+ timeout is treated as unverified, not trusted — a live smoke test
3372
+ of iteration 2 measured a >60s overrun against a real offline
3373
+ machine with the root cause never confirmed. Each per-machine sweep
3374
+ future is additionally wrapped in ``asyncio.wait_for(...,
3375
+ timeout=_SESSIONS_HARD_TIMEOUT)`` so this endpoint itself gives up
3376
+ on a stalled sweep regardless of what's slow underneath (the
3377
+ in-flight thread keeps running to completion in the background —
3378
+ ``asyncio.wait_for`` cannot cancel a blocking OS thread — but the
3379
+ request no longer waits on it).
3346
3380
  """
3347
3381
  if _fixture is not None:
3348
3382
  # Seeded roster — no tmux, no ssh fan-out in fixture mode.
@@ -3386,6 +3420,21 @@ def build_app(
3386
3420
  async def _cached_empty(machine, is_local):
3387
3421
  return machine, [], is_local
3388
3422
 
3423
+ async def _bounded_sweep(machine, is_local):
3424
+ # #1228: `asyncio.wait_for` bounds how long THIS request waits
3425
+ # on the sweep — it cannot cancel the underlying OS thread, so
3426
+ # on timeout the thread keeps running in `_sessions_executor` to
3427
+ # completion (and its result, when it eventually lands, is just
3428
+ # discarded). That's an acceptable trade for never letting one
3429
+ # stalled host block the response past `_SESSIONS_HARD_TIMEOUT`.
3430
+ future = loop.run_in_executor(_sessions_executor, _sweep_one, machine)
3431
+ try:
3432
+ return await asyncio.wait_for(future, timeout=_SESSIONS_HARD_TIMEOUT)
3433
+ except asyncio.TimeoutError:
3434
+ if not is_local:
3435
+ _sessions_offline_since[machine.name] = time.monotonic()
3436
+ return machine, [], is_local
3437
+
3389
3438
  tasks = []
3390
3439
  for m in config.machines:
3391
3440
  is_local = _is_local_machine(m)
@@ -3397,7 +3446,7 @@ def build_app(
3397
3446
  ):
3398
3447
  tasks.append(_cached_empty(m, is_local))
3399
3448
  else:
3400
- tasks.append(loop.run_in_executor(_sessions_executor, _sweep_one, m))
3449
+ tasks.append(_bounded_sweep(m, is_local))
3401
3450
 
3402
3451
  sweeps = await asyncio.gather(*tasks)
3403
3452
  # Local host(s) first so they win any session-name collision, matching
@@ -438,6 +438,25 @@ def is_permanent_block_reason(text: str | None) -> bool:
438
438
  # the ceiling is reached.
439
439
  MAX_BLOCKED_RESUMES = 3
440
440
 
441
+ # #3536: default cap on how many CONFIRMED-CLEAR `blocked`-entry resumes/
442
+ # merge-only releases one `plan_tick` call grants per repo, from EITHER
443
+ # `_reconcile_blocked`'s gate-clear check (#2230) or `_reconcile_blocked_
444
+ # after`'s `after=` prereq-chain resume (#2362/#2756) -- a latch clearing
445
+ # for a whole repo's worth of `blocked` rows at once (#3386's baseline-red
446
+ # gate, cleared by #3532) and a single landed prereq clearing every row
447
+ # chained `--after` it are the SAME synchronized-poll shape, so both count
448
+ # against one cap. Either one otherwise releases every row on the SAME
449
+ # tick -- each then driving its own live `gh` re-checks on the very next
450
+ # poll, which is exactly the pattern that trips GitHub's secondary rate
451
+ # limit fleet-wide (the 2026-10-02 incident). 2 is deliberately small:
452
+ # large enough that a single or double blocked entry (the overwhelming
453
+ # common case, and every pre-#3536 test fixture) still resumes in the same
454
+ # tick it clears, small enough that a dozen-row mass clear spreads over
455
+ # several ticks instead of one. `None`/`0` disables the cap entirely
456
+ # (unstaggered, pre-#3536 behaviour) — see `plan_tick`'s
457
+ # `max_resumes_per_tick_per_repo` parameter.
458
+ DEFAULT_MAX_RESUMES_PER_TICK_PER_REPO = 2
459
+
441
460
  # ── deploy-gate states (#1757) ───────────────────────────────────────────────
442
461
  #
443
462
  # `hold_state` is the gate's LIFECYCLE, orthogonal to the entry's queue
@@ -2524,6 +2543,17 @@ class Reconcile:
2524
2543
  see :func:`coord.commands.drive_queue._run_merge_only_candidates`),
2525
2544
  which is why this Reconcile's own ``updates`` stays empty: neither
2526
2545
  outcome is knowable at the moment :func:`plan_tick` returns.
2546
+ * ``resume_staggered`` — #3536: either `_reconcile_blocked`'s gate-clear
2547
+ check or `_reconcile_blocked_after`'s `after=` prereq-chain resume
2548
+ read CONFIRMED CLEAR (same evidence ``resumed``/``merge_only`` act
2549
+ on), but this tick's *max_resumes_per_tick_per_repo* cap for this
2550
+ entry's repo was already spent by an earlier entry THIS SAME tick —
2551
+ a mass latch clear, or a single landed prereq clearing many rows
2552
+ chained `--after` it, releasing a dozen rows at once, the exact
2553
+ synchronized-poll shape that trips GitHub's secondary rate limiter.
2554
+ Writes NO state: the entry stays `blocked` and gets first refusal at
2555
+ the same check next tick, so a repo's worth of newly-clear rows
2556
+ releases gradually over several ticks instead of one.
2527
2557
  """
2528
2558
 
2529
2559
  key: str
@@ -6384,6 +6414,7 @@ def plan_tick(
6384
6414
  roll_pending_reason: str = "",
6385
6415
  live_prereq_terminal: Mapping[str, bool] | None = None,
6386
6416
  fix_round_config_default: int | None = None,
6417
+ max_resumes_per_tick_per_repo: int | None = DEFAULT_MAX_RESUMES_PER_TICK_PER_REPO,
6387
6418
  ) -> TickPlan:
6388
6419
  """Decide one tick. Pure; the caller executes the returned plan.
6389
6420
 
@@ -6710,6 +6741,19 @@ def plan_tick(
6710
6741
  relaunch decision and the launch it gates always agree on the budget.
6711
6742
  ``None`` (the default) falls back to :data:`DEFAULT_TICK_MAX_FIX_ROUNDS`,
6712
6743
  same as every other caller of :func:`effective_max_fix_rounds`.
6744
+
6745
+ *max_resumes_per_tick_per_repo* (#3536) caps how many CONFIRMED-CLEAR
6746
+ `blocked`-entry resumes/merge-only releases THIS tick grants per repo,
6747
+ from EITHER `_reconcile_blocked`'s gate-clear check or
6748
+ `_reconcile_blocked_after`'s `after=` prereq-chain resume (#2362/#2756)
6749
+ — see :data:`DEFAULT_MAX_RESUMES_PER_TICK_PER_REPO` for why both count
6750
+ against the same cap. The ``resumed``/``merge_only`` reconciles beyond
6751
+ the cap are replaced with a ``resume_staggered`` one: no state write,
6752
+ so the entry stays `blocked` and re-enters this same check next tick,
6753
+ where it either wins a slot then or is staggered again. Every state
6754
+ other than `blocked` is unaffected. ``None`` or ``0`` disables the cap
6755
+ entirely (unstaggered — the only behaviour this repo's test suite
6756
+ exercised before #3536).
6713
6757
  """
6714
6758
  ordered = sorted(entries, key=lambda e: (e.position, e.key))
6715
6759
  states: dict[str, str] = {e.key: e.state for e in ordered}
@@ -6766,6 +6810,10 @@ def plan_tick(
6766
6810
  # #2350: entries this tick decided to attempt `coord merge --only` on
6767
6811
  # directly rather than relaunch — see `Reconcile`'s `merge_only` outcome.
6768
6812
  merge_only_candidates: list[QueueEntry] = []
6813
+ # #3536: how many `_reconcile_blocked` CONFIRMED-CLEAR resumes/merge-only
6814
+ # releases this tick has already granted, per repo — see the stagger
6815
+ # check inside the `STATE_BLOCKED` branch below.
6816
+ resume_quota_used: dict[str, int] = {}
6769
6817
  occupied = 0
6770
6818
  # #1972: the same count, keyed by repo. Populated from the SAME
6771
6819
  # `reconcile.occupies` verdict as `occupied` above — one source of truth, so
@@ -6971,6 +7019,59 @@ def plan_tick(
6971
7019
  live_blocked_unreadable,
6972
7020
  live_blocked_gate_reason,
6973
7021
  )
7022
+ # #3536: a latch that was gating many entries at once (#3386's
7023
+ # baseline-red gate, cleared by one merge) reads CONFIRMED CLEAR
7024
+ # for every one of them on the SAME tick — without a cap, EITHER
7025
+ # `_reconcile_blocked`'s gate-clear check above OR
7026
+ # `_reconcile_blocked_after`'s prereq-chain resume (#2362/#2756:
7027
+ # one landed dep clearing the SAME unsatisfiable verdict for
7028
+ # every row chained `--after` it) hands back `resumed`/
7029
+ # `merge_only` for all of them here, and every one of those rows
7030
+ # then drives its OWN live `gh` re-checks (branch head, CI
7031
+ # status) on this same tick's very next poll. A dozen rows doing
7032
+ # that together is exactly the synchronized-poll pattern
7033
+ # `coord.github_throttle`'s module docstring identifies as what
7034
+ # trips GitHub's secondary rate limiter — the 2026-10-02 incident
7035
+ # this issue describes, and issue #3536 itself names BOTH the
7036
+ # #2230 and #2362 paths as in scope for the stagger (a review
7037
+ # round of this same fix caught that an earlier version capped
7038
+ # only `_reconcile_blocked`'s gate-clear path, leaving the
7039
+ # `after=` cascade above unstaggered even though a many-rows-
7040
+ # chained-on-one-prereq clear is the identical synchronized-poll
7041
+ # shape). Stagger it: only the first
7042
+ # `max_resumes_per_tick_per_repo` CONFIRMED-CLEAR resumes per
7043
+ # repo actually release this tick, from EITHER path; the rest
7044
+ # stay `blocked` (no state write, so they re-enter this exact
7045
+ # branch next tick and get first refusal then) with a reason
7046
+ # explaining why, instead of all firing at once.
7047
+ if (
7048
+ blocked_reconcile is not None
7049
+ and blocked_reconcile.outcome in ("resumed", "merge_only")
7050
+ and max_resumes_per_tick_per_repo is not None
7051
+ and max_resumes_per_tick_per_repo > 0
7052
+ ):
7053
+ used = resume_quota_used.get(entry.repo, 0)
7054
+ if used >= max_resumes_per_tick_per_repo:
7055
+ reason = (
7056
+ f"{entry.key}'s block cleared (merge gate reads "
7057
+ "clear, or a chained `after=` prereq landed), but "
7058
+ f"this tick already released "
7059
+ f"{max_resumes_per_tick_per_repo}/"
7060
+ f"{max_resumes_per_tick_per_repo} {entry.repo} "
7061
+ "resume slot(s) — staggering the rest to avoid "
7062
+ "a mass clear tripping GitHub's secondary "
7063
+ "rate limit fleet-wide (#3536); resuming on a "
7064
+ "later tick"
7065
+ )
7066
+ blocked_reconcile = Reconcile(
7067
+ entry.key,
7068
+ "resume_staggered",
7069
+ reason,
7070
+ occupies=False,
7071
+ updates=_refresh_only(reason, entry.last_reason),
7072
+ )
7073
+ else:
7074
+ resume_quota_used[entry.repo] = used + 1
6974
7075
  if blocked_reconcile is not None:
6975
7076
  reconciles.append(blocked_reconcile)
6976
7077
  if blocked_reconcile.outcome == "merge_only":
@@ -486,6 +486,67 @@ def _resolve_caller(explicit: str) -> str:
486
486
  return "unknown"
487
487
 
488
488
 
489
+ def _precall_throttle(
490
+ args: Sequence[str], caller: str, *, force_through_backoff: bool = False,
491
+ ) -> None:
492
+ """Shared pre-call seam: consult the reactive backoff, then take a token
493
+ from the proactive pacing bucket (#3536 review follow-up).
494
+
495
+ Extracted out of :func:`_gh` so :func:`get_pr_checks` — which cannot
496
+ funnel through ``_gh()`` itself, because a non-zero ``gh pr checks`` exit
497
+ can still carry usable JSON on stdout and ``_gh()``'s raise-on-nonzero
498
+ contract can't express that, see that function's own docstring — still
499
+ gets paced and damped the same way every ``_gh()``-backed call does.
500
+ ``get_pr_checks`` is the single ``gh`` sink for
501
+ :class:`coord.ci_github.GitHubCi`, i.e. the dominant CI-check/branch-head
502
+ read the #3536 incident actually stalled on; a `pace()` call added only
503
+ inside `_gh()` would leave exactly that path unpaced, which an earlier
504
+ review round of this issue caught.
505
+
506
+ Raises :class:`GhRateLimitError` when deep inside an active backoff
507
+ window (same as ``_gh()``); otherwise sleeps for the jittered amount
508
+ ``consult()``/``pace()`` compute (possibly ``0.0``) and returns.
509
+ """
510
+ backoff_sleep_s, active_backoff = github_throttle.consult()
511
+ if active_backoff is not None:
512
+ remaining = active_backoff.until - time.time()
513
+ if remaining > github_throttle.MAX_PRECALL_SLEEP_S and not force_through_backoff:
514
+ # Still well inside a known backoff window -- don't add another
515
+ # request to a limiter that only recovers when the rate drops.
516
+ # This is not a fresh observation, so it is not re-recorded.
517
+ record_gh_call(
518
+ args, outcome="transient", duration_s=0.0, caller=caller,
519
+ detail=(
520
+ f"skipped: coordinated backoff active ({active_backoff.reason}, "
521
+ f"{remaining:.0f}s remaining)"
522
+ ),
523
+ )
524
+ raise GhRateLimitError(
525
+ f"gh {' '.join(args)} skipped: GitHub {active_backoff.reason} "
526
+ f"backoff active for {remaining:.0f}s more "
527
+ f"(status={active_backoff.status}, request_id={active_backoff.request_id})",
528
+ status_code=active_backoff.status,
529
+ request_id=active_backoff.request_id,
530
+ retry_after_s=remaining,
531
+ secondary=active_backoff.reason == "secondary_rate_limit",
532
+ from_cache=True,
533
+ )
534
+ if backoff_sleep_s > 0:
535
+ time.sleep(backoff_sleep_s)
536
+ # #3536: proactive pacing, ahead of any 403 -- a reactive backoff above
537
+ # has nothing to say about a caller that hasn't been rate-limited yet,
538
+ # which is exactly the mass-resume shape #3536 describes (a dozen
539
+ # newly-unblocked rows each making their own first live `gh` call with
540
+ # no shared history of a hit). Both ``_gh()`` and ``get_pr_checks()``
541
+ # call this one seam, so pacing it once here paces every polling path
542
+ # (drive-queue merge-wait re-checks -- including the CI-check read
543
+ # itself -- the merge-queue sweep, `coord notify` ticks) without each one
544
+ # needing its own call to `github_throttle.pace()`.
545
+ pace_sleep_s = github_throttle.pace()
546
+ if pace_sleep_s > 0:
547
+ time.sleep(pace_sleep_s)
548
+
549
+
489
550
  def _gh(*args: str, caller: str = "", force_through_backoff: bool = False) -> str:
490
551
  """Run ``gh`` with *args* and return its stdout, or raise :class:`GhError`.
491
552
 
@@ -536,32 +597,7 @@ def _gh(*args: str, caller: str = "", force_through_backoff: bool = False) -> st
536
597
  low-frequency caller from being permanently outbid by them.
537
598
  """
538
599
  caller = _resolve_caller(caller)
539
- backoff_sleep_s, active_backoff = github_throttle.consult()
540
- if active_backoff is not None:
541
- remaining = active_backoff.until - time.time()
542
- if remaining > github_throttle.MAX_PRECALL_SLEEP_S and not force_through_backoff:
543
- # Still well inside a known backoff window -- don't add another
544
- # request to a limiter that only recovers when the rate drops.
545
- # This is not a fresh observation, so it is not re-recorded.
546
- record_gh_call(
547
- args, outcome="transient", duration_s=0.0, caller=caller,
548
- detail=(
549
- f"skipped: coordinated backoff active ({active_backoff.reason}, "
550
- f"{remaining:.0f}s remaining)"
551
- ),
552
- )
553
- raise GhRateLimitError(
554
- f"gh {' '.join(args)} skipped: GitHub {active_backoff.reason} "
555
- f"backoff active for {remaining:.0f}s more "
556
- f"(status={active_backoff.status}, request_id={active_backoff.request_id})",
557
- status_code=active_backoff.status,
558
- request_id=active_backoff.request_id,
559
- retry_after_s=remaining,
560
- secondary=active_backoff.reason == "secondary_rate_limit",
561
- from_cache=True,
562
- )
563
- if backoff_sleep_s > 0:
564
- time.sleep(backoff_sleep_s)
600
+ _precall_throttle(args, caller, force_through_backoff=force_through_backoff)
565
601
  # #1896 Phase 0: time + classify every `gh` invocation through this one
566
602
  # seam so `coord diagnose --forge-availability` has real data on how
567
603
  # often the forge is actually unreachable, not just anecdote from one
@@ -2745,28 +2781,62 @@ def get_pr_checks(repo: str, number: int) -> list[dict]:
2745
2781
  empty (a real lookup failure: bad PR number, auth, rate-limit, an old gh
2746
2782
  that doesn't support ``--json`` at all, ...). The single ``gh`` sink for
2747
2783
  :class:`coord.ci_github.GitHubCi`, the CI backend behind the merge gate
2748
- (#1483).
2784
+ (#1483) — and, per #3536's incident narrative, the dominant call the
2785
+ merge gate's CI-wait polling actually makes, so it is paced and damped
2786
+ the same way ``_gh()``-backed calls are even though it cannot itself
2787
+ route through ``_gh()`` (see the non-zero-exit-with-usable-stdout note
2788
+ above).
2749
2789
 
2750
2790
  Raises :class:`GhTooOldForJsonChecks` — instead of the generic
2751
2791
  ``RuntimeError`` below — when the installed ``gh`` doesn't recognise
2752
2792
  ``--json`` on ``pr checks`` at all (#1564 Addendum 2), so callers can
2753
2793
  surface a distinct, actionable "upgrade gh" message rather than lumping
2754
2794
  it in with ordinary read failures.
2755
- """
2795
+
2796
+ #3536 review follow-up: this used to shell out directly with no pacing
2797
+ or backoff of its own, which meant the module-wide claim "every `gh`
2798
+ call funnels through `_gh()`, so pacing it once there paces every
2799
+ polling path" was false for exactly the path #3521 stalled on for 40+
2800
+ minutes. It now calls :func:`_precall_throttle` (the same seam ``_gh()``
2801
+ calls) before the network call, and feeds a rate-limit hit it detects
2802
+ itself back into :mod:`coord.github_throttle` the same way ``_gh()``
2803
+ does, so every OTHER caller on this host learns about a 403 this read
2804
+ hits, not just the ones that happen to go through ``_gh()``.
2805
+ """
2806
+ caller = _resolve_caller("github_ops.get_pr_checks")
2807
+ args = (
2808
+ "pr", "checks", str(number),
2809
+ "--repo", repo,
2810
+ "--json", ",".join(PR_CHECKS_JSON_FIELDS),
2811
+ )
2812
+ _precall_throttle(args, caller)
2813
+ _t0 = time.monotonic()
2756
2814
  result = subprocess.run(
2757
- [
2758
- "gh", "pr", "checks", str(number),
2759
- "--repo", repo,
2760
- "--json", ",".join(PR_CHECKS_JSON_FIELDS),
2761
- ],
2815
+ ["gh", *args],
2762
2816
  capture_output=True, text=True, timeout=30,
2763
2817
  )
2818
+ duration = time.monotonic() - _t0
2764
2819
  stdout = (result.stdout or "").strip()
2765
2820
  if result.returncode != 0 and not stdout:
2766
2821
  stderr = result.stderr.strip()
2767
2822
  if _GH_UNKNOWN_JSON_FLAG_MARKER in stderr:
2823
+ record_gh_call(args, outcome="unreachable", duration_s=duration,
2824
+ detail=stderr, caller=caller)
2768
2825
  raise GhTooOldForJsonChecks(_gh_too_old_message(stderr))
2826
+ is_rate_limit, is_secondary = _classify_rate_limit(stderr)
2827
+ if is_rate_limit:
2828
+ if not is_secondary and _primary_quota_healthy():
2829
+ is_secondary = True
2830
+ text_meta = _extract_rate_limit_detail(stderr)
2831
+ github_throttle.record(
2832
+ reason="secondary_rate_limit" if is_secondary else "primary_rate_limit",
2833
+ status=text_meta.status, request_id=text_meta.request_id,
2834
+ retry_after_s=text_meta.retry_after_s,
2835
+ )
2836
+ record_gh_call(args, outcome=_classify_gh_exit(stderr), duration_s=duration,
2837
+ detail=stderr, caller=caller)
2769
2838
  raise RuntimeError(f"gh pr checks failed: {stderr}")
2839
+ record_gh_call(args, outcome="ok", duration_s=duration, caller=caller)
2770
2840
  # #1525: unlike the fail-open sites elsewhere in this module, a malformed
2771
2841
  # (non-empty) response here must NOT be swallowed to a quiet ``[]`` —
2772
2842
  # ``ci_github.GitHubCi._fetch`` deliberately catches the ``ValueError``
@@ -62,6 +62,33 @@ missing/unwritable state dir, a corrupt file, an unreachable daemon) without
62
62
  ever raising into or delaying a caller beyond the bound it already asked
63
63
  for — damping must never become a new way to break `gh` access, only a way
64
64
  to reduce it.
65
+
66
+ **Proactive pacing (#3536), not just reactive backoff.** Everything above
67
+ reacts to a 403 that already happened. #3536's incident showed that is not
68
+ enough on its own: when a latch clears and a dozen `blocked` rows resume
69
+ together, EVERY ONE of them immediately drives its own live `gh` re-checks
70
+ (branch head, CI status) with no shared awareness of the others — none of
71
+ them has hit a 403 yet, so :func:`consult` above has nothing to say, and the
72
+ fleet trips the secondary limiter from a cold start, then backs off and
73
+ resumes in lockstep exactly as the module docstring above already warns a
74
+ synchronized-poll pattern will. :func:`pace` is the proactive half: a small,
75
+ best-effort, file-backed token bucket (:func:`local_pace_acquire`) that every
76
+ `gh` call takes a token from BEFORE it knows whether it will even be
77
+ rate-limited, smoothing the aggregate request rate instead of only reacting
78
+ once GitHub has already said no. Same failure posture as everything else
79
+ here — a missing/unwritable state dir degrades to "no pacing" (0.0s),
80
+ never a raised exception or an unbounded sleep.
81
+
82
+ Today this is single-host only (the same file every process on this host
83
+ shares, same pattern :func:`local_record`/:func:`local_consult` use) — true
84
+ fleet-wide pacing across machines would need a daemon endpoint the way
85
+ :func:`record`/:func:`consult` get one via ``/github-backoff``
86
+ (:mod:`coord.board_service`/:mod:`coord.client`/:mod:`coord.serve_app`), which
87
+ is out of scope for the files this change touches. In practice this still
88
+ covers #3536's own incident: the board daemon host is where the drive-queue
89
+ tick, `coord notify`, and the merge-queue sweep all actually run, so pacing
90
+ their shared funnel on that one host already smooths the aggregate rate the
91
+ incident describes.
65
92
  """
66
93
 
67
94
  from __future__ import annotations
@@ -109,6 +136,30 @@ MAX_PRECALL_SLEEP_S = 20.0
109
136
  # secondary limit tripped in the first place.
110
137
  _JITTER_FRACTION = 0.2
111
138
 
139
+ # #3536: filename for the proactive-pacing token bucket's state, kept
140
+ # separate from `_STATE_FILENAME` (the reactive backoff) — the two answer
141
+ # different questions (one "is a hit already in force", the other "is this
142
+ # call about to push the rate too high") and have independent schemas, so a
143
+ # corrupt/stale one must never be able to take the other down with it.
144
+ _PACE_STATE_FILENAME = "github_pace.json"
145
+
146
+ # Steady-state ceiling: one token every 2s, i.e. 30 `gh` calls/minute
147
+ # fleet-wide (today: per-host — see the module docstring). Chosen well under
148
+ # GitHub's own documented secondary-limit guidance (no more than ~1 request/
149
+ # second sustained, a few minutes' cooldown once tripped) so staying inside
150
+ # this budget should mean never tripping it in the first place, while still
151
+ # comfortably covering ordinary poll cadences (#2809's own 15s-60s range).
152
+ PACE_DEFAULT_RATE_PER_S = 0.5
153
+
154
+ # Burst allowance: a short caller clump (e.g. a drive-queue tick's handful of
155
+ # live re-checks firing in the same second) can spend up to this many tokens
156
+ # at once before the steady-state rate above starts throttling it. Small on
157
+ # purpose — big enough that an ordinary tick's few calls sail through
158
+ # un-delayed, small enough that a dozen-row mass resume (#3536's own
159
+ # incident) still gets smoothed out over several seconds rather than firing
160
+ # all at once.
161
+ PACE_DEFAULT_BURST = 8.0
162
+
112
163
 
113
164
  class Backoff(NamedTuple):
114
165
  """One recorded rate-limit hit and how long to back off because of it."""
@@ -383,3 +434,151 @@ def local_consult(*, now: float | None = None) -> tuple[float, Backoff | None]:
383
434
  """
384
435
  now = now if now is not None else time.time()
385
436
  return _consult_from(current(now=now), now=now)
437
+
438
+
439
+ # ── #3536: proactive pacing (a token bucket, ahead of any 403) ──────────────
440
+
441
+
442
+ def _pace_state_path() -> Path:
443
+ """Resolve the pacing-bucket state file path.
444
+
445
+ ``$COORD_GITHUB_PACE_STATE`` overrides first — same seam
446
+ :func:`_state_path` offers for the backoff file, so a test can redirect
447
+ this with a one-line ``monkeypatch.setenv`` instead of patching a private
448
+ function.
449
+ """
450
+ override = os.environ.get("COORD_GITHUB_PACE_STATE")
451
+ if override:
452
+ return Path(override).expanduser()
453
+ return default_coord_dir() / _PACE_STATE_FILENAME
454
+
455
+
456
+ def _pace_step(
457
+ state: dict | None, *, now: float, rate_per_s: float, burst: float,
458
+ ) -> tuple[float, dict]:
459
+ """One token-bucket step: ``(sleep_s, new_state)``.
460
+
461
+ Pure — no file I/O, no clock read — so the bucket arithmetic itself is
462
+ cheaply unit-testable independent of :func:`local_pace_acquire`'s
463
+ read/write wrapper. *state* is the previous ``{"tokens", "last"}``
464
+ mapping (or ``None``/malformed, treated as a freshly-full bucket — a
465
+ missing/corrupt file must never itself become a reason to block `gh`
466
+ traffic, same fail-open posture :func:`_read` takes for the backoff
467
+ file).
468
+
469
+ Refills *tokens* by elapsed wall-clock time at *rate_per_s*, capped at
470
+ *burst*. A caller that finds at least one token available is granted
471
+ immediately (``sleep_s == 0.0``) and consumes it. Otherwise the bucket
472
+ is empty: the caller is charged the wait needed for ONE token to accrue
473
+ (``deficit / rate_per_s``) rather than being granted for free — the
474
+ token it is about to "spend" is accounted for up front (``tokens``
475
+ pinned at ``0.0``, ``last`` advanced to *now*) so a second concurrent
476
+ caller reading the freshly-written state a moment later sees the same
477
+ empty bucket, not a stale one that would hand out the same token twice.
478
+
479
+ A non-positive *rate_per_s* never grants a wait longer than the deficit
480
+ itself would imply at a reasonable floor — guarded by the caller
481
+ (:func:`local_pace_acquire`) clamping *rate_per_s* to a small positive
482
+ floor before this ever sees it, so a float divide-by-zero here is not a
483
+ live concern; this function still tolerates it defensively (returns
484
+ ``0.0`` rather than raising) because the caller's clamp isn't part of
485
+ this function's own contract.
486
+ """
487
+ tokens = burst
488
+ last = now
489
+ if isinstance(state, dict):
490
+ try:
491
+ tokens = float(state.get("tokens", burst))
492
+ last = float(state.get("last", now))
493
+ except (TypeError, ValueError):
494
+ tokens, last = burst, now
495
+ elapsed = max(0.0, now - last)
496
+ tokens = min(burst, tokens + elapsed * rate_per_s)
497
+ if tokens >= 1.0:
498
+ return 0.0, {"tokens": tokens - 1.0, "last": now}
499
+ if rate_per_s <= 0:
500
+ return 0.0, {"tokens": tokens, "last": now}
501
+ deficit = 1.0 - tokens
502
+ wait = deficit / rate_per_s
503
+ return wait, {"tokens": 0.0, "last": now}
504
+
505
+
506
+ def local_pace_acquire(
507
+ *,
508
+ now: float | None = None,
509
+ rate_per_s: float = PACE_DEFAULT_RATE_PER_S,
510
+ burst: float = PACE_DEFAULT_BURST,
511
+ ) -> float:
512
+ """Take one token from THIS HOST's shared pacing bucket; return the
513
+ jittered number of seconds the caller should sleep first (#3536).
514
+
515
+ Shared across every process on this host via the same small JSON file
516
+ :func:`local_record`/:func:`local_consult` use for the reactive backoff
517
+ (a different file — see :data:`_PACE_STATE_FILENAME` — but the identical
518
+ read/compute/atomic-replace shape), so a drive-queue tick, `coord
519
+ notify`, and the merge-queue sweep all draw from the SAME bucket instead
520
+ of each pacing only its own calls. ``0.0`` means "go ahead now" — the
521
+ overwhelmingly common case outside a burst.
522
+
523
+ Best-effort, unconditionally (never raises): a missing/unwritable state
524
+ dir or a corrupt file degrades to "no pacing" (``0.0``), same posture
525
+ every other function in this module takes — pacing must never become a
526
+ new way to break `gh` access, only a way to smooth it.
527
+
528
+ Jittered the same way :func:`_jitter` smooths every other wait here, for
529
+ the identical reason: several callers racing the exact same computed
530
+ wait would otherwise wake and retry in lockstep, right back into the
531
+ synchronized-poll pattern this module exists to avoid.
532
+ """
533
+ now = now if now is not None else time.time()
534
+ rate_per_s = rate_per_s if rate_per_s > 0 else PACE_DEFAULT_RATE_PER_S
535
+ burst = burst if burst > 0 else PACE_DEFAULT_BURST
536
+ try:
537
+ path = _pace_state_path()
538
+ try:
539
+ raw = json.loads(path.read_text(encoding="utf-8"))
540
+ except (OSError, json.JSONDecodeError, ValueError):
541
+ raw = None
542
+ sleep_s, new_state = _pace_step(
543
+ raw if isinstance(raw, dict) else None,
544
+ now=now, rate_per_s=rate_per_s, burst=burst,
545
+ )
546
+ path.parent.mkdir(parents=True, exist_ok=True)
547
+ fd, tmp = tempfile.mkstemp(prefix=".github_pace.", suffix=".tmp", dir=path.parent)
548
+ try:
549
+ with os.fdopen(fd, "w", encoding="utf-8") as fh:
550
+ json.dump(new_state, fh, sort_keys=True)
551
+ fh.write("\n")
552
+ os.replace(tmp, path)
553
+ except Exception:
554
+ try:
555
+ os.unlink(tmp)
556
+ except OSError:
557
+ pass
558
+ raise
559
+ return _jitter(sleep_s)
560
+ except Exception as exc: # noqa: BLE001 -- pacing must never break a caller
561
+ _log.debug("github_throttle: pace acquire failed: %s", exc)
562
+ return 0.0
563
+
564
+
565
+ def pace(
566
+ *,
567
+ now: float | None = None,
568
+ rate_per_s: float = PACE_DEFAULT_RATE_PER_S,
569
+ burst: float = PACE_DEFAULT_BURST,
570
+ ) -> float:
571
+ """Proactive pacing for a caller about to issue a `gh` call (#3536).
572
+
573
+ Today this is exactly :func:`local_pace_acquire` — single-host only, no
574
+ daemon branch, because true fleet-wide pacing across machines would need
575
+ a ``/github-pace``-shaped endpoint the way :func:`record`/:func:`consult`
576
+ get one for the reactive backoff, which is out of scope for the files
577
+ this change touches (see the module docstring). Kept as its own public
578
+ name — rather than every caller importing :func:`local_pace_acquire`
579
+ directly — so a future daemon-routed version slots in behind this ONE
580
+ name, the same ``record``/``local_record`` and ``consult``/``local_
581
+ consult`` split this module already uses, without every call site
582
+ needing to change again.
583
+ """
584
+ return local_pace_acquire(now=now, rate_per_s=rate_per_s, burst=burst)