Repository navigation
fix(OMN-15378): gate deploy-agent tests through CI Summary — advisory job becomes mechanism - #2553
Conversation
… 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.
📝 WalkthroughWalkthroughThe 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. ChangesDeploy-agent CI enforcement
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
…ource (OCC#5549) into the PR body
|
| 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)
…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.
OMN-15378 AC3 — enforcement leg: the deploy-agent guard was code, not mechanism
OMN-15378AC1 wiredscripts/deploy-agent/tests/to RUN on PRs. Live adjudication of AC3 found it was wired into no aggregator:deploy-agent-testslived in its own workflow file (ownrun_id), path-filtered onscripts/deploy-agent/**.scripts/ci/ci_summary_gate.pypollsactions/runs/${RUN_ID}/jobsfor ci.yml's own run only — so it structurally could not observe that job.omnibase_infradev's required set (live:["CI Summary"], single umbrella context) and absent from bothSTRICT_GATE_JOBS(17 entries) andSKIPPABLE_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)
.github/workflows/ci.ymldeploy-agent-testsjob that calls the existing workflow, so its result lands in ci.yml's own run as the check-runDeploy Agent Tests (OMN-15378) / deploy-agent-tests.github/workflows/deploy-agent-tests.ymlworkflow_call-only (was path-filteredpull_request/push/merge_group): no duplicate double-run, and the path filter's blind spot — a break outsidescripts/deploy-agent/**produced zero signal — is gone.concurrency:dropped (in a called workflowgithub.workflowresolves to the caller, shadowing ci.yml's PR-keyed group)scripts/ci/ci_summary_gate.pySTRICT_GATE_JOBStests/ci/test_ci_summary_gate.pyscripts/validation/validate_test_root_collection.pypull_requesttrigger, or a PR-reachable workflow calls it viauses:)tests/ci/test_validate_test_root_collection.pyscripts/enforcement_parity_manifest.yamldeploy-agent-testsMISSING entry is resolved, with the residual flaggedWhy 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 Summaryumbrella is the same pattern used forEffect-Assertion Gate (RT-5)andOCC Companion Merged Gate (OMN-15214).Why not fold the tests into the root
tests/tree: unchanged from #2542 — both trees declare a top-leveltestspackage, so one pytest session raisesImportPathMismatchError, andscripts/deploy-agentcarries 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):RED-proofs (run on
.200,env -u PYTHONPATH uv run pytest):STRICT_GATE_JOBSentry →test_deploy_agent_tests_gate_is_strict_and_fails_closedFAILS (1 failed, 26 passed).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 Summaryfails closed at its deadline on every PR. That misfix would have wedged the repo; it is now unshippable.test_live_repo_has_no_uncollected_test_rootsandtest_deploy_agent_wiring_workflow_is_pr_reachable_in_this_repo(the guard now notices the root is unreachable again).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.72suv run --project scripts/deploy-agent --extra dev pytest scripts/deploy-agent/tests→ 193 passed, 8 skippeduv run ruff format/ruff checkon all touched Python → cleanpre-commit run --files <7 changed files>→ zero failurespre-commit run --all-files→ only inherited failures, none from this diff:shellcheckabsent 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), andcheck-required-env-varswantingGITHUB_TOKENin the host env file.Live-surface facts this rests on (verified via
gh api, 2026-07-30):gh api repos/OmniNode-ai/omnibase_infra/branches/dev/protection/required_status_checks --jq '.contexts'→["CI Summary"].30506617326: executed caller →occ-preflight / eligibility(no bareocc-preflightrow); 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 Summarycannot go green unlessDeploy Agent Tests (OMN-15378) / deploy-agent-testsis present and successful in this run.Residuals (flagged, not silently forgiven)
scripts/enforcement_parity_manifest.yamlhas no coverage mode for poller-strict gates:directis false (no own required context) andneeds_childis false (ci-summaryis a NO-needspoller, so a needs-closure check reportsNEEDS_CLOSUREfor every poller-strict gate). Apoller_strict_gatemode — aggregator-required AND inSTRICT_GATE_JOBSAND 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 17STRICT_GATE_JOBSentries, none of which the manifest declares either.tests/ci/test_validate_test_root_collection.pyrides the required pytest job, so underENABLE_SMART_TESTSchange-aware selection a PR that adds a straytests/root elsewhere may not select it (thealways_run: truepre-commit hook covers the local path). Unchanged by this PR; the selector adjacency question belongs with OMN-15410's debt sweep.KNOWN_UNCOLLECTED_DEBTstill lists 4 uncollected roots of the identical class — OMN-15410, out of scope here.pushtodev; ci.yml'spushtrigger 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_groupstill covered via ci.yml, andmainpushes still run it.Evidence-Ticket: OMN-15378
Evidence-Source: OCC#5549
Summary by CodeRabbit
CI Improvements
Validation
Tests