Skip to content

chore(OMN-12934): continue dev to main promotion for prod redeploy - #1240

Merged
jonahgabriel merged 11 commits into
mainfrom
promotion/omn-12934-core-dev-to-main
Jun 15, 2026
Merged

jonahgabriel merged 11 commits into
mainfrom
promotion/omn-12934-core-dev-to-main

Conversation

@jonahgabriel

Copy link
Copy Markdown
Contributor

OMN-12934 — continue dev -> main promotion for prod redeploy

Promotes the current omnibase_core dev lane to main so the prod redeploy can build from the latest aligned dev/stability runtime state captured on 2026-06-15.

Evidence-Ticket: OMN-12934
Evidence-Source: OCC#2641
promotion-receipt: OCC-12934

Scope

  • Continuation after the June 11 OMN-12934 promotion PR for this repo merged.
  • Current remote delta: origin/dev ahead of origin/main by 10 commits.
  • Promotion source: origin/dev at 35fce1b.
  • Includes the narrow main-target guard alignment allowing ticketed promotion/* branches with promotion-receipt to target main.
  • This PR performs no direct prod mutation, no deploy, no restart, no destructive cleanup.

Evidence

  • Today's handoff: docs/handoffs/2026-06-15-overnight-finish-summary.md
  • Overnight proof bundle: docs/evidence/2026-06-14-final-aligned/
  • Central OCC contract/receipts: onex_change_control contracts/OMN-12934.yaml and drift/dod_receipts/OMN-12934/.

Prod redeploy remains gated behind merge, image digest availability, prod source-clone cleanup, and serial live-prod validation.

jonahgabriel and others added 11 commits June 11, 2026 13:54
…h-surface test gate (#1228)

Collapse the two hand-synced marker-key envelope-unwrap predicates
(omnibase_infra.runtime.auto_wiring.handler_wiring and
omnimarket.nodes.evidence_pipeline_native) into one authoritative source in
omnibase_core.utils.util_envelope_unwrap. The two sets had drifted again
(infra was missing __bindings vs omnimarket), re-introducing the OMN-12946
defect class on the infra side. Both call sites now import the single source.

By layering this wire-level concern belongs in omnibase_compat, but the compat
pin is policy-frozen, so per the P1.4 plan it lands in omnibase_core (already a
runtime dep of both consumers) with a documented note.

Also adds the dispatch-surface-test-required validator: a path-heuristic gate
(pre-commit + CI quality-gate) that makes a real-dispatch-path test MANDATORY
for any change touching dispatch / routing / handler-registration /
message-envelope source surfaces. Handler-isolation tests pass while live
dispatch fails — this is the durable ratchet for that defect class.

Evidence-Ticket: OMN-12960
…lane validator rules (#1229)

Generalizes OMN-12950: a contract could declare any runtime_profiles string,
and a nonexistent profile (e.g. [compute]) silently orphaned the node — the
auto-wiring ownership filter assigned it to no running runtime, so zero
consumer groups, zero errors, empty projection tables.

Adds the canonical runtime-profile name registry in omnibase_core
(constants_runtime_profiles.REGISTERED_RUNTIME_PROFILES /
CONSUMER_ATTACHED_RUNTIME_PROFILES) so contract validation can enforce
membership without a core->infra dependency, and extends
ValidatorRuntimeProfiles with two new rules:

- runtime_profile_unregistered: every declared runtime_profiles value must be
  in REGISTERED_RUNTIME_PROFILES (catches the OMN-12950 class directly; finds
  16 real orphans in omnimarket).
- runtime_profile_no_consumer_lane: a subscribing REDUCER/EFFECT must name at
  least one consumer-attached profile (main/effects/workers) or its
  subscriptions are never drained — the second silent-orphan class flagged in
  operator review (manifest-declares-node != consumer-attached).

Consumer repos vendor a frozen baseline allowlist at
<repo>/validation/runtime_profiles_allowlist.yaml, discovered deterministically
by walking up to the pyproject.toml root (no env var — passes the
no-new-os.environ gate). The gate blocks NEW orphans; pre-existing ones are
frozen and drained via OMN-12982.

All 3 rules wire via the existing precommit hook + CI workflow (default
contract enables all three; core self-scan stays green).

Evidence-Ticket: OMN-12957
…lerResolver (#1230)

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver

A typing.Protocol used as a handler_routing target is a non-instantiable
interface. Its synthetic __init__(*args, **kwargs) exposes only VAR_POSITIONAL/
VAR_KEYWORD params, so the resolver's required-param scan saw zero required
params and Step 5 called handler_cls() -> typing raised the anonymous
TypeError('Protocols cannot be instantiated') from typing.py:1774, crashing
runtime bootstrap with no attribution to the offending contract/handler.

Add Step 1a: fail fast on _is_protocol handler_cls BEFORE any instantiation
path, with an identifying TypeError naming the handler module.name and owning
contract. Mirrors the infra OMN-12501 quarantine guard semantics (which catches
this TypeError and quarantines as PROTOCOL_HANDLER_DECLARATION) — the failure
stays a TypeError but becomes attributable. Placed after Step 1 so a Protocol
handler on a node not hosted here still skips cleanly.

TDD: 6 unit tests reproduce the crash and assert attribution + precedence
ordering (rejected before container/event_bus probing; exempted by ownership
skip).

Evidence-Ticket: OMN-12961

* test(OMN-12961): silence CodeQL no-effect on Protocol stub bodies

The two Protocol handler stubs in test_service_handler_resolver.py used a
trailing `...` Ellipsis as the method body, which CodeQL flags as
"Statement has no effect" (alerts 2554/2555) — two unresolved review
threads that blocked merge under required_conversation_resolution.

Replace the `...` bodies with a one-line docstring (which has an effect:
it is the method's __doc__), preserving the Protocol semantics while
silencing the false-positive. No behavior change; all 21 resolver unit
tests still pass.

Evidence-Ticket: OMN-12961
Evidence-Source: OCC#2486
…Mock on EventBus/transport surfaces (#1231)

Adds omnibase_core.validators.transport_mock_lint with 25 unit tests.
Detects AsyncMock()/MagicMock() without spec=/spec_set= on EventBus/
transport/kafka mock surfaces (assignment targets, annotated assignments,
and keyword arguments). Exports transport-mock-lint pre-commit hook for
per-repo wiring. Ratchet baseline mode (--baseline <yaml>) allows
activation on repos with existing violations without blocking every PR.
Reference incident: PR #1181 bare AsyncMock hid missing EventBusKafka.stop().

Evidence-Ticket: OMN-13026
…validator (#1233)

The migration window for OMN-10421 closed on 2026-04-30. Receipts with
contract_sha256=None were silently passing the OCC merge eligibility gate
(lines 184-185: `if receipt.contract_sha256 is None: pass`) — a bypass
that diverged from validator_receipt_gate's post-cutoff hard-fail.

Fix: replace the silent `pass` with a hard CONTRACT_HASH_MISMATCH failure
matching validator_receipt_gate._check_one_receipt behaviour. Uses the
shared _CONTRACT_SHA256_REQUIRED_AFTER sentinel for cutoff documentation.

Historical corpus ADVISORY scanners (OMN-13060) are unchanged.

Test: rename test_missing_contract_hash_is_migration_compatible →
test_missing_contract_hash_is_ineligible_post_cutoff with inverted
assertions; all 13 tests pass.
…rel_path baseline fix (#1234)

- Add tests/unit/validators/test_transport_mock_protocol_conformance.py:
  33 tests verifying each transport-surface Protocol
  (ProtocolEventBusBase, ProtocolEventBus, ProtocolAsyncEventBus,
  ProtocolEventBusPublisher, ProtocolEventBusSubscriber,
  ProtocolEventBusLifecycle, ProtocolKafkaClient,
  ProtocolDispatchBusClientTransport) can be imported and used as
  AsyncMock/MagicMock spec=, and that the spec correctly rejects
  nonexistent attributes.

- Fix transport_mock_lint.py --write-baseline to emit portable relative
  paths (via new _rel_path helper) instead of absolute machine-specific
  paths, making baseline YAML files portable across machines/CIs.

DoD: one protocol-conformance test per Protocol defined (OMN-13026).
…n omnibase_core (#1232)

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core

PR-2 of OMN-12803. Ships the canonical ValidatorBase subclass for the url-authority
gate so it participates in the ecosystem-wide validation pipeline.

Detects three violation classes in Python source:
- public-https-literal: quoted https:// URLs to real connection-target hosts
- env-url-read: os.environ[*_URL] / os.environ.get(*_ENDPOINT) reads
- url-const-assignment: module-level *_URL/*_ENDPOINT constants from env or literal

Ratchet (mirrors OMN-12791 receipt-honesty): sha256(repo+path+normalized-snippet)
fingerprint; fail only on NEW fingerprints; baseline burn-down only (assert_baseline_
shrinks_only guards against gaming). Baseline = 13 frozen violations across omnibase_core.

Migration debt baselined-with-tickets: OMN-12806 (omnibase_core), OMN-12807
(omnibase_infra), OMN-12808 (other repos) — cited, not resolved in this PR.

Wired as BLOCKING pre-commit hook (check-url-authority) and required CI workflow
(URL Authority Gate) on omnibase_core. 40 dedicated tests; validator self-checks
clean through its own gate.

Gate probe: RED on synthetic NEW_API_URL literal / GREEN on baselined tip.

Evidence-Ticket: OMN-12818

* fix(OMN-12818): resolve 3 CI failures on url-authority gate PR

1. ci.yml: exclude url_authority_baseline.json from detect-secrets scan
   (sha256 fingerprints triggered Hex High Entropy String false-positive)
2. url-authority-gate.yml: anti-gaming check exits 0 when baseline file
   is new on this PR (initial introduction — no prior to compare against)
3. yamlfmt: reformat .yaml-validation-allowlist, OMN-12663 contract,
   url_authority validation contract (pre-commit hook auto-applied)

Evidence-Source: OCC#2561
Evidence-Ticket: OMN-12818
… models (#1235)

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] receipt models

Phase 0b of the skill-output-suppression plan (epic OMN-13089).

- Add omnibase_core.models.artifacts.ModelArtifactRef: frozen
  content-addressed artifact reference enforcing sha256:<64 hex>,
  with from_bytes() and hex_digest helpers. Single ref type consumed
  by the artifact store (Phase 1) and later phases.
- Add omnibase_core.models.dispatch.ModelSkillResult[T]: generic typed
  skill dispatch receipt envelope (skill-surface analogue of
  ModelHandlerOutput[T]) carrying the FULL typed result, concrete
  result_model FQN for schema identity, metrics, artifact_refs, and
  schema_version. Exported from models.dispatch.
- Resolve duplicate-model-filename collisions surfaced by the
  validate-no-duplicate-models gate (no allowlist additions):
  - models/handlers/model_artifact_ref.py -> model_handler_artifact_ref.py
    (class ModelHandlerArtifactRef; opaque registry ref, internal-only)
  - models/skill/model_skill_result.py -> model_skill_result_file.py
    (class ModelSkillResultFile; the OMN-3867 skill-results file contract)
- Add SPDX header to empty tests/unit/models/telemetry/__init__.py
  (pre-existing SPDX gate failure under --all-files).

Tests: new unit suites for both models (validation, frozen/extra-forbid
contract, JSON round-trip, generic parametrization).

* fix(OMN-13091): drop URL literal from ModelHandlerArtifactRef docstring example

The module rename moved the docstring's illustrative registry URL out of
the url-authority frozen baseline, making it count as a NEW violation.
Replace with an opaque registry-scheme example — the field is an opaque
source locator, no real endpoint belongs in the example.
… 1) (#1236)

* feat(OMN-13093): minimal content-addressed ArtifactStore slice

Phase 1 of the skill-output-suppression plan (epic OMN-13089):
src/omnibase_core/artifacts/artifact_store.py — write_blob (sha256
content addressing, sharded <root>/<hh>/<full-hex> layout, atomic
temp+rename, idempotent on existing hash), JSON metadata sidecar with
the artifact-captured required fields + writer_version, hash-verified
read_blob, read_meta. Store root from ONEX_ARTIFACT_STORE_ROOT
(required env, KeyError on absence). Stdlib + Pydantic only so
omniclaude hooks can import it. Parent durable-capture Phase 1 extends
this in place (retention/quota, redaction, read-API hardening).

* test(OMN-13093): register artifacts module in CI test-selection adjacency map

New src/omnibase_core/artifacts/ module needs an adjacency entry or
test_every_src_module_has_adjacency_entry fails. No reverse deps yet —
downstream consumers (CLI receipt mode, omniclaude hooks) land in
Phase 2a/3.
)

Add validate_skill_dispatch_receipt_mode in omnibase_core/validators/ —
the enforcement validator for the skill-output-suppression epic (OMN-13089).
Four checks on every skill under plugins/onex/skills/:

(a) every skill declares skill_kind: dispatch | methodology (explicit, never
    heuristic); missing/invalid value FAILS;
(b) dispatch skills' commands must be the single onex skill / onex delegate
    receipt-mode form — bare onex (run|node|run-node) FAILS;
(c) dispatch skill directories contain markdown only — no *.py, _lib/, or
    shell scripts (pycache ignored);
(d) prompt-instruction consistency — no 'cat workflow_result.json' /
    'surface JSON verbatim' instruction in a receipt-mode dispatch; a negation
    guard tolerates prohibitions ('no cat of workflow_result.json').

Ratchet semantics live in main(): an allowlist tolerates not-yet-migrated
skills but FAILS if it grows, if a listed skill is migrated (stale entry) or
removed, or if a new skill ships an unreceipted dispatch. Absent allowlist =
unconditional gate (the end state). --generate-allowlist regenerates the
violation set as a migration aid.

Supporting: EnumSkillReceiptRule, ModelSkillDispatchReceiptFinding (models/
validation/), enums/__init__ registration, no-manual-yaml exclude for the
validator. File-location validator: Enum* in validation/ carve-out (matches
the existing Model*/Protocol* validation/ helper-class allowances) so the
pre-existing EnumHonestyRule co-location passes.

