code-coordinator 0.5.577__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.577 → code_coordinator-0.5.578}/PKG-INFO +1 -1
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/PKG-INFO +1 -1
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_version.json +2 -2
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/ci_github.py +10 -4
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/drive_queue.py +101 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/github_ops.py +103 -33
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/github_throttle.py +199 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/merge_queue.py +51 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notify.py +115 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/conftest.py +27 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue.py +151 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_github_ops.py +209 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_github_throttle.py +144 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_merge_queue.py +31 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stalled_pipeline.py +94 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.claude/commands/board.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.claude/commands/complete-session.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.claude/commands/coordinator.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.githooks/_lib.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.githooks/post-checkout +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.githooks/post-commit +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.githooks/post-merge +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.github/coord-ci-acceptance.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.github/workflows/auto-release.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.github/workflows/publish.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.github/workflows/test.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/.gitignore +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/CLAUDE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/GOAL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/LICENSE +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/MANIFEST.in +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/README.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/SOURCES.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/dependency_links.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/entry_points.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/requires.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/scm_file_list.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/code_coordinator.egg-info/top_level.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/_board_mapping.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/acceptance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/acceptance_drivers.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agent.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agent_app.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agent_update.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agents/opencode/.gitignore +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agents/opencode/agents/work.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/agents/opencode/routing.jsonc +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/approved_work.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/auto_loop.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/backup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/block_log.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/board_schema.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/board_service.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/board_wire.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/brain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/branch_model.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/bug_intake.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/bugbash.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/cargo_cache.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/ci_fix.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/ci_gitlab.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/ci_store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/claim.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/claude_setup_token.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/client.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/codegen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/_common.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/acceptance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/agent_ops.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/backup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/bugbash.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/ci.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/codegen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/dispatch_workers.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/dr.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/drive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/drive_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/gate_a.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/gates.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/issues.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/lifecycle.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/machine.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/merge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/milestone.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/plan_followup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/plans.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/portal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/pr.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/release.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/repo.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/report.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/review.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/scorecard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/sessions.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/setup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/status.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/store_migrate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/terminal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/test_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/commands/tui.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/comments.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/config_reload.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/confirm_test.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/conflict_fix.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dao.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/index.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/reports.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/server.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dashboard/terminal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/db.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dead_end.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/decomposition_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/README.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-agent.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-backup.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-backup.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-db-backup.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-dr-verify.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-drive-queue.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-failure-notify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-fleet-watchdog.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-notify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-notify.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-release-propagate.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-release-window.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-serve.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-web-dist-build.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy/coord-web.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy_manifest.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deploy_units.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deprecation_telemetry.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/deps.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/diagnose.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dispatch_liveness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dist_name.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dr_promote.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/dr_verify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/drive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/drive_sessions_snapshot.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/drive_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/events.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/failure_class.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/failure_classifier.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/filelock.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/fleet_config_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/forge_availability.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/freshness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gate_a.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gate_b.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gate_snapshot.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gates.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gen_board_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/goal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/graph_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/gtk_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/aggregate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/_ci_pin.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/agent_install.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/cargo_targets.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/claude_binary.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/config_drift.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/coord_tui_ci_pin.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/coord_web_ci_pin.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/deploy_lane_facts.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/disk.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/fleet_board.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/fleet_deploy_lanes.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/fleet_phantom.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/fleet_unit_drift.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/graph.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/graphify_cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/index_lock.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/issues_sync_staleness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/local_machine_identity.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/plan_usage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/pr_churn.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/release_cordon.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/repo_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/spawned_coord.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/stalled_pipeline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/timer_active.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/toolchain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/unit_drift.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/unit_enablement.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/wedged_drive_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/checks/worktrees.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/context.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/fleet_snapshot.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/models.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/pypi.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/registry.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/render.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/health/units.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/hooks.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/housekeeping.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/interactive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/invariant_alarms.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/issue_store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/issues_sync_status.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/liveness_auditor.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/mac_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/machine_fault.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/machine_metrics.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/machine_onboard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/machine_pause.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/machine_stats.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/milestone_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/milestone_dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/milestone_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/milestone_order.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/mock_author.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/models.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/network.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/new_issue_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/baseline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/collect.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/digest.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/models.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/predicate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/service.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/notifier/transport.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/openapi.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/overlap_fence.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/overlap_predict.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/parentage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/parentage_github.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/pipeline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/plan_parser.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/plans.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/platform_paths.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/portal_bridge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/portal_store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/portal_sync.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/pr_body_lint.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/prereqs.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/progress.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/providers/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/providers/base.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/providers/claude.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/providers/claude_pty.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/providers/opencode.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/queue_diagnose.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/reconcile.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/reconcile_tick.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/refine_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/release_cordon.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/release_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/release_propagate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/release_verify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/release_window.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/repo_dormancy.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/repo_edit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/repo_onboard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/reports.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/rest_schema.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/restart_cmd.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/revalidate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/review.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/scorecard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/self_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/serve_app.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/coord-dispatch-verbs/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/drive-queue-preflight/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/fleet-restart-safety/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/merge-stuck-triage/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/pipeline-limbo-triage/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/portal-followup/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/release-now/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/review-verdict-recovery/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/tui-quadraui-workflow/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/skills/update-issue/SKILL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/smoke.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/smoke_tags.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/spend_ceiling.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/split_work.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/sql.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/stage_projection.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/store_migrate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/store_parity.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/templates/deploy-cloudflare.node.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/test_author.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/test_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/test_orchestrator.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/test_report.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/tui_pty_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/tui_release.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/uat_checks.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/usage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/usage_limits.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/usage_rollup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/win_native_bridge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/win_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coord/worker_events.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/coordinator.example.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-agent.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-backup.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-backup.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-db-backup.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-db-backup.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-db-backup.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-dr-verify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-dr-verify.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-drive-queue.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-drive-queue.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-failure-notify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-failure-notify.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-fleet-watchdog.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-notify.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-notify.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-release-propagate.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-release-propagate.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-release-window.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-release-window.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-serve.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-web-dist-build.timer +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-web-rollback.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/coord-web.service +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/deploy/node-shim.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ADR_COORD_TUI_CI.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_ACCEPTANCE_SUITE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_CI.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ADR_COORD_WEB_DIST.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ADR_PY_RUST_MIRRORS.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/AGENT_OPERATIONS.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ARCHITECTURE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ARCH_SECURITY_GATES.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/COCKPIT.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/CONTROL_CENTER.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/COST_DISCIPLINE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/CROSS_PLATFORM.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/CUSTOMER_FACING_APPS.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/CUSTOMER_PORTAL.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/DATA_STORE_SELECTION.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/DISASTER_RECOVERY.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/DRIVE_QUEUE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/EPHEMERAL_WORKERS.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/FORGE_MIGRATION.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/GRAPHIFY_SETUP.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ISSUE_GUIDANCE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/MAC_MINI.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/MERGE_AUTO_DRAIN_TRUST_BAR.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/NOTIFIER.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/OPENCODE_VERIFICATION.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/OPERATING_GOTCHAS.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/OPERATOR_GUIDES.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/ORACLE_LOOP.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/PHONE_WEBAPP.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/PIPELINE_V2.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/PLATFORM_EVOLUTION.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/SECOND_BACKEND.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/STORE_SERVICE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/TEST_FIRST_BUG_LANE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/WEB_CONTROL_CENTER.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/WSL_WINDOWS_WORKER.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/mocks/web/README.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/mocks/web/_tokens.css +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/mocks/web/issue-detail.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-narrow.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/docs/mocks/web/pipeline-wide.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/graphify-out/.gitignore +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/install-agent.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/pyproject.toml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/audit_review_verdict_overrides.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/bootstrap-shared.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/build-worker-image.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/coordinator-machine.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/dr-down.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/dr-up.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/epic-down.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/epic-up.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/preflight.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/provision-server.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/provision-worker.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/scrub-and-generalize.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/tailnet-acl.hujson +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/throwaway-vm.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/azure-workers/verify-github-token.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/check_gh_argv_containment.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/codegen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-test-runner.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/coord-ci-acceptance.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/cargo-test.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/.github/workflows/codegen-drift.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-tui-scaffold/CLAUDE.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/coord-venv-rollback.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/drive-batch.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/extract-coord-tui.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/fleet_watchdog.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/gen_board_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/gen_mock_index.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/lib/provision-core.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/next_release_tag.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/provision-machine.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/run_tests_in_populated_home.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/run_tests_without_gh.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/setup-macmini.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/smoke_437_interactive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/verify-provision-noble.sh +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/verify_878_review_capture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/verify_release_published.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/scripts/verify_release_wheel.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/setup.cfg +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/SMOKE_SET.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/__init__.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-37/conftest.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-37/contract.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-37/manifest.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_cli_1115.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-37/test_usage_core_1118.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/contract.md +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active-extended.spec.ts +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/home-active.spec.ts +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/manifest.yml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/mocks/home-active.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-51/tsconfig.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/acceptance/ms-example/mocks/home-active.html +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/backends.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-basic.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/board-pipeline-terminal-gates.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_failure_sample.jsonl +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_length_sample.jsonl +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/opencode_run_sample.jsonl +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/all_pass.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/global_setup_crash.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/mixed_fail.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/retry_then_pass.junit.xml +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/skip.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/playwright/truncated.json +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_compile_error.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_multi_target_failures.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/cargo_no_parseable_failures.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_collection_error.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_log_record.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_error_string_in_body.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_internal_error.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_mixed_failures.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/fixtures/test_report/pytest_no_parseable_failures.txt +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_acceptance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_acceptance_drivers.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_api_error.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_app.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_branch_base.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_branch_capture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_config_free_1712.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_deploy_units_endpoint.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_dirty_worktree.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_drive_queue_reconcile_2373.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_graph_self_heal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_health_h3.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_idle_restart.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_push_failure.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_reap.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_repos_and_pull.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_restart_services_endpoint.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_skills_self_heal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_startup_diagnostics.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_update.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_update_bluegreen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_usage_limit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_agent_zero_commit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ambient_home_isolation.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approve_capability_reroute_3241.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approve_dependency_busy_2804.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approve_reject_plan.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approve_usage_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approved_work_2532.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_approved_work_2996.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_assignment_already_recorded_daemon.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_audit_log.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_audit_outcome.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_audit_query.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_auto_loop.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_auto_release_publish_2035.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_backend_selection.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_backup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_base_checkout_restore.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_block_log.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_cap_762.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_read_path.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_schema.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_service.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_board_wire.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_brain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_branch_model.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_bug_intake.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_bugbash.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_build_worker_image_env_update.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cargo_cache.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_check_gh_argv_containment.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_acceptance_gate_1950.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_fix.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_github.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_gitlab.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_parity_2091.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_ci_store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_claim.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_claude_md_budget.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_claude_setup_token.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_acceptance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_assign.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_oracle_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_assign_interactive_remote.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_assign_provider.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_assign_repo_drift_2219.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_chat_continue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_ci.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_codegen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_decide.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_capability_rules.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_config_provenance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_forge_availability.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_graph.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_self.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_diagnose_test_coverage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_doctor.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_free_1801.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_doctor_config_mismatch_1712.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_doctor_store_backend_3084.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_drive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_drive_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_escalate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_fix_headless_review.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_gate_a.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_install_drift.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_install_skills.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_issue_comment.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_issue_create_label.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_issue_reopen.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_issue_view_list.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_issues.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_merge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_assign.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_capture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_chat_add_child.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_b.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_gate_c.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_order.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_remove_and_issue_close.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_milestone_ship.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_network.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_new_issue_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_plans.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_portal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_pr.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_pull_artifact.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_reattach_sessions.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_refine_board.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_release_preflight.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_release_propagate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_release_window.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_repo_2220.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_review_test_author_tracking_epic_2639.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_scorecard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_serve_store_backend_3084.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_set_review_findings.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_advisory_terminal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_contested_tag.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_invariant_alarms.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_machine_fault.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_merge_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_provider.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_retried_3340.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_review_finalizing.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_supervisor_3366.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_test_failed_tag.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_status_usage_limit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_sync_comments_873.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_test_plan.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_track.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_tui_update.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cli_wait.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_client.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_client_base_install.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_client_config_cache_atomic_3052.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_client_resource_migration_1946.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_commands_common.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_comments.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_completion_summary.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_acceptance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_drift_check.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_effective.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_pricing.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_snapshot_noncanonical_2208.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_config_usage_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_confirm_test.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_conflict_fix.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_conflict_fix_semantic.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_log_daemon_fallback_2547.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test_runner_acceptance_toolchain_2936.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test_runner_baseline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test_runner_populated_home.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test_runner_routing.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_test_runner_toolchain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_uat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coord_web_sse_restart_live.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_coordinator_machine.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_cross_platform_imports.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dao.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_api.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_reports.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_server.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_terminal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dashboard_terminal_live.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_db.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dead_end.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_decomposition_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_coord_db_backup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_dist.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_coord_web_rollback.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_db_backup_unit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_drive_queue_unit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_failure_notify_unit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_manifest.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_notify_unit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_units_lane.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deploy_web_unit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deprecation_telemetry.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_deps.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_diagnose.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dispatch_liveness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dispatch_target_validation.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dispatch_workers.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dist_name.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_done_housekeeping.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dr_azure_scripts.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dr_promote.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_dr_verify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_machine_fault.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_blocked_rendering.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_launch_argv.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_max_parallel_per_repo_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_roll_pending.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_queue_self_cordon_escalation.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_sessions_snapshot.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_drive_tmux.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_epic_up_capability_detection.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_epic_up_down_symlinked_config_1887.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_epic_up_image_provenance.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_errors.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_events.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_failure_class.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_failure_classifier.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_filelock.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_finalize_interactive_exit_test_verdict.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fix_escalation_classifier.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fix_of_force_override.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fleet_config_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fleet_health_probes.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fleet_health_snapshot.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_fleet_watchdog.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_forge_availability.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_freshness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gate_a.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gate_b.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gate_snapshot_staleness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gates.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gather_fleet_tmux_sessions.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gen_mock_index.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_generated_rust_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_generated_rust_requests.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_generated_types_fixture.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_goal.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_graph_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_graph_selfheal_absent_2237.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_gtk_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_handoff.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_checks.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_cli_graph.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_context.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_coord_tui_ci_pin.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_coord_web_ci_pin.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_deploy_lane_facts.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_fix.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_incident_regression.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_issues_sync_staleness.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_pr_churn.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_pypi.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_registry.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_release_cordon_probe.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_timer_active.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_toolchain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_unit_drift.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_unit_enablement.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_health_wedged_drive_queue.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_hooks.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_housekeeping.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_human_attended_437.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_init.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_install_agent_capabilities_3515.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_install_agent_venv_2911.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_install_agent_wsl_bridge_3515.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_integration.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_briefing_echo.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_pane_log_2541.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_prefill_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_session_relaunch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_test_verdict_backstop.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_token_attribution.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_interactive_worktree.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_invariant_alarms.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_issue_store_seam.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_issues_sync_status.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_liveness_auditor.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_liveness_notify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_lock_contention_ratchet.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_mac_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_machine_fault.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_machine_metrics.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_machine_onboard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_machine_pause.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_machine_stats.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_merge_verify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_milestone_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_milestone_dispatch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_milestone_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_milestone_order.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_milestone_seam.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_mock_author.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_model_tiering.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_models.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_models_config_labels.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_needs_attention.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_network.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_new_issue_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_next_release_tag.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_node_shim.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_baseline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_cli.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_collect.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_drive_seam.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_isolation.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_predicate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_quiet_hours.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notifier_service.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_notify_drain.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_openapi.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_operational_defaults.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_overlap_fence.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_overlap_predict.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_packaged_deploy_units.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_parentage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_paste_landed.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_phantom_heal_venv_independence_2570.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_pipeline.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_plan_followup_approve_plan_command.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_plan_followup_pr_command.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_plan_followup_review_command.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_plan_only.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_plan_parser.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_platform_paths.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_portal_bridge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_portal_config.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_portal_store.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_portal_sync.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_pr_body_lint.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_prereqs.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_production_db_guard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_progress.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_provider_seam.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_providers.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_providers_config_labels.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_providers_pty.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_provision_core.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_provision_machine.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_py_rust_mirror_inventory.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_quiet_hours.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_quiet_hours_store_2146.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reap_merged_sessions.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reap_stale_interactive_tick.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_branch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_completions.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_late_agent_reports_2547.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_merges.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_no_agent_record.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_tick.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reconcile_usage_limit_done.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_refine_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_cordon_2101.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_cordon_daemon_leads_2176.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_cordon_deadlock_2240.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_cordon_drain_stall_3336.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_cordon_stuck_2490.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_gate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_propagate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_propagate_threshold.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_roll_between_legs_2854.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_roll_window_handoff.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_unified_1242.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_verify.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_release_window.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_remote_auto_prune.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_remote_interactive_reaper.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_add.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_dormancy.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_edit_2220.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_graph_fleet_2237.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_max_parallel_3423.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_repo_onboard_2220.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_report_public_export.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_report_result_push.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_reports.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_restart_cmd.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_retry.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_retry_advisory_1606.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_retry_escalation_classify_3360.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_retry_type_1636.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_revalidate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_end_review_without_verdict.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_parse_failure_diagnostic.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_reaffirm.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_verdict_backstop.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_verdict_override_audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_verdict_relay.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_review_zero_commits.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_scoped_review_wiring.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_scorecard.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_self_health.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_serve.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_serve_app.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_serve_app_board_trim.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_serve_rest_routes.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_session.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_slice_issue_attribution.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_smoke.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_smoke_fanout_manifest_3333.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_smoke_live_checkout_restore.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_smoke_workflow.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_spend_ceiling.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_spend_ceiling_coordinator.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_split.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_split_work.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_sql_dialect.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_sqlite_connect_ratchet.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stage_projection.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stale_busy_reviewer_697.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_state.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_state_review_findings_daemon.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_status_fleet_footer.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stop_1567.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_store_contract.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_store_migrate.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stuck.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_stuck_test_state_watchdog_2803.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_terminal_command.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_author.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_chat.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_orchestrator.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_report.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_verdict_parsing.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_test_verdict_transcript_floor.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_text_io_encoding_audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_thin_client_board_audit.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_thin_client_config_load_1080.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_thin_client_daemon_routing_906.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_throwaway_vm.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_tmux_host.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_tmux_session.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_transcript_floor.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_tui_pty_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_uat_checks.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_usage.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_usage_limits.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_usage_rollup.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_venv_live_install_2121.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_version_single_source.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_watch.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_win_native_bridge.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_win_native_driver.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_windows_job_is_a_real_gate_2000.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worker_env_venv_isolation.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worker_events.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worker_image_pin_sync.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worker_safety.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worker_test_scoping.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worktree.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_worktree_rmtree_chokepoint.py +0 -0
- {code_coordinator-0.5.577 → code_coordinator-0.5.578}/tests/test_write_parity.py +0 -0
- {code_coordinator-0.5.577 → 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)
|
|
@@ -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)
|
|
@@ -2218,6 +2218,57 @@ def is_ci_pending_reason(reason: str | None) -> bool:
|
|
|
2218
2218
|
return (reason or "").startswith(CI_PENDING_PREFIX)
|
|
2219
2219
|
|
|
2220
2220
|
|
|
2221
|
+
# #3536: floor/cap for `ci_pending_poll_interval_s`'s exponential growth.
|
|
2222
|
+
# `CI_PENDING_POLL_BASE_S` matches the fastest fixed poll cadence #2809's own
|
|
2223
|
+
# incident narrative already named (15s); `CI_PENDING_POLL_CAP_S` keeps a
|
|
2224
|
+
# long-pending entry from ever waiting so long that a genuinely-resolved
|
|
2225
|
+
# check goes unnoticed for minutes at a stretch.
|
|
2226
|
+
CI_PENDING_POLL_BASE_S = 15.0
|
|
2227
|
+
CI_PENDING_POLL_CAP_S = 300.0
|
|
2228
|
+
|
|
2229
|
+
|
|
2230
|
+
def ci_pending_poll_interval_s(
|
|
2231
|
+
consecutive_pending_polls: int,
|
|
2232
|
+
*,
|
|
2233
|
+
base: float = CI_PENDING_POLL_BASE_S,
|
|
2234
|
+
cap: float = CI_PENDING_POLL_CAP_S,
|
|
2235
|
+
) -> float:
|
|
2236
|
+
"""How long a caller should wait before re-checking CI again, given how
|
|
2237
|
+
many CONSECUTIVE times in a row it has already observed this entry as
|
|
2238
|
+
``checks_pending`` (#3536).
|
|
2239
|
+
|
|
2240
|
+
Doubles *base* once per consecutive pending observation, capped at
|
|
2241
|
+
*cap*: ``ci_pending_poll_interval_s(0)`` is *base* itself (the very
|
|
2242
|
+
first pending read — no reason yet to slow down),
|
|
2243
|
+
``ci_pending_poll_interval_s(1)`` is ``2 * base``, and so on, never
|
|
2244
|
+
exceeding *cap* once the doubling would.
|
|
2245
|
+
|
|
2246
|
+
#2814's fix made every poll re-issue a real, attempt-exempt ``coord
|
|
2247
|
+
merge --only`` re-check for as long as an entry sits CI-pending — the
|
|
2248
|
+
only thing that refreshes a standalone drive's cached ``error`` (see
|
|
2249
|
+
:func:`coord.drive._decide_merge`'s module comment on the four
|
|
2250
|
+
CI-outcome siblings `is_ci_pending_reason` is one of). That is correct
|
|
2251
|
+
for a single entry in isolation, but #3536's incident shows it does not
|
|
2252
|
+
scale: several sibling entries on the same host parked on CI-pending at
|
|
2253
|
+
once all re-check on the SAME fixed interval, serializing through the
|
|
2254
|
+
host-wide merge lock and adding `gh` calls that only grow GitHub's
|
|
2255
|
+
secondary-limit exposure the longer CI genuinely stays pending — exactly
|
|
2256
|
+
when the fleet can least afford more traffic.
|
|
2257
|
+
|
|
2258
|
+
This is the pure interval policy a caller tracking a per-entry pending
|
|
2259
|
+
streak (a persisted counter alongside the existing
|
|
2260
|
+
``ci_infra_reruns``/``ci_flaky_reruns``/``ci_unreadable_reruns``) can use
|
|
2261
|
+
to space those re-checks out the longer CI stays pending, instead of
|
|
2262
|
+
polling on the same fixed cadence indefinitely. Deliberately pure (no
|
|
2263
|
+
clock read, no persistence, no `gh` call) so the growth policy itself is
|
|
2264
|
+
cheaply unit-testable independent of wherever a caller decides to track
|
|
2265
|
+
the streak and the wall-clock moment it last actually checked.
|
|
2266
|
+
"""
|
|
2267
|
+
consecutive_pending_polls = max(0, int(consecutive_pending_polls))
|
|
2268
|
+
interval = base * (2.0 ** consecutive_pending_polls)
|
|
2269
|
+
return min(interval, cap)
|
|
2270
|
+
|
|
2271
|
+
|
|
2221
2272
|
# #2347: the reason string prefix for a `checks_failed` block whose failing
|
|
2222
2273
|
# check(s) are ALL the #1525 synthetic "could not read CI status"/"gh too
|
|
2223
2274
|
# old" stand-ins (`coord.ci_store.is_unreadable_check`) — the check-list
|