Skip to content

fix(OMN-20522): CI Summary holds an L4 red while a newer producer run is unfinished - #1882

Merged
jonahgabriel merged 3 commits into
devfrom
OMN-20522-l4-wait
Oct 4, 2026
Merged

jonahgabriel merged 3 commits into
devfrom
OMN-20522-l4-wait

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Ticket OMN-20522, repository omnibase_core. This PR modifies scripts/ci/ci_summary_gate.py, the CI Summary poller step in .github/workflows/ci.yml, tests/ci/test_ci_summary_l4_wait_omn20522.py, and fixtures in tests/ci/fixtures/omn20522/*.json.

The defect occurred when the CI Summary read a cancelled DB ownership CI twin (B1) row as a failure while a newer run of the same producer workflow was still running. The fix allows the poller to write actions/runs?head_sha=<sha> to workflow_runs.json and pass the new optional --workflow-runs-file. The gate maps the stale row's run id (from details_url) to its workflow_id and holds the context pending (never green) when a run of the same workflow_id, same event, same head, that is not completed is either a higher run id or the stale row's own run id restarted after the row concluded. This applies to cancelled, failure, and skipped rows only; timed_out and action_required remain strict.

  • Case A: omnibase_core#1881 head 4ba4fdba, CI run 37191706046, verdict FAILURE at 09:28:15Z. The row read was check-run 111405107275 (run 37191600018) cancelled at 09:18:11Z, 604 s old against CANCELLED_SUPERSESSION_GRACE_S = 600. Replacement run 37191705833 (same workflow, started 09:18:02Z) was running; its DB ownership job needs occ-preflight / eligibility (in progress until 09:28:55Z), so its row (check-run 111406835614) only appeared at 09:28:58Z and concluded success at 09:29:04Z. The replacement lives in a different check suite, so the existing suite-sibling hold could not see it.
  • Case B: omnibase_core#1869 head f7402aa6, CI run 37178554646 attempt 2, verdict FAILURE at 05:30:38Z (job ran 05:30:30Z to 05:30:40Z). Stale row check-run 111366443636 was the attempt-1 cancelled row of run 37178554468 (cancelled 05:00:34Z). Attempt 2 of the same run started 05:30:27Z; its row (111370863248) started 05:31:26Z and concluded success.
  • Replay: Fixtures are public GitHub API rows, ids and timestamps verbatim, trimmed to the fields the gate reads, re-stated as of the replay instant.
    • Case A at now=09:28:15Z: before (origin/dev gate) failures=[DB ownership CI twin (B1)]; after, pending=[DB ownership CI twin (B1)].
    • Case B at now=05:30:38Z: before failures; after pending.
    • Case B reconstruction: the poller's own payload is not in the job log; the live FAILURE proves no unfinished sibling was visible in the stale row's suite, so the in-suite occ-preflight row is omitted from that replay.
  • RED: With scripts/ci/ci_summary_gate.py and ci.yml restored to origin/dev, tests/ci/test_ci_summary_l4_wait_omn20522.py: 56 failed, 5 passed. With the change: 212 passed across that file, tests/ci/test_external_verdict_supersession_omn18807.py and tests/unit/scripts/ci/test_ci_summary_gate.py.

Behaviour kept strict

  • Fail-closed: a missing or unreadable runs file, an unparseable details_url, a run absent from the list, a run without workflow_id or status, another head, another event, another workflow: not held, so the red fails on the poll that observes it, as before.
  • Only a real success row resolves a context.
  • The poller deadline (DEADLINE_MINUTES 130) and the exit-2 PENDING handling are untouched, so a sustained hold still becomes FAILURE at the deadline.
  • The runs fetch is not part of the mandatory fetch chain; a failed fetch removes the file.

Lab

Lab: h201 (omninode-pc), lane ci-summary-l4-wait, uv run pytest on the three focused files at 2e0c3b4 exit 0 (212 passed); the live poller path was not exercised on a lab runtime, the replay of the real case A and case B rows is the proof surface.

  • Host: h201 (hostname omninode-pc)
  • Lane: ci-summary-l4-wait
  • SHA: 2e0c3b4604
  • Command: uv run pytest tests/ci/test_ci_summary_l4_wait_omn20522.py tests/ci/test_external_verdict_supersession_omn18807.py tests/unit/scripts/ci/test_ci_summary_gate.py -q -n 0
  • Exit: 0
  • Result: 212 passed.
  • The live poller path was NOT exercised on a lab runtime; the replay of the real case A and case B rows through the gate is the proof surface.

Not exercised

  • Sibling repos: omnimarket (replacement_run_in_flight, #3039) and omnibase_infra (replacement_run_in_flight) already carry an equivalent hold, so no PR there.
  • Pre-existing, not touched: pre-commit run --all-files reports a single-class-per-file violation for SprintRollJournal in src/omnibase_core/nodes/node_sprint_roll_apply_effect/runtime_sprint_roll_apply.py; mypy reports one unreachable-statement note at the parser.error return in the gate's main, present on origin/dev as well.

Evidence-Ticket: OMN-20522
Evidence-Source: OCC#12773

@jonahgabriel
jonahgabriel requested a review from a team as a code owner October 4, 2026 10:12
@jonahgabriel
jonahgabriel enabled auto-merge (squash) October 4, 2026 10:34
jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Oct 4, 2026
…12773)

* evidence(OMN-20522): author OCC companion for OmniNode-ai/omnibase_core#1882

OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 2e0c3b4604a93f77ecc03475ee56a0f894d96675.

* evidence(OMN-20522): self-bind OCC#12773 + rebind contract_sha256

---------

Co-authored-by: omnimarket-bot <bot@omninode.ai>
@jonahgabriel
jonahgabriel merged commit 7f5123d into dev Oct 4, 2026
476 of 545 checks passed
@jonahgabriel
jonahgabriel deleted the OMN-20522-l4-wait branch October 4, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant