Skip to content

fix(OMN-15532): exempt structurally-unreportable external contexts by PR author — Dependabot PRs wedge on absent 'gate / CodeRabbit Thread Check' - #2574

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-15532-dependabot-external-context-exemption
Jul 30, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-15532-dependabot-external-context-exemption

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 30, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-15532 — regression introduced by OMN-15496 (#2569)

#2569 (merged 2026-07-30T18:14:35Z) taught the CI Summary poller to assert 17 cross-workflow contexts against commits/{sha}/check-runs, fail-closed. One admitted context — gate / CodeRabbit Thread Check — is structurally absent on Dependabot PRs, so every untouched Dependabot PR on infra dev now burns the 90-minute poll deadline and then fails the sole required context.

Root cause

.github/workflows/cr-thread-gate-caller.yml gates the gate job on (github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'). The context name is the caller-job / reusable-job form, so when the caller job skips, the reusable's inner job never materialises and no check-run is created at all — the context is absent, not skipped.

scripts/ci/ci_summary_gate.py:193 already stated the hazard: "a permanently-absent entry burns the poll deadline and then fails closed." ci.yml sets DEADLINE_MINUTES: "90".

Why the seed measurement missed it

OMN-15496 admitted this context after measuring it 16/16 present over #2546–#2567. That window contains no Dependabot PR (the last batch was #2515–#2522 on 2026-07-28). A context can be 16/16 present and still absent in production if the sample never covered the PR shape.

Live readback — the actor is the discriminator (all pull_request, run_attempt=1):

PR head run actor CR-gate run context
#2522 2cdf352d dependabot[bot] skipped ABSENT
#2521 841c292f dependabot[bot] skipped ABSENT
#2520 feb6627b jonahgabriel ran success
#2519 08e356cc jonahgabriel ran success
#2518 e2d38605 jonahgabriel ran success

CI Summary itself does run and report on Dependabot PRs (success on #2522/#2521 pre-#2569), so the poller reaches the assertion and fails on it. Same class already live on a sibling repo: rolling ledger 2026-07-29T06:20Z records omnibase_core#1522/#1523 blocked as "missing required contexts gate / CodeRabbit Thread Check".

Fix — consumer-side, and why not producer-side

A declared ACTOR_CONDITIONAL_CONTEXTS registry drops a context only for the authors whose PRs structurally cannot produce it. This is an applicability rule, not a bypass: the context stays fail-closed for every other author, and a missing --pr-author drops nothing (forgotten argument enforces).

OMN-10276 fixed this on omnimemory by removing the producer skip. That is not portable here: omnimemory calls a local reusable and passes no secrets, whereas this caller invokes omniclaude's reusable with secrets: CROSS_REPO_PAT. Dependabot pull_request runs do not receive regular repo secrets, so dropping the skip here risks trading an absent-wedge for a red-wedge. Stated as a premise to verify, not assumed.

RED-before / GREEN-after against the real #2522 payload (98 unedited check-run rows, fixture tests/ci/fixtures/omn15532_dependabot_pr2522_check_runs.json) — "exists but wrong", not an ImportError:

PRE-CHANGE gate (origin/dev, live right now):
  verdict: PENDING(2) -> FAILURE at the 90m deadline
  external contexts missing/pending: gate / CodeRabbit Thread Check
POST-CHANGE, pr_author=dependabot[bot]:  SUCCESS(0)
POST-CHANGE, pr_author=jonahgabriel:     PENDING -> FAILURE   (enforcement preserved)

AC6 no-wedge replay, whole Dependabot batch #2515–#2522 at merge time:

blocked
PRE (live code) 5/8 — 3 of them wedged on the CR context
POST (this PR) 2/8 — #2517/#2518, genuine URL Authority Gate reds, correctly preserved

Zero residual blocks attributable to the CR context; no real failure was suppressed.

The fixture is also asserted to isolate the case: gate / CodeRabbit Thread Check is the only admitted context absent on that head; the other 16 are all present+success.

Acceptance criteria

  • AC1 RED-before on the real absent-context payload → test_dependabot_pr_is_not_wedged
  • AC2 enforcement preserved for human authors → test_same_payload_still_blocks_a_human_author
  • AC3 falsification control — registry entry monkeypatched away, same fixture blocks again → test_exemption_entry_is_load_bearing
  • AC4 registry keys must be asserted contexts; actors must be concrete logins (no wildcards) → test_registry_keys_are_asserted_contexts, test_registry_actors_are_concrete_logins
  • AC5 bound in ci.yml in the same change → test_ci_yml_passes_pr_author
  • AC6 batch replay above
  • Plus: a failing context still fails for dependabot (exemption ≠ bypass), and a forgotten --pr-author enforces the full set.

Gates (run on .200, patch-transfer; per-file sha256 verified identical local↔remote before gates ran)

  • ruff format + ruff check --fix — clean
  • mypy scripts/ci/ci_summary_gate.py — Success, no issues
  • pytest tests/ci/test_ci_summary_gate.py — 51 passed (41 pre-existing + 10 new)
  • pre-commit run --files <4 changed> — rc=0

Scope

No branch-protection mutation — dev's required set stays ["CI Summary"]. Does not touch OMN-15484 hold-gate fan-out. The omnibase_core instance of the same wedge is called out on the ticket as a separate fan-out.

Disclosure

I did not author the OCC companion for this PR (implementer must not author its own evidence). occ-preflight / eligibility and its cascade will be red until an independent evidence author supplies the Evidence-Source: line — the standing OCC-companion jam class, not a defect in this change.

dod_evidence: OMN-15532 — RED-before/GREEN-after against the real #2522 check-runs payload; 8-PR merge-time batch replay 5/8→2/8 with both real reds preserved; 4 gates green on .200 with sha256 parity verified pre-gate.

Closes OMN-15532

Evidence-Ticket: OMN-15532
Evidence-Source: OCC#5646

… PR author

OMN-15496 (#2569, merged 2026-07-30T18:14:35Z) made CI Summary assert 17
cross-workflow contexts fail-closed. One of them, "gate / CodeRabbit Thread
Check", is structurally absent on Dependabot PRs: cr-thread-gate-caller.yml
skips the caller job when github.actor == dependabot[bot], and because the
context is the caller-job/reusable-job form, the inner job never materialises
so NO check-run is created. Absent burns the 90 min poll deadline and then
fails closed against the SOLE required context on infra dev.

The OMN-15496 seed measured this context 16/16 present over #2546-#2567 -- a
window containing no Dependabot PR, which is how a 16/16 context can still be
absent in production.

Fixed consumer-side via a declared ACTOR_CONDITIONAL_CONTEXTS registry, not by
removing the producer skip: OMN-10276 took the producer route on omnimemory,
but omnimemory calls a LOCAL reusable and passes no secrets, whereas this
caller invokes omniclaude reusable with secrets: CROSS_REPO_PAT. Dependabot
pull_request runs do not receive regular repo secrets, so dropping the skip
here risks trading an absent-wedge for a red-wedge.

This is an applicability rule, not a bypass: the context stays fail-closed for
every author not named in the registry, and a missing --pr-author drops
nothing.

RED-before/GREEN-after on the real #2522 payload (98 unedited check-run rows):
pre-change gate -> PENDING (deadline FAILURE) naming the CR context;
post-change with dependabot[bot] -> SUCCESS; post-change with jonahgabriel ->
still PENDING. Replaying the whole Dependabot batch #2515-#2522 at merge time:
5/8 blocked before, 2/8 after, and both survivors are genuine URL Authority
Gate reds that are correctly preserved -- zero residual blocks attributable to
the CR context.

Bound in ci.yml in the same change (--pr-author), pinned by a test.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 6 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06dd0c66-573a-44ff-a2cf-49daec10b14e

📥 Commits

Reviewing files that changed from the base of the PR and between 27478af and 7487bbf.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • scripts/ci/ci_summary_gate.py
  • tests/ci/fixtures/omn15532_dependabot_pr2522_check_runs.json
  • tests/ci/test_ci_summary_gate.py

Comment @coderabbitai help to get the list of available commands.

jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Jul 30, 2026
#5646)

* evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2574

* evidence: OCC companion self-bind for #5646

---------

Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8468/OMN-8524) and do not block merge. Error: all review endpoints [192.168.86.201:8000 192.168.86.201:8001 ] unreachable — preflight short-circuit (no models available)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical findings No
blocked CRITICAL findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)

@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Recovery (lane-recover-0730): close+reopen to force GitHub to recompute refs/pull/N/merge against the repinned dev (efe52ef, #2577). The existing ci.yml run on this head is a startup failure built from the pre-repin merge commit and is not retryable (HTTP 403 "cannot be retried" — 0-job runs). Head SHA is unchanged, so the merged OCC companion and its Evidence-Source stamp stay valid; that is why update-branch/empty-commit were NOT used. Proven on #2575: run assembled with 33 jobs. No merge, no auto-merge, no bypass.

@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Recovery pass 2 (lane-recover-0730): the previous cycle's CI Summary failure was an artifact of my own back-to-back close+reopen — cycle 2 cancelled cycle 1's in-flight external contexts, and a cancelled context is read as failed/unresolved by the OMN-15496 fail-closed poller, which sampled in the ~2min window before the re-run went green. ci_summary_gate.latest_check_run_by_name is latest-wins, so a single clean cycle with nothing in flight resolves it. All 40+ ci.yml jobs passed on the last run; CI Summary was the only failure. Head SHA unchanged; merged OCC companion and Evidence-Source stamp untouched. No merge, no bypass.

@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Recovery pass 3 (lane-recover-0730), final: this head now carries TWO CI Summary check-runs — a stale FAILURE from a run my own pass-2 cycle cancelled, and a later SUCCESS. CI Summary is the sole required context on infra dev (strict=false), and the PR is BLOCKED even though the newest one is green — a live instance of the duplicate-context ANY-vs-ALL branch-protection exposure tracked in OMN-15112. Control: #2575 merged with exactly ONE CI Summary check-run on its head. Firing one final cycle with nothing in flight (so nothing can be cancelled) to produce an unambiguous newest green. Head SHA unchanged throughout; merged OCC companion and Evidence-Source stamp untouched. If this does not clear, the head is poisoned and only a new head SHA will — that call belongs to Codex/the owning lane, not this recovery lane. No merge, no bypass.

@jonahgabriel jonahgabriel reopened this Jul 30, 2026
@jonahgabriel
jonahgabriel merged commit f2e905f into dev Jul 30, 2026
493 of 510 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-15532-dependabot-external-context-exemption branch July 30, 2026 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant