Skip to content

fix(OMN-15378): gate deploy-agent tests through CI Summary — advisory job becomes mechanism - #2553

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-15378-ac3-strict-wiring
Jul 30, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-15378-ac3-strict-wiring

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 30, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-15378 AC3 — enforcement leg: the deploy-agent guard was code, not mechanism

OMN-15378 AC1 wired scripts/deploy-agent/tests/ to RUN on PRs. Live adjudication of AC3 found it was wired into no aggregator:

  • deploy-agent-tests lived in its own workflow file (own run_id), path-filtered on scripts/deploy-agent/**.
  • scripts/ci/ci_summary_gate.py polls actions/runs/${RUN_ID}/jobs for ci.yml's own run only — so it structurally could not observe that job.
  • The job was absent from omnibase_infra dev's required set (live: ["CI Summary"], single umbrella context) and absent from both STRICT_GATE_JOBS (17 entries) and SKIPPABLE_GATE_JOBS, which PR fix(OMN-15378): wire scripts/deploy-agent/tests into CI + guard uncollected roots #2542 never touched.

Net: a RED deploy-agent run left the sole required context GREEN. Visibility yes, enforcement no — the exact "test exists but blocks nothing" class the ticket was filed to close ([[feedback_a_rule_is_not_a_mechanism]]).

What changed (7 files, +456/-25)

File Change
.github/workflows/ci.yml new unconditional deploy-agent-tests job that calls the existing workflow, so its result lands in ci.yml's own run as the check-run Deploy Agent Tests (OMN-15378) / deploy-agent-tests
.github/workflows/deploy-agent-tests.yml workflow_call-only (was path-filtered pull_request/push/merge_group): no duplicate double-run, and the path filter's blind spot — a break outside scripts/deploy-agent/** produced zero signal — is gone. concurrency: dropped (in a called workflow github.workflow resolves to the caller, shadowing ci.yml's PR-keyed group)
scripts/ci/ci_summary_gate.py registers that check-run in STRICT_GATE_JOBS
tests/ci/test_ci_summary_gate.py pins the strict registration; proves red/skipped/absent all fail closed; new meta-test: every gate name must be a name the jobs API can actually report for ci.yml's run
scripts/validation/validate_test_root_collection.py a registered standalone root now also requires its wiring workflow to reference the root and be PR-reachable (own pull_request trigger, or a PR-reachable workflow calls it via uses:)
tests/ci/test_validate_test_root_collection.py 3 synthetic RED cases + a live assertion that the shipped registration is PR-reachable
scripts/enforcement_parity_manifest.yaml the deploy-agent-tests MISSING entry is resolved, with the residual flagged

Why not the branch-protection PUT the parity manifest anticipated: that workflow was path-filtered, and a required context that does not report on every PR shape wedges merges indefinitely. Folding it under the CI Summary umbrella is the same pattern used for Effect-Assertion Gate (RT-5) and OCC Companion Merged Gate (OMN-15214).

Why not fold the tests into the root tests/ tree: unchanged from #2542 — both trees declare a top-level tests package, so one pytest session raises ImportPathMismatchError, and scripts/deploy-agent carries its own uv sub-project/dependency set.

dod_evidence

Ticket: OMN-15378 (AC3 enforcement leg). Prior AC1/AC2 evidence: #2542

BEFORE/AFTER on the gate's own verdict (same job-snapshot, old vs new STRICT_GATE_JOBS; evaluate() driven directly):

PRE-FIX  (deploy-agent tests RED in their own workflow → absent from ci.yml's run): SUCCESS   <-- false green
POST-FIX (same absent job, gate registered):                                        PENDING   -> FAILURE at the poller deadline
    - Deploy Agent Tests (OMN-15378) / deploy-agent-tests: <absent>
  gates missing/pending: Deploy Agent Tests (OMN-15378) / deploy-agent-tests
POST-FIX (job present + RED):                                                       FAILURE
  strict-gate failures: Deploy Agent Tests (OMN-15378) / deploy-agent-tests

RED-proofs (run on .200, env -u PYTHONPATH uv run pytest):

  1. Remove the STRICT_GATE_JOBS entry → test_deploy_agent_tests_gate_is_strict_and_fails_closed FAILS (1 failed, 26 passed).
  2. Register the pre-fix bare job name deploy-agent-tests (the tempting misfix) → 2 failed: the pinned test and the meta-test, which explains that a reusable caller reports "<caller display name> / <inner job>" and never its own job id, so that entry would be absent forever → PENDING → CI Summary fails closed at its deadline on every PR. That misfix would have wedged the repo; it is now unshippable.
  3. Delete the ci.yml caller job → 4 failed, incl. test_live_repo_has_no_uncollected_test_roots and test_deploy_agent_wiring_workflow_is_pr_reachable_in_this_repo (the guard now notices the root is unreachable again).
  4. Guard hardening synthetics: workflow_call-only workflow with no caller → never runs on a pull request; registration re-pointed at an unrelated PR-triggered workflow → never references scripts/widget-agent; reusable + PR-triggered caller → clean.

GREEN (all on .200, clean-runtime gate host):

  • uv run pytest tests/ci/test_ci_summary_gate.py tests/ci/test_validate_test_root_collection.py tests/ci/test_ci_workflow_resilience.py tests/ci/test_required_context_parity.py -q → 102 passed in 2.72s
  • the exact command the new job runs: uv run --project scripts/deploy-agent --extra dev pytest scripts/deploy-agent/tests → 193 passed, 8 skipped
  • uv run ruff format / ruff check on all touched Python → clean
  • pre-commit run --files <7 changed files> → zero failures
  • pre-commit run --all-files → only inherited failures, none from this diff: shellcheck absent on the gate host (fail-closed hook, shell files untouched), SPDX year 2026≠2025 in two files this PR does not touch (tests/scripts/test_deploy_runtime_core_contracts_resolution.py, tests/ci/test_runner_routing_audit.py), and check-required-env-vars wanting GITHUB_TOKEN in the host env file.

Live-surface facts this rests on (verified via gh api, 2026-07-30):

  • dev required contexts: gh api repos/OmniNode-ai/omnibase_infra/branches/dev/protection/required_status_checks --jq '.contexts' → ["CI Summary"].
  • Reusable-caller check-run naming confirmed on live run 30506617326: executed caller → occ-preflight / eligibility (no bare occ-preflight row); skipped caller → bare row (zone-filter, Runtime Boot Smoke (compose)). The new gate name follows the executed-caller form.

proof_class: receipt-bound — code + executed tests + this PR's own CI run, which is the first live instance of the new strict gate: CI Summary cannot go green unless Deploy Agent Tests (OMN-15378) / deploy-agent-tests is present and successful in this run.

Residuals (flagged, not silently forgiven)

  1. scripts/enforcement_parity_manifest.yaml has no coverage mode for poller-strict gates: direct is false (no own required context) and needs_child is false (ci-summary is a NO-needs poller, so a needs-closure check reports NEEDS_CLOSURE for every poller-strict gate). A poller_strict_gate mode — aggregator-required AND in STRICT_GATE_JOBS AND job present in ci.yml — would let the report-only ratchet audit this class. Filed as OMN-15457 (https://linear.app/omninode/issue/OMN-15457). Until then the tests in this PR are the enforcement of record. The same limitation applies to the other 17 STRICT_GATE_JOBS entries, none of which the manifest declares either.
  2. tests/ci/test_validate_test_root_collection.py rides the required pytest job, so under ENABLE_SMART_TESTS change-aware selection a PR that adds a stray tests/ root elsewhere may not select it (the always_run: true pre-commit hook covers the local path). Unchanged by this PR; the selector adjacency question belongs with OMN-15410's debt sweep.
  3. KNOWN_UNCOLLECTED_DEBT still lists 4 uncollected roots of the identical class — OMN-15410, out of scope here.
  4. Deliberate trade, stated not hidden: the old workflow also ran on push to dev; ci.yml's push trigger is [main] only, so this suite loses its post-merge-to-dev run. PR-time coverage is strictly stronger than before (unconditional instead of path-filtered), merge_group still covered via ci.yml, and main pushes still run it.

Evidence-Ticket: OMN-15378
Evidence-Source: OCC#5549

Summary by CodeRabbit

  • CI Improvements

    • Added deploy-agent tests as a required job in the main CI workflow.
    • CI now reports failures or unavailable results from deploy-agent tests appropriately.
    • Deploy-agent tests run through the main pull-request CI workflow and remain available for manual runs.
  • Validation

    • Strengthened checks to ensure registered standalone test workflows are connected to pull-request runs and reference the expected project roots.
  • Tests

    • Added coverage for gate reporting, workflow connectivity, naming, and fail-closed behavior.

… job becomes mechanism

OMN-15378 AC1 wired scripts/deploy-agent/tests/ to RUN on PRs, but into no
aggregator: `deploy-agent-tests` lived in its own workflow (own run_id), and
ci_summary_gate.py polls actions/runs/${RUN_ID}/jobs for ci.yml is own run only.
It was absent from dev is required set (only "CI Summary") and from both
STRICT_GATE_JOBS and SKIPPABLE_GATE_JOBS, so a RED deploy-agent run left the
required context GREEN — visibility without enforcement, code not mechanism.

- ci.yml: new unconditional `deploy-agent-tests` job CALLS the existing
  workflow, so its result lands in ci.yml is own run as the check-run
  "Deploy Agent Tests (OMN-15378) / deploy-agent-tests".
- deploy-agent-tests.yml: `workflow_call`-only (was path-filtered
  pull_request/push/merge_group). Removes the duplicate-producer double-run AND
  the path-filter hole where a break outside scripts/deploy-agent/** produced no
  signal. Concurrency block dropped (github.workflow resolves to the caller).
- ci_summary_gate.py: registers that check-run in STRICT_GATE_JOBS —
  absent → PENDING → FAILURE at deadline; red/skipped → FAILURE.
- test_ci_summary_gate.py: pins the strict registration, proves red/skipped/
  absent all fail closed, and adds a meta-test that every gate name is a name
  the jobs API can actually report for ci.yml is run (a gate naming an
  unobservable job wedges EVERY PR — that is the misfix this makes unshippable).
- validate_test_root_collection.py: a registered standalone root is now only
  satisfied if its wiring workflow references the root AND is PR-reachable
  (own pull_request trigger, or a PR-reachable workflow calls it via uses:).
- enforcement_parity_manifest.yaml: the deploy-agent-tests MISSING entry is
  resolved (its anticipated branch-protection PUT would have wedged non-
  deploy-agent PRs, since that workflow was path-filtered); residual flagged —
  the manifest has no coverage mode for poller-strict gates.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR wires deploy-agent tests into the main CI workflow, makes the resulting job a strict CI summary gate, removes direct triggers from the reusable workflow, and adds fail-closed validation for PR-reachable standalone test workflows.

Changes

Deploy-agent CI enforcement

Layer / File(s) Summary
Deploy-agent workflow wiring and gate enforcement
.github/workflows/ci.yml, .github/workflows/deploy-agent-tests.yml, scripts/ci/ci_summary_gate.py, tests/ci/test_ci_summary_gate.py, scripts/enforcement_parity_manifest.yaml
The main CI workflow invokes deploy-agent tests as an unconditional reusable workflow; the called workflow accepts workflow_call and workflow_dispatch; the inner job is added to strict gate evaluation; workflow naming, reachability, and fail-closed verdict behavior are tested; the obsolete parity manifest entry is removed.
PR-reachable standalone workflow validation
scripts/validation/validate_test_root_collection.py, tests/ci/test_validate_test_root_collection.py
Standalone registrations now require a workflow root reference and PR reachability through direct triggers or recursive reusable-workflow calls, with synthetic acceptance and rejection cases covered by tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant CIWorkflow
  participant DeployAgentTests
  participant CISummaryGate
  PullRequest->>CIWorkflow: start CI workflow
  CIWorkflow->>DeployAgentTests: invoke reusable workflow
  DeployAgentTests-->>CIWorkflow: return deploy-agent-tests result
  CIWorkflow->>CISummaryGate: expose job result
  CISummaryGate-->>PullRequest: return strict gate verdict
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: making deploy-agent tests enforced through CI Summary.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-15378-ac3-strict-wiring

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

@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 pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Jul 30, 2026
jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Jul 30, 2026
jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Jul 30, 2026
@jonahgabriel
jonahgabriel merged commit 2a1dca2 into dev Jul 30, 2026
151 of 153 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-15378-ac3-strict-wiring branch July 30, 2026 03:48
jonahgabriel added a commit that referenced this pull request Jul 30, 2026
…lity leg)

Peer PR #2553 (OMN-15378 follow-up) merged to dev at 03:48:40Z while this PR
was open, touching the same guard module and its test file. Hand-merged, not
blind-rebased:

- validate_test_root_collection.py docstring: kept #2553's accurate
  three-legs description of STANDALONE_PROJECT_ROOTS verification (it added
  real code -- _workflow_runs_on_pull_request -- that the OMN-15410 text
  under-described), plus this PR's ci.yml-seam and selector-seam items, plus
  the KNOWN_UNCOLLECTED_DEBT-is-now-empty fact.
- test_validate_test_root_collection.py: both sides added a docstring item 5.
  #2553's continues from item 4 (same STANDALONE_PROJECT_ROOTS subject) so it
  stays 5; the OMN-15410 item becomes 6. Neither was dropped.

PAIR_INCOMPATIBLE break found and fixed (both PRs were individually green):
#2553's three new synthetic-repo tests built a tmp_path repo with no root
pyproject.toml and no tests/ dir. OMN-15410 makes testpaths the single source
of truth, so collected_roots() fails closed without one -- 3 tests went RED on
merge. Fixed the FIXTURE, not the guard: a repo with no root pyproject.toml is
not a faithful stand-in for any real repo, and weakening the fail-closed check
would reintroduce the silent-empty-collection failure mode this PR exists to
kill. testpaths lists only tests/ so scripts/widget-agent/tests stays
uncollected and the standalone-registration path under test is still the thing
exercised.

RED-proof that the merge kept #2553 load-bearing: mutating
_workflow_runs_on_pull_request to return True unconditionally makes
test_registered_workflow_that_never_runs_on_a_pr_fails_closed FAIL (assert
0 == 1); restored and re-verified green. 101 passed across the guard, selector
and CI-summary suites on .200.
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