Repository navigation
feat(OMN-19888): scheduled heals update release-window reds and re-run vendor-parity reds once their cause is gone - #3026
Conversation
…ty reds once their cause is gone A PR synced inside a release window fails Release Identity Gate and a rerun replays the same merge ref; a PR whose migration was vendored into omnibase_infra dev after its parity gate failed stays red because nothing reruns the gate. pr_stale_red_heal.py decides both from live reads and acts once per head: a branch update pinned to expected_head_sha (App token, so the new head gets CI) when the failed version is below dev and dev is out of the window; a rerun of the parity run plus CI Summary when every named migration is byte-identical on infra dev and was vendored after the gate failed. Onex-Lane: market-heals-83 Onex-Session: 73ed3d50de9e420c9d831fe17a2275a3
…its merge-queue commit date omnibase_infra#4206's squash commit is dated 15:38:41Z and reached dev at 16:01:07Z; a parity gate that failed at 15:53:01Z ran before the bytes landed. Reading the committer date misclassified it as a real red. Onex-Lane: market-heals-83 Onex-Session: 73ed3d50de9e420c9d831fe17a2275a3
|
| Rule | Description |
|---|---|
| ARCH-TOPIC-001 | No hardcoded Kafka topic strings in handler code |
| ARCH-DI-001 | No event_bus=None bypass |
| ARCH-DI-002 | No direct Handler instantiation outside workflow_runner/adapters |
| ARCH-DI-003 | No reinvented DI containers |
| ARCH-TOPIC-002 | contract.yaml topics follow `onex.{cmd |
ARCH-DI-002: Direct Handler instantiation (warning)\n\n```\nsrc/omnimarket/nodes/node_projection_delegation/handlers/handler_delegation.py:1909: row.update(HandlerDelegationCohortKeyFold().handle(event).row_columns())
src/omnimarket/nodes/node_projection_delegation/handlers/handler_delegation.py:1914: ticket = HandlerDelegationTicketFold().handle(event)
src/omnimarket/nodes/node_projection_delegation/handlers/handler_delegation.py:1926: caller_lane = HandlerDelegationCallerLaneFold().handle(event)
src/omnimarket/nodes/node_projection_delegation/handlers/handler_projection_delegation.py:993: row.update(HandlerDelegationCohortKeyFold().handle(event).row_columns())
src/omnimarket/nodes/node_projection_delegation/handlers/handler_projection_delegation.py:1011: ticket = HandlerDelegationTicketFold().handle(event)
src/omnimarket/nodes/node_projection_delegation/handlers/handler_projection_delegation.py:1023: caller_lane = HandlerDelegationCallerLaneFold().handle(event)\n```\n\nHandler classes should be wired only in workflow_runner.py or adapter modules. Direct instantiation elsewhere bypasses the contract system.\n\n
Static architectural lint — no model inference (OMN-14176).
…nimarket#3026 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36333868449
✅ Hostile Reviewer — PASSEDBlocking findings (critical/error): 0 Gate semantics
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524) |
| class GhPort(Protocol): | ||
| """The GitHub reads and writes both heals need.""" | ||
|
|
||
| def open_pull_requests(self, *, repo: str) -> tuple[OpenPr, ...]: ... |
|
|
||
| def open_pull_requests(self, *, repo: str) -> tuple[OpenPr, ...]: ... | ||
|
|
||
| def check_runs(self, *, repo: str, head_sha: str) -> list[dict[str, object]]: ... |
|
|
||
| def check_runs(self, *, repo: str, head_sha: str) -> list[dict[str, object]]: ... | ||
|
|
||
| def job_log(self, *, repo: str, job_id: int) -> str: ... |
|
|
||
| def job_log(self, *, repo: str, job_id: int) -> str: ... | ||
|
|
||
| def job(self, *, repo: str, job_id: int) -> dict[str, object]: ... |
|
|
||
| def job(self, *, repo: str, job_id: int) -> dict[str, object]: ... | ||
|
|
||
| def run_jobs(self, *, repo: str, run_id: int) -> list[dict[str, object]]: ... |
|
|
||
| Any other failure raises :class:`RuntimeError`. | ||
| """ | ||
| ... |
| The merge time of the PR that landed it when there is one, else the | ||
| commit's committer date; ``""`` when unread. | ||
| """ | ||
| ... |
|
|
||
| def update_branch( | ||
| self, *, repo: str, pr_number: int, expected_head_sha: str | ||
| ) -> None: ... |
| self, *, repo: str, pr_number: int, expected_head_sha: str | ||
| ) -> None: ... | ||
|
|
||
| def rerun_run(self, *, repo: str, run_id: int) -> None: ... |
|
|
||
| def rerun_run(self, *, repo: str, run_id: int) -> None: ... | ||
|
|
||
| def rerun_job(self, *, repo: str, job_id: int) -> None: ... |
* evidence(OMN-19888): author OCC companion for OmniNode-ai/omnimarket#3026 OCC companion by node_pr_lifecycle_fix_effect (OMN-13317 F1 / OMN-13990 / OMN-14285). Product PR head 77c098b612764b78805df10d58bb03952ace5b6e. * evidence(OMN-19888): self-bind OCC#11670 + rebind contract_sha256 * evidence(OMN-16859): executed test_passes receipts for OmniNode-ai/omnimarket#3026 The declared checks were executed for real in the OmniNode-ai/omnimarket checkout at the PR head by the product-repo OCC receipt runner, and the results written append-only into this companion. Producer-minted PENDING receipts are superseded by a net-new record; no existing receipt was edited. Ticket: OMN-16859 (AC3b) Onex-Workflow: OCC Receipt Runner Onex-Run: https://github.com/OmniNode-ai/omnimarket/actions/runs/36333868449 --------- Co-authored-by: omnimarket-bot <bot@omninode.ai> Co-authored-by: onexbot-occ-writer[bot] <307849072+onexbot-occ-writer[bot]@users.noreply.github.com>
OMN-19888: scheduled heals for release-window and vendor-parity reds
Ticket: OMN-19888 (child of OMN-19852). Source: the omnimarket stall diagnosis, ledger TERMINAL 2026-09-27T16:07:43Z lane=market-armed-stall-83, findings 3 and 4.
What this fixes
Two required reds on omnimarket PRs are caused by something outside the PR, and neither one clears when that cause goes away.
Release Identity Gate. A rerun replays the same pinned merge ref, so only a branch update clears it (fix(OMN-19234): the bus receipt names the backend key that answered, not uuid5 of the model id #3009, feat(OMN-19513): node_projection_claude_hook_events -- every Claude Code hook, with subagent lineage #2956, feat(OMN-19513): the emit registry routes hook.event and redaction governs nested members by dotted name #2955, feat(OMN-19550): full-content capture topic, a span-scrub capture class and a session_content projection #2905 on 2026-09-27).node-migration-vendor-parity-gatefails until omnibase_infra dev vendors the PR's migration. Nothing reruns it afterwards, andCI Summaryasserts it as an external context.What this adds
scripts/ci/pr_stale_red_heal.pyfollows the shape ofocc_companion_merge_heal.py(OMN-18812). It has two pure decision functions, aGhPortprotocol, and one enumerated outcome per branch. An unreadable open-PR list exits red, and so does a pass where every write fails.update-branchpinned toexpected_head_shawhen all three hold:Release Identity Gatefailed naming a version below dev's current one;CI Summaryjob, when both hold:merged_at, not the squash commit's date. On omnibase_infra#4206 the merge queue dated the commit 15:38:41Z, and it merged at 16:01:07Z..github/workflows/pr-stale-red-heal.ymlruns every 10 minutes, offset 5 minutes from the companion heal. It also runs on push to dev touchingpyproject.toml(the bump PR merging) and onworkflow_dispatch(pr-number, heal, dry-run).pull_requesttrigger and nocontinue-on-error, and it is not a required context.actions: writeis scoped to its one job.release-on-merge.ymluses. An update-branch authored byGITHUB_TOKENstarts no workflow on the new head. Without the token, the update is refused, not issued.tests/ci/test_pr_stale_red_heal_omn19852.pyhas 54 tests, including the ticket's AC falsifiers:-k release_window: 20 pass-k release_window_refuses: 14 pass-k vendor_parity: 22+ pass-k vendor_parity_refuses: 15+ pass-k workflow: 5 passWhy not bulk_pr_throttle.py
Lanes route bulk update-branch and rerun through omnibase_infra's
bulk_pr_throttle.py. This scheduled workflow cannot use it, for two reasons:CROSS_REPO_PATis being retired under OMN-16373.expected_head_sha.The script applies the same bound itself: at most 5 branch updates and 10 rerun PRs per pass, with the rest deferred to the next pass.
Controls (live, read-only; no write was issued)
conflicted.not_vendored. Infra PRs fix(OMN-17427): release staleness counts dev merge tags as published #4210, docs(OMN-17427): remove 33 unreferenced docs files after archiving them #4169, feat(OMN-20910): native Anthropic Messages protocol with prompt caching for the review gateway #4209 and feat(OMN-21144): score recorded gate cascades #4154 are still open.gate_not_red.dev_in_window, so it is not updated while dev is inside the window.update_required, parsed from the live gate log "pyproject version 0.4.248 is NOT ahead of the latest published version 0.4.248".rerun_requiredfor run 36331166338. That is the run a lane reran by hand at 16:15Z after omnibase_infra#4206 merged.failed_after_vendor. That was the defect the second commit fixes.Checks
ruff format/ruff checkclean on the new files.mypy --strictclean on the module and the test.pre-commit run --fileson the three files: rc 0.check_action_pins.pyOK.check_workflow_module_refs.pyPASS.test_ci_summary_gate.py,test_self_hosted_sibling_clone_hygiene.pyand the OMN-18812 heal suite (246 tests).Lab
The change is CI-only: a workflow, a script under
scripts/ci/and a test. It touches nothing undersrc/, docker or migrations. It is not runtime-affecting, so there is no lab pass to cite. There is also no tenant, RLS or reader path.No collision with omnimarket#3023, which edits
occ_companion_merge_heal.py, its workflow and its test. This PR touches none of those files.Evidence-Ticket: OMN-19888
Evidence-Source: OCC#11670