Operant Studio
OPER-70

agent-size-override workflow silently skips size-XL PRs (check_run.head_sha != PR head)

Suggested
Justin Cooke

Body

feature_id: FEAT-studio-dispatcher

## Context

`.github/workflows/agent-size-override.yml` (POR-358) is silently no-op'ing on new size-XL PRs. Observed today on Portico #1260 (`feat(platform): AI search visibility score — engines + weekly cron (POR-316) [1/2]`), which opened at 1,718 additions across 18 files, marked ready-for-review, size/XL label applied by `pr-size.yml` — but never received the `size-override-blocked` label, was never converted to draft, and was never assigned to Justin. The workflow triggered (`check_run.completed` for `Check PR size` with conclusion `failure` fired), and the run is present in the workflow-run list — but every run for this SHA family shows `conclusion=skipped`.

**Root cause:** the `Resolve PR + gates` step uses:

```bash
gh pr list --repo "$GITHUB_REPOSITORY" \
  --search "sha:$HEAD_SHA" \
  --json ... \
  --jq '.[0]'
```

where `HEAD_SHA = github.event.check_run.head_sha`. For `check_run` events GitHub sets `head_sha` to the SHA the *check run* executed against, which for many pull-request-triggered workflows is a merge-preview SHA — not the branch head. `gh pr list --search "sha:..."` matches only against branch-head or merge-commit SHAs, so it returns empty for merge-preview SHAs and the step prints "No PR found" and exits 0.

Consequence: every size-XL PR the dispatcher has opened since (some earlier date TBD by log inspection) has slipped past auto-block. Historically some PRs (#1259, #1251) do carry the `size-override-blocked` label, so the workflow *has* worked in the past — but it is at best flaky and at worst broken across a range of head-SHA scenarios. #1260 is the confirmed current failure.

Adjacent related problem: `.github/workflows/agent-auto-ready.yml` (POR-308 flap guard) has an `if size/XL && !size-override then leave-draft` branch that only runs when the auto-ready workflow itself fires. #1251 is currently `size/XL + size-override-blocked` **without** being draft, which suggests something else transitioned it to ready after auto-ready set it draft, and no re-check runs. Worth investigating in the same PR.

## Scope

Fix the PR-resolver in `agent-size-override.yml` (and any peer workflow using the same pattern):

- Prefer `github.event.check_run.pull_requests[]` — GitHub populates this array on `check_run` events with the branch PR(s) that own the check run. Iterate this list first; only fall back to `gh pr list --search "sha:..."` if it is empty.
- If `pull_requests[]` is present, use `pull_requests[0].number` and fetch the full PR JSON via `gh pr view <n> --json ...`. This is what the rest of the step needs.
- Grep the workflows dir for other uses of `check_run.head_sha` + `gh pr list --search "sha:..."` pattern and apply the same fix wholesale.

Also — while touching this file — add an audit-trail sticky comment on the PR when the workflow *skips* (i.e. when neither `pull_requests[]` nor SHA search finds a PR), so silent skips become visible. Today the workflow's only output on the "PR not found" path is a `::notice::` in the run log, which no one reads until they go looking.

Address the auto-ready flap:

- Audit `agent-auto-ready.yml`: is there a code path where a PR marked draft-by-auto-ready gets re-flipped-to-ready by another workflow (e.g. `ready-on-green`)? If yes, gate `ready-on-green` on `size-override-blocked` label absence too.
- Real-world regression test: script a size/XL agent PR against a preview branch and confirm the label + draft state remain sticky after every check-run completion.

## Acceptance Criteria

- After merge: open a synthetic size-XL agent PR (>1,500 LOC across 18+ files, `agent/*` branch). Within 60 seconds of the `Check PR size` job failing, the PR carries `size-override-blocked`, is a draft, and Justin is assigned. Verified against a preview run.
- The workflow-run summary shows the PR number, LOC total, file count, and the failing gate — not "No PR found".
- No regression on the trusted-context reviewer-artifact gate or auto-merge flow. Auto-merge should still fire on green + size-override-labeled + not-draft PRs.
- Silent-skip fallback: if the resolver genuinely cannot find a PR (e.g. cross-repo fork), the workflow posts a run-summary annotation but does not fail closed — same shape as today's `::notice::`, but visible in the Actions run summary.

## Non-goals

- Redefining the size-override ceiling. It stays at 1,500 LOC / 25 files / 2 new deps / etc.
- Auto-splitting oversized PRs. That is a much bigger dispatcher change (POR-316's split into "PR 1/2" is doing this manually today, and half of it still exceeded the ceiling — see #1260).
- Backfilling labels on already-open PRs. Once the fix lands, any missing labels can be applied by re-running the workflow via `gh workflow run` or by pushing an empty commit to the branch. Manual fix on #1260 is already done.

## Verification

`gh workflow run agent-size-override.yml --repo Operant-Health/portico` against a synthetic size-XL PR on a preview branch. Confirm the label, draft state, and Justin-assignment all appear.

## Cross-references

- Manual tactical fix on #1260 ([REDACTED-DOB]) — labeled `size-override-blocked`, converted to draft, assigned Justin.
- Manual tactical fix on #1251 ([REDACTED-DOB]) — converted to draft (was `size/XL + size-override-blocked` without draft, flap-guard violation).
- Related workflow: `.github/workflows/agent-auto-ready.yml` — audit for re-flip path.

Attachments

Loading attachments…

Comments

Loading comments…