|
| 1 | +# Design note: watch the external PR/MR CI pipeline to green |
| 2 | + |
| 3 | +Status: proposal, not implemented. Recommendation: file as its own ticket. |
| 4 | + |
| 5 | +## Problem |
| 6 | + |
| 7 | +Today the workflow bot runs the dashboard-configured pre-PR checks inside the Run |
| 8 | +Workspace, then pushes the branch and opens the PR/MR. Once the PR is open, the |
| 9 | +provider (GitHub Actions / GitLab CI) runs its own pipeline. The bot never looks |
| 10 | +at that pipeline. When the provider pipeline fails (for reasons the in-sandbox |
| 11 | +pre-PR checks did not or could not catch), nobody feeds that failure back into a |
| 12 | +fix loop. A client hit exactly this: an MR opened, GitLab's `lint` / |
| 13 | +`Lint-Docker-Frontend` jobs failed, and the run had already reported success. |
| 14 | + |
| 15 | +The related fix in this PR stops one silent-skip (a pre-PR check that exits 0 |
| 16 | +while its dependencies are not installed now fails loudly). Watching the external |
| 17 | +pipeline is the broader, separate capability the client also asked for and is |
| 18 | +intentionally out of scope here. |
| 19 | + |
| 20 | +## Proposed behavior |
| 21 | + |
| 22 | +After `open_pr` publishes a PR/MR, a new optional block (working name |
| 23 | +`watch_ci_pipeline`) polls the provider's pipeline for the pushed head SHA until |
| 24 | +it reaches a terminal state, then branches on the result: |
| 25 | + |
| 26 | +1. Resolve the pipeline for the PR's head SHA via the VCS adapter |
| 27 | + (`apps/worker/src/adapters/vcs/*`): GitHub check runs / commit statuses for a |
| 28 | + ref; GitLab pipelines + jobs for a ref. |
| 29 | +2. Poll on an interval with a bounded deadline, driven by the run budget's |
| 30 | + remaining duration (reuse `ctx.observeBudget()` so a stuck pipeline cannot |
| 31 | + outlive the run). Poll cadence and max wait are block params. |
| 32 | +3. Ignore non-gating checks. Meticulous is explicitly excluded (it posts its own |
| 33 | + visual-review status that must not gate the bot). Maintain an ignore-list of |
| 34 | + check/job names (and/or contexts), defaulting to a Meticulous matcher, so the |
| 35 | + watcher only waits on and reacts to gating jobs. |
| 36 | +4. Terminal outcomes: |
| 37 | + - all gating jobs succeeded -> `ok: true` (branch to done / Slack / ticket move); |
| 38 | + - one or more gating jobs failed -> collect each failed job's name + log tail |
| 39 | + and feed them into the existing fix loop (same shape the pre-PR runner uses |
| 40 | + for `runFixAgent`: a prompt with the failing job output, then re-push and |
| 41 | + re-watch), capped by a max-attempts param and the run budget; |
| 42 | + - pipeline never reaches terminal state before the deadline -> surface a |
| 43 | + bounded, transparent failure (budget/deadline), never a silent pass. |
| 44 | + |
| 45 | +## Where it plugs in |
| 46 | + |
| 47 | +- New block type registered in `apps/worker/src/workflow-definition/block-registry.ts` |
| 48 | + and a matching case in the interpreter/agent block switch (`agent.ts`). |
| 49 | +- New VCS adapter methods: `getPipelineForRef(headSha)` / `listCheckRunsForRef` |
| 50 | + returning a normalized `{ name, status, conclusion, logsUrl }[]` across GitHub |
| 51 | + and GitLab, plus a way to fetch a failed job's log tail. |
| 52 | +- Reuse the fix-agent machinery already in `pre-pr-checks/runner.ts` |
| 53 | + (`runFixAgent`, `buildFixPrompt`) so external-CI failures and pre-PR failures |
| 54 | + share one repair path and one budget accounting. |
| 55 | +- Ignore-list config (Meticulous by default) alongside the pre-PR checks config |
| 56 | + so it is dashboard-managed and versioned like the rest of the gate config. |
| 57 | + |
| 58 | +## Risks / open questions (for the ticket) |
| 59 | + |
| 60 | +- Polling long pipelines against the per-invocation limit: this must be |
| 61 | + budget-bounded and heartbeat-safe; a pipeline that runs for an hour cannot pin |
| 62 | + the run. Confirm the WDK invocation model tolerates the poll loop. |
| 63 | +- Re-push after a fix re-triggers the provider pipeline, which re-triggers the |
| 64 | + watcher: needs a clear max-attempts and loop-boundary so it cannot ping-pong. |
| 65 | +- Which statuses gate (required checks only vs all): should read the provider's |
| 66 | + branch-protection / required-checks set where available rather than guessing. |
| 67 | +- Meticulous-style checks that are `pending` forever must be treated as ignored, |
| 68 | + not as "still running", or the watcher waits on them until the deadline. |
| 69 | + |
| 70 | +## Recommendation |
| 71 | + |
| 72 | +File as its own ticket (its own block type, adapter surface, and budget/loop |
| 73 | +design). Do not fold it into the missing-dependency pre-PR fix, which is a |
| 74 | +narrow, self-contained correctness fix. |
0 commit comments