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.
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/PKG-INFO +1 -1
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/PKG-INFO +1 -1
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_version.json +2 -2
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_github.py +10 -4
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/server.py +50 -1
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_queue.py +101 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/github_ops.py +103 -33
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/github_throttle.py +199 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/merge_queue.py +51 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notify.py +115 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/conftest.py +27 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard.py +156 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue.py +151 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_github_ops.py +209 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_github_throttle.py +144 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_merge_queue.py +31 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stalled_pipeline.py +94 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/board.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/complete-session.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.claude/commands/coordinator.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/_lib.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-checkout +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-commit +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.githooks/post-merge +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/coord-ci-acceptance.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/auto-release.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/publish.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.github/workflows/test.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/.gitignore +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/CLAUDE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/GOAL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/LICENSE +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/MANIFEST.in +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/README.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/SOURCES.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/dependency_links.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/entry_points.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/requires.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_file_list.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/code_coordinator.egg-info/top_level.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/_board_mapping.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/acceptance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/acceptance_drivers.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent_app.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agent_update.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/.gitignore +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/agents/work.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/agents/opencode/routing.jsonc +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/approved_work.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/auto_loop.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/backup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/block_log.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_schema.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_service.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/board_wire.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/brain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/branch_model.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/bug_intake.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/bugbash.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/cargo_cache.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_fix.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_gitlab.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/ci_store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/claim.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/claude_setup_token.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/client.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/codegen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/_common.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/acceptance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/agent_ops.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/backup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/bugbash.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/ci.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/codegen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dispatch_workers.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/dr.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/drive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/drive_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/gate_a.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/gates.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/issues.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/lifecycle.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/machine.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/merge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/milestone.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/plan_followup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/plans.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/portal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/pr.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/release.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/repo.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/report.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/review.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/scorecard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/sessions.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/setup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/status.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/store_migrate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/terminal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/test_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/commands/tui.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/comments.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/config_reload.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/confirm_test.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/conflict_fix.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dao.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/index.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/reports.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dashboard/terminal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/db.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dead_end.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/decomposition_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/README.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-agent.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-backup.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-backup.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-failure-notify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-notify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-notify.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-serve.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy/coord-web.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy_manifest.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deploy_units.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deprecation_telemetry.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/deps.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/diagnose.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dispatch_liveness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dist_name.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dr_promote.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/dr_verify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_sessions_snapshot.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/drive_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/events.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/failure_class.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/failure_classifier.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/filelock.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/fleet_config_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/forge_availability.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/freshness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_a.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_b.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gate_snapshot.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gates.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gen_board_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/goal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/graph_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/gtk_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/aggregate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/_ci_pin.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/agent_install.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/cargo_targets.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/claude_binary.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/config_drift.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/coord_tui_ci_pin.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/coord_web_ci_pin.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/deploy_lane_facts.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/disk.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_board.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_deploy_lanes.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_phantom.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/fleet_unit_drift.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/graph.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/graphify_cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/index_lock.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/issues_sync_staleness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/local_machine_identity.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/plan_usage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/pr_churn.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/release_cordon.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/repo_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/spawned_coord.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/stalled_pipeline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/timer_active.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/toolchain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/unit_drift.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/unit_enablement.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/wedged_drive_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/checks/worktrees.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/context.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/fleet_snapshot.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/models.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/pypi.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/registry.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/render.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/health/units.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/hooks.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/housekeeping.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/interactive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/invariant_alarms.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/issue_store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/issues_sync_status.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/liveness_auditor.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/mac_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_fault.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_metrics.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_onboard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_pause.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/machine_stats.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/milestone_order.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/mock_author.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/models.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/network.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/new_issue_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/baseline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/collect.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/digest.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/models.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/predicate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/service.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/notifier/transport.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/openapi.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/overlap_fence.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/overlap_predict.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/parentage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/parentage_github.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/pipeline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/plan_parser.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/plans.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/platform_paths.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_bridge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/portal_sync.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/pr_body_lint.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/prereqs.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/progress.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/base.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/claude.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/claude_pty.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/providers/opencode.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/queue_diagnose.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reconcile.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reconcile_tick.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/refine_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_cordon.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_propagate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_verify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/release_window.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_dormancy.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_edit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/repo_onboard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/reports.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/rest_schema.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/restart_cmd.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/revalidate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/review.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/scorecard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/self_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/serve_app.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/coord-dispatch-verbs/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/drive-queue-preflight/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/fleet-restart-safety/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/merge-stuck-triage/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/pipeline-limbo-triage/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/portal-followup/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/release-now/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/review-verdict-recovery/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/tui-quadraui-workflow/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/skills/update-issue/SKILL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/smoke.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/smoke_tags.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/spend_ceiling.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/split_work.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/sql.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/stage_projection.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/store_migrate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/store_parity.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/templates/deploy-cloudflare.node.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_author.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_orchestrator.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/test_report.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/tui_pty_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/tui_release.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/uat_checks.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage_limits.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/usage_rollup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/win_native_bridge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/win_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coord/worker_events.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/coordinator.example.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-agent.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-backup.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-backup.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-db-backup.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-dr-verify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-dr-verify.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-drive-queue.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-drive-queue.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-failure-notify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-failure-notify.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-notify.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-notify.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-propagate.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-propagate.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-window.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-release-window.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-serve.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.timer +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web-rollback.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/coord-web.service +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/deploy/node-shim.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_TUI_CI.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_ACCEPTANCE_SUITE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_CI.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_DIST.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ADR_PY_RUST_MIRRORS.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/AGENT_OPERATIONS.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ARCHITECTURE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ARCH_SECURITY_GATES.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/COCKPIT.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CONTROL_CENTER.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/COST_DISCIPLINE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CROSS_PLATFORM.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CUSTOMER_FACING_APPS.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/CUSTOMER_PORTAL.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DATA_STORE_SELECTION.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DISASTER_RECOVERY.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/DRIVE_QUEUE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/EPHEMERAL_WORKERS.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/FORGE_MIGRATION.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/GRAPHIFY_SETUP.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ISSUE_GUIDANCE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/MAC_MINI.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/MERGE_AUTO_DRAIN_TRUST_BAR.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/NOTIFIER.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPENCODE_VERIFICATION.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPERATING_GOTCHAS.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/OPERATOR_GUIDES.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/ORACLE_LOOP.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PHONE_WEBAPP.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PIPELINE_V2.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/PLATFORM_EVOLUTION.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/SECOND_BACKEND.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/STORE_SERVICE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/TEST_FIRST_BUG_LANE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/WEB_CONTROL_CENTER.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/WSL_WINDOWS_WORKER.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/README.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/_tokens.css +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/issue-detail.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-narrow.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-wide.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/graphify-out/.gitignore +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/install-agent.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/pyproject.toml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/audit_review_verdict_overrides.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/bootstrap-shared.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/build-worker-image.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/coordinator-machine.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/dr-down.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/dr-up.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/epic-down.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/epic-up.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/preflight.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/provision-server.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/provision-worker.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/scrub-and-generalize.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/tailnet-acl.hujson +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/throwaway-vm.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/azure-workers/verify-github-token.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/check_gh_argv_containment.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/codegen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-test-runner.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/coord-ci-acceptance.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/cargo-test.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/codegen-drift.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/CLAUDE.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/coord-venv-rollback.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/drive-batch.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/extract-coord-tui.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/fleet_watchdog.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/gen_board_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/gen_mock_index.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/lib/provision-core.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/next_release_tag.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/provision-machine.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/run_tests_in_populated_home.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/run_tests_without_gh.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/setup-macmini.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/smoke_437_interactive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify-provision-noble.sh +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_878_review_capture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_release_published.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/scripts/verify_release_wheel.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/setup.cfg +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/SMOKE_SET.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/__init__.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/conftest.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/contract.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/manifest.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_cli_1115.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_core_1118.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/contract.md +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active-extended.spec.ts +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active.spec.ts +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/manifest.yml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/mocks/home-active.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-51/tsconfig.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/acceptance/ms-example/mocks/home-active.html +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/backends.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-basic.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-terminal-gates.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_failure_sample.jsonl +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_length_sample.jsonl +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_sample.jsonl +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/all_pass.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/global_setup_crash.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/mixed_fail.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.junit.xml +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/skip.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/playwright/truncated.json +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_compile_error.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_multi_target_failures.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_no_parseable_failures.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_collection_error.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_log_record.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_string_in_body.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_internal_error.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_mixed_failures.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_no_parseable_failures.txt +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_acceptance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_acceptance_drivers.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_api_error.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_app.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_branch_base.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_branch_capture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_config_free_1712.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_deploy_units_endpoint.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_dirty_worktree.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_drive_queue_reconcile_2373.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_graph_self_heal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_health_h3.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_idle_restart.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_push_failure.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_reap.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_repos_and_pull.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_restart_services_endpoint.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_skills_self_heal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_startup_diagnostics.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_update.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_update_bluegreen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_usage_limit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_agent_zero_commit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ambient_home_isolation.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_capability_reroute_3241.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_dependency_busy_2804.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_reject_plan.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approve_usage_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approved_work_2532.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_approved_work_2996.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_assignment_already_recorded_daemon.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_log.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_outcome.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_audit_query.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_auto_loop.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_auto_release_publish_2035.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_backend_selection.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_backup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_base_checkout_restore.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_block_log.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_cap_762.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_read_path.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_schema.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_service.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_board_wire.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_brain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_branch_model.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_bug_intake.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_bugbash.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_build_worker_image_env_update.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cargo_cache.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_check_gh_argv_containment.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_acceptance_gate_1950.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_fix.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_github.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_gitlab.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_parity_2091.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_ci_store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claim.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claude_md_budget.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_claude_setup_token.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_acceptance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_oracle_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_remote.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_provider.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_assign_repo_drift_2219.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_chat_continue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_ci.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_codegen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_decide.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_capability_rules.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_config_provenance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_forge_availability.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_graph.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_self.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_diagnose_test_coverage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_free_1801.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_mismatch_1712.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_doctor_store_backend_3084.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_drive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_drive_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_escalate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_fix_headless_review.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_gate_a.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_install_drift.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_install_skills.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_comment.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_create_label.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_reopen.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issue_view_list.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_issues.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_merge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_assign.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_capture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_chat_add_child.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_b.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_c.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_order.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_remove_and_issue_close.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_milestone_ship.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_network.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_new_issue_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_plans.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_portal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_pr.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_pull_artifact.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_reattach_sessions.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_refine_board.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_preflight.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_propagate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_release_window.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_repo_2220.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_review_test_author_tracking_epic_2639.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_scorecard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_serve_store_backend_3084.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_set_review_findings.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_advisory_terminal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_contested_tag.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_invariant_alarms.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_machine_fault.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_merge_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_provider.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_retried_3340.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_review_finalizing.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_supervisor_3366.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_test_failed_tag.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_status_usage_limit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_sync_comments_873.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_test_plan.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_track.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_tui_update.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cli_wait.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_base_install.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_config_cache_atomic_3052.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_client_resource_migration_1946.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_commands_common.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_comments.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_completion_summary.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_acceptance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_drift_check.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_effective.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_pricing.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_snapshot_noncanonical_2208.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_config_usage_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_confirm_test.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_conflict_fix.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_conflict_fix_semantic.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_log_daemon_fallback_2547.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_acceptance_toolchain_2936.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_baseline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_populated_home.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_routing.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_test_runner_toolchain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_uat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coord_web_sse_restart_live.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_coordinator_machine.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_cross_platform_imports.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dao.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_api.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_reports.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_server.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_terminal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dashboard_terminal_live.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_db.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dead_end.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_decomposition_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_db_backup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_dist.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_rollback.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_db_backup_unit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_drive_queue_unit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_failure_notify_unit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_manifest.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_notify_unit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_units_lane.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deploy_web_unit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deprecation_telemetry.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_deps.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_diagnose.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_liveness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_target_validation.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dispatch_workers.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dist_name.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_done_housekeeping.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_azure_scripts.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_promote.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_dr_verify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_machine_fault.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_blocked_rendering.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_launch_argv.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_per_repo_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_roll_pending.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_queue_self_cordon_escalation.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_sessions_snapshot.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_drive_tmux.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_capability_detection.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_down_symlinked_config_1887.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_epic_up_image_provenance.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_errors.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_events.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_failure_class.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_failure_classifier.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_filelock.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_finalize_interactive_exit_test_verdict.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fix_escalation_classifier.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fix_of_force_override.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_config_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_health_probes.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_health_snapshot.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_fleet_watchdog.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_forge_availability.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_freshness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_a.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_b.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gate_snapshot_staleness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gates.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gather_fleet_tmux_sessions.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gen_mock_index.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_rust_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_rust_requests.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_generated_types_fixture.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_goal.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_graph_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_graph_selfheal_absent_2237.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_gtk_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_handoff.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_checks.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_cli_graph.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_context.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_coord_tui_ci_pin.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_coord_web_ci_pin.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_deploy_lane_facts.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_fix.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_incident_regression.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_issues_sync_staleness.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_pr_churn.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_pypi.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_registry.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_release_cordon_probe.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_timer_active.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_toolchain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_unit_drift.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_unit_enablement.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_health_wedged_drive_queue.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_hooks.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_housekeeping.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_human_attended_437.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_init.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_capabilities_3515.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_venv_2911.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_install_agent_wsl_bridge_3515.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_integration.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_briefing_echo.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_pane_log_2541.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_prefill_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_session_relaunch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_test_verdict_backstop.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_token_attribution.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_interactive_worktree.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_invariant_alarms.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_issue_store_seam.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_issues_sync_status.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_liveness_auditor.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_liveness_notify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_lock_contention_ratchet.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_mac_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_fault.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_metrics.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_onboard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_pause.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_machine_stats.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_merge_verify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_dispatch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_order.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_milestone_seam.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_mock_author.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_model_tiering.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_models.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_models_config_labels.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_needs_attention.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_network.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_new_issue_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_next_release_tag.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_node_shim.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_baseline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_cli.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_collect.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_drive_seam.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_isolation.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_predicate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_quiet_hours.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notifier_service.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_notify_drain.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_openapi.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_operational_defaults.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_overlap_fence.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_overlap_predict.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_packaged_deploy_units.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_parentage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_paste_landed.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_phantom_heal_venv_independence_2570.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_pipeline.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_approve_plan_command.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_pr_command.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_followup_review_command.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_only.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_plan_parser.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_platform_paths.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_bridge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_config.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_store.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_portal_sync.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_pr_body_lint.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_prereqs.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_production_db_guard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_progress.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provider_seam.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers_config_labels.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_providers_pty.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provision_core.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_provision_machine.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_py_rust_mirror_inventory.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_quiet_hours.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_quiet_hours_store_2146.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reap_merged_sessions.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reap_stale_interactive_tick.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_branch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_completions.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_late_agent_reports_2547.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_merges.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_no_agent_record.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_tick.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reconcile_usage_limit_done.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_refine_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_2101.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_daemon_leads_2176.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_deadlock_2240.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_drain_stall_3336.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_cordon_stuck_2490.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_gate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_propagate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_propagate_threshold.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_roll_between_legs_2854.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_roll_window_handoff.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_unified_1242.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_verify.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_release_window.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_remote_auto_prune.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_remote_interactive_reaper.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_add.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_dormancy.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_edit_2220.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_graph_fleet_2237.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_max_parallel_3423.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_repo_onboard_2220.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_report_public_export.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_report_result_push.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_reports.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_restart_cmd.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_advisory_1606.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_escalation_classify_3360.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_retry_type_1636.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_revalidate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_end_review_without_verdict.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_parse_failure_diagnostic.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_reaffirm.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_backstop.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_override_audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_verdict_relay.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_review_zero_commits.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_scoped_review_wiring.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_scorecard.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_self_health.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_app.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_app_board_trim.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_serve_rest_routes.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_session.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_slice_issue_attribution.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_fanout_manifest_3333.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_live_checkout_restore.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_smoke_workflow.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_spend_ceiling.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_spend_ceiling_coordinator.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_split.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_split_work.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_sql_dialect.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_sqlite_connect_ratchet.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stage_projection.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stale_busy_reviewer_697.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_state.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_state_review_findings_daemon.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_status_fleet_footer.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stop_1567.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_store_contract.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_store_migrate.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stuck.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_stuck_test_state_watchdog_2803.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_terminal_command.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_author.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_chat.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_orchestrator.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_report.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_verdict_parsing.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_test_verdict_transcript_floor.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_text_io_encoding_audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_board_audit.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_config_load_1080.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_thin_client_daemon_routing_906.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_throwaway_vm.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tmux_host.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tmux_session.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_transcript_floor.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_tui_pty_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_uat_checks.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage_limits.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_usage_rollup.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_venv_live_install_2121.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_version_single_source.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_watch.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_win_native_bridge.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_win_native_driver.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_windows_job_is_a_real_gate_2000.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_env_venv_isolation.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_events.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_image_pin_sync.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_safety.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worker_test_scoping.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worktree.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_worktree_rmtree_chokepoint.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/test_write_parity.py +0 -0
- {code_coordinator-0.5.576 → code_coordinator-0.5.578}/tests/write_parity.py +0 -0
|
@@ -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
|
-
#
|
|
801
|
-
#
|
|
802
|
-
#
|
|
803
|
-
#
|
|
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(
|
|
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
|
-
|
|
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)
|