feat: add branch follower debug step

This commit is contained in:
Codex
2026-07-03 17:56:08 +00:00
parent b98b131bb7
commit 917cba6659
8 changed files with 486 additions and 8 deletions
@@ -11,12 +11,25 @@ bun scripts/cli.ts cicd branch-follower status
bun scripts/cli.ts cicd branch-follower status --live
bun scripts/cli.ts cicd branch-follower run-once --all --dry-run
bun scripts/cli.ts cicd branch-follower run-once --follower <id> --confirm --wait
bun scripts/cli.ts cicd branch-follower debug-step --follower <id> --step state-read
bun scripts/cli.ts cicd branch-follower debug-step --follower <id> --step status-read
bun scripts/cli.ts cicd branch-follower debug-step --follower <id> --step decide
bun scripts/cli.ts cicd branch-follower debug-step --follower <id> --step state-write --confirm
bun scripts/cli.ts cicd branch-follower events --follower <id>
bun scripts/cli.ts cicd branch-follower logs --follower <id>
```
`apply --confirm --wait` is the one-command deploy/update entry for the K8s controller. `status` is the default intermediate-state query. `status --live` and local `run-once` submit a bounded K8s reconcile Job; the Job performs all source, Tekton, Argo and runtime reads inside the cluster and may write only the compact state summary. `events` and `logs` are read-only drill-downs for the same Kubernetes-native state. `run-once --confirm --wait` is the manual one-command trigger and closeout path.
`debug-step` is the required single-step troubleshooting entry before changing branch-follower code for repeated CI/CD convergence issues. It runs in a bounded target-side Job when called from the operator host, and uses the same controller modules as the real flow:
- `state-read`: read only the compact ConfigMap state, value bytes, resourceVersion and `_updatedAt`.
- `status-read`: read native source/Tekton/Argo/runtime status without triggering adapters.
- `decide`: run the decision function in dry-run mode without triggering adapters or writing state.
- `state-write --confirm`: patch the stored follower state back through the normal ConfigMap write helper and report before/after resourceVersion; this is for isolating state write failures, not for normal rollout.
Do not debug the same state/read/write problem by repeatedly pushing empty or tiny source commits to drive the full automatic follower loop.
## Source Authority
- Follower decisions must not read host source worktrees, target dev directories, `.worktree/*`, local git state, or direct GitHub branch refs.
@@ -67,6 +80,8 @@ Default `status` output must show follower id, phase, adapter, source branch + o
Stage timing must be queryable through normal CLI output, not only raw JSON. `status` and `run-once` print a bounded `STAGE TIMINGS` table with `total`, `status-read`, git-mirror, Kubernetes Job, PipelineRun, TaskRun, Argo, runtime and closeout rows when available. `followers[].timings` remains available in `--raw`/JSON for machine consumers.
`run-once` also prints a bounded `STATE WRITES` table whenever it writes follower state. The table must include follower id, write status, before/after ConfigMap resourceVersion, whether timing was preserved, exit code and a short message. Missing write evidence is a visibility defect; use `debug-step --step state-write` before any further full-loop validation.
`timings.totalSeconds` is the authoritative end-to-end wall-clock measurement for a triggered run: measure from `timings.startedAt` until `timings.finishedAt`, or until query time while closeout is still running. Do not compute total by summing stage rows, because stage rows can overlap, omit external waiting, or be reported by different native objects.
Do not backfill, infer, or migrate old branch-follower state when historical timing, stage timing, or other observability fields are missing or known to be unreliable. Compatibility starts with future state written by the current controller; old missing data must render as `-`/unknown in CLI output instead of being recovered from unrelated native objects.