Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 64 additions & 24 deletions .github/workflows/call-occ-preflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,20 @@ name: OCC Preflight
# a hotfix base branch name that does not also exist in omnibase_core (this
# repo's live hotfix bases, e.g. hotfix/omn-13208-..., do not match
# omnibase_core's, e.g. hotfix/omn-14104-...) now fails the checkout step
# hard instead of resolving to a stale-but-working default. This is a real
# behavior change on a still-declared trigger branch, not a regression this
# ticket silently introduced and hid: hotfix bases carry no branch
# protection here (nothing is blocked), and non-dev-base-guard already
# requires a `Stacked-Parent:` declaration on any hotfix-targeted PR. No
# allowlist/fallback was added — treated as the ruling's intended fail-closed
# posture for a base ref genuinely absent from omnibase_core.
# hard instead of resolving to a stale-but-working default. hotfix bases
# carry no branch protection here (nothing is blocked), and non-dev-base-guard
# already requires a `Stacked-Parent:` declaration on any hotfix-targeted PR.
#
# OMN-15698 (Option A, operator propose-and-proceed): a scoped fallback now
# covers exactly this hotfix case. When the resolved ref matches `hotfix/**`
# AND does not exist as a branch in omnibase_core/omnibase_compat, the
# `validator_ref` step falls back to that dependency repo's own default
# branch (resolved dynamically via the GitHub API, never a hardcoded
# `@main`/`@dev` literal) instead of failing the checkout. The dev/main
# paths are untouched and remain byte-identical fail-closed — no fallback is
# consulted unless the resolved ref is hotfix-shaped. Option B (accept the
# fail-closed posture permanently, won't-fix) was the documented alternative;
# the operator selected Option A as the scoped, fail-closed-preserving fix.
on:
pull_request:
branches: [main, dev, "hotfix/**"]
Expand Down Expand Up @@ -105,6 +112,7 @@ jobs:
env:
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
MERGE_GROUP_BASE_REF: ${{ github.event.merge_group.base_ref }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

Expand All @@ -124,6 +132,33 @@ jobs:
echo "ref=${resolved_ref}" >> "$GITHUB_OUTPUT"
echo "::notice::OMN-15689: omnibase_core validator ref resolved dynamically to '${resolved_ref}'."

# OMN-15698 (Option A): hotfix-targeted PRs may name a base branch
# that exists in onex_change_control but not in omnibase_core /
# omnibase_compat (hotfix branches are per-repo and not mirrored).
# Only in that case, fall back to each dependency repo's own
# default branch (resolved dynamically via the API — never a
# hardcoded literal). dev/main targets never hit this branch:
# resolved_ref never matches hotfix/** there, so core_ref/compat_ref
# stay identical to resolved_ref and the checkout below fails
# closed exactly as before if the ref doesn't exist.
core_ref="${resolved_ref}"
compat_ref="${resolved_ref}"
case "${resolved_ref}" in
hotfix/*)
if ! gh api "repos/OmniNode-ai/omnibase_core/branches/${resolved_ref}" >/dev/null 2>&1; then
core_ref="$(gh api repos/OmniNode-ai/omnibase_core --jq '.default_branch')"
echo "::notice::OMN-15698: hotfix base '${resolved_ref}' not found in omnibase_core — falling back to its default branch '${core_ref}'."
fi
if ! gh api "repos/OmniNode-ai/omnibase_compat/branches/${resolved_ref}" >/dev/null 2>&1; then
compat_ref="$(gh api repos/OmniNode-ai/omnibase_compat --jq '.default_branch')"
echo "::notice::OMN-15698: hotfix base '${resolved_ref}' not found in omnibase_compat — falling back to its default branch '${compat_ref}'."
fi
;;
esac

echo "core_ref=${core_ref}" >> "$GITHUB_OUTPUT"
echo "compat_ref=${compat_ref}" >> "$GITHUB_OUTPUT"

- name: Resolve OCC preflight event scope
id: event_scope
run: |
Expand Down Expand Up @@ -409,40 +444,45 @@ jobs:
# module is available. Pattern mirrors call-receipt-gate.yml's install
# block.
#
# OMN-15689 round-1 fix: omnibase_compat now uses the SAME dynamically
# OMN-15689 round-1 fix: omnibase_compat uses the SAME dynamically
# resolved PR-base-branch ref as the omnibase_core validator checkout
# below (steps.validator_ref.outputs.ref), not a hardcoded literal. The
# prior "dev here, main in call-receipt-gate.yml" split was itself a
# per-branch caller variant of the same dependency (adversarial finding,
# OMN-15689 round 1) — the ticket's AC(e) text is not scoped to the
# omnibase_core validator ref alone, so this dependency checkout is in
# scope too. Acknowledged consequence: a PR base branch that does not
# exist in omnibase_compat now fails this checkout step hard (fail-closed,
# same posture as the omnibase_core checkout below), rather than silently
# resolving to a fixed branch that may be stale relative to the PR's
# actual target.
# below, not a hardcoded literal. The prior "dev here, main in
# call-receipt-gate.yml" split was itself a per-branch caller variant
# of the same dependency (adversarial finding, OMN-15689 round 1) — the
# ticket's AC(e) text is not scoped to the omnibase_core validator ref
# alone, so this dependency checkout is in scope too.
#
# OMN-15698 (Option A): ref is steps.validator_ref.outputs.compat_ref,
# which equals the resolved PR base ref for dev/main targets (fail-closed
# unchanged) and falls back to omnibase_compat's own default branch ONLY
# when the resolved ref is hotfix-shaped and absent from omnibase_compat.
- name: Check out omnibase_compat (transitive dep)
if: "steps.event_scope.outputs.required == 'true' && steps.bot_exempt.outputs.exempt != 'true' && ! hashFiles('./src/omnibase_compat/__init__.py') && ! hashFiles('./omnibase_compat/pyproject.toml')"
uses: actions/checkout@v7
with:
repository: OmniNode-ai/omnibase_compat
path: .occ-preflight-deps/omnibase_compat
ref: ${{ steps.validator_ref.outputs.ref }}
ref: ${{ steps.validator_ref.outputs.compat_ref }}
fetch-depth: 1
persist-credentials: false

# OMN-15689 (R3a): checkout ref is the dynamically-resolved PR base
# branch (steps.validator_ref.outputs.ref), never a literal @main, @dev,
# or the old `core-ref` input's hardcoded "dev" default. A base ref that
# does not exist in omnibase_core fails this checkout step hard — no
# fallback ref is provided.
# branch, never a literal @main, @dev, or the old `core-ref` input's
# hardcoded "dev" default.
#
# OMN-15698 (Option A): ref is steps.validator_ref.outputs.core_ref,
# which equals the resolved PR base ref for dev/main targets (fail-closed
# unchanged — a dev/main base ref absent from omnibase_core still fails
# this checkout step hard) and falls back to omnibase_core's own default
# branch ONLY when the resolved ref is hotfix-shaped and absent from
# omnibase_core.
- name: Check out omnibase_core (for eligibility validator)
if: "steps.event_scope.outputs.required == 'true' && steps.bot_exempt.outputs.exempt != 'true' && ! hashFiles('./src/omnibase_core/__init__.py') && ! hashFiles('./omnibase_core/pyproject.toml')"
uses: actions/checkout@v7
with:
repository: OmniNode-ai/omnibase_core
path: .occ-preflight-deps/omnibase_core
ref: ${{ steps.validator_ref.outputs.ref }}
ref: ${{ steps.validator_ref.outputs.core_ref }}
fetch-depth: 1
persist-credentials: false

Expand Down
86 changes: 63 additions & 23 deletions .github/workflows/call-receipt-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,20 @@ name: Receipt Gate
# a hotfix base branch name that does not also exist in omnibase_core (this
# repo's live hotfix bases, e.g. hotfix/omn-13208-..., do not match
# omnibase_core's, e.g. hotfix/omn-14104-...) now fails the checkout step
# hard instead of resolving to a stale-but-working default. This is a real
# behavior change on a still-declared trigger branch, not a regression this
# ticket silently introduced and hid: hotfix bases carry no branch
# protection here (nothing is blocked), and non-dev-base-guard already
# requires a `Stacked-Parent:` declaration on any hotfix-targeted PR. No
# allowlist/fallback was added — treated as the ruling's intended fail-closed
# posture for a base ref genuinely absent from omnibase_core.
# hard instead of resolving to a stale-but-working default. hotfix bases
# carry no branch protection here (nothing is blocked), and non-dev-base-guard
# already requires a `Stacked-Parent:` declaration on any hotfix-targeted PR.
#
# OMN-15698 (Option A, operator propose-and-proceed): a scoped fallback now
# covers exactly this hotfix case. When the resolved ref matches `hotfix/**`
# AND does not exist as a branch in omnibase_core/omnibase_compat, the
# `validator_ref` step falls back to that dependency repo's own default
# branch (resolved dynamically via the GitHub API, never a hardcoded
# `@main`/`@dev` literal) instead of failing the checkout. The dev/main
# paths are untouched and remain byte-identical fail-closed — no fallback is
# consulted unless the resolved ref is hotfix-shaped. Option B (accept the
# fail-closed posture permanently, won't-fix) was the documented alternative;
# the operator selected Option A as the scoped, fail-closed-preserving fix.
on:
pull_request:
types: [opened, synchronize, reopened, edited]
Expand Down Expand Up @@ -104,6 +111,7 @@ jobs:
env:
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
MERGE_GROUP_BASE_REF: ${{ github.event.merge_group.base_ref }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail

Expand All @@ -123,6 +131,33 @@ jobs:
echo "ref=${resolved_ref}" >> "$GITHUB_OUTPUT"
echo "::notice::OMN-15689: omnibase_core validator ref resolved dynamically to '${resolved_ref}'."

# OMN-15698 (Option A): hotfix-targeted PRs may name a base branch
# that exists in onex_change_control but not in omnibase_core /
# omnibase_compat (hotfix branches are per-repo and not mirrored).
# Only in that case, fall back to each dependency repo's own
# default branch (resolved dynamically via the API — never a
# hardcoded literal). dev/main targets never hit this branch:
# resolved_ref never matches hotfix/** there, so core_ref/compat_ref
# stay identical to resolved_ref and the checkout below fails
# closed exactly as before if the ref doesn't exist.
core_ref="${resolved_ref}"
compat_ref="${resolved_ref}"
case "${resolved_ref}" in
hotfix/*)
if ! gh api "repos/OmniNode-ai/omnibase_core/branches/${resolved_ref}" >/dev/null 2>&1; then
core_ref="$(gh api repos/OmniNode-ai/omnibase_core --jq '.default_branch')"
echo "::notice::OMN-15698: hotfix base '${resolved_ref}' not found in omnibase_core — falling back to its default branch '${core_ref}'."
fi
if ! gh api "repos/OmniNode-ai/omnibase_compat/branches/${resolved_ref}" >/dev/null 2>&1; then
compat_ref="$(gh api repos/OmniNode-ai/omnibase_compat --jq '.default_branch')"
echo "::notice::OMN-15698: hotfix base '${resolved_ref}' not found in omnibase_compat — falling back to its default branch '${compat_ref}'."
fi
;;
esac

echo "core_ref=${core_ref}" >> "$GITHUB_OUTPUT"
echo "compat_ref=${compat_ref}" >> "$GITHUB_OUTPUT"

- name: Resolve receipt gate branch policy
id: branch_policy
env:
Expand Down Expand Up @@ -516,38 +551,43 @@ jobs:
# fallback where omnibase-core's published package references a git+https
# URL for omnibase-compat that no longer resolves.
#
# OMN-15689 round-1 fix: omnibase_compat now uses the SAME dynamically
# OMN-15689 round-1 fix: omnibase_compat uses the SAME dynamically
# resolved PR-base-branch ref as the omnibase_core validator checkout
# below (steps.validator_ref.outputs.ref), not a hardcoded literal. The
# prior "main here, dev in call-occ-preflight.yml" split was itself a
# per-branch caller variant of the same dependency (adversarial finding,
# OMN-15689 round 1) — the ticket's AC(e) text is not scoped to the
# omnibase_core validator ref alone, so this dependency checkout is
# in scope too. Acknowledged consequence: a PR base branch that does not
# exist in omnibase_compat now fails this checkout step hard (fail-closed,
# same posture as the omnibase_core checkout below), rather than silently
# resolving to a fixed branch that may be stale relative to the PR's
# actual target.
# below, not a hardcoded literal. The prior "main here, dev in
# call-occ-preflight.yml" split was itself a per-branch caller variant
# of the same dependency (adversarial finding, OMN-15689 round 1) — the
# ticket's AC(e) text is not scoped to the omnibase_core validator ref
# alone, so this dependency checkout is in scope too.
#
# OMN-15698 (Option A): ref is steps.validator_ref.outputs.compat_ref,
# which equals the resolved PR base ref for dev/main targets (fail-closed
# unchanged) and falls back to omnibase_compat's own default branch ONLY
# when the resolved ref is hotfix-shaped and absent from omnibase_compat.
- name: Check out omnibase_compat (transitive dep)
if: "steps.bot_exempt.outputs.exempt != 'true' && ! hashFiles('./src/omnibase_compat/__init__.py') && ! hashFiles('./omnibase_compat/pyproject.toml')"
uses: actions/checkout@v7
with:
repository: OmniNode-ai/omnibase_compat
path: .receipt-gate-deps/omnibase_compat
ref: ${{ steps.validator_ref.outputs.ref }}
ref: ${{ steps.validator_ref.outputs.compat_ref }}
fetch-depth: 1

# OMN-15689 (R3a): checkout ref is the dynamically-resolved PR base
# branch (steps.validator_ref.outputs.ref), never a literal @main.
# A base ref that does not exist in omnibase_core fails this checkout
# step hard — no fallback ref is provided.
# branch, never a literal @main.
#
# OMN-15698 (Option A): ref is steps.validator_ref.outputs.core_ref,
# which equals the resolved PR base ref for dev/main targets (fail-closed
# unchanged — a dev/main base ref absent from omnibase_core still fails
# this checkout step hard) and falls back to omnibase_core's own default
# branch ONLY when the resolved ref is hotfix-shaped and absent from
# omnibase_core.
- name: Check out omnibase_core (for receipt-gate deps)
if: "steps.bot_exempt.outputs.exempt != 'true' && ! hashFiles('./src/omnibase_core/__init__.py') && ! hashFiles('./omnibase_core/pyproject.toml')"
uses: actions/checkout@v7
with:
repository: OmniNode-ai/omnibase_core
path: .receipt-gate-deps/omnibase_core
ref: ${{ steps.validator_ref.outputs.ref }}
ref: ${{ steps.validator_ref.outputs.core_ref }}
fetch-depth: 1

- name: Install omnibase_core
Expand Down
27 changes: 27 additions & 0 deletions contracts/OMN-15698.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,30 @@ dod_evidence:
checks:
- check_type: "command"
check_value: "gh pr view 6130 --repo OmniNode-ai/onex_change_control --json number,state"
- id: "dod-workflow-yaml-parse-pr-6122"
description: "PR #6122 changed workflow files parse as YAML."
source: "manual"
checks:
- check_type: "command"
check_value: >-
uv run python -c 'import yaml; [yaml.safe_load(open(f)) for f in [".github/workflows/call-occ-preflight.yml",".github/workflows/call-receipt-gate.yml"]];
print("ok")'
- id: "dod-precommit-workflow-files-pr-6122"
description: "PR #6122 changed workflow files pass repo pre-commit hooks."
source: "manual"
checks:
- check_type: "command"
check_value: "uv run pre-commit run --files .github/workflows/call-occ-preflight.yml .github/workflows/call-receipt-gate.yml"
- id: "dod-occ-evidence-admissibility-validator-pr-6122"
description: "Hosted OCC evidence admissibility validator for PR #6122 (OMN-15247)."
source: "manual"
evidence_artifact: "supersedes_dod_evidence:dod-OmniNode-ai-onex_change_control-pr-6122"
checks:
- check_type: "command"
check_value: "uv run pytest tests/test_evidence_admissibility.py -q"
- id: "occ-self-bind-pr-6122"
description: "Binds OMN-15698 to OCC PR #6122 (self-bind)."
source: "manual"
checks:
- check_type: "command"
check_value: "gh pr view 6122 --repo OmniNode-ai/onex_change_control --json number,state,headRefName"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
schema_version: "1.0.0"
ticket_id: "OMN-15698"
evidence_item_id: "dod-occ-evidence-admissibility-validator-pr-6122"
check_type: "command"
check_value: "uv run pytest tests/test_evidence_admissibility.py -q"
contract_entry_sha256: "sha256:6e2257d71ff6a513278d27a6ad7edf5e0ba996ed248237cecbc86861a175c234"
status: PASS
run_timestamp: "2026-08-05T22:36:00Z"
commit_sha: "7ba1343ae6082f093a65bce41e3e92937e8157ff"
runner: "codex-manual-merge-sweep"
verifier: "manual-occ-companion-repair"
probe_command: "uv run pytest tests/test_evidence_admissibility.py -q"
probe_stdout: |
........................................................................ [ 94%]
.... [100%]
76 passed in 0.06s
actual_output: "PASS: local declared validator command returned 76 passed in 0.06s."
exit_code: 0
pr_number: 6122
branch: "jonah/omn-15698-hotfix-base-fallback"
Loading
Loading