Show release blockers on the dashboard and add a controller-only deploy

Makes the dashboard show where the release actually stands and adds a safe way to redeploy only the controller.

  • Ledger: the controller's tick reads the failed package job from GitLab and records Package · blocked with the job link. Incident status stays awaiting_canary, so retrying the job still packages the verified SHA. Each failed job is recorded once.
  • Public detail: blocked rows show a fixed reason per stage. Private error text is still never published.
  • Dashboard: progress strip with stage detail, metrics (alert → MR, alert → verified merge, attempts, changed lines), agent steps, release gate, struck-through cleared blocks, hash-chain badge, dark mode. No italics, taglines or helper text.
  • Deploy: python -m scripts.bootstrap controller ... builds Dockerfile.control only and refuses a Terraform plan that changes anything other than the controller image.

Tests: 115 passed locally, including new tests for package-failure recording, public reasons, the dashboard DOM contract and the plan guard.

🤖 Generated with Claude Code

Merge request reports

Loading
Loading