dod_evidence:
- uv run pytest tests/unit/validators/test_skill_dispatch_receipt_mode.py -v
  => 29 passed (four checks + negation guard + ratchet growth/regression/
     stale/absent semantics + generate-allowlist + usage-error exit codes)
- uv run mypy src/.../skill_dispatch_receipt_mode.py ... --strict => clean
- uv run ruff format/check => clean
- end-to-end vs real omniclaude@dev skills tree + committed ratchet => exit 0
- negative: a dispatch skill with bare 'uv run onex run foo' => exit 1
- pre-commit run --files <staged> => all green

Evidence-Ticket: OMN-13098

Epic: OMN-13089 (Skill Output Suppression). Plan:
docs/plans/2026-06-12-skill-output-suppression-plan.md Phase 4 items 2-4.
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1190317e-d2e0-44aa-99dd-eb37a9c40e91

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch promotion/omn-12934-core-dev-to-main

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

@jonahgabriel
jonahgabriel merged commit 45a0e15 into main Jun 15, 2026
103 of 104 checks passed
@jonahgabriel
jonahgabriel deleted the promotion/omn-12934-core-dev-to-main branch June 15, 2026 06:36
jonahgabriel added a commit that referenced this pull request Jun 18, 2026
…tion branch

The pull_request main-target-guard runs the workflow definition from the PR head
tree. dev's guard is the restrictive (dev-only) OMN-12477 version; main already
carries the permissive (dev || promotion/*) version from #1240. A promotion/*
head therefore fails the dev-tree restrictive guard. Adopting main's permissive
guard on the promotion branch lets the promotion/* head pass; net diff to main is
zero (main already has this exact file). dev->main promotion via promotion/* is
the sanctioned shape (memory: dev-only-promotion-to-main + #1240 precedent).

Evidence-Ticket: OMN-13131
promotion-receipt: OCC-2742
jonahgabriel added a commit that referenced this pull request Jun 18, 2026
…e (v0.45.0) (#1260)

* feat(OMN-12960): single transport-envelope unwrap predicate + dispatch-surface test gate (#1228)

Collapse the two hand-synced marker-key envelope-unwrap predicates
(omnibase_infra.runtime.auto_wiring.handler_wiring and
omnimarket.nodes.evidence_pipeline_native) into one authoritative source in
omnibase_core.utils.util_envelope_unwrap. The two sets had drifted again
(infra was missing __bindings vs omnimarket), re-introducing the OMN-12946
defect class on the infra side. Both call sites now import the single source.

By layering this wire-level concern belongs in omnibase_compat, but the compat
pin is policy-frozen, so per the P1.4 plan it lands in omnibase_core (already a
runtime dep of both consumers) with a documented note.

Also adds the dispatch-surface-test-required validator: a path-heuristic gate
(pre-commit + CI quality-gate) that makes a real-dispatch-path test MANDATORY
for any change touching dispatch / routing / handler-registration /
message-envelope source surfaces. Handler-isolation tests pass while live
dispatch fails — this is the durable ratchet for that defect class.

Evidence-Ticket: OMN-12960

* feat(OMN-12957): runtime-profile registry + unregistered/no-consumer-lane validator rules (#1229)

Generalizes OMN-12950: a contract could declare any runtime_profiles string,
and a nonexistent profile (e.g. [compute]) silently orphaned the node — the
auto-wiring ownership filter assigned it to no running runtime, so zero
consumer groups, zero errors, empty projection tables.

Adds the canonical runtime-profile name registry in omnibase_core
(constants_runtime_profiles.REGISTERED_RUNTIME_PROFILES /
CONSUMER_ATTACHED_RUNTIME_PROFILES) so contract validation can enforce
membership without a core->infra dependency, and extends
ValidatorRuntimeProfiles with two new rules:

- runtime_profile_unregistered: every declared runtime_profiles value must be
  in REGISTERED_RUNTIME_PROFILES (catches the OMN-12950 class directly; finds
  16 real orphans in omnimarket).
- runtime_profile_no_consumer_lane: a subscribing REDUCER/EFFECT must name at
  least one consumer-attached profile (main/effects/workers) or its
  subscriptions are never drained — the second silent-orphan class flagged in
  operator review (manifest-declares-node != consumer-attached).

Consumer repos vendor a frozen baseline allowlist at
<repo>/validation/runtime_profiles_allowlist.yaml, discovered deterministically
by walking up to the pyproject.toml root (no env var — passes the
no-new-os.environ gate). The gate blocks NEW orphans; pre-existing ones are
frozen and drained via OMN-12982.

All 3 rules wire via the existing precommit hook + CI workflow (default
contract enables all three; core self-scan stays green).

Evidence-Ticket: OMN-12957

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver (#1230)

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver

A typing.Protocol used as a handler_routing target is a non-instantiable
interface. Its synthetic __init__(*args, **kwargs) exposes only VAR_POSITIONAL/
VAR_KEYWORD params, so the resolver's required-param scan saw zero required
params and Step 5 called handler_cls() -> typing raised the anonymous
TypeError('Protocols cannot be instantiated') from typing.py:1774, crashing
runtime bootstrap with no attribution to the offending contract/handler.

Add Step 1a: fail fast on _is_protocol handler_cls BEFORE any instantiation
path, with an identifying TypeError naming the handler module.name and owning
contract. Mirrors the infra OMN-12501 quarantine guard semantics (which catches
this TypeError and quarantines as PROTOCOL_HANDLER_DECLARATION) — the failure
stays a TypeError but becomes attributable. Placed after Step 1 so a Protocol
handler on a node not hosted here still skips cleanly.

TDD: 6 unit tests reproduce the crash and assert attribution + precedence
ordering (rejected before container/event_bus probing; exempted by ownership
skip).

Evidence-Ticket: OMN-12961

* test(OMN-12961): silence CodeQL no-effect on Protocol stub bodies

The two Protocol handler stubs in test_service_handler_resolver.py used a
trailing `...` Ellipsis as the method body, which CodeQL flags as
"Statement has no effect" (alerts 2554/2555) — two unresolved review
threads that blocked merge under required_conversation_resolution.

Replace the `...` bodies with a one-line docstring (which has an effect:
it is the method's __doc__), preserving the Protocol semantics while
silencing the false-positive. No behavior change; all 21 resolver unit
tests still pass.

Evidence-Ticket: OMN-12961
Evidence-Source: OCC#2486

* feat(OMN-13026): transport-mock lint validator — bare AsyncMock/MagicMock on EventBus/transport surfaces (#1231)

Adds omnibase_core.validators.transport_mock_lint with 25 unit tests.
Detects AsyncMock()/MagicMock() without spec=/spec_set= on EventBus/
transport/kafka mock surfaces (assignment targets, annotated assignments,
and keyword arguments). Exports transport-mock-lint pre-commit hook for
per-repo wiring. Ratchet baseline mode (--baseline <yaml>) allows
activation on repos with existing violations without blocking every PR.
Reference incident: PR #1181 bare AsyncMock hid missing EventBusKafka.stop().

Evidence-Ticket: OMN-13026

* fix(OMN-13061): hard-fail on contract_sha256=None in OCC eligibility validator (#1233)

The migration window for OMN-10421 closed on 2026-04-30. Receipts with
contract_sha256=None were silently passing the OCC merge eligibility gate
(lines 184-185: `if receipt.contract_sha256 is None: pass`) — a bypass
that diverged from validator_receipt_gate's post-cutoff hard-fail.

Fix: replace the silent `pass` with a hard CONTRACT_HASH_MISMATCH failure
matching validator_receipt_gate._check_one_receipt behaviour. Uses the
shared _CONTRACT_SHA256_REQUIRED_AFTER sentinel for cutoff documentation.

Historical corpus ADVISORY scanners (OMN-13060) are unchanged.

Test: rename test_missing_contract_hash_is_migration_compatible →
test_missing_contract_hash_is_ineligible_post_cutoff with inverted
assertions; all 13 tests pass.

* feat(OMN-13026): protocol-conformance tests per Protocol + portable _rel_path baseline fix (#1234)

- Add tests/unit/validators/test_transport_mock_protocol_conformance.py:
  33 tests verifying each transport-surface Protocol
  (ProtocolEventBusBase, ProtocolEventBus, ProtocolAsyncEventBus,
  ProtocolEventBusPublisher, ProtocolEventBusSubscriber,
  ProtocolEventBusLifecycle, ProtocolKafkaClient,
  ProtocolDispatchBusClientTransport) can be imported and used as
  AsyncMock/MagicMock spec=, and that the spec correctly rejects
  nonexistent attributes.

- Fix transport_mock_lint.py --write-baseline to emit portable relative
  paths (via new _rel_path helper) instead of absolute machine-specific
  paths, making baseline YAML files portable across machines/CIs.

DoD: one protocol-conformance test per Protocol defined (OMN-13026).

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core (#1232)

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core

PR-2 of OMN-12803. Ships the canonical ValidatorBase subclass for the url-authority
gate so it participates in the ecosystem-wide validation pipeline.

Detects three violation classes in Python source:
- public-https-literal: quoted https:// URLs to real connection-target hosts
- env-url-read: os.environ[*_URL] / os.environ.get(*_ENDPOINT) reads
- url-const-assignment: module-level *_URL/*_ENDPOINT constants from env or literal

Ratchet (mirrors OMN-12791 receipt-honesty): sha256(repo+path+normalized-snippet)
fingerprint; fail only on NEW fingerprints; baseline burn-down only (assert_baseline_
shrinks_only guards against gaming). Baseline = 13 frozen violations across omnibase_core.

Migration debt baselined-with-tickets: OMN-12806 (omnibase_core), OMN-12807
(omnibase_infra), OMN-12808 (other repos) — cited, not resolved in this PR.

Wired as BLOCKING pre-commit hook (check-url-authority) and required CI workflow
(URL Authority Gate) on omnibase_core. 40 dedicated tests; validator self-checks
clean through its own gate.

Gate probe: RED on synthetic NEW_API_URL literal / GREEN on baselined tip.

Evidence-Ticket: OMN-12818

* fix(OMN-12818): resolve 3 CI failures on url-authority gate PR

1. ci.yml: exclude url_authority_baseline.json from detect-secrets scan
   (sha256 fingerprints triggered Hex High Entropy String false-positive)
2. url-authority-gate.yml: anti-gaming check exits 0 when baseline file
   is new on this PR (initial introduction — no prior to compare against)
3. yamlfmt: reformat .yaml-validation-allowlist, OMN-12663 contract,
   url_authority validation contract (pre-commit hook auto-applied)

Evidence-Source: OCC#2561
Evidence-Ticket: OMN-12818

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] typed receipt models (#1235)

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] receipt models

Phase 0b of the skill-output-suppression plan (epic OMN-13089).

- Add omnibase_core.models.artifacts.ModelArtifactRef: frozen
  content-addressed artifact reference enforcing sha256:<64 hex>,
  with from_bytes() and hex_digest helpers. Single ref type consumed
  by the artifact store (Phase 1) and later phases.
- Add omnibase_core.models.dispatch.ModelSkillResult[T]: generic typed
  skill dispatch receipt envelope (skill-surface analogue of
  ModelHandlerOutput[T]) carrying the FULL typed result, concrete
  result_model FQN for schema identity, metrics, artifact_refs, and
  schema_version. Exported from models.dispatch.
- Resolve duplicate-model-filename collisions surfaced by the
  validate-no-duplicate-models gate (no allowlist additions):
  - models/handlers/model_artifact_ref.py -> model_handler_artifact_ref.py
    (class ModelHandlerArtifactRef; opaque registry ref, internal-only)
  - models/skill/model_skill_result.py -> model_skill_result_file.py
    (class ModelSkillResultFile; the OMN-3867 skill-results file contract)
- Add SPDX header to empty tests/unit/models/telemetry/__init__.py
  (pre-existing SPDX gate failure under --all-files).

Tests: new unit suites for both models (validation, frozen/extra-forbid
contract, JSON round-trip, generic parametrization).

* fix(OMN-13091): drop URL literal from ModelHandlerArtifactRef docstring example

The module rename moved the docstring's illustrative registry URL out of
the url-authority frozen baseline, making it count as a NEW violation.
Replace with an opaque registry-scheme example — the field is an opaque
source locator, no real endpoint belongs in the example.

* feat(OMN-13093): minimal content-addressed ArtifactStore slice (Phase 1) (#1236)

* feat(OMN-13093): minimal content-addressed ArtifactStore slice

Phase 1 of the skill-output-suppression plan (epic OMN-13089):
src/omnibase_core/artifacts/artifact_store.py — write_blob (sha256
content addressing, sharded <root>/<hh>/<full-hex> layout, atomic
temp+rename, idempotent on existing hash), JSON metadata sidecar with
the artifact-captured required fields + writer_version, hash-verified
read_blob, read_meta. Store root from ONEX_ARTIFACT_STORE_ROOT
(required env, KeyError on absence). Stdlib + Pydantic only so
omniclaude hooks can import it. Parent durable-capture Phase 1 extends
this in place (retention/quota, redaction, read-API hardening).

* test(OMN-13093): register artifacts module in CI test-selection adjacency map

New src/omnibase_core/artifacts/ module needs an adjacency entry or
test_every_src_module_has_adjacency_entry fails. No reverse deps yet —
downstream consumers (CLI receipt mode, omniclaude hooks) land in
Phase 2a/3.

* feat(OMN-13098): skill-dispatch receipt-mode validator (Phase 4b) (#1237)

Add validate_skill_dispatch_receipt_mode in omnibase_core/validators/ —
the enforcement validator for the skill-output-suppression epic (OMN-13089).
Four checks on every skill under plugins/onex/skills/:

(a) every skill declares skill_kind: dispatch | methodology (explicit, never
    heuristic); missing/invalid value FAILS;
(b) dispatch skills' commands must be the single onex skill / onex delegate
    receipt-mode form — bare onex (run|node|run-node) FAILS;
(c) dispatch skill directories contain markdown only — no *.py, _lib/, or
    shell scripts (pycache ignored);
(d) prompt-instruction consistency — no 'cat workflow_result.json' /
    'surface JSON verbatim' instruction in a receipt-mode dispatch; a negation
    guard tolerates prohibitions ('no cat of workflow_result.json').

Ratchet semantics live in main(): an allowlist tolerates not-yet-migrated
skills but FAILS if it grows, if a listed skill is migrated (stale entry) or
removed, or if a new skill ships an unreceipted dispatch. Absent allowlist =
unconditional gate (the end state). --generate-allowlist regenerates the
violation set as a migration aid.

Supporting: EnumSkillReceiptRule, ModelSkillDispatchReceiptFinding (models/
validation/), enums/__init__ registration, no-manual-yaml exclude for the
validator. File-location validator: Enum* in validation/ carve-out (matches
the existing Model*/Protocol* validation/ helper-class allowances) so the
pre-existing EnumHonestyRule co-location passes.

