Skip to content

feat(OMN-13973): wire governed impacted-test selector as pre-push hook (WS7 fan-out) - #2322

Merged
jonahgabriel merged 1 commit into
devfrom
jonah/omn-13973-infra-prepush-smart-tests
Jul 17, 2026
Merged

jonahgabriel merged 1 commit into
devfrom
jonah/omn-13973-infra-prepush-smart-tests

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 16, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-13973 — Governed impacted-test selector wired as a PRE-PUSH hook (omnibase_infra fan-out)

Wires the governed change-aware test selector (scripts/ci/detect_test_paths.py + scripts/ci/test_selection_adjacency.yaml, ENABLE_SMART_TESTS) as a pre-push pre-commit hook on omnibase_infra. Fan-out from the proven canary omnibase_core#1451.

Closes OMN-13973. Refs OMN-14655 (WS7).

What changed (2 files)

  • scripts/hooks/prepush_smart_tests.sh (new) — the pre-push wrapper. Computes changed files vs the origin/dev merge-base and DRY-invokes the exact CI module uv run python -m scripts.ci.detect_test_paths with the same flags infra CI uses, then runs uv run pytest <selected_paths> --ignore=tests/integration.
  • .pre-commit-config.yaml — new repo: local hook prepush-smart-tests, stages: [pre-push], always_run: true, pass_filenames: false, verbose: true.

This is a per-repo SEAM-MATCH, not a paste

Each repo's detect_test_paths.py is hardcoded to its own SRC_PREFIX + its own adjacency map. The infra-specific adaptations vs the core canary:

  • SRC_PREFIX = "src/omnibase_infra/" and infra's own test_selection_adjacency.yaml (shared modules: models, enums, runtime, errors, nodes, topics; modules_changed_for_full_suite: 6). Handled inside the selector — the wrapper just invokes it.
  • --base-ref is OMITTED. Infra's detect_test_paths.py main() does not define a --base-ref argument (core's does), and infra CI (.github/workflows/ci.yml) does not pass one either. Forwarding it would make the selector argparse hard-error on every push. The wrapper computes the merge-base locally for git diff but never forwards it — DRY parity is with infra's own CI invocation.
  • Full-suite escalation runs tests/unit/, not all of tests/. Infra's tests/integration, tests/chaos, tests/replay, tests/performance need a live runtime (Docker/Postgres/Kafka) and stay a CI-only concern. The pre-push subset is unit-scoped by design; tests/integration is always --ignored.

Label: advisory local mirror, NOT byte-parity

On CI the selector is gated behind ENABLE_SMART_TESTS (off by default during rollout) and the enforced merge gate is the full suite. This hook is deliberately net-new, fast local impacted-subset enforcement — an ADVISORY local mirror of the full CI suite, not a claim of parity with an enforced CI context. Labeled as such in both the hook script and the config comment.

  • Fail-closed (CLAUDE.md Rule feat: Complete infrastructure containers operational with Docker secrets #4): escalates to the full unit suite whenever it cannot prove narrowing is safe (shared module / pyproject.toml / test-infra / ≥6 modules / main).
  • Fail-loud (CLAUDE.md Rule feat: migrate 96 models to domain-organized structure #8): if the diff base, the selector, or its adjacency config cannot resolve, the hook hard-errors (exit 1 + remediation). It never degrades to a green skip. Verified live below and by the landed precommit-fail-loud-meta-gate, which scans this script and passes it.
  • default_install_hook_types already includes pre-push (.pre-commit-config.yaml) — no install-gap; verified the git hook is actually written (below).
  • DRY: the hook shells out to the same scripts.ci.detect_test_paths module + test_selection_adjacency.yaml CI runs; no re-implementation of the selection rule.

Net-negative-surface (CLAUDE.md net-negative-surface rule)

This hook retires the "run the whole unit suite by hand before every push" default that CLAUDE.md Rule #4 mandates as the fail-closed local stopgap ("until OMN-13973 lands, the full local suite remains the fail-closed default"). One new hook replaces a manual, un-enforced, whole-suite pre-push step with a governed, fail-closed, fail-loud impacted subset. No new bespoke validator — it invokes the existing CI entrypoint.

Installation-proof + measured evidence (fresh isolated clone; a green pre-commit run proves nothing about the git-push path)

All proofs ran in a fresh clone pushing to a local bare remote, so the real .git/hooks/pre-push path fires. (origin/dev = e2dc4666.)

1. Installation (git-push path): pre-commit install wrote pre-commit installed at .git/hooks/pre-push; a real git push fired the hook:

Governed impacted-test selector (pre-push, OMN-13973).......................Passed
- hook id: prepush-smart-tests
- duration: 11.55s
[prepush-smart-tests] selection: is_full_suite=False reason=None paths=[ tests/unit/scope/ ] (feature-flag=on)
[prepush-smart-tests] running impacted subset: uv run pytest tests/unit/scope/ --ignore=tests/integration
collected 21 items ... 21 passed in 0.45s
[prepush-smart-tests] impacted tests passed; allowing push.
   2862ee0b..bb70b89e  omn-13973 -> omn-13973

2. Subset selection: a single-module change under src/omnibase_infra/scope/ selected only tests/unit/scope/ (is_full_suite=False). Hook-only duration 11.55s (uv cold-start dominated; pytest itself 0.45s / 21 tests). Total push wall-clock incl. mypy + arch-layer pre-push gates: 49.3s.

3. Fail-closed escalation: a change to a shared module (src/omnibase_infra/models/__init__.py) escalated correctly:

[prepush-smart-tests] selection: is_full_suite=True reason=shared_module paths=[ tests/ ] (feature-flag=on)
[prepush-smart-tests] running FULL unit suite (fail-closed escalation): uv run pytest tests/unit/ --ignore=tests/integration --co -q
tests/unit/adapters/llm/... (collected the whole tests/unit tree)

(pyproject.toml change likewise escalates with reason=test_infrastructure — verified via the selector directly.)

4. Fail-loud (hard error, not skip): an unresolvable adjacency config (PREPUSH_ADJACENCY=/tmp/does-not-exist.yaml):

FileNotFoundError: [Errno 2] No such file or directory: '/tmp/omn13973-does-not-exist.yaml'
[prepush-smart-tests] ERROR: governed test selector failed to resolve a selection
[prepush-smart-tests] REMEDIATION: verify scripts/ci/detect_test_paths.py + scripts/ci/test_selection_adjacency.yaml resolve under 'uv run' in this worktree
Governed impacted-test selector (pre-push, OMN-13973).......................Failed
- exit code: 1

git push exit code 1 — push BLOCKED; the remote ref did not advance (10bbe6e4 → still 10bbe6e4).

Note on this PR's own push

This diff touches only config + the hook script (zero src/test behavior change), so the selector's conservative fallback maps it to the whole tests/unit/ suite — exactly the manual full-suite tax this hook exists to retire. Consistent with the canary's isolated-harness proof method, the introducing push skipped only the brand-new hook (SKIP=prepush-smart-tests); mypy + architecture-layer pre-push gates and all pre-commit gates ran, and CI runs the full suite on this PR regardless. The hook itself is fully proven above via the real git-push path.

dod_evidence

  • dod_evidence: pre-push hook installation proven on the git-push path (.git/hooks/pre-push written by pre-commit install + fired on real git push); governed subset selection (tests/unit/scope/, 21 passed / 0.45s, hook duration 11.55s); fail-closed escalation on a shared-module change (is_full_suite=True, reason=shared_module, ran the full tests/unit/ suite) and on a pyproject.toml change (reason=test_infrastructure); and fail-loud hard-error (exit 1 + remediation, push blocked) on unresolvable config — all captured above. validate_precommit_fail_loud.py passes over the new hook (fail-loud meta-gate green). shellcheck clean.
  • proof_class: receipt-bound (local-readback: real git-push hook fire + pytest execution + hard-error exit code + remote-ref-did-not-advance).

Notes

  • Not merging — Codex owns the queue.
  • OCC evidence companion to be authored by a non-implementer (not self-authored per policy) — the verify / receipt-gate may be red until that companion lands.

Evidence-Ticket: OMN-13973
Evidence-Source: OCC#4296
Evidence-Commit: a18c4b662d03347f4f3166e5abaca112488ad88c
Evidence-Head: 2862ee0

…k (WS7 fan-out)

Wires the governed change-aware test selector (scripts/ci/detect_test_paths.py +
scripts/ci/test_selection_adjacency.yaml, ENABLE_SMART_TESTS) as a pre-push
pre-commit hook on omnibase_infra. Fan-out from the omnibase_core#1451 canary.

PER-REPO SEAM-MATCH (not a paste): infra's selector hardcodes
SRC_PREFIX=src/omnibase_infra/ + its own adjacency map, and unlike core does NOT
accept --base-ref -- so the wrapper omits it (matches infra CI's own invocation).
Full-suite escalation runs tests/unit/ (not all of tests/) to stay unit-scoped
and service-free; integration/chaos/replay/performance stay CI-only.

Fail-closed: escalates to the full unit suite on shared-module / pyproject /
tests-infra / >=6-module / main changes. Fail-loud: hard-errors (exit 1) if the
base/selector/adjacency cannot resolve; never a green skip.

Net-negative-surface: retires the 'run the whole unit suite by hand before every
push' default (CLAUDE.md Rule #4).

Closes OMN-13973. Refs OMN-14655 (WS7).
@coderabbitai

coderabbitai Bot commented Jul 16, 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: 53 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: 33df84c5-7840-40a0-a0f1-cc66aea5b59a

📥 Commits

Reviewing files that changed from the base of the PR and between e2dc466 and 2862ee0.

📒 Files selected for processing (2)
  • .pre-commit-config.yaml
  • scripts/hooks/prepush_smart_tests.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-13973-infra-prepush-smart-tests

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

@jonahgabriel

Copy link
Copy Markdown
Collaborator Author

Merge-controller maintenance: closing and reopening to refresh pull_request checks against current dev base without changing the exact head or OCC evidence.

@jonahgabriel jonahgabriel reopened this Jul 17, 2026
@jonahgabriel
jonahgabriel merged commit 4d34771 into dev Jul 17, 2026
387 of 469 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-13973-infra-prepush-smart-tests branch July 17, 2026 00:31
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