dod_evidence:
- uv run pytest tests/unit/validators/test_skill_dispatch_receipt_mode.py -v
  => 29 passed (four checks + negation guard + ratchet growth/regression/
     stale/absent semantics + generate-allowlist + usage-error exit codes)
- uv run mypy src/.../skill_dispatch_receipt_mode.py ... --strict => clean
- uv run ruff format/check => clean
- end-to-end vs real omniclaude@dev skills tree + committed ratchet => exit 0
- negative: a dispatch skill with bare 'uv run onex run foo' => exit 1
- pre-commit run --files <staged> => all green

Evidence-Ticket: OMN-13098

Epic: OMN-13089 (Skill Output Suppression). Plan:
docs/plans/2026-06-12-skill-output-suppression-plan.md Phase 4 items 2-4.

* docs(OMN-13182): refresh omnibase_core documentation (#1241)

- Replace Poetry references with uv in installation.md (Poetry was listed
  as Method 1/recommended; project uses uv exclusively)
- Fix "Always use Poetry" design rule in docs/INDEX.md to "Always use uv"
- Add 15 missing top-level source modules to Package Structure in INDEX.md
  (artifacts/, dispatch/, doctor/, event_bus/, gate/, adapters/, agents/,
  analysis/, discovery/, navigation/, normalization/, overlays/, validators/,
  workflows/)
- Remove all 6 references to deleted EnvelopeRouter/runtime_envelope_router.py
  in onex_terminology.md (deleted OMN-12526/v0.43.0); update to
  RuntimeMessageDispatch + RuntimeHandlerRegistry
- Add onex-demo-path-topic-gate CLI entrypoint to VALIDATION_OWNERSHIP.md
  (OMN-12777, present in pyproject.toml since v0.44.0 but missing from doc)
- Add section listing 6 pre-commit/CI-only validators shipped since April 24:
  ValidatorUrlAuthority (OMN-12818), ValidatorReceiptHonesty (OMN-12791),
  ValidatorRuntimeProfiles (OMN-12957), gitignore_baseline (OMN-12452),
  transport-mock lint (OMN-13026), skill-dispatch receipt-mode (OMN-13098)
- Add CHANGELOG entries for v0.44.0/v0.44.1/v0.44.2 (all three tagged and
  shipped but had zero CHANGELOG entries)
- Add 5 missing subsystem rows to CLAUDE.md Architecture Extensions table:
  ArtifactStore (OMN-13093), Dispatch Bus Client, Doctor Health Checks,
  In-Memory Event Bus, OmniGate (OMN-11137/11139/11140)

Parent: OMN-13172
All changes AI-generated.

* refactor(OMN-13189): delete dead ModelOnexEnvelopeV1 — completes OMN-4152 (#1242)

Remove ModelOnexEnvelopeV1 (zero production callers, zero test imports across
omnibase_core/omnibase_infra/omnimarket src+tests). Deletes the class file,
both export lines in models/core/__init__.py, and the 3 predecessor mentions
in model_onex_envelope.py that reference the now-deleted class.

Completes OMN-4152 (Task 6: Retire ModelOnexEnvelopeV1) — verification confirmed
V1 fully dead, so this deletes it outright rather than retaining for backward-
compat deserialization.

grep -rn ModelOnexEnvelopeV1 src/ tests/ => zero.

* refactor(OMN-13192): migrate sole live ModelOnexEnvelope constructor to ModelEventEnvelope[ModelEventPublishIntent] (#1245)

Retarget the one production ModelOnexEnvelope(...) constructor at
mixin_intent_publisher.py to ModelEventEnvelope[ModelEventPublishIntent](...),
publishing the TYPED ModelEventPublishIntent as the envelope payload (not a
serialized dict). Field remap: source_node->source_tool,
timestamp->envelope_timestamp, drop operation, payload=intent (typed).

This leaves ZERO live ModelOnexEnvelope constructor calls in src/ so B4 can
delete the class. The class definition and its docstring examples in
model_onex_envelope.py are untouched (B4 scope).

Verification REFUTED the 'Kafka consumers will break' framing: there are NO
Kafka consumers of onex.runtime.intents. IntentExecutor is a synchronous
runtime service (not a topic listener) and MixinIntentPublisher has zero
production call sites. This is a type-correctness + test change only; there is
no consumer-node migration.

Tests updated to assert the new ModelEventEnvelope wire shape and a
serialize->deserialize round-trip. The strict
ModelEventEnvelope[ModelEventPublishIntent] cannot reconstruct from JSON because
ModelEventPublishIntent.target_event_payload is a ModelEventPayloadUnion whose
before-validator rejects the plain dict JSON decoding yields (no discriminator)
-- a pre-existing property of the intent model, so the round-trip is asserted on
the generic ModelEventEnvelope (payload preserved as a mapping).

Evidence-Source: OCC#PENDING
Evidence-Ticket: OMN-13192

* chore(OMN-13187): refresh core dependency pins (#1246)

* refactor(OMN-13194): re-annotate envelope_validator.py from ModelOnexEnvelope to ModelEventEnvelope[Any] (#1248)

B3 of the platform-debt envelope-dedup plan (docs/plans/2026-06-16-platform-debt-contract-topics-and-envelope-dedup-plan.md).

Re-annotates the 4 ModelOnexEnvelope sites in
src/omnibase_core/validation/envelope_validator.py to ModelEventEnvelope[Any]:
- TYPE_CHECKING import -> omnibase_core.models.events.model_event_envelope
- validate / _validate_structure / _validate_payload parameter annotations
The 2 prose docstring mentions are updated too so the module references zero
ModelOnexEnvelope. ModelEventEnvelope[T] is a PEP 695 generic, so [Any] is valid.

Annotation-only: the validator reads every field via getattr(envelope, ..., None)
(duck-typed), so no runtime code path changes. Does NOT delete ModelOnexEnvelope
(B4 / OMN-13196 scope).

Predecessor B2 (OMN-13192, PR #1245) merged to dev (a84bb24).

dod_evidence:
- grep: zero ModelOnexEnvelope in envelope_validator.py
- mypy --strict envelope_validator.py: Success, no issues
- focused suite tests/unit/validation/test_envelope_validator.py: 40 passed, 4 skipped
- full pytest tests/ -n auto (no -k): 41739 passed; the 1 perf flake
  (test_source_node_id_overhead round-trip overhead under 16-way load) passes in
  isolation (1.39s) and does not reference the validator
- pre-commit run --all-files: all hooks pass

* chore(OMN-13195): bump validate-boundaries action pin (#1249)

* feat(OMN-12804): non-model URL contract authority — integration catalog + design doc (#1251)

Part 2A/2B of OMN-12803 URL-authority epic.  OMN-12818 shipped the gate
(ValidatorUrlAuthority); this PR completes the design by establishing the
canonical authority surface for non-model URLs.

## Design (Part 2A): two authority surfaces

ONEX now has exactly two URL authority surfaces:

1. **Model/inference routing** — `configs/bifrost_delegation.yaml`
   (omnimarket/omniclaude).  Owns LLM backend URLs and inference endpoints.

2. **Non-model integration endpoints** — `contracts/integrations/catalog.yaml`
   (this repo, new in this PR).  Owns GitHub API, Linear GraphQL, OpenRouter
   non-inference, projection API, bus bootstrap, dashboard data sources, and
   all other URLs that are NOT LLM inference endpoints.

The validator `_AUTHORITY_PATH_SUFFIXES` already exempts
`contracts/integrations/catalog.yaml` from the gate (URLs inside the
authority file are canonical, not violations).

## Deliverables

- `src/omnibase_core/contracts/integrations/catalog.yaml` — non-model URL
  authority (schema v1.0.0, `catalog_version: {major: 1, minor: 0, patch: 0}`).
  Entries: `github.rest_api`, `linear.graphql_api`, `openrouter.completions`,
  `projection_api.base`, `bus.redpanda_schema_registry`, `bus.kafka_bootstrap`,
  `dashboard.data_source`, `infisical.addr`, `deployment.callback_url`.

- `docs/architecture/URL_CONTRACT_AUTHORITY.md` — design doc covering both
  authority surfaces, resolution contract, catalog schema, gate rules, and
  cross-repo wiring pattern.

- `tests/unit/validation/test_validator_url_authority.py` — 9 new catalog
  structure tests (TestIntegrationCatalogStructure): file existence, YAML
  validity, semver format, required categories, entry completeness, authority
  path allowlist match, required external API entries.

## Gate status

url-authority gate: PASSED (0 new violations, 13 grandfathered from OMN-12818 baseline).

Cross-repo wiring to omnibase_infra (48 violations to baseline) is tracked
by OMN-12807 and will land as a follow-on PR to that repo.

Evidence-Ticket: OMN-12804

* refactor(OMN-13196): delete ModelOnexEnvelope (B4) + retarget validator test (#1250)

B4 of the platform-debt envelope-dedup plan. Deletes the legacy
ModelOnexEnvelope class entirely and collapses the canonical envelope
surface to ModelEventEnvelope[T].

Changes:
- Delete src/omnibase_core/models/core/model_onex_envelope.py (the class
  whose docstring falsely self-described as "the canonical envelope format";
  1 live constructor migrated in B2/OMN-13192, 4 validator annotations
  re-annotated in B3/OMN-13194, V1 retired in B1/OMN-13193).
- Remove the 2 exports (import + __all__) in models/core/__init__.py.
- Delete the 4 ModelOnexEnvelope-specific test files:
  test_model_onex_envelope.py, test_model_onex_envelope_source_node_id.py,
  test_model_onex_envelope_chunking.py, and the perf benchmark
  test_source_node_id_overhead.py — these exercised ModelOnexEnvelope's own
  fields (source_node_id, chunking, operation) which have no ModelEventEnvelope
  equivalent, so they retire with the class.
- Retarget tests/unit/validation/test_envelope_validator.py: EnvelopeValidator
  survives (it is duck-typed via getattr) but ModelEventEnvelope[T] lacks the
  dispatch-routing fields (source_node/operation/target_node) the validator
  reads. Replace the ModelOnexEnvelope fixture with a minimal frozen Pydantic
  stub (_ValidatorEnvelope) exposing exactly those attributes. 40/40 pass.
- Retarget stale docstring/comment references to the deleted class in
  model_envelope_metadata.py, model_chunked_envelope.py,
  type_serializable_value.py, and the mixin_metadata.yaml `requires` entry
  (which pointed at the already-wrong models.events.model_onex_envelope path)
  to ModelEventEnvelope.

dod_evidence:
- grep -rniE 'ModelOnexEnvelope|model_onex_envelope' src/ tests/ -> ZERO
- ruff format + ruff check --fix: All checks passed
- mypy src/ --strict: no NEW errors (3 pre-existing errors in untouched
  contract_loader.py / cli_install.py reproduce on clean origin/dev)
- pytest tests/unit/validation/test_envelope_validator.py: 40 passed
- FULL pytest tests/ -n 8 (no -k): 41576 passed; the 21 failures are
  full-suite-only xdist ordering flakes (RegistryNode forward-ref
  model_rebuild + DI-singleton contamination) that ALL pass in isolation
  (48/48) and reference neither envelopes nor any file in this diff.

OMN-13196

* chore(OMN-13200): bump omnibase_core to v0.45.0 (B6 — envelope-dedup pin propagation) (#1252)

Final phase of the platform-debt envelope-dedup workstream. ModelOnexEnvelope
was deleted from the public API in B4 (PR #1250, merged to dev). This bumps the
omnibase_core version to propagate the breaking-deletion signal to dependents
and trigger pin-update bot PRs.

- pyproject version 0.44.2 -> 0.45.0 (minor bump: pre-1.0 semver convention for
  a breaking public-API deletion; pyproject is the single source of truth)
- uv.lock self-version updated to match
- CHANGELOG entry under Breaking Changes

Verification on origin/dev HEAD (e9bb51a):
- grep ModelOnexEnvelope over src/ + tests/ -> 0 references (class fully gone)
- mypy src/omnibase_core (CI-canonical strict gate) -> Success, no issues
- pytest tests/unit/validation/test_envelope_validator.py +
  tests/unit/mixins/test_mixin_intent_publisher.py -> 67 passed

dod_evidence: contracts/OMN-13200.yaml (OCC receipt, verifier!=runner)

* refactor(OMN-13197): remove dead onex.runtime.intents hardcoded topic + dead intent-publisher path (#1253)

A-followup of OMN-13188 (OMN-12803 topic-authority family). Removes the
`onex.runtime.intents` hardcoded topic at its root by deleting the dead
publisher path that was its sole consumer.

Decision (per OMN-13197 DoD: contract-source the topic OR confirm-and-delete
the dead path): confirm-and-delete. The topic could not be contract-sourced —
no contract declares it (the `intent_publisher.yaml` referenced in the mixin
docstring was never authored) and `ServiceTopicRegistry` lives in
omnibase_infra (core cannot import it per layering). The mechanism was
architecturally dead from both sides:
- MixinIntentPublisher (sole publisher) had ZERO production call sites.
- onex.runtime.intents had ZERO Kafka consumers (IntentExecutor is a
  synchronous in-memory runtime service, verified in OMN-13192/OMN-13188).
Dead code is debt to delete, not park/guard/migrate.

Removed:
- TOPIC_EVENT_PUBLISH_INTENT (duplicate of canonical TOPIC_RUNTIME_INTENTS,
  existed only to feed the dead mixin) + all re-exports.
- MixinIntentPublisher + ModelIntentPublishResult (only used by the mixin)
  + their capability-mapping / metadata census entries.
- Dead tests + fixtures + intent-publisher guide docs (with inbound links).

Retained: TOPIC_RUNTIME_INTENTS (canonical taxonomy derivation) and
ModelEventPublishIntent (live consumer in util_payload_migration).

Added regression guard test asserting the dead symbols stay removed.

dod_evidence: ruff format+check clean; mypy --strict clean on all changed
files (6 pre-existing errors in untouched files only); 171 focused tests
green incl. new guard; full collection (1389 tests) imports clean;
pre-commit run all-green (markdown-links pass, skill-routing pass vs
omniclaude main snapshot).

* feat(OMN-13209): promote runtime-deployment wire DTOs (EnumRuntimeLane + ModelRuntimeDeploymentProof) to core (#1254)

A2 (canonical node migration, epic OMN-13205): graduate the runtime-deployment
lane enum and deployment-proof wire DTO from the transient omnibase_compat mirror
to their canonical core home, per the compat copy's COMPAT_MIGRATION_TARGET and
the >=2-repos graduation condition (node_redeploy is now a 2nd-repo importer).

- omnibase_core.enums.enum_runtime_lane.EnumRuntimeLane (UtilStrValueHelper enum,
  file-location convention)
- omnibase_core.models.runtime_deployment.wire.ModelRuntimeDeploymentProof +
  ProbeStatus/DeploymentProofStatus aliases, re-exporting the enum

Path note: the plan cited contracts.runtime_deployment.wire, but Pydantic
BaseModels under any non-exempt namespace trip core's disallow_any_explicit
mypy gate (documented in mypy.ini for pipeline/hooks/package). Wire DTOs live
under models.* (the established graduated-wire home, cf. models.delegation.wire
from OMN-12126); enums under enums.* per the file-location validator.

Promoted from the compat copy (not authored fresh from node files).

* feat(OMN-13130): UI contract primitives + EnumEmptyStateReason in omnibase_core (#1255)

* feat(OMN-13130): UI contract primitives + EnumEmptyStateReason in omnibase_core

Phase 0 of the Contract-Driven UI Platform (epic OMN-13129). Adds six frozen
Pydantic UI contract primitives (additive over ModelWidgetConfig) plus the
empty-state vocabulary and supporting capability enums.

Models (src/omnibase_core/models/dashboard/, one file each):
- ModelComponentContract  — composes the other primitives; component_kind reuses EnumWidgetType
- ModelActionContract     — declared onex.cmd.* emitter; COMPOSES ModelGate (approval), no duplication
- ModelDataBindingContract — /projection/{topic} bind with explicit ordering authority; no raw DB
- ModelPermissionContract  — view/act scopes + mandatory declared disabled_reason
- ModelEvidenceRequirementContract — composes OCC ModelEvidenceRequirement
- ModelRendererCapabilityContract  — model only (omnimarket reducer/topic is Phase 1; no node)

Enums (src/omnibase_core/enums/):
- EnumEmptyStateReason — exactly four values mirroring omnidash/shared/types/chart-config.ts
- EnumBindingOrderDirection, EnumEvidenceGateMoment, EnumRendererInteractionModel, EnumAccessibilityTier

ActionContract.command_topic is validated via the canonical validate_topic_suffix
(no hardcoded onex.cmd. literal) and requires kind == TOPIC_KIND_CMD. Version fields
use ModelSemVer (strong typing). All six models registered in scripts/emit_ts_types.py
for Stage 2 TS codegen. ModelGate / ModelGateSpec source untouched (ADR D2).

Refs: OMN-13130, epic OMN-13129. ADR: docs/adr/2026-06-17-ui-deterministic-projection-effect-layer.md

* fix(OMN-13130): use canonical interfaces_touched enum (public_api) in DoD contract

contract-validation CI rejected free-text interfaces_touched values; the field
is a closed enum (events/topics/protocols/envelopes/public_api). The touched
surface is the new public API exports -> public_api.

* feat(OMN-13132): Contract Graph IR + read-only import (#1256)

* feat(OMN-13132): Contract Graph IR + read-only import

Phase 2 of the Contract-Driven UI Platform (epic OMN-13129). Adds the
canonical read-only Contract Graph IR to omnibase_core plus dialect adapters
that import backend node contracts and Phase-0 UI component contracts into one
deterministic IR, with a no-op round-trip proven zero-semantic-diff through the
shipped cli_contract_diff spine.

Name-collision handling (plan §8: IR models are distinct from workflow-viz
graph models): new IR models live in the distinct models/contract_graph/
namespace with ModelContractGraph* names (ModelContractGraphIr/Node/Edge/
Protocol/ContractRef/SourceSet) — the bare ModelGraphNode/ModelGraphEdge
(models/graph/) and ModelContractRef (models/events/contract_validation/)
identifiers are NOT reused.

- Models: 6 frozen Pydantic IR models (frozen, extra=forbid, from_attributes)
  + EnumContractGraphNodeRole (incl renderer) + EnumContractGraphEdgeKind
  (incl component_renders/action_emits/data_binds).
- Adapters (read-only): node-contract + ui-component dialect adapters;
  manifest-driven discovery excluding .venv/omni_worktrees/generated.
- Hashing: sha256 over canonicalized contract bytes (per source) + stable
  per-adapter version hash, both embedded in the IR.
- Round-trip: IR -> canonical normalized contract form; no-op round-trip =
  zero semantic diff via cli_contract_diff (reused, not rebuilt).
- Tests: 29 unit tests incl deterministic-IR over >=2 real contracts (effect +
  reducer node contracts + 1 UI component) and no-op round-trip zero-diff.

Strictly read-only: no authoring UI, no contract mutation.

Refs: OMN-13132, epic OMN-13129.

* fix(OMN-13132): register contract_graph in test-selection adjacency + revert OMN-13130 scope bleed

- Add contract_graph adjacency entry (leaf module, reverse_deps: []) so
  test_every_src_module_has_adjacency_entry passes. contract_graph imports
  models/enums/cli (already shared_modules) and types; types.reverse_deps now
  includes contract_graph so a types change re-runs contract_graph tests.
- Revert contracts/OMN-13130.yaml to origin/dev (unrelated whitespace-only
  line-wrap edit was scope bleed; diff vs origin/dev is now empty).

Fixes the only red CI signal on PR #1256; contract_graph IR code unchanged.

* fix(OMN-13214): port hardened arm+update-branch+enqueue+verify auto-merge flow (#1257)

* fix(OMN-13214): port hardened arm+update-branch+enqueue+verify auto-merge flow to omnibase_core

Ports the OMN-13214 armed-but-not-enqueued fix from omnimarket (PR #1253,
merge 8fad5e11) into omnibase_core.

Root cause: arming auto-merge is NOT the same as enqueuing. On queue-controlled
dev, a CLEAN + all-required-green + armed PR can sit OUTSIDE the merge queue
indefinitely. The old workflow also passed `--auto --squash`, which dev's queue
REJECTS ("The merge strategy for dev is set by the merge queue"), so the PR was
never enqueued. The old "Force enqueue" step never verified the PR actually
entered the queue.

Changes:
- .github/workflows/auto-merge.yml:
  - "Enable auto-merge" now arms bare `--auto` (was `--auto --squash`) and
    falls through instead of exiting on success.
  - Replaces "Force enqueue" with "Enqueue armed PR and verify it entered the
    queue": classify -> (update-branch on strict-update BEHIND) -> enqueue ->
    poll-and-VERIFY isInMergeQueue, failing loudly if a green+armed PR is not
    enqueued. Preserves this repo's pre-check fanout guard, self-hosted runner
    selection, and OCC preflight.
- scripts/ci/merge_queue_enqueue.py: stdlib-only, no-network classify/verify
  decision helper (mypy --strict clean; explicit-Any-free via dict[str, object]).
- tests/unit/scripts/ci/test_merge_queue_enqueue.py: 32 unit tests pinning the
  CLEAN-armed-not-queued -> ENQUEUE bug, ALREADY_QUEUED no-op, BEHIND strict vs
  non-strict, WAIT/BLOCKED states, verify, and error-marker classification.

Verification: 32/32 tests pass; mypy --strict clean; ruff clean; actionlint
clean on the new steps; full omnibase_core pre-commit suite green (40 hooks).

The one skipped local hook (validate-deterministic-skill-routing) scans
omniclaude-owned SKILL.md files via a sibling clone; its 16 violations
pre-exist on omniclaude@dev, are unrelated to this PR (no SKILL.md touched),
and the check is NOT a required status check on omnibase_core dev.

OMN-13214

* test(OMN-13214): update auto-merge workflow-shape test for arm+enqueue+verify flow

The existing test_auto_merge_workflow_shape.py pinned the old step name
"Force enqueue to merge queue". The OMN-13214 port renamed it to "Enqueue armed
PR and verify it entered the queue" and changed "Enable auto-merge" from
--auto --squash to bare --auto.

- Point the ordering assertion at the new enqueue step name.
- Add test_enable_auto_merge_arms_bare_auto_not_squash: the gh pr merge command
  arms bare --auto (no --squash).
- Add test_enqueue_step_classifies_enqueues_and_verifies: the enqueue step
  classifies + verifies via scripts/ci/merge_queue_enqueue.py, calls
  enqueuePullRequest, runs gh pr update-branch, and fails loudly (::error::).

OMN-13214

* fix(OMN-13214): make merge_queue_enqueue.main() returns explicit (CodeQL)

CodeQL flagged "explicit returns mixed with implicit (fall through) returns" in
main(). Restructure the command dispatch as if/elif/else where the defensive
else raises SystemExit, so every branch terminates with an explicit return or
raise (no implicit None fall-through). mypy --strict + ruff + 32 unit tests
remain green.

OMN-13214

* feat(OMN-13219): canonical-inference enforcement gate (pre-commit + required CI) (#1258)

* feat(OMN-13219): canonical-inference enforcement gate (pre-commit + required CI)

Adds ValidatorCanonicalInference — a ratchet gate wired as a pre-commit hook
and a required CI status check (parallel to the OMN-12818 URL-authority gate)
that fails on non-canonical model-inference surfaces:

- model-cli-shellout: a model-CLI binary (codex/claude/gemini/opencode) passed
  to subprocess/exec/os.system or resolved via shutil.which — the exact
  non-canonical surface OMN-13215 shipped and nothing caught.
- model-id-env-read: os.environ[*_MODEL] / os.environ.get(*_PROVIDER) reads.

Endpoint URLs and *_URL/*_ENDPOINT env reads remain owned by the URL-authority
gate (OMN-12818); freestanding imperative IO generally by
scan_freestanding_imperative_io (OMN-12515/12540). No parallel one-off — the
three guards partition the space.

Fail-closed regression test: a NEW shell-out and a NEW env-resolved model each
trip the gate (exit 1); the contract-resolved tier (OMN-13215 target shape)
passes. Ratchet baseline (sha256 fingerprints) grandfathers existing violations;
omnibase_core seeds at 0 (clean). Burn-down only — CI rejects baseline growth.
codex shell-out removal tracked by OMN-13215.

Evidence-Source: OCC#PENDING
Evidence-Ticket: OMN-13219

* fix(OMN-13219): use env suffix constant in inference validator

* ci(OMN-13131): adopt main's permissive main-target-guard on the promotion branch

The pull_request main-target-guard runs the workflow definition from the PR head
tree. dev's guard is the restrictive (dev-only) OMN-12477 version; main already
carries the permissive (dev || promotion/*) version from #1240. A promotion/*
head therefore fails the dev-tree restrictive guard. Adopting main's permissive
guard on the promotion branch lets the promotion/* head pass; net diff to main is
zero (main already has this exact file). dev->main promotion via promotion/* is
the sanctioned shape (memory: dev-only-promotion-to-main + #1240 precedent).

Evidence-Ticket: OMN-13131
promotion-receipt: OCC-2742
andywu42 pushed a commit to andywu42/omnibase_core that referenced this pull request Jul 1, 2026
…0 promotion) (OmniNode-ai#1345)

* chore(OMN-12934): continue dev to main promotion for prod redeploy (#1240)

* feat(OMN-12960): single transport-envelope unwrap predicate + dispatch-surface test gate (#1228)

Collapse the two hand-synced marker-key envelope-unwrap predicates
(omnibase_infra.runtime.auto_wiring.handler_wiring and
omnimarket.nodes.evidence_pipeline_native) into one authoritative source in
omnibase_core.utils.util_envelope_unwrap. The two sets had drifted again
(infra was missing __bindings vs omnimarket), re-introducing the OMN-12946
defect class on the infra side. Both call sites now import the single source.

By layering this wire-level concern belongs in omnibase_compat, but the compat
pin is policy-frozen, so per the P1.4 plan it lands in omnibase_core (already a
runtime dep of both consumers) with a documented note.

Also adds the dispatch-surface-test-required validator: a path-heuristic gate
(pre-commit + CI quality-gate) that makes a real-dispatch-path test MANDATORY
for any change touching dispatch / routing / handler-registration /
message-envelope source surfaces. Handler-isolation tests pass while live
dispatch fails — this is the durable ratchet for that defect class.

Evidence-Ticket: OMN-12960

* feat(OMN-12957): runtime-profile registry + unregistered/no-consumer-lane validator rules (#1229)

Generalizes OMN-12950: a contract could declare any runtime_profiles string,
and a nonexistent profile (e.g. [compute]) silently orphaned the node — the
auto-wiring ownership filter assigned it to no running runtime, so zero
consumer groups, zero errors, empty projection tables.

Adds the canonical runtime-profile name registry in omnibase_core
(constants_runtime_profiles.REGISTERED_RUNTIME_PROFILES /
CONSUMER_ATTACHED_RUNTIME_PROFILES) so contract validation can enforce
membership without a core->infra dependency, and extends
ValidatorRuntimeProfiles with two new rules:

- runtime_profile_unregistered: every declared runtime_profiles value must be
  in REGISTERED_RUNTIME_PROFILES (catches the OMN-12950 class directly; finds
  16 real orphans in omnimarket).
- runtime_profile_no_consumer_lane: a subscribing REDUCER/EFFECT must name at
  least one consumer-attached profile (main/effects/workers) or its
  subscriptions are never drained — the second silent-orphan class flagged in
  operator review (manifest-declares-node != consumer-attached).

Consumer repos vendor a frozen baseline allowlist at
<repo>/validation/runtime_profiles_allowlist.yaml, discovered deterministically
by walking up to the pyproject.toml root (no env var — passes the
no-new-os.environ gate). The gate blocks NEW orphans; pre-existing ones are
frozen and drained via OMN-12982.

All 3 rules wire via the existing precommit hook + CI workflow (default
contract enables all three; core self-scan stays green).

Evidence-Ticket: OMN-12957

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver (#1230)

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver

A typing.Protocol used as a handler_routing target is a non-instantiable
interface. Its synthetic __init__(*args, **kwargs) exposes only VAR_POSITIONAL/
VAR_KEYWORD params, so the resolver's required-param scan saw zero required
params and Step 5 called handler_cls() -> typing raised the anonymous
TypeError('Protocols cannot be instantiated') from typing.py:1774, crashing
runtime bootstrap with no attribution to the offending contract/handler.

Add Step 1a: fail fast on _is_protocol handler_cls BEFORE any instantiation
path, with an identifying TypeError naming the handler module.name and owning
contract. Mirrors the infra OMN-12501 quarantine guard semantics (which catches
this TypeError and quarantines as PROTOCOL_HANDLER_DECLARATION) — the failure
stays a TypeError but becomes attributable. Placed after Step 1 so a Protocol
handler on a node not hosted here still skips cleanly.

TDD: 6 unit tests reproduce the crash and assert attribution + precedence
ordering (rejected before container/event_bus probing; exempted by ownership
skip).

Evidence-Ticket: OMN-12961

* test(OMN-12961): silence CodeQL no-effect on Protocol stub bodies

The two Protocol handler stubs in test_service_handler_resolver.py used a
trailing `...` Ellipsis as the method body, which CodeQL flags as
"Statement has no effect" (alerts 2554/2555) — two unresolved review
threads that blocked merge under required_conversation_resolution.

Replace the `...` bodies with a one-line docstring (which has an effect:
it is the method's __doc__), preserving the Protocol semantics while
silencing the false-positive. No behavior change; all 21 resolver unit
tests still pass.

Evidence-Ticket: OMN-12961
Evidence-Source: OCC#2486

* feat(OMN-13026): transport-mock lint validator — bare AsyncMock/MagicMock on EventBus/transport surfaces (#1231)

Adds omnibase_core.validators.transport_mock_lint with 25 unit tests.
Detects AsyncMock()/MagicMock() without spec=/spec_set= on EventBus/
transport/kafka mock surfaces (assignment targets, annotated assignments,
and keyword arguments). Exports transport-mock-lint pre-commit hook for
per-repo wiring. Ratchet baseline mode (--baseline <yaml>) allows
activation on repos with existing violations without blocking every PR.
Reference incident: PR #1181 bare AsyncMock hid missing EventBusKafka.stop().

Evidence-Ticket: OMN-13026

* fix(OMN-13061): hard-fail on contract_sha256=None in OCC eligibility validator (#1233)

The migration window for OMN-10421 closed on 2026-04-30. Receipts with
contract_sha256=None were silently passing the OCC merge eligibility gate
(lines 184-185: `if receipt.contract_sha256 is None: pass`) — a bypass
that diverged from validator_receipt_gate's post-cutoff hard-fail.

Fix: replace the silent `pass` with a hard CONTRACT_HASH_MISMATCH failure
matching validator_receipt_gate._check_one_receipt behaviour. Uses the
shared _CONTRACT_SHA256_REQUIRED_AFTER sentinel for cutoff documentation.

Historical corpus ADVISORY scanners (OMN-13060) are unchanged.

Test: rename test_missing_contract_hash_is_migration_compatible →
test_missing_contract_hash_is_ineligible_post_cutoff with inverted
assertions; all 13 tests pass.

* feat(OMN-13026): protocol-conformance tests per Protocol + portable _rel_path baseline fix (#1234)

- Add tests/unit/validators/test_transport_mock_protocol_conformance.py:
  33 tests verifying each transport-surface Protocol
  (ProtocolEventBusBase, ProtocolEventBus, ProtocolAsyncEventBus,
  ProtocolEventBusPublisher, ProtocolEventBusSubscriber,
  ProtocolEventBusLifecycle, ProtocolKafkaClient,
  ProtocolDispatchBusClientTransport) can be imported and used as
  AsyncMock/MagicMock spec=, and that the spec correctly rejects
  nonexistent attributes.

- Fix transport_mock_lint.py --write-baseline to emit portable relative
  paths (via new _rel_path helper) instead of absolute machine-specific
  paths, making baseline YAML files portable across machines/CIs.

DoD: one protocol-conformance test per Protocol defined (OMN-13026).

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core (#1232)

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core

PR-2 of OMN-12803. Ships the canonical ValidatorBase subclass for the url-authority
gate so it participates in the ecosystem-wide validation pipeline.

Detects three violation classes in Python source:
- public-https-literal: quoted https:// URLs to real connection-target hosts
- env-url-read: os.environ[*_URL] / os.environ.get(*_ENDPOINT) reads
- url-const-assignment: module-level *_URL/*_ENDPOINT constants from env or literal

Ratchet (mirrors OMN-12791 receipt-honesty): sha256(repo+path+normalized-snippet)
fingerprint; fail only on NEW fingerprints; baseline burn-down only (assert_baseline_
shrinks_only guards against gaming). Baseline = 13 frozen violations across omnibase_core.

Migration debt baselined-with-tickets: OMN-12806 (omnibase_core), OMN-12807
(omnibase_infra), OMN-12808 (other repos) — cited, not resolved in this PR.

Wired as BLOCKING pre-commit hook (check-url-authority) and required CI workflow
(URL Authority Gate) on omnibase_core. 40 dedicated tests; validator self-checks
clean through its own gate.

Gate probe: RED on synthetic NEW_API_URL literal / GREEN on baselined tip.

Evidence-Ticket: OMN-12818

* fix(OMN-12818): resolve 3 CI failures on url-authority gate PR

1. ci.yml: exclude url_authority_baseline.json from detect-secrets scan
   (sha256 fingerprints triggered Hex High Entropy String false-positive)
2. url-authority-gate.yml: anti-gaming check exits 0 when baseline file
   is new on this PR (initial introduction — no prior to compare against)
3. yamlfmt: reformat .yaml-validation-allowlist, OMN-12663 contract,
   url_authority validation contract (pre-commit hook auto-applied)

Evidence-Source: OCC#2561
Evidence-Ticket: OMN-12818

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] typed receipt models (#1235)

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] receipt models

Phase 0b of the skill-output-suppression plan (epic OMN-13089).

- Add omnibase_core.models.artifacts.ModelArtifactRef: frozen
  content-addressed artifact reference enforcing sha256:<64 hex>,
  with from_bytes() and hex_digest helpers. Single ref type consumed
  by the artifact store (Phase 1) and later phases.
- Add omnibase_core.models.dispatch.ModelSkillResult[T]: generic typed
  skill dispatch receipt envelope (skill-surface analogue of
  ModelHandlerOutput[T]) carrying the FULL typed result, concrete
  result_model FQN for schema identity, metrics, artifact_refs, and
  schema_version. Exported from models.dispatch.
- Resolve duplicate-model-filename collisions surfaced by the
  validate-no-duplicate-models gate (no allowlist additions):
  - models/handlers/model_artifact_ref.py -> model_handler_artifact_ref.py
    (class ModelHandlerArtifactRef; opaque registry ref, internal-only)
  - models/skill/model_skill_result.py -> model_skill_result_file.py
    (class ModelSkillResultFile; the OMN-3867 skill-results file contract)
- Add SPDX header to empty tests/unit/models/telemetry/__init__.py
  (pre-existing SPDX gate failure under --all-files).

Tests: new unit suites for both models (validation, frozen/extra-forbid
contract, JSON round-trip, generic parametrization).

* fix(OMN-13091): drop URL literal from ModelHandlerArtifactRef docstring example

The module rename moved the docstring's illustrative registry URL out of
the url-authority frozen baseline, making it count as a NEW violation.
Replace with an opaque registry-scheme example — the field is an opaque
source locator, no real endpoint belongs in the example.

* feat(OMN-13093): minimal content-addressed ArtifactStore slice (Phase 1) (#1236)

* feat(OMN-13093): minimal content-addressed ArtifactStore slice

Phase 1 of the skill-output-suppression plan (epic OMN-13089):
src/omnibase_core/artifacts/artifact_store.py — write_blob (sha256
content addressing, sharded <root>/<hh>/<full-hex> layout, atomic
temp+rename, idempotent on existing hash), JSON metadata sidecar with
the artifact-captured required fields + writer_version, hash-verified
read_blob, read_meta. Store root from ONEX_ARTIFACT_STORE_ROOT
(required env, KeyError on absence). Stdlib + Pydantic only so
omniclaude hooks can import it. Parent durable-capture Phase 1 extends
this in place (retention/quota, redaction, read-API hardening).

* test(OMN-13093): register artifacts module in CI test-selection adjacency map

New src/omnibase_core/artifacts/ module needs an adjacency entry or
test_every_src_module_has_adjacency_entry fails. No reverse deps yet —
downstream consumers (CLI receipt mode, omniclaude hooks) land in
Phase 2a/3.

* feat(OMN-13098): skill-dispatch receipt-mode validator (Phase 4b) (#1237)

Add validate_skill_dispatch_receipt_mode in omnibase_core/validators/ —
the enforcement validator for the skill-output-suppression epic (OMN-13089).
Four checks on every skill under plugins/onex/skills/:

(a) every skill declares skill_kind: dispatch | methodology (explicit, never
    heuristic); missing/invalid value FAILS;
(b) dispatch skills' commands must be the single onex skill / onex delegate
    receipt-mode form — bare onex (run|node|run-node) FAILS;
(c) dispatch skill directories contain markdown only — no *.py, _lib/, or
    shell scripts (pycache ignored);
(d) prompt-instruction consistency — no 'cat workflow_result.json' /
    'surface JSON verbatim' instruction in a receipt-mode dispatch; a negation
    guard tolerates prohibitions ('no cat of workflow_result.json').

Ratchet semantics live in main(): an allowlist tolerates not-yet-migrated
skills but FAILS if it grows, if a listed skill is migrated (stale entry) or
removed, or if a new skill ships an unreceipted dispatch. Absent allowlist =
unconditional gate (the end state). --generate-allowlist regenerates the
violation set as a migration aid.

Supporting: EnumSkillReceiptRule, ModelSkillDispatchReceiptFinding (models/
validation/), enums/__init__ registration, no-manual-yaml exclude for the
validator. File-location validator: Enum* in validation/ carve-out (matches
the existing Model*/Protocol* validation/ helper-class allowances) so the
pre-existing EnumHonestyRule co-location passes.

dod_evidence:
- uv run pytest tests/unit/validators/test_skill_dispatch_receipt_mode.py -v
  => 29 passed (four checks + negation guard + ratchet growth/regression/
     stale/absent semantics + generate-allowlist + usage-error exit codes)
- uv run mypy src/.../skill_dispatch_receipt_mode.py ... --strict => clean
- uv run ruff format/check => clean
- end-to-end vs real omniclaude@dev skills tree + committed ratchet => exit 0
- negative: a dispatch skill with bare 'uv run onex run foo' => exit 1
- pre-commit run --files <staged> => all green

Evidence-Ticket: OMN-13098

Epic: OMN-13089 (Skill Output Suppression). Plan:
docs/plans/2026-06-12-skill-output-suppression-plan.md Phase 4 items 2-4.

* ci(OMN-12934): allow ticketed promotion branches to target main

* chore(OMN-13131): promote core dev->main for renderer platform release (v0.45.0) (#1260)

* feat(OMN-12960): single transport-envelope unwrap predicate + dispatch-surface test gate (#1228)

Collapse the two hand-synced marker-key envelope-unwrap predicates
(omnibase_infra.runtime.auto_wiring.handler_wiring and
omnimarket.nodes.evidence_pipeline_native) into one authoritative source in
omnibase_core.utils.util_envelope_unwrap. The two sets had drifted again
(infra was missing __bindings vs omnimarket), re-introducing the OMN-12946
defect class on the infra side. Both call sites now import the single source.

By layering this wire-level concern belongs in omnibase_compat, but the compat
pin is policy-frozen, so per the P1.4 plan it lands in omnibase_core (already a
runtime dep of both consumers) with a documented note.

Also adds the dispatch-surface-test-required validator: a path-heuristic gate
(pre-commit + CI quality-gate) that makes a real-dispatch-path test MANDATORY
for any change touching dispatch / routing / handler-registration /
message-envelope source surfaces. Handler-isolation tests pass while live
dispatch fails — this is the durable ratchet for that defect class.

Evidence-Ticket: OMN-12960

* feat(OMN-12957): runtime-profile registry + unregistered/no-consumer-lane validator rules (#1229)

Generalizes OMN-12950: a contract could declare any runtime_profiles string,
and a nonexistent profile (e.g. [compute]) silently orphaned the node — the
auto-wiring ownership filter assigned it to no running runtime, so zero
consumer groups, zero errors, empty projection tables.

Adds the canonical runtime-profile name registry in omnibase_core
(constants_runtime_profiles.REGISTERED_RUNTIME_PROFILES /
CONSUMER_ATTACHED_RUNTIME_PROFILES) so contract validation can enforce
membership without a core->infra dependency, and extends
ValidatorRuntimeProfiles with two new rules:

- runtime_profile_unregistered: every declared runtime_profiles value must be
  in REGISTERED_RUNTIME_PROFILES (catches the OMN-12950 class directly; finds
  16 real orphans in omnimarket).
- runtime_profile_no_consumer_lane: a subscribing REDUCER/EFFECT must name at
  least one consumer-attached profile (main/effects/workers) or its
  subscriptions are never drained — the second silent-orphan class flagged in
  operator review (manifest-declares-node != consumer-attached).

Consumer repos vendor a frozen baseline allowlist at
<repo>/validation/runtime_profiles_allowlist.yaml, discovered deterministically
by walking up to the pyproject.toml root (no env var — passes the
no-new-os.environ gate). The gate blocks NEW orphans; pre-existing ones are
frozen and drained via OMN-12982.

All 3 rules wire via the existing precommit hook + CI workflow (default
contract enables all three; core self-scan stays green).

Evidence-Ticket: OMN-12957

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver (#1230)

* fix(OMN-12961): reject typing.Protocol handler targets in ServiceHandlerResolver

A typing.Protocol used as a handler_routing target is a non-instantiable
interface. Its synthetic __init__(*args, **kwargs) exposes only VAR_POSITIONAL/
VAR_KEYWORD params, so the resolver's required-param scan saw zero required
params and Step 5 called handler_cls() -> typing raised the anonymous
TypeError('Protocols cannot be instantiated') from typing.py:1774, crashing
runtime bootstrap with no attribution to the offending contract/handler.

Add Step 1a: fail fast on _is_protocol handler_cls BEFORE any instantiation
path, with an identifying TypeError naming the handler module.name and owning
contract. Mirrors the infra OMN-12501 quarantine guard semantics (which catches
this TypeError and quarantines as PROTOCOL_HANDLER_DECLARATION) — the failure
stays a TypeError but becomes attributable. Placed after Step 1 so a Protocol
handler on a node not hosted here still skips cleanly.

TDD: 6 unit tests reproduce the crash and assert attribution + precedence
ordering (rejected before container/event_bus probing; exempted by ownership
skip).

Evidence-Ticket: OMN-12961

* test(OMN-12961): silence CodeQL no-effect on Protocol stub bodies

The two Protocol handler stubs in test_service_handler_resolver.py used a
trailing `...` Ellipsis as the method body, which CodeQL flags as
"Statement has no effect" (alerts 2554/2555) — two unresolved review
threads that blocked merge under required_conversation_resolution.

Replace the `...` bodies with a one-line docstring (which has an effect:
it is the method's __doc__), preserving the Protocol semantics while
silencing the false-positive. No behavior change; all 21 resolver unit
tests still pass.

Evidence-Ticket: OMN-12961
Evidence-Source: OCC#2486

* feat(OMN-13026): transport-mock lint validator — bare AsyncMock/MagicMock on EventBus/transport surfaces (#1231)

Adds omnibase_core.validators.transport_mock_lint with 25 unit tests.
Detects AsyncMock()/MagicMock() without spec=/spec_set= on EventBus/
transport/kafka mock surfaces (assignment targets, annotated assignments,
and keyword arguments). Exports transport-mock-lint pre-commit hook for
per-repo wiring. Ratchet baseline mode (--baseline <yaml>) allows
activation on repos with existing violations without blocking every PR.
Reference incident: PR #1181 bare AsyncMock hid missing EventBusKafka.stop().

Evidence-Ticket: OMN-13026

* fix(OMN-13061): hard-fail on contract_sha256=None in OCC eligibility validator (#1233)

The migration window for OMN-10421 closed on 2026-04-30. Receipts with
contract_sha256=None were silently passing the OCC merge eligibility gate
(lines 184-185: `if receipt.contract_sha256 is None: pass`) — a bypass
that diverged from validator_receipt_gate's post-cutoff hard-fail.

Fix: replace the silent `pass` with a hard CONTRACT_HASH_MISMATCH failure
matching validator_receipt_gate._check_one_receipt behaviour. Uses the
shared _CONTRACT_SHA256_REQUIRED_AFTER sentinel for cutoff documentation.

Historical corpus ADVISORY scanners (OMN-13060) are unchanged.

Test: rename test_missing_contract_hash_is_migration_compatible →
test_missing_contract_hash_is_ineligible_post_cutoff with inverted
assertions; all 13 tests pass.

* feat(OMN-13026): protocol-conformance tests per Protocol + portable _rel_path baseline fix (#1234)

- Add tests/unit/validators/test_transport_mock_protocol_conformance.py:
  33 tests verifying each transport-surface Protocol
  (ProtocolEventBusBase, ProtocolEventBus, ProtocolAsyncEventBus,
  ProtocolEventBusPublisher, ProtocolEventBusSubscriber,
  ProtocolEventBusLifecycle, ProtocolKafkaClient,
  ProtocolDispatchBusClientTransport) can be imported and used as
  AsyncMock/MagicMock spec=, and that the spec correctly rejects
  nonexistent attributes.

- Fix transport_mock_lint.py --write-baseline to emit portable relative
  paths (via new _rel_path helper) instead of absolute machine-specific
  paths, making baseline YAML files portable across machines/CIs.

DoD: one protocol-conformance test per Protocol defined (OMN-13026).

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core (#1232)

* feat(OMN-12818): url-authority ratchet gate — ValidatorUrlAuthority in omnibase_core

PR-2 of OMN-12803. Ships the canonical ValidatorBase subclass for the url-authority
gate so it participates in the ecosystem-wide validation pipeline.

Detects three violation classes in Python source:
- public-https-literal: quoted https:// URLs to real connection-target hosts
- env-url-read: os.environ[*_URL] / os.environ.get(*_ENDPOINT) reads
- url-const-assignment: module-level *_URL/*_ENDPOINT constants from env or literal

Ratchet (mirrors OMN-12791 receipt-honesty): sha256(repo+path+normalized-snippet)
fingerprint; fail only on NEW fingerprints; baseline burn-down only (assert_baseline_
shrinks_only guards against gaming). Baseline = 13 frozen violations across omnibase_core.

Migration debt baselined-with-tickets: OMN-12806 (omnibase_core), OMN-12807
(omnibase_infra), OMN-12808 (other repos) — cited, not resolved in this PR.

Wired as BLOCKING pre-commit hook (check-url-authority) and required CI workflow
(URL Authority Gate) on omnibase_core. 40 dedicated tests; validator self-checks
clean through its own gate.

Gate probe: RED on synthetic NEW_API_URL literal / GREEN on baselined tip.

Evidence-Ticket: OMN-12818

* fix(OMN-12818): resolve 3 CI failures on url-authority gate PR

1. ci.yml: exclude url_authority_baseline.json from detect-secrets scan
   (sha256 fingerprints triggered Hex High Entropy String false-positive)
2. url-authority-gate.yml: anti-gaming check exits 0 when baseline file
   is new on this PR (initial introduction — no prior to compare against)
3. yamlfmt: reformat .yaml-validation-allowlist, OMN-12663 contract,
   url_authority validation contract (pre-commit hook auto-applied)

Evidence-Source: OCC#2561
Evidence-Ticket: OMN-12818

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] typed receipt models (#1235)

* feat(OMN-13091): ModelArtifactRef + ModelSkillResult[T] receipt models

Phase 0b of the skill-output-suppression plan (epic OMN-13089).

- Add omnibase_core.models.artifacts.ModelArtifactRef: frozen
  content-addressed artifact reference enforcing sha256:<64 hex>,
  with from_bytes() and hex_digest helpers. Single ref type consumed
  by the artifact store (Phase 1) and later phases.
- Add omnibase_core.models.dispatch.ModelSkillResult[T]: generic typed
  skill dispatch receipt envelope (skill-surface analogue of
  ModelHandlerOutput[T]) carrying the FULL typed result, concrete
  result_model FQN for schema identity, metrics, artifact_refs, and
  schema_version. Exported from models.dispatch.
- Resolve duplicate-model-filename collisions surfaced by the
  validate-no-duplicate-models gate (no allowlist additions):
  - models/handlers/model_artifact_ref.py -> model_handler_artifact_ref.py
    (class ModelHandlerArtifactRef; opaque registry ref, internal-only)
  - models/skill/model_skill_result.py -> model_skill_result_file.py
    (class ModelSkillResultFile; the OMN-3867 skill-results file contract)
- Add SPDX header to empty tests/unit/models/telemetry/__init__.py
  (pre-existing SPDX gate failure under --all-files).

Tests: new unit suites for both models (validation, frozen/extra-forbid
contract, JSON round-trip, generic parametrization).

* fix(OMN-13091): drop URL literal from ModelHandlerArtifactRef docstring example

The module rename moved the docstring's illustrative registry URL out of
the url-authority frozen baseline, making it count as a NEW violation.
Replace with an opaque registry-scheme example — the field is an opaque
source locator, no real endpoint belongs in the example.

* feat(OMN-13093): minimal content-addressed ArtifactStore slice (Phase 1) (#1236)

* feat(OMN-13093): minimal content-addressed ArtifactStore slice

Phase 1 of the skill-output-suppression plan (epic OMN-13089):
src/omnibase_core/artifacts/artifact_store.py — write_blob (sha256
content addressing, sharded <root>/<hh>/<full-hex> layout, atomic
temp+rename, idempotent on existing hash), JSON metadata sidecar with
the artifact-captured required fields + writer_version, hash-verified
read_blob, read_meta. Store root from ONEX_ARTIFACT_STORE_ROOT
(required env, KeyError on absence). Stdlib + Pydantic only so
omniclaude hooks can import it. Parent durable-capture Phase 1 extends
this in place (retention/quota, redaction, read-API hardening).

* test(OMN-13093): register artifacts module in CI test-selection adjacency map

New src/omnibase_core/artifacts/ module needs an adjacency entry or
test_every_src_module_has_adjacency_entry fails. No reverse deps yet —
downstream consumers (CLI receipt mode, omniclaude hooks) land in
Phase 2a/3.

* feat(OMN-13098): skill-dispatch receipt-mode validator (Phase 4b) (#1237)

Add validate_skill_dispatch_receipt_mode in omnibase_core/validators/ —
the enforcement validator for the skill-output-suppression epic (OMN-13089).
Four checks on every skill under plugins/onex/skills/:

(a) every skill declares skill_kind: dispatch | methodology (explicit, never
    heuristic); missing/invalid value FAILS;
(b) dispatch skills' commands must be the single onex skill / onex delegate
    receipt-mode form — bare onex (run|node|run-node) FAILS;
(c) dispatch skill directories contain markdown only — no *.py, _lib/, or
    shell scripts (pycache ignored);
(d) prompt-instruction consistency — no 'cat workflow_result.json' /
    'surface JSON verbatim' instruction in a receipt-mode dispatch; a negation
    guard tolerates prohibitions ('no cat of workflow_result.json').

Ratchet semantics live in main(): an allowlist tolerates not-yet-migrated
skills but FAILS if it grows, if a listed skill is migrated (stale entry) or
removed, or if a new skill ships an unreceipted dispatch. Absent allowlist =
unconditional gate (the end state). --generate-allowlist regenerates the
violation set as a migration aid.

Supporting: EnumSkillReceiptRule, ModelSkillDispatchReceiptFinding (models/
validation/), enums/__init__ registration, no-manual-yaml exclude for the
validator. File-location validator: Enum* in validation/ carve-out (matches
the existing Model*/Protocol* validation/ helper-class allowances) so the
pre-existing EnumHonestyRule co-location passes.

dod_evidence:
- uv run pytest tests/unit/validators/test_skill_dispatch_receipt_mode.py -v
  => 29 passed (four checks + negation guard + ratchet growth/regression/
     stale/absent semantics + generate-allowlist + usage-error exit codes)
- uv run mypy src/.../skill_dispatch_receipt_mode.py ... --strict => clean
- uv run ruff format/check => clean
- end-to-end vs real omniclaude@dev skills tree + committed ratchet => exit 0
- negative: a dispatch skill with bare 'uv run onex run foo' => exit 1
- pre-commit run --files <staged> => all green

Evidence-Ticket: OMN-13098

Epic: OMN-13089 (Skill Output Suppression). Plan:
docs/plans/2026-06-12-skill-output-suppression-plan.md Phase 4 items 2-4.

* docs(OMN-13182): refresh omnibase_core documentation (#1241)

- Replace Poetry references with uv in installation.md (Poetry was listed
  as Method 1/recommended; project uses uv exclusively)
- Fix "Always use Poetry" design rule in docs/INDEX.md to "Always use uv"
- Add 15 missing top-level source modules to Package Structure in INDEX.md
  (artifacts/, dispatch/, doctor/, event_bus/, gate/, adapters/, agents/,
  analysis/, discovery/, navigation/, normalization/, overlays/, validators/,
  workflows/)
- Remove all 6 references to deleted EnvelopeRouter/runtime_envelope_router.py
  in onex_terminology.md (deleted OMN-12526/v0.43.0); update to
  RuntimeMessageDispatch + RuntimeHandlerRegistry
- Add onex-demo-path-topic-gate CLI entrypoint to VALIDATION_OWNERSHIP.md
  (OMN-12777, present in pyproject.toml since v0.44.0 but missing from doc)
- Add section listing 6 pre-commit/CI-only validators shipped since April 24:
  ValidatorUrlAuthority (OMN-12818), ValidatorReceiptHonesty (OMN-12791),
  ValidatorRuntimeProfiles (OMN-12957), gitignore_baseline (OMN-12452),
  transport-mock lint (OMN-13026), skill-dispatch receipt-mode (OMN-13098)
- Add CHANGELOG entries for v0.44.0/v0.44.1/v0.44.2 (all three tagged and
  shipped but had zero CHANGELOG entries)
- Add 5 missing subsystem rows to CLAUDE.md Architecture Extensions table:
  ArtifactStore (OMN-13093), Dispatch Bus Client, Doctor Health Checks,
  In-Memory Event Bus, OmniGate (OMN-11137/11139/11140)

Parent: OMN-13172
All changes AI-generated.

* refactor(OMN-13189): delete dead ModelOnexEnvelopeV1 — completes OMN-4152 (#1242)

Remove ModelOnexEnvelopeV1 (zero production callers, zero test imports across
omnibase_core/omnibase_infra/omnimarket src+tests). Deletes the class file,
both export lines in models/core/__init__.py, and the 3 predecessor mentions
in model_onex_envelope.py that reference the now-deleted class.

Completes OMN-4152 (Task 6: Retire ModelOnexEnvelopeV1) — verification confirmed
V1 fully dead, so this deletes it outright rather than retaining for backward-
compat deserialization.

grep -rn ModelOnexEnvelopeV1 src/ tests/ => zero.

* refactor(OMN-13192): migrate sole live ModelOnexEnvelope constructor to ModelEventEnvelope[ModelEventPublishIntent] (#1245)

Retarget the one production ModelOnexEnvelope(...) constructor at
mixin_intent_publisher.py to ModelEventEnvelope[ModelEventPublishIntent](...),
publishing the TYPED ModelEventPublishIntent as the envelope payload (not a
serialized dict). Field remap: source_node->source_tool,
timestamp->envelope_timestamp, drop operation, payload=intent (typed).

This leaves ZERO live ModelOnexEnvelope constructor calls in src/ so B4 can
delete the class. The class definition and its docstring examples in
model_onex_envelope.py are untouched (B4 scope).

Verification REFUTED the 'Kafka consumers will break' framing: there are NO
Kafka consumers of onex.runtime.intents. IntentExecutor is a synchronous
runtime service (not a topic listener) and MixinIntentPublisher has zero
production call sites. This is a type-correctness + test change only; there is
no consumer-node migration.

Tests updated to assert the new ModelEventEnvelope wire shape and a
serialize->deserialize round-trip. The strict
ModelEventEnvelope[ModelEventPublishIntent] cannot reconstruct from JSON because
ModelEventPublishIntent.target_event_payload is a ModelEventPayloadUnion whose
before-validator rejects the plain dict JSON decoding yields (no discriminator)
-- a pre-existing property of the intent model, so the round-trip is asserted on
the generic ModelEventEnvelope (payload preserved as a mapping).

Evidence-Source: OCC#PENDING
Evidence-Ticket: OMN-13192

* chore(OMN-13187): refresh core dependency pins (#1246)

* refactor(OMN-13194): re-annotate envelope_validator.py from ModelOnexEnvelope to ModelEventEnvelope[Any] (#1248)

B3 of the platform-debt envelope-dedup plan (docs/plans/2026-06-16-platform-debt-contract-topics-and-envelope-dedup-plan.md).

Re-annotates the 4 ModelOnexEnvelope sites in
src/omnibase_core/validation/envelope_validator.py to ModelEventEnvelope[Any]:
- TYPE_CHECKING import -> omnibase_core.models.events.model_event_envelope
- validate / _validate_structure / _validate_payload parameter annotations
The 2 prose docstring mentions are updated too so the module references zero
ModelOnexEnvelope. ModelEventEnvelope[T] is a PEP 695 generic, so [Any] is valid.

Annotation-only: the validator reads every field via getattr(envelope, ..., None)
(duck-typed), so no runtime code path changes. Does NOT delete ModelOnexEnvelope
(B4 / OMN-13196 scope).

Predecessor B2 (OMN-13192, PR #1245) merged to dev (a84bb24).

dod_evidence:
- grep: zero ModelOnexEnvelope in envelope_validator.py
- mypy --strict envelope_validator.py: Success, no issues
- focused suite tests/unit/validation/test_envelope_validator.py: 40 passed, 4 skipped
- full pytest tests/ -n auto (no -k): 41739 passed; the 1 perf flake
  (test_source_node_id_overhead round-trip overhead under 16-way load) passes in
  isolation (1.39s) and does not reference the validator
- pre-commit run --all-files: all hooks pass

* chore(OMN-13195): bump validate-boundaries action pin (#1249)

* feat(OMN-12804): non-model URL contract authority — integration catalog + design doc (#1251)

Part 2A/2B of OMN-12803 URL-authority epic.  OMN-12818 shipped the gate
(ValidatorUrlAuthority); this PR completes the design by establishing the
canonical authority surface for non-model URLs.

## Design (Part 2A): two authority surfaces

ONEX now has exactly two URL authority surfaces:

1. **Model/inference routing** — `configs/bifrost_delegation.yaml`
   (omnimarket/omniclaude).  Owns LLM backend URLs and inference endpoints.

2. **Non-model integration endpoints** — `contracts/integrations/catalog.yaml`
   (this repo, new in this PR).  Owns GitHub API, Linear GraphQL, OpenRouter
   non-inference, projection API, bus bootstrap, dashboard data sources, and
   all other URLs that are NOT LLM inference endpoints.

The validator `_AUTHORITY_PATH_SUFFIXES` already exempts
`contracts/integrations/catalog.yaml` from the gate (URLs inside the
authority file are canonical, not violations).

## Deliverables

- `src/omnibase_core/contracts/integrations/catalog.yaml` — non-model URL
  authority (schema v1.0.0, `catalog_version: {major: 1, minor: 0, patch: 0}`).
  Entries: `github.rest_api`, `linear.graphql_api`, `openrouter.completions`,
  `projection_api.base`, `bus.redpanda_schema_registry`, `bus.kafka_bootstrap`,
  `dashboard.data_source`, `infisical.addr`, `deployment.callback_url`.

- `docs/architecture/URL_CONTRACT_AUTHORITY.md` — design doc covering both
  authority surfaces, resolution contract, catalog schema, gate rules, and
  cross-repo wiring pattern.

- `tests/unit/validation/test_validator_url_authority.py` — 9 new catalog
  structure tests (TestIntegrationCatalogStructure): file existence, YAML
  validity, semver format, required categories, entry completeness, authority
  path allowlist match, required external API entries.

## Gate status

url-authority gate: PASSED (0 new violations, 13 grandfathered from OMN-12818 baseline).

Cross-repo wiring to omnibase_infra (48 violations to baseline) is tracked
by OMN-12807 and will land as a follow-on PR to that repo.

Evidence-Ticket: OMN-12804

* refactor(OMN-13196): delete ModelOnexEnvelope (B4) + retarget validator test (#1250)

B4 of the platform-debt envelope-dedup plan. Deletes the legacy
ModelOnexEnvelope class entirely and collapses the canonical envelope
surface to ModelEventEnvelope[T].

Changes:
- Delete src/omnibase_core/models/core/model_onex_envelope.py (the class
  whose docstring falsely self-described as "the canonical envelope format";
  1 live constructor migrated in B2/OMN-13192, 4 validator annotations
  re-annotated in B3/OMN-13194, V1 retired in B1/OMN-13193).
- Remove the 2 exports (import + __all__) in models/core/__init__.py.
- Delete the 4 ModelOnexEnvelope-specific test files:
  test_model_onex_envelope.py, test_model_onex_envelope_source_node_id.py,
  test_model_onex_envelope_chunking.py, and the perf benchmark
  test_source_node_id_overhead.py — these exercised ModelOnexEnvelope's own
  fields (source_node_id, chunking, operation) which have no ModelEventEnvelope
  equivalent, so they retire with the class.
- Retarget tests/unit/validation/test_envelope_validator.py: EnvelopeValidator
  survives (it is duck-typed via getattr) but ModelEventEnvelope[T] lacks the
  dispatch-routing fields (source_node/operation/target_node) the validator
  reads. Replace the ModelOnexEnvelope fixture with a minimal frozen Pydantic
  stub (_ValidatorEnvelope) exposing exactly those attributes. 40/40 pass.
- Retarget stale docstring/comment references to the deleted class in
  model_envelope_metadata.py, model_chunked_envelope.py,
  type_serializable_value.py, and the mixin_metadata.yaml `requires` entry
  (which pointed at the already-wrong models.events.model_onex_envelope path)
  to ModelEventEnvelope.

dod_evidence:
- grep -rniE 'ModelOnexEnvelope|model_onex_envelope' src/ tests/ -> ZERO
- ruff format + ruff check --fix: All checks passed
- mypy src/ --strict: no NEW errors (3 pre-existing errors in untouched
  contract_loader.py / cli_install.py reproduce on clean origin/dev)
- pytest tests/unit/validation/test_envelope_validator.py: 40 passed
- FULL pytest tests/ -n 8 (no -k): 41576 passed; the 21 failures are
  full-suite-only xdist ordering flakes (RegistryNode forward-ref
  model_rebuild + DI-singleton contamination) that ALL pass in isolation
  (48/48) and reference neither envelopes nor any file in this diff.

OMN-13196

* chore(OMN-13200): bump omnibase_core to v0.45.0 (B6 — envelope-dedup pin propagation) (#1252)

Final phase of the platform-debt envelope-dedup workstream. ModelOnexEnvelope
was deleted from the public API in B4 (PR #1250, merged to dev). This bumps the
omnibase_core version to propagate the breaking-deletion signal to dependents
and trigger pin-update bot PRs.

- pyproject version 0.44.2 -> 0.45.0 (minor bump: pre-1.0 semver convention for
  a breaking public-API deletion; pyproject is the single source of truth)
- uv.lock self-version updated to match
- CHANGELOG entry under Breaking Changes

Verification on origin/dev HEAD (e9bb51aac):
- grep ModelOnexEnvelope over src/ + tests/ -> 0 references (class fully gone)
- mypy src/omnibase_core (CI-canonical strict gate) -> Success, no issues
- pytest tests/unit/validation/test_envelope_validator.py +
  tests/unit/mixins/test_mixin_intent_publisher.py -> 67 passed

dod_evidence: contracts/OMN-13200.yaml (OCC receipt, verifier!=runner)

* refactor(OMN-13197): remove dead onex.runtime.intents hardcoded topic + dead intent-publisher path (#1253)

A-followup of OMN-13188 (OMN-12803 topic-authority family). Removes the
`onex.runtime.intents` hardcoded topic at its root by deleting the dead
publisher path that was its sole consumer.

Decision (per OMN-13197 DoD: contract-source the topic OR confirm-and-delete
the dead path): confirm-and-delete. The topic could not be contract-sourced —
no contract declares it (the `intent_publisher.yaml` referenced in the mixin
docstring was never authored) and `ServiceTopicRegistry` lives in
omnibase_infra (core cannot import it per layering). The mechanism was
architecturally dead from both sides:
- MixinIntentPublisher (sole publisher) had ZERO production call sites.
- onex.runtime.intents had ZERO Kafka consumers (IntentExecutor is a
  synchronous in-memory runtime service, verified in OMN-13192/OMN-13188).
Dead code is debt to delete, not park/guard/migrate.

Removed:
- TOPIC_EVENT_PUBLISH_INTENT (duplicate of canonical TOPIC_RUNTIME_INTENTS,
  existed only to feed the dead mixin) + all re-exports.
- MixinIntentPublisher + ModelIntentPublishResult (only used by the mixin)
  + their capability-mapping / metadata census entries.
- Dead tests + fixtures + intent-publisher guide docs (with inbound links).

Retained: TOPIC_RUNTIME_INTENTS (canonical taxonomy derivation) and
ModelEventPublishIntent (live consumer in util_payload_migration).

Added regression guard test asserting the dead symbols stay removed.

dod_evidence: ruff format+check clean; mypy --strict clean on all changed
files (6 pre-existing errors in untouched files only); 171 focused tests
green incl. new guard; full collection (1389 tests) imports clean;
pre-commit run all-green (markdown-links pass, skill-routing pass vs
omniclaude main snapshot).

* feat(OMN-13209): promote runtime-deployment wire DTOs (EnumRuntimeLane + ModelRuntimeDeploymentProof) to core (#1254)

A2 (canonical node migration, epic OMN-13205): graduate the runtime-deployment
lane enum and deployment-proof wire DTO from the transient omnibase_compat mirror
to their canonical core home, per the compat copy's COMPAT_MIGRATION_TARGET and
the >=2-repos graduation condition (node_redeploy is now a 2nd-repo importer).

- omnibase_core.enums.enum_runtime_lane.EnumRuntimeLane (UtilStrValueHelper enum,
  file-location convention)
- omnibase_core.models.runtime_deployment.wire.ModelRuntimeDeploymentProof +
  ProbeStatus/DeploymentProofStatus aliases, re-exporting the enum

Path note: the plan cited contracts.runtime_deployment.wire, but Pydantic
BaseModels under any non-exempt namespace trip core's disallow_any_explicit
mypy gate (documented in mypy.ini for pipeline/hooks/package). Wire DTOs live
under models.* (the established graduated-wire home, cf. models.delegation.wire
from OMN-12126); enums under enums.* per the file-location validator.

Promoted from the compat copy (not authored fresh from node files).

* feat(OMN-13130): UI contract primitives + EnumEmptyStateReason in omnibase_core (#1255)

* feat(OMN-13130): UI contract primitives + EnumEmptyStateReason in omnibase_core

Phase 0 of the Contract-Driven UI Platform (epic OMN-13129). Adds six frozen
Pydantic UI contract primitives (additive over ModelWidgetConfig) plus the
empty-state vocabulary and supporting capability enums.

Models (src/omnibase_core/models/dashboard/, one file each):
- ModelComponentContract  — composes the other primitives; component_kind reuses EnumWidgetType
- ModelActionContract     — declared onex.cmd.* emitter; COMPOSES ModelGate (approval), no duplication
- ModelDataBindingContract — /projection/{topic} bind with explicit ordering authority; no raw DB
- ModelPermissionContract  — view/act scopes + mandatory declared disabled_reason
- ModelEvidenceRequirementContract — composes OCC ModelEvidenceRequirement
- ModelRendererCapabilityContract  — model only (omnimarket reducer/topic is Phase 1; no node)

Enums (src/omnibase_core/enums/):
- EnumEmptyStateReason — exactly four values mirroring omnidash/shared/types/chart-config.ts
- EnumBindingOrderDirection, EnumEvidenceGateMoment, EnumRendererInteractionModel, EnumAccessibilityTier

ActionContract.command_topic is validated via the canonical validate_topic_suffix
(no hardcoded onex.cmd. literal) and requires kind == TOPIC_KIND_CMD. Version fields
use ModelSemVer (strong typing). All six models registered in scripts/emit_ts_types.py
for Stage 2 TS codegen. ModelGate / ModelGateSpec source untouched (ADR D2).

Refs: OMN-13130, epic OMN-13129. ADR: docs/adr/2026-06-17-ui-deterministic-projection-effect-layer.md

* fix(OMN-13130): use canonical interfaces_touched enum (public_api) in DoD contract

contract-validation CI rejected free-text interfaces_touched values; the field
is a closed enum (events/topics/protocols/envelopes/public_api). The touched
surface is the new public API exports -> public_api.

* feat(OMN-13132): Contract Graph IR + read-only import (#1256)

* feat(OMN-13132): Contract Graph IR + read-only import

Phase 2 of the Contract-Driven UI Platform (epic OMN-13129). Adds the
canonical read-only Contract Graph IR to omnibase_core plus dialect adapters
that import backend node contracts and Phase-0 UI component contracts into one
deterministic IR, with a no-op round-trip proven zero-semantic-diff through the
shipped cli_contract_diff spine.

Name-collision handling (plan §8: IR models are distinct from workflow-viz
graph models): new IR models live in the distinct models/contract_graph/
namespace with ModelContractGraph* names (ModelContractGraphIr/Node/Edge/
Protocol/ContractRef/SourceSet) — the bare ModelGraphNode/ModelGraphEdge
(models/graph/) and ModelContractRef (models/events/contract_validation/)
identifiers are NOT reused.

- Models: 6 frozen Pydantic IR models (frozen, extra=forbid, from_attributes)
  + EnumContractGraphNodeRole (incl renderer) + EnumContractGraphEdgeKind
  (incl component_renders/action_emits/data_binds).
- Adapters (read-only): node-contract + ui-component dialect adapters;
  manifest-driven discovery excluding .venv/omni_worktrees/generated.
- Hashing: sha256 over canonicalized contract bytes (per source) + stable
  per-adapter version hash, both embedded in the IR.
- Round-trip: IR -> canonical normalized contract form; no-op round-trip =
  zero semantic diff via cli_contract_diff (reused, not rebuilt).
- Tests: 29 unit tests incl deterministic-IR over >=2 real contracts (effect +
  reducer node contracts + 1 UI component) and no-op round-trip zero-diff.

Strictly read-only: no authoring UI, no contract mutation.

Refs: OMN-13132, epic OMN-13129.

* fix(OMN-13132): register contract_graph in test-selection adjacency + revert OMN-13130 scope bleed

- Add contract_graph adjacency entry (leaf module, reverse_deps: []) so
  test_every_src_module_has_adjacency_entry passes. contract_graph imports
  models/enums/cli (already shared_modules) and types; types.reverse_deps now
  includes contract_graph so a types change re-runs contract_graph tests.
- Revert contracts/OMN-13130.yaml to origin/dev (unrelated whitespace-only
  line-wrap edit was scope bleed; diff vs origin/dev is now empty).

Fixes the only red CI signal on PR #1256; contract_graph IR code unchanged.

* fix(OMN-13214): port hardened arm+update-branch+enqueue+verify auto-merge flow (#1257)

* fix(OMN-13214): port hardened arm+update-branch+enqueue+verify auto-merge flow to omnibase_core

Ports the OMN-13214 armed-but-not-enqueued fix from omnimarket (PR #1253,
merge 8fad5e11) into omnibase_core.

Root cause: arming auto-merge is NOT the same as enqueuing. On queue-controlled
dev, a CLEAN + all-required-green + armed PR can sit OUTSIDE the merge queue
indefinitely. The old workflow also passed `--auto --squash`, which dev's queue
REJECTS ("The merge strategy for dev is set by the merge queue"), so the PR was
never enqueued. The old "Force enqueue" step never verified the PR actually
entered the queue.

Changes:
- .github/workflows/auto-merge.yml:
  - "Enable auto-merge" now arms bare `--auto` (was `--auto --squash`) and
    falls through instead of exiting on success.
  - Replaces "Force enqueue" with "Enqueue armed PR and verify it entered the
    queue": classify -> (update-branch on strict-update BEHIND) -> enqueue ->
    poll-and-VERIFY isInMergeQueue, failing loudly if a green+armed PR is not
    enqueued. Preserves this repo's pre-check fanout guard, self-hosted runner
    selection, and OCC preflight.
- scripts/ci/merge_queue_enqueue.py: stdlib-only, no-network classify/verify
  decision helper (mypy --strict clean; explicit-Any-free via dict[str, object]).
- tests/unit/scripts/ci/test_merge_queue_enqueue.py: 32 unit tests pinning the
  CLEAN-armed-not-queued -> ENQUEUE bug, ALREADY_QUEUED no-op, BEHIND strict vs
  non-strict, WAIT/BLOCKED states, verify, and error-marker classification.

Verification: 32/32 tests pass; mypy --strict clean; ruff clean; actionlint
clean on the new steps; full omnibase_core pre-commit suite green (40 hooks).

The one skipped local hook (validate-deterministic-skill-routing) scans
omniclaude-owned SKILL.md files via a sibling clone; its 16 violations
pre-exist on omniclaude@dev, are unrelated to this PR (no SKILL.md touched),
and the check is NOT a required status check on omnibase_core dev.

OMN-13214

* test(OMN-13214): update auto-merge workflow-shape test for arm+enqueue+verify flow

The existing test_auto_merge_workflow_shape.py pinned the old step name
"Force enqueue to merge queue". The OMN-13214 port renamed it to "Enqueue armed
PR and verify it entered the queue" and changed "Enable auto-merge" from
--auto --squash to bare --auto.

- Point the ordering assertion at the new enqueue step name.
- Add test_enable_auto_merge_arms_bare_auto_not_squash: the gh pr merge command
  arms bare --auto (no --squash).
- Add test_enqueue_step_classifies_enqueues_and_verifies: the enqueue step
  classifies + verifies via scripts/ci/merge_queue_enqueue.py, calls
  enqueuePullRequest, runs gh pr update-branch, and fails loudly (::error::).

OMN-13214

* fix(OMN-13214): make merge_queue_enqueue.main() returns explicit (CodeQL)

CodeQL flagged "explicit returns mixed with implicit (fall through) returns" in
main(). Restructure the command dispatch as if/elif/else where the defensive
else raises SystemExit, so every branch terminates with an explicit return or
raise (no implicit None fall-through). mypy --strict + ruff + 32 unit tests
remain green.

OMN-13214

* feat(OMN-13219): canonical-inference enforcement gate (pre-commit + required CI) (#1258)

* feat(OMN-13219): canonical-inference enforcement gate (pre-commit + required CI)

Adds ValidatorCanonicalInference — a ratchet gate wired as a pre-commit hook
and a required CI status check (parallel to the OMN-12818 URL-authority gate)
that fails on non-canonical model-inference surfaces:

- model-cli-shellout: a model-CLI binary (codex/claude/gemini/opencode) passed
  to subprocess/exec/os.system or resolved via shutil.which — the exact
  non-canonical surface OMN-13215 shipped and nothing caught.
- model-id-env-read: os.environ[*_MODEL] / os.environ.get(*_PROVIDER) reads.

Endpoint URLs and *_URL/*_ENDPOINT env reads remain owned by the URL-authority
gate (OMN-12818); freestanding imperative IO generally by
scan_freestanding_imperative_io (OMN-12515/12540). No parallel one-off — the
three guards partition the space.

Fail-closed regression test: a NEW shell-out and a NEW env-resolved model each
trip the gate (exit 1); the contract-resolved tier (OMN-13215 target shape)
passes. Ratchet baseline (sha256 fingerprints) grandfathers existing violations;
omnibase_core seeds at 0 (clean). Burn-down only — CI rejects baseline growth.
codex shell-out removal tracked by OMN-13215.

Evidence-Source: OCC#PENDING
Evidence-Ticket: OMN-13219

* fix(OMN-13219): use env suffix constant in inference validator

* ci(OMN-13131): adopt main's permissive main-target-guard on the promotion branch

The pull_request main-target-guard runs the workflow definition from the PR head
tree. dev's guard is the restrictive (dev-only) OMN-12477 version; main already
carries the permissive (dev || promotion/*) version from #1240. A promotion/*
head therefore fails the dev-tree restrictive guard. Adopting main's permissive
guard on the promotion branch lets the promotion/* head pass; net diff to main is
zero (main already has this exact file). dev->main promotion via promotion/* is
the sanctioned shape (memory: dev-only-promotion-to-main + #1240 precedent).

Evidence-Ticket: OMN-13131
promotion-receipt: OCC-2742

* ci(OMN-13332): pin occ-preflight to Evidence-Source OCC SHA (#1344)

* ci(OMN-13332): pin occ-preflight evidence source

* ci(OMN-13332): refresh occ-preflight promotion checks

---------

Co-authored-by: jonahgabriel <jonah.neugass@gmail.com>

---------

Co-authored-by: jonahgabriel <jonah.neugass@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant