Skip to content

feat(runtime): type database ownership wiring (OMN-15418) - #2548

Merged
jonahgabriel merged 9 commits into
devfrom
jonah/omn-15418-p0-replace-raw-db_io-loading-with-typed-declarations-and
Jul 31, 2026
Merged

jonahgabriel merged 9 commits into
devfrom
jonah/omn-15418-p0-replace-raw-db_io-loading-with-typed-declarations-and

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Jul 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • replace raw db_io.db_tables dictionary loading with the exact typed ModelDbOwnershipSubcontract on filesystem and Kafka registration paths
  • resolve declared logical database/schema/domain through the checked-in deployment topology at both cold boot and live materialization
  • preserve exact db_io, canonical handler_routing, and runtime event_bus fields through real registry events
  • add exactly-one-owner validation over node declarations, service manifests, rich live-inventory evidence, explicit readers, and seeded fail-closed defects

Exact stack

This is a landing-blocked draft.

  1. omnibase_core#1529 — exact 1f4549d71d4d39560ac5a162ac1d39e54d86e688; strict database_ref + schema contract owner.
  2. omnibase_infra#2549 — exact d7f1ac464a54696ac9ed05fd8f3766463a0a7eea; this branch is directly stacked on that seven-profile topology owner.
  3. omninode_infra#772 — exact 1a1fff92cbf8e02e488ac6e6e89b1087ca396657; deploys the explicit ONEX_DATABASE_TOPOLOGY_PROFILE consumer seam.
  4. omnimarket#1956 — exact a0f65e9471da06b88eecb91bbc1c847989cb10d8; typed node declarations and rich relation inventory.
  5. omninode_infra#771 — exact 39033d55147ef22a061b665345b506246d3aa543; service ownership manifests.
  6. omnimarket#1964 — exact e66a70bdbeedf0f4fabd4f9c50f4625bad78c5ee; registry producer preservation and strict declaration migration, pinned to this PR's exact head.

OMN-15421 still owns separate tenant/internal/catalog adapters. Until it lands, non-tenant projection declarations fail closed before the existing tenant adapter can be constructed.

Runtime behavior

  • ModelDiscoveredContract.db_io is the typed core subcontract; raw YAML table-location reads are removed.
  • The composition root loads only explicit ONEX_DATABASE_TOPOLOGY_PROFILE; event namespaces never select database topology.
  • Cold boot rejects any db_io manifest when no explicit topology profile is loaded.
  • Kafka registration caches the exact descriptor, validates the canonical handler shell and typed extensions independently, then materializes through the same topology-aware wiring path.
  • Same-physical-database declarations may span multiple schemas/domains; only multiple physical database connections fail closed.
  • Legacy filesystem DLQ fallback remains compatible while typed registry events carry DLQ/consumer-group/terminal metadata directly.

Ownership validator

  • merges node and service owners while keeping readers explicit and non-owning
  • distinguishes tables, views, materialized views, functions, migration ledgers, sequences, and extensions
  • rejects missing/duplicate/conflicting ownership, unknown database/schema, retired parallel database: location, blocked evidence, and incomplete census
  • reconciles rich inventory aggregate counts, typed projected rows, excluded objects, and retained live table/view census so an artifact cannot self-assert passed with missing rows
  • parses the exact OMN-15423 artifact: 94 source objects = 79 typed relations + 15 excluded objects, with its five blockers retained fail-closed

Verification

  • governed .200 full unit suite on exact 9e9e62c3177f568b7e5110f653ee4be6dcda965c: 22,380 passed, 40 skipped in 400.79s
  • focused changed unit: 173 passed
  • changed integration: 17 passed
  • legacy DLQ compatibility regression: exact failing test plus adjacent runtime/materialization selection 82 passed
  • independent adversarial acceptance review: 79 passed, no remaining blocker across production composition, registry preservation, non-tenant fail-closed behavior, or rich-census completeness
  • strict mypy across changed runtime/validator sources: PASS
  • Ruff and full changed-file pre-commit: PASS
  • GitHub review comments on final head: none unresolved
  • Hosted final-head rollup: 62 passed, 36 skipped, 9 failed, 0 pending across 107 statuses; every independent code/build/type/contract/security check passed, with the nine failures confined to the OCC/deploy/Env-Parity holds below

Known landing holds

  • All stack PRs above remain draft/unmerged.
  • The explicit topology env key is present on omninode_infra#772, so owner Env Parity honestly remains red until that consumer lands; no duplicate literal or bypass is added here.
  • The registry companion's exact infra repin exposes 15 pre-existing ORPHANED_CONSUMER findings from cumulative infra audit subscriptions added after omnimarket's old pin (OMN-15006/OMN-15168). That cross-package graph stays fail-closed; this ticket adds no exemption or baseline expansion.
  • The companion's full unit suite has one order-dependent OMN-13842 process-boundary timeout after test_local_dispatch_evidence.py (4,450 passed, 8 skipped, 1 failed); the isolated test passes and the two-file predecessor reproducer preserves the same single failure. This is pre-existing and unrelated to the sole final infra compatibility delta.
  • OCC receipt/deploy gates remain red by design. This ticket does not author OCC evidence.
  • Rebuilt Docker startup, deploy, and post-merge validation belong to the later landing/runtime gate; no live runtime or database was mutated here.

Runtime startup gate

  • Real rebuilt-Docker manifest/startup proof attached
  • Compose health reaches ready with RestartCount == 0
  • Post-merge runtime validation complete
  • Source-only production composition passes the exact focused and governed unit proofs above

Scope fence

No merge, OCC authoring, deploy, restart, .201, live database access, adapter split, grant, RLS, migration application, data copy, cutover, or destructive change.

Linear: OMN-15418

Evidence-Ticket: OMN-15418
Evidence-Source: OCC#5635

Summary by CodeRabbit

  • New Features

    • Added topology-aware database access for projections, including tenant isolation, authorization checks, and explicit read/write bindings.
    • Added live contract materialization with deployment topology validation.
    • Added application database ACL generation, validation, phased SQL rendering, and relation ownership checks.
    • Added PostgreSQL 16 proof environments covering ACL rollback, permissions, tenant isolation, and adapter behavior.
  • Bug Fixes

    • Dispatch failures now fail closed, restore transaction state reliably, and record message-loss metrics.
    • Missing or invalid database configuration is rejected during startup or wiring.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This change adds PostgreSQL 16 ACL generation and proof workflows, typed application database topology and ownership validation, cryptographic tenant authority for projection writes, topology-backed adapter wiring, dynamic contract materialization, and extensive unit and integration coverage.

Changes

Database governance and proofs

Layer / File(s) Summary
ACL generation and SQL rendering
src/omnibase_infra/validation/*, scripts/generate_application_database_acl.py
Adds typed evidence models, fail-closed ACL matrix validation, deterministic scaffold and full SQL rendering, source-lock verification, and blocked-output handling.
PostgreSQL ACL proof harness
scripts/ci/prove_application_database_acl.py, docker/application-acl-proof/*, .github/workflows/application-acl-postgres16-proof.yml
Adds synthetic PostgreSQL 16 fixtures and proofs for ACL application, rollback, restoration, isolation, defaults, memberships, and catalog state.
Relation ownership validation
src/omnibase_infra/validation/application_relation_ownership.py, tests/fixtures/application_relation_ownership/*
Adds typed inventory loading and deterministic checks for relation locations, domains, owners, readers, census completeness, blockers, and migration-ledger classification.

Runtime topology and projection dispatch

Layer / File(s) Summary
Typed contract and topology wiring
src/omnibase_infra/runtime/auto_wiring/*, src/omnibase_infra/runtime/service_kernel.py
Contracts now carry typed db_io and event-bus fields. Bootstrap resolves explicit deployment topology and requires it for database-I/O contracts.
Tenant authority and domain adapters
src/omnibase_infra/runtime/projection_tenant_authority.py, src/omnibase_infra/runtime/dispatch_envelope_context.py, src/omnibase_infra/runtime/auto_wiring/handler_wiring.py
Projection writes require verified signed tenant authority. Adapters resolve topology bindings, attest connection identity, enforce domain privileges and RLS, preserve UUID values, and close connections deterministically.
Dynamic materialization and dispatch context
src/omnibase_infra/runtime/kafka_contract_source.py, src/omnibase_infra/runtime/runtime_host_process.py, src/omnibase_infra/runtime/message_dispatch_engine.py
Cached database-I/O contracts can be materialized through an authorized topology-aware path. Dispatch envelope and tenant-authority context propagates through asynchronous and executor-based synchronous handlers.

Validation and integration coverage

Layer / File(s) Summary
Runtime and projection tests
tests/unit/runtime/*, tests/integration/runtime/*, tests/integration/projectors/*, tests/integration/db/*
Tests cover typed database declarations, topology resolution, authority verification, RLS, domain isolation, adapter cleanup, wiring failures, DLQ behavior, terminal events, and context propagation.
ACL and ownership tests
tests/unit/validation/*, tests/ci/*, tests/unit/scripts/*, tests/incident_replays/*
Tests cover evidence completeness, SQL safety, privilege boundaries, blocked matrices, source locks, durable ACL drift, rollback behavior, and relation ownership violations.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ServiceKernel
  participant RuntimeHostProcess
  participant KafkaContractSource
  participant HandlerWiring
  participant ProjectionAdapter
  participant PostgreSQL
  ServiceKernel->>RuntimeHostProcess: provide deployment topology
  RuntimeHostProcess->>KafkaContractSource: materialize cached db_io contract
  KafkaContractSource->>HandlerWiring: authorize dynamic topology wiring
  HandlerWiring->>ProjectionAdapter: resolve target and tenant authority
  ProjectionAdapter->>PostgreSQL: attest identity and execute RLS-scoped operation
  PostgreSQL-->>ProjectionAdapter: return database result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.97% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: replacing raw database ownership wiring with typed runtime wiring.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jonah/omn-15418-p0-replace-raw-db_io-loading-with-typed-declarations-and

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

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8468/OMN-8524) and do not block merge. Error: all review endpoints [192.168.86.201:8000 192.168.86.201:8001 ] unreachable — preflight short-circuit (no models available)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical findings No
blocked CRITICAL findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)

jonahgabriel added a commit to OmniNode-ai/onex_change_control that referenced this pull request Jul 30, 2026
#5635)

* evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2548

* evidence: OCC companion self-bind for #5635

---------

Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
petros-double-test1 and others added 8 commits July 30, 2026 22:40
* feat(runtime): split projection database domains (OMN-15421)

* fix(runtime): register tenant binding resolver protocol (OMN-15421)

---------

Co-authored-by: jonahgabriel <jonahgabriel@users.noreply.github.com>
* feat(database): generate application ACL matrix

* fix(database): satisfy ACL type gates

* test(database): register ACL role-state protocol

---------

Co-authored-by: t <t@t.t>
* test(runtime): isolate config prefetch environment

* fix(database): preserve ACL proof credentials

---------

Co-authored-by: t <t@t.t>
@jonahgabriel
jonahgabriel force-pushed the jonah/omn-15418-p0-replace-raw-db_io-loading-with-typed-declarations-and branch from 7228ce0 to b65dd28 Compare July 31, 2026 05:45
@jonahgabriel
jonahgabriel merged commit 3863623 into dev Jul 31, 2026
131 of 132 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-15418-p0-replace-raw-db_io-loading-with-typed-declarations-and branch July 31, 2026 06:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/integration/runtime/test_projection_handler_db_injection_integration.py (1)

391-406: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

These two tests no longer exercise _wire_handler_entry.

Both docstrings state that _wire_handler_entry selects the projection callback or the standard path. Neither body calls _wire_handler_entry. They now assert only that ModelDiscoveredContract.db_io holds the values passed to the constructor, which Pydantic already guarantees. The branch selection that this PR changes is left uncovered. Either call the wiring function and assert which callback it produces, or rename the tests to describe the contract-shape assertion they now make.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/integration/runtime/test_projection_handler_db_injection_integration.py`
around lines 391 - 406, Update
test_wire_handler_entry_uses_projection_path_when_db_io_declared and
test_wire_handler_entry_uses_standard_path_when_no_db_io to invoke
_wire_handler_entry and assert the selected projection versus standard callback,
covering the changed branch. Alternatively, if these tests should remain
contract-shape checks, rename them and revise their docstrings to describe only
the ModelDiscoveredContract.db_io assertions.
🧹 Nitpick comments (29)
tests/unit/validation/test_application_relation_ownership.py (1)

141-143: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Tighten the match pattern for the strict-declaration test.

match="database" accepts any ValidationError whose text contains "database". The test then passes even if parallel-location.yaml fails for an unrelated reason, such as a different missing field. Assert the specific field and error type that the strict ModelDbTableDeclaration produces.

♻️ Suggested tightening
 def test_service_loader_reuses_strict_typed_table_declaration() -> None:
-    with pytest.raises(ValidationError, match="database"):
-        load_service_ownership_manifest(_FIXTURES / "parallel-location.yaml")
+    with pytest.raises(ValidationError) as excinfo:
+        load_service_ownership_manifest(_FIXTURES / "parallel-location.yaml")
+
+    assert {error["loc"][-1] for error in excinfo.value.errors()} == {"database_ref"}

Replace database_ref with the exact field that parallel-location.yaml violates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/validation/test_application_relation_ownership.py` around lines
141 - 143, Update test_service_loader_reuses_strict_typed_table_declaration to
replace the broad match="database" pattern with the exact database_ref field and
validation error text produced by ModelDbTableDeclaration for
parallel-location.yaml, ensuring unrelated ValidationError messages cannot
satisfy the test.
src/omnibase_infra/validation/application_database_acl.py (1)

4-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the module docstring with the hardcoded database scope.

Lines 6-9 state that no allowlist is maintained in this module. Lines 108-119 define _DEPLOYMENT_CONNECT_DATABASES, a fixed eight-database CONNECT scope that gates deployment authorization at line 916. State this exception in the docstring, or derive the set from the locked topology so the two cannot drift.

Also applies to: 108-119

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/application_database_acl.py` around lines 4 -
10, The module docstring incorrectly claims no database allowlist is maintained
while `_DEPLOYMENT_CONNECT_DATABASES` defines the fixed CONNECT scope used by
deployment authorization. Update the docstring to explicitly document this
hardcoded eight-database exception, or replace the constant with the locked
topology’s derived database set so the scope cannot drift.
src/omnibase_infra/runtime/auto_wiring/handler_wiring.py (2)

5530-5548: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the typed-then-YAML DLQ resolution into one helper.

Both sites resolve DLQ topics with the same rule: prefer contract.event_bus.dlq_topics, then fall back to _read_dlq_topics(contract.contract_path). The docstring of _contract_provision_topics states that the provisioned string must stay byte-identical to the routing target "by construction". Two copies of the rule can drift. Extract one helper, for example _resolve_dlq_topics(contract) -> tuple[str, ...], and call it from both places.

Also applies to: 6846-6857

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/auto_wiring/handler_wiring.py` around lines 5530 -
5548, The typed-then-YAML DLQ topic resolution is duplicated and must be
centralized. Add a helper such as _resolve_dlq_topics(contract) that prefers
contract.event_bus.dlq_topics and otherwise reads contract.contract_path,
preserving the existing fallback/error behavior, then replace the resolution
logic at the shown site and _contract_provision_topics with calls to that helper
so both provisioning and routing use the same result.

2762-2782: 🚀 Performance & Scalability | 🔵 Trivial

Consider a pooled or reused connection path for projection dispatch.

The wiring builds a new ProjectionDatabaseOperations for every dispatched event, and the finally block closes every per-binding connection after each event. Each event therefore pays a TCP/TLS connect, an authentication round trip, and the SELECT current_user, current_database() attestation query per binding. On a high-volume projection topic this adds a fixed per-message latency floor and increases backend churn on PostgreSQL.

A per-binding pool with attestation performed once per physical connection would keep the identity guarantee and remove the per-event connect cost. This is deployment guidance, not a blocker for this PR.

Also applies to: 2908-2912, 2922-2954

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/auto_wiring/handler_wiring.py` around lines 2762 -
2782, Reuse pooled database connections for projection dispatch instead of
creating and closing a new ProjectionDatabaseOperations connection for every
event. Update the projection wiring and cleanup paths around the dispatch flow
and its finally block to acquire connections from a per-binding pool, while
retaining attestation (SELECT current_user, current_database()) once for each
physical connection before reuse.
src/omnibase_infra/runtime/projection_tenant_authority.py (2)

30-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Infra errors are raised without ModelInfraErrorContext. Both new failure paths raise a typed infrastructure error with a message only, so neither failure carries a correlation id into logs. The coding guidelines require the narrowest infrastructure error class together with a context built by ModelInfraErrorContext.with_correlation(...).

  • src/omnibase_infra/runtime/projection_tenant_authority.py#L30-L33: build the context from envelope.trace_id and pass it to ProjectionTenantContextError, and keep tenant identifiers and signature material out of the message.
  • src/omnibase_infra/runtime/service_kernel.py#L2637-L2648: pass context=ModelInfraErrorContext.with_correlation(correlation_id=correlation_id, ...) to the RuntimeHostError, matching the other RuntimeHostError raises in bootstrap().
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/projection_tenant_authority.py` around lines 30 -
33, Update _tenant_context_error in
src/omnibase_infra/runtime/projection_tenant_authority.py#L30-L33 to build
ModelInfraErrorContext with envelope.trace_id and pass it to
ProjectionTenantContextError, keeping tenant identifiers and signature material
out of the message. Update the RuntimeHostError raise in
src/omnibase_infra/runtime/service_kernel.py#L2637-L2648 to pass
context=ModelInfraErrorContext.with_correlation(correlation_id=correlation_id,
...), matching the other RuntimeHostError raises in bootstrap().

Source: Coding guidelines


180-190: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider an explicit freshness window on emitted_at.

The minted capability carries emitted_at but no code rejects an old envelope. A captured signed envelope stays acceptable forever. The event_envelope_id and payload-hash binding restricts a replay to the same event, so the current exposure is limited. An explicit maximum age still narrows the window and makes the intent visible.

🔒️ Sketch of an age check
+_MAX_AUTHORITY_AGE = timedelta(minutes=5)
+
 def verify_signed_projection_tenant_authority(
     envelope: object,
     key_provider: ProtocolKeyProvider,
     tenant_binding_resolver: ProtocolProjectionTenantBindingResolver,
 ) -> VerifiedProjectionTenantAuthority:
@@
+    if datetime.now(UTC) - envelope.emitted_at > _MAX_AUTHORITY_AGE:
+        raise _tenant_context_error(
+            "Projection tenant envelope is outside the accepted freshness window"
+        )
     tenant_id = parse_canonical_tenant_uuid(
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/projection_tenant_authority.py` around lines 180 -
190, Update the projection tenant authority verification flow that constructs
VerifiedProjectionTenantAuthority to validate envelope.emitted_at against an
explicit maximum freshness window before minting the capability. Reject stale
envelopes while preserving the existing event_envelope_id and payload-hash
bindings, and define or reuse a clearly named configuration constant for the
allowed age.
tests/unit/runtime/test_kafka_contract_source.py (1)

1229-1237: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that both string replacements changed the YAML.

Both str.replace calls depend on the exact indentation and quoting emitted by _market_contract_yaml. If that helper changes, each call becomes a silent no-op. The test then still passes while no longer exercising the version-less routing payload or the string event_model form. Add explicit preconditions.

♻️ Proposed precondition assertions
-        contract_yaml = _market_contract_yaml(
+        base_yaml = _market_contract_yaml(
             routing_module=self._MODULE,
             routing_class=self._CLASS,
-        ).replace(
+        )
+        contract_yaml = base_yaml.replace(
             "  version:\n    major: 1\n    minor: 0\n    patch: 0\n",
             "",
         )
-        contract_yaml = contract_yaml.replace(
+        assert contract_yaml != base_yaml, "handler_routing version block not removed"
+        with_event_model = contract_yaml.replace(
             '    - operation: "sweep"\n',
             '    - operation: "sweep"\n'
             '      event_model: "omnimarket.models.ModelSweepRequested"\n',
         )
+        assert with_event_model != contract_yaml, "event_model not injected"
+        contract_yaml = with_event_model
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/test_kafka_contract_source.py` around lines 1229 - 1237,
Update the test around the two contract_yaml str.replace calls to assert that
each expected source fragment is present before replacement, ensuring both
replacements actually modify the YAML. Add explicit precondition assertions for
the version block removed by the first replace and the sweep operation line
replaced by the second, while preserving the existing replacement behavior.
src/omnibase_infra/runtime/runtime_host_process.py (1)

3446-3453: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Fail loudly when a db_io contract has no deployment topology.

topology resolves to None when the runtime was constructed without deployment_topology. The docstring of materialize_cached_contract states that topology is required when the contract declares db_io. In that case the call still runs and the result is reported only as a generic rejection at line 3459, so operators cannot tell a missing-topology misconfiguration from a wiring failure. Add an explicit precondition check with a named reason.

♻️ Proposed guard
             source = getattr(self, "_kafka_contract_source", None)
             dispatch_engine = getattr(self, "_dispatch_engine", None)
             if source is None or dispatch_engine is None:
                 logger.warning(
                     "Cannot materialize db_io contract without Kafka source and "
                     "dispatch engine",
                     extra={
                         "node_name": node_name,
                         "correlation_id": str(correlation_id),
                     },
                 )
                 return False
+
+            topology = getattr(self, "_deployment_topology", None)
+            if topology is None:
+                logger.warning(
+                    "Cannot materialize db_io contract without deployment topology",
+                    extra={
+                        "node_name": node_name,
+                        "correlation_id": str(correlation_id),
+                    },
+                )
+                return False
@@
                 materialization = await source.materialize_cached_contract(
                     node_name=node_name,
                     dispatch_engine=dispatch_engine,
                     event_bus=getattr(self, "_event_bus", None),
                     environment=source.environment,
                     container=getattr(self, "_container", None),
-                    topology=getattr(self, "_deployment_topology", None),
+                    topology=topology,
                 )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/runtime_host_process.py` around lines 3446 - 3453,
Before calling materialize_cached_contract in the surrounding runtime flow,
detect when the contract declares db_io and deployment topology is unavailable;
fail immediately with an explicit, named reason identifying the missing
topology. Preserve the existing materialization path when topology is present or
the contract does not require db_io.
src/omnibase_infra/runtime/auto_wiring/models/model_db_table_validation_warning.py (1)

20-20: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Remove the schema shadowing warning.

The locked Pydantic 2.13.4 accepts this field but emits a UserWarning because it shadows BaseModel.schema(). Use Field(alias="schema") if import-time warnings must be clean.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/runtime/auto_wiring/models/model_db_table_validation_warning.py`
at line 20, Update the schema field declaration in the model to use a
non-shadowing Python attribute with Pydantic Field(alias="schema"), preserving
the external alias while eliminating the BaseModel.schema() warning; adjust any
related model configuration or references as needed to support population and
serialization through the alias.
tests/unit/runtime/auto_wiring/test_projection_domain_adapters.py (1)

61-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Annotate the helpers with ProjectionDatabaseTarget and drop the suppressions.

_adapter, _verified_adapter, and _target type target as object, which forces the two type: ignore[arg-type] comments at lines 70-71. The concrete type is already importable from the same module you import _build_projection_db_adapter from.

♻️ Proposed refactor
 from omnibase_infra.runtime.auto_wiring.handler_wiring import (
+    ProjectionDatabaseTarget,
     _build_projection_db_adapter,
     _resolve_projection_database_target,
 )
 def _adapter(
-    target: object,
+    target: ProjectionDatabaseTarget,
     *,
     authority: VerifiedProjectionTenantAuthority | None = None,
     tenant_event: object | None = None,
     default_url: str = "postgresql://fixture",
     **binding_urls: str,
 ) -> object:
     return _build_projection_db_adapter(
-        projection_database_urls(target, default_url, **binding_urls),  # type: ignore[arg-type]
-        target,  # type: ignore[arg-type]
+        projection_database_urls(target, default_url, **binding_urls),
+        target,
         authority,
         tenant_event,
     )

Apply the same annotation to _verified_adapter and the _target return type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/auto_wiring/test_projection_domain_adapters.py` around
lines 61 - 96, Annotate the target parameters and helper return values in
_adapter, _verified_adapter, and _target with ProjectionDatabaseTarget,
importing it from the module that provides _build_projection_db_adapter. Remove
the unnecessary type: ignore[arg-type] suppressions from _adapter once the
concrete type is used.
tests/helpers/application_db_topology.py (1)

125-126: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Preserve sibling database entries when you copy the topology.

model_copy(update={"databases": {"application": database}}) replaces the whole mapping. Today topology.yaml declares only application, so behavior is correct. If the fixture later declares a second database, every target that references it fails with Unknown database_ref, and the cause is this helper. Merge instead of replace.

♻️ Proposed refactor
     database = database.model_copy(update={"principals": principals})
-    return topology.model_copy(update={"databases": {"application": database}})
+    databases = dict(topology.databases)
+    databases["application"] = database
+    return topology.model_copy(update={"databases": databases})

Apply the same merge at lines 156-160.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/helpers/application_db_topology.py` around lines 125 - 126, Update the
topology-copy logic in the helper to merge the updated application database into
the existing topology.databases mapping instead of replacing the mapping,
preserving all sibling database entries. Apply the same merge behavior in the
related topology-copy logic around the second database update referenced by the
comment.
tests/integration/projectors/test_handler_wiring_projection_dispatch.py (1)

49-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the stale os.environ.get patch and rename the local variable.

_make_projection_dispatch_callback now reads DSNs at construction time, and the construction happens outside the patch(_PATCH_ENVIRON_GET, ...) block. The autouse fixture supplies the DSN. The _PATCH_ENVIRON_GET context therefore has no effect on these tests. Also, db_tables now holds a ProjectionDatabaseTarget, not a table list; db_target states the type.

♻️ Proposed refactor for lines 49-66
-    db_tables = projection_database_target("node_service_registry")
+    db_target = projection_database_target("node_service_registry")
     handler = FakeProjectionHandler()
     callback = _make_projection_dispatch_callback(
-        handler, db_tables, ("onex.evt.platform.node-heartbeat.v1",)
+        handler, db_target, ("onex.evt.platform.node-heartbeat.v1",)
     )
@@
     fake_adapter = MagicMock()
 
-    with patch(
-        _PATCH_ENVIRON_GET,
-        return_value="postgresql://postgres:test@localhost:5436/omnidash_analytics",
-    ):
-        with patch(_PATCH_BUILD_ADAPTER, return_value=fake_adapter):
-            asyncio.run(callback(envelope))
+    with patch(_PATCH_BUILD_ADAPTER, return_value=fake_adapter):
+        asyncio.run(callback(envelope))

Apply the same change at line 96 and in tests/integration/projectors/test_projection_terminal_event_emission.py.

Also applies to: 96-96

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/projectors/test_handler_wiring_projection_dispatch.py` at
line 49, Remove the stale patch(_PATCH_ENVIRON_GET, ...) context from the
affected tests because DSNs are resolved during
_make_projection_dispatch_callback construction outside that block and the
autouse fixture provides them. Rename the local variable db_tables to db_target
at both referenced locations and apply the same updates in
test_projection_terminal_event_emission.py.
tests/unit/runtime/test_service_kernel_database_topology_wiring.py (1)

82-86: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Assert the fail-closed behavior instead of the source text.

These assertions compare exact substrings of service_kernel.py, including "if db_io_contracts and deployment_topology is None:". A formatter that wraps that condition, or a rename of db_io_contracts, breaks the test without changing behavior. The test then reports a defect that does not exist.

The guarantee under test is that a db_io contract without a resolved topology fails closed. tests/unit/runtime/test_handler_wiring_state_io.py lines 197-202 already assert that guarantee behaviorally with pytest.raises(ModelOnexError, match="no checked-in ModelDeploymentTopology"). Prefer the same approach here, and keep a source assertion only for the operator-facing message text.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/test_service_kernel_database_topology_wiring.py` around
lines 82 - 86, Update test_db_io_boot_requires_explicit_profile to exercise
service-kernel startup with a db_io contract and no resolved deployment
topology, asserting pytest.raises(ModelOnexError, match="no checked-in
ModelDeploymentTopology") instead of matching implementation source text; retain
only a source assertion for the operator-facing "ONEX_DATABASE_TOPOLOGY_PROFILE
is not set" message.
tests/unit/runtime/auto_wiring/test_handler_wiring_db_injection.py (1)

447-456: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the mock-connection setup into one helper.

Lines 447-456, 483-492, 522-531, 588-597, and 709-718 repeat the same six-line connection double, including the ("omninode_runtime", "omnidash_analytics") attestation tuple. If the attestation query or its expected shape changes, you must edit five copies. tests/unit/runtime/auto_wiring/test_projection_domain_adapters.py lines 45-58 already defines an equivalent _connection helper.

♻️ Proposed refactor

Add one helper next to _internal_db_adapter:

def _attested_connection() -> tuple[MagicMock, MagicMock]:
    """Return a psycopg2 connection double that passes identity attestation."""
    cursor = MagicMock()
    cursor.fetchone.return_value = ("omninode_runtime", "omnidash_analytics")
    cursor_context = MagicMock()
    cursor_context.__enter__.return_value = cursor
    conn = MagicMock()
    conn.closed = False
    conn.cursor.return_value = cursor_context
    return conn, cursor

Then reduce each call site:

-    cursor = MagicMock()
-    cursor.fetchone.return_value = ("omninode_runtime", "omnidash_analytics")
-    cursor_context = MagicMock()
-    cursor_context.__enter__.return_value = cursor
-    conn = MagicMock()
-    conn.closed = False
-    conn.cursor.return_value = cursor_context
-
-    with patch("psycopg2.connect", return_value=conn):
+    conn, cursor = _attested_connection()
+
+    with patch("psycopg2.connect", return_value=conn):
         adapter = _internal_db_adapter("savings_estimates")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/auto_wiring/test_handler_wiring_db_injection.py` around
lines 447 - 456, Extract the repeated attested psycopg2 mock setup into an
_attested_connection helper adjacent to _internal_db_adapter, returning both the
connection and cursor while preserving the existing identity tuple and
context-manager behavior. Replace all five duplicated setup blocks in this test
module with calls to the helper, keeping each patch and test-specific assertion
unchanged.
tests/integration/db/test_projection_writer_tenant_rls_omn15301.py (1)

284-297: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the normalized tenant value, not only the return code.

The test name states that a matching tenant string becomes a UUID. The body only asserts that upsert returns True, so the normalization it names is never observed. Read the owner-side row and assert the stored type and value.

♻️ Proposed assertion
 def test_equal_tenant_string_is_replaced_with_uuid(domain_dsns: dict[str, str]) -> None:
     adapter = _tenant_adapter(domain_dsns["tenant"], TENANT_A)
+    correlation_id = uuid4()
     try:
         assert adapter.upsert(
             TENANT_TABLE,
             "correlation_id",
             {
-                "correlation_id": uuid4(),
+                "correlation_id": correlation_id,
                 "task_type": "proof",
                 "tenant_id": str(TENANT_A),
             },
         )
     finally:
         adapter.close()
+    assert _tenant_rows(domain_dsns["owner"]) == [(correlation_id, TENANT_A)]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/db/test_projection_writer_tenant_rls_omn15301.py` around
lines 284 - 297, Update test_equal_tenant_string_is_replaced_with_uuid to read
the owner-side row after the upsert and assert that the stored tenant_id is a
UUID with the expected TENANT_A value, rather than only asserting the upsert
return value.
tests/integration/runtime/test_projection_handler_db_injection_integration.py (1)

54-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The written contract.yaml omits the db_io block that the model declares.

_make_contract writes YAML without db_io, then constructs ModelDiscoveredContract with a ModelDbOwnershipSubcontract when declare_db_io=True. Any code that re-reads contract_path sees a contract with no database ownership. Add the db_io block to the written text so the file and the model agree.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tests/integration/runtime/test_projection_handler_db_injection_integration.py`
around lines 54 - 66, Update _make_contract so the YAML written to contract_path
includes the db_io ownership block whenever declare_db_io is true, matching the
ModelDbOwnershipSubcontract supplied to ModelDiscoveredContract. Preserve the
existing YAML for contracts that do not declare database I/O.
tests/unit/runtime/auto_wiring/test_db_table_validator.py (1)

39-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add the return annotation for consistency.

_contract declares its return type. _table does not. Annotate it as -> ModelDbTableDeclaration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/auto_wiring/test_db_table_validator.py` at line 39, Update
the _table helper signature to include the return annotation ->
ModelDbTableDeclaration, matching the existing annotation on _contract while
leaving its behavior unchanged.
.github/workflows/docker-build.yml (1)

81-114: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hoist COMPOSE_PROJECT_NAME to job level.

COMPOSE_PROJECT_NAME is set separately in two steps (Lines 99-100 and 108-109). Declare it once as job-level env:, as the rebuilt-postgres16-proof job in application-acl-postgres16-proof.yml does. This removes duplication and keeps both workflows consistent.

♻️ Proposed refactor
   domain-adapter-proof:
     name: Projection Domain Adapter Proof (OMN-15421)
+    env:
+      COMPOSE_PROJECT_NAME: omn15421-${{ github.run_id }}-${{ github.run_attempt }}
     runs-on: >-
       ${{
         (github.event_name == 'pull_request' &&
          github.event.pull_request.head.repo.full_name != github.repository)
         && fromJSON(vars.OMNI_PUBLIC_PR_RUNS_ON_JSON || '["ubuntu-latest"]')
         || fromJSON(vars.OMNI_DOCKER_CI_RUNS_ON_JSON || vars.OMNI_TRUSTED_CI_RUNS_ON_JSON || '["self-hosted","omnibase-ci"]')
       }}
     timeout-minutes: 15

     steps:
       - name: Checkout code
         uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

       - name: Verify Docker socket access
         run: docker info

       - name: Run rebuilt-image PostgreSQL 16 proof
-        env:
-          COMPOSE_PROJECT_NAME: omn15421-${{ github.run_id }}-${{ github.run_attempt }}
         run: >-
           docker compose
           -f docker/domain-adapter-proof/compose.yml
           up --build --abort-on-container-exit --exit-code-from proof

       - name: Remove proof containers and volumes
         if: always()
-        env:
-          COMPOSE_PROJECT_NAME: omn15421-${{ github.run_id }}-${{ github.run_attempt }}
         run: >-
           docker compose
           -f docker/domain-adapter-proof/compose.yml
           down --volumes --remove-orphans
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/docker-build.yml around lines 81 - 114, Move
COMPOSE_PROJECT_NAME from the env blocks of the “Run rebuilt-image PostgreSQL 16
proof” and “Remove proof containers and volumes” steps to a single job-level env
declaration in the Projection Domain Adapter Proof job, preserving the existing
value and ensuring both steps inherit it.
src/omnibase_infra/validation/models/model_application_inventory_relation.py (1)

20-53: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add from_attributes=True to the new model_*.py classes. All six new models in this cohort set ConfigDict(frozen=True, extra="forbid") but omit from_attributes=True, which the coding guideline for src/omnibase_infra/**/model_*.py calls for. Add the setting to each class's ConfigDict so the models can be built from attribute-bearing objects, not only from dicts/JSON.

  • src/omnibase_infra/validation/models/model_application_inventory_relation.py#L20-L53: add from_attributes=True to ModelApplicationInventoryRelation.model_config.
  • src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py#L9-L22: add from_attributes=True to ModelApplicationInventoryRelationCounts.model_config.
  • src/omnibase_infra/validation/models/model_application_relation_declaration.py#L22-L44: add from_attributes=True to ModelApplicationRelationDeclaration.model_config.
  • src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py#L25-L58: add from_attributes=True to ModelApplicationRelationEvidenceInventory.model_config.
  • src/omnibase_infra/validation/models/model_internal_tenant_column_transform.py#L13-L24: add from_attributes=True to ModelInternalTenantColumnTransform.model_config.
  • src/omnibase_infra/validation/models/model_live_application_relation.py#L21-L45: add from_attributes=True to ModelLiveApplicationRelation.model_config.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/models/model_application_inventory_relation.py`
around lines 20 - 53, Enable attribute-based validation by adding
from_attributes=True to the ConfigDict for ModelApplicationInventoryRelation in
src/omnibase_infra/validation/models/model_application_inventory_relation.py:20-53,
ModelApplicationInventoryRelationCounts in
src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py:9-22,
ModelApplicationRelationDeclaration in
src/omnibase_infra/validation/models/model_application_relation_declaration.py:22-44,
ModelApplicationRelationEvidenceInventory in
src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py:25-58,
ModelInternalTenantColumnTransform in
src/omnibase_infra/validation/models/model_internal_tenant_column_transform.py:13-24,
and ModelLiveApplicationRelation in
src/omnibase_infra/validation/models/model_live_application_relation.py:21-45,
preserving their existing frozen and extra-forbid settings.

Source: Coding guidelines

tests/ci/test_application_database_acl_contract.py (1)

19-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Import ModelApplicationDatabaseAclSource from its own module.

model_application_database_acl_matrix binds this name only because it imports it for its own field types, and its __all__ lists just ModelApplicationDatabaseAclMatrix. The import works today, but it breaks if that transitive import is ever removed or restructured. Import the symbol from its defining module.

♻️ Proposed import fix
 from omnibase_infra.validation.models.model_application_database_acl_matrix import (
     ModelApplicationDatabaseAclMatrix,
-    ModelApplicationDatabaseAclSource,
+)
+from omnibase_infra.validation.models.model_application_database_acl_source import (
+    ModelApplicationDatabaseAclSource,
 )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ci/test_application_database_acl_contract.py` around lines 19 - 22,
Update the imports in test_application_database_acl_contract.py so
ModelApplicationDatabaseAclSource is imported from its defining module rather
than model_application_database_acl_matrix; keep
ModelApplicationDatabaseAclMatrix imported from the matrix module.
src/omnibase_infra/validation/models/model_application_database_acl_matrix.py (1)

46-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add from_attributes=True to the model config.

The repository guideline requires model_<name>.py models to generally use frozen, strict Pydantic ConfigDict settings with from_attributes=True. This config sets frozen=True and extra="forbid" only. The same omission repeats in the sibling models added by this PR (model_application_database_acl_object.py, model_application_database_acl_source.py, model_application_database_default_acl_row.py, model_application_database_role_membership.py), so apply the change consistently or record the deviation.

As per coding guidelines: "Model files named model_<name>.py must define Model<Name> and generally use frozen, strict Pydantic ConfigDict settings with from_attributes=True."

♻️ Proposed config change
-    model_config = ConfigDict(frozen=True, extra="forbid")
+    model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/models/model_application_database_acl_matrix.py`
at line 46, Update the ConfigDict declarations in the affected Model classes,
including the ACL matrix and sibling model files, to retain frozen and
extra="forbid" while adding from_attributes=True consistently.

Source: Coding guidelines

src/omnibase_infra/validation/models/model_application_database_principal_inventory.py (1)

158-173: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reuse the set computed at lines 119-123.

classified_present_roles repeats the exact expression already assigned to classified_activity_roles. Keep one name and one computation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/models/model_application_database_principal_inventory.py`
around lines 158 - 173, In the validation logic around
classified_activity_roles, reuse that existing set for the
unclassified_catalog_owners subtraction instead of recomputing it as
classified_present_roles. Remove the duplicate assignment and preserve the
existing owner classification and ValueError behavior.
src/omnibase_infra/validation/types/type_application_database_function_signature.py (1)

32-36: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Reject all control characters inside quoted identifiers.

The quoted branch rejects only \n, \r, and \x00. Characters such as \t, \x0b, \x0c, and \x1b still pass into rendered SQL and into evidence log lines. Test one property instead of three members.

🛡️ Proposed fix to widen the control-character check
         if quoted:
-            if character in {"\n", "\r", "\x00"}:
+            if not character.isprintable():
                 raise ValueError(
                     "function_signature quoted identifiers cannot contain controls"
                 )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/types/type_application_database_function_signature.py`
around lines 32 - 36, Update the quoted-identifier validation in the
function-signature parser to reject any control character, replacing the
explicit newline, carriage-return, and NUL membership check with a single
character-control predicate. Preserve the existing ValueError and message for
invalid quoted identifiers, and ensure tabs and other control characters are
rejected before SQL rendering or evidence logging.
src/omnibase_infra/validation/models/model_application_database_activity_evidence.py (1)

29-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the fromisoformat(isoformat()) round-trip in both window validators. AwareDatetime fields are already datetime instances, so both round-trips are no-ops that only add parse cost and hide the comparison. Subtract the fields directly.

  • src/omnibase_infra/validation/models/model_application_database_activity_evidence.py#L29-L31: replace the two local round-trips with if self.window_ended_at - self.window_started_at < timedelta(hours=24):.
  • src/omnibase_infra/validation/models/model_application_database_activity_result_evidence.py#L40-L42: apply the same replacement, keeping the existing error text.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/models/model_application_database_activity_evidence.py`
around lines 29 - 31, Remove the datetime.fromisoformat/isoformat round-trips in
both window validators and subtract the AwareDatetime fields directly in the
duration checks. Update model_application_database_activity_evidence.py lines
29-31 and model_application_database_activity_result_evidence.py lines 40-42;
preserve the existing validation behavior and error text.
src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py (1)

23-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Define a dedicated enum for the catalog-kind vocabulary.

EnumApplicationDatabaseObjectKind omits table, view, and materialized_view. EnumApplicationInventoryObjectKind adds extension. Add an enum with exactly these seven values and reuse it in both catalog models.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py`
around lines 23 - 31, Define a dedicated enum containing exactly table, view,
materialized_view, sequence, function, procedure, and type, then replace the
inline catalog_kind Literal annotations in both catalog models with
EnumApplicationDatabaseObjectKind. Do not include extension or omit any of the
seven catalog kinds.
src/omnibase_infra/validation/application_relation_ownership.py (3)

772-784: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the unreachable duplicate-owner branch.

The loop at Lines 704-708 iterates every identity in declarations_by_identity and adds each identity with more than one owner to duplicate_owner_identities. candidates at Line 762 comes from the same mapping, so len(owners) > 1 always implies identity in duplicate_owner_identities. This elif body never runs.

Delete the branch, or narrow the earlier loop if the live-relation duplicate message is the one you want to keep.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/application_relation_ownership.py` around lines
772 - 784, Remove the unreachable `elif len(owners) > 1 and identity not in
duplicate_owner_identities` branch that appends `DUPLICATE_OWNER` violations.
Keep the surrounding ownership-validation logic unchanged, unless intentionally
narrowing the earlier population of `duplicate_owner_identities` to make this
live-relation message reachable.

312-320: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Split _append_service_declarations into focused helpers.

The function spans Lines 312-626 and mixes census checks, blocked relations, table declarations, relation evidence, view counts, and function objects. Extraction into helpers such as _append_manifest_census_violations, _append_manifest_tables, _append_relation_evidence, and _append_function_objects reduces the branching depth and makes each rule testable alone.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/application_relation_ownership.py` around lines
312 - 320, Refactor _append_service_declarations into focused helper functions
that separately handle census violations, blocked relations, table declarations,
relation evidence, view counts, and function objects, using helpers such as
_append_manifest_census_violations, _append_manifest_tables,
_append_relation_evidence, and _append_function_objects. Preserve the existing
declaration and violation behavior while reducing branching and keeping each
rule independently testable.

157-160: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Classify topology lookup failures from topology data, not exception text.

_lookup_violation_code maps every ValueError that does not start with "Unknown database_ref" to UNKNOWN_SCHEMA. Check database_ref membership in topology.databases, then check schema membership in that database's schemas. Use the exception only for human-readable detail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/application_relation_ownership.py` around lines
157 - 160, Update _lookup_violation_code to classify the failure using topology
data: check whether database_ref exists in topology.databases, then whether the
schema exists in that database’s schemas, returning the corresponding violation
code. Stop using exception-message prefixes for classification, while retaining
the exception only for human-readable error details.
src/omnibase_infra/validation/models/model_application_database_acl_policy.py (1)

30-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add from_attributes=True to the new model_*.py ConfigDict settings. All six new validation models set frozen=True and an extra policy but omit from_attributes=True, which the repository requires for model_<name>.py files. Keep each existing extra value.

  • src/omnibase_infra/validation/models/model_application_database_acl_policy.py#L30-L30: change to ConfigDict(frozen=True, extra="forbid", from_attributes=True).
  • src/omnibase_infra/validation/models/model_application_database_connection_policy.py#L18-L18: change to ConfigDict(frozen=True, extra="forbid", from_attributes=True).
  • src/omnibase_infra/validation/models/model_application_database_role_state.py#L16-L16: change to ConfigDict(frozen=True, extra="forbid", from_attributes=True).
  • src/omnibase_infra/validation/models/model_application_relation_ownership_report.py#L22-L22: change to ConfigDict(frozen=True, extra="forbid", from_attributes=True).
  • src/omnibase_infra/validation/models/model_application_relation_violation.py#L16-L16: change to ConfigDict(frozen=True, extra="forbid", from_attributes=True).
  • src/omnibase_infra/validation/models/model_node_ownership_document.py#L16-L16: change to ConfigDict(frozen=True, extra="ignore", from_attributes=True).

As per coding guidelines: "Model files named model_<name>.py must define Model<Name> and generally use frozen, strict Pydantic ConfigDict settings with from_attributes=True."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/omnibase_infra/validation/models/model_application_database_acl_policy.py`
at line 30, Update the ConfigDict settings in all six listed model files to
include from_attributes=True while preserving each existing extra value: use
extra="forbid" for the five application policy/report/violation models and
extra="ignore" for ModelNodeOwnershipDocument. Apply the changes at the
model_config definitions in model_application_database_acl_policy.py:30-30,
model_application_database_connection_policy.py:18-18,
model_application_database_role_state.py:16-16,
model_application_relation_ownership_report.py:22-22,
model_application_relation_violation.py:16-16, and
model_node_ownership_document.py:16-16.

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6fb0e3a6-05b0-4d19-b050-cd104015c1c0

📥 Commits

Reviewing files that changed from the base of the PR and between beebd1d and 74bd131.

⛔ Files ignored due to path filters (2)
  • docker/application-acl-proof/generated/candidate-matrix.yaml is excluded by !**/generated/**
  • docker/application-acl-proof/generated/prechange-fixture-acl.json is excluded by !**/generated/**
📒 Files selected for processing (128)
  • .github/workflows/application-acl-postgres16-proof.yml
  • .github/workflows/docker-build.yml
  • .onex_ratchets/noncanonical_class_allowlist.yaml
  • docker/application-acl-proof/Dockerfile
  • docker/application-acl-proof/README.md
  • docker/application-acl-proof/compose.yml
  • docker/application-acl-proof/seed.sql
  • docker/application-acl-proof/source-lock.yaml
  • docker/domain-adapter-proof/Dockerfile
  • docker/domain-adapter-proof/compose.yml
  • docker/domain-adapter-proof/prove.py
  • scripts/ci/prove_application_database_acl.py
  • scripts/generate_application_database_acl.py
  • src/omnibase_infra/errors/error_projection.py
  • src/omnibase_infra/runtime/auto_wiring/db_table_validator.py
  • src/omnibase_infra/runtime/auto_wiring/discovery.py
  • src/omnibase_infra/runtime/auto_wiring/handler_wiring.py
  • src/omnibase_infra/runtime/auto_wiring/models/model_db_table_validation_warning.py
  • src/omnibase_infra/runtime/auto_wiring/models/model_discovered_contract.py
  • src/omnibase_infra/runtime/auto_wiring/models/model_event_bus_wiring.py
  • src/omnibase_infra/runtime/auto_wiring/protocol_db_table_catalog_connection.py
  • src/omnibase_infra/runtime/dispatch_envelope_context.py
  • src/omnibase_infra/runtime/kafka_contract_source.py
  • src/omnibase_infra/runtime/message_dispatch_engine.py
  • src/omnibase_infra/runtime/projection_tenant_authority.py
  • src/omnibase_infra/runtime/runtime_host_process.py
  • src/omnibase_infra/runtime/service_kernel.py
  • src/omnibase_infra/runtime/state_io/state_store_adapter.py
  • src/omnibase_infra/validation/application_database_acl.py
  • src/omnibase_infra/validation/application_relation_ownership.py
  • src/omnibase_infra/validation/enums/enum_application_database_acl_authorization_scope.py
  • src/omnibase_infra/validation/enums/enum_application_database_acl_policy_source_kind.py
  • src/omnibase_infra/validation/enums/enum_application_database_acl_render_phase.py
  • src/omnibase_infra/validation/enums/enum_application_database_object_kind.py
  • src/omnibase_infra/validation/enums/enum_application_database_principal_inventory_source_kind.py
  • src/omnibase_infra/validation/enums/enum_application_inventory_object_kind.py
  • src/omnibase_infra/validation/enums/enum_application_relation_kind.py
  • src/omnibase_infra/validation/enums/enum_application_relation_purpose.py
  • src/omnibase_infra/validation/enums/enum_application_relation_violation.py
  • src/omnibase_infra/validation/enums/enum_internal_tenant_column_transform_status.py
  • src/omnibase_infra/validation/enums/enum_ownership_evidence_status.py
  • src/omnibase_infra/validation/models/model_application_database_acl_matrix.py
  • src/omnibase_infra/validation/models/model_application_database_acl_object.py
  • src/omnibase_infra/validation/models/model_application_database_acl_policy.py
  • src/omnibase_infra/validation/models/model_application_database_acl_row.py
  • src/omnibase_infra/validation/models/model_application_database_acl_source.py
  • src/omnibase_infra/validation/models/model_application_database_activity_evidence.py
  • src/omnibase_infra/validation/models/model_application_database_activity_principal_observation.py
  • src/omnibase_infra/validation/models/model_application_database_activity_result_evidence.py
  • src/omnibase_infra/validation/models/model_application_database_catalog_object_evidence.py
  • src/omnibase_infra/validation/models/model_application_database_catalog_result_evidence.py
  • src/omnibase_infra/validation/models/model_application_database_connection_policy.py
  • src/omnibase_infra/validation/models/model_application_database_default_acl_row.py
  • src/omnibase_infra/validation/models/model_application_database_observed_role_state.py
  • src/omnibase_infra/validation/models/model_application_database_principal_inventory.py
  • src/omnibase_infra/validation/models/model_application_database_role_membership.py
  • src/omnibase_infra/validation/models/model_application_database_role_state.py
  • src/omnibase_infra/validation/models/model_application_inventory_relation.py
  • src/omnibase_infra/validation/models/model_application_inventory_relation_counts.py
  • src/omnibase_infra/validation/models/model_application_inventory_runtime_evidence.py
  • src/omnibase_infra/validation/models/model_application_relation_declaration.py
  • src/omnibase_infra/validation/models/model_application_relation_evidence_inventory.py
  • src/omnibase_infra/validation/models/model_application_relation_inventory.py
  • src/omnibase_infra/validation/models/model_application_relation_ownership_report.py
  • src/omnibase_infra/validation/models/model_application_relation_violation.py
  • src/omnibase_infra/validation/models/model_blocked_relation.py
  • src/omnibase_infra/validation/models/model_database_object_evidence.py
  • src/omnibase_infra/validation/models/model_internal_tenant_column_transform.py
  • src/omnibase_infra/validation/models/model_live_application_relation.py
  • src/omnibase_infra/validation/models/model_migration_ownership_manifest.py
  • src/omnibase_infra/validation/models/model_node_ownership_document.py
  • src/omnibase_infra/validation/models/model_relation_evidence.py
  • src/omnibase_infra/validation/models/model_retained_live_census.py
  • src/omnibase_infra/validation/models/model_runtime_evidence_status.py
  • src/omnibase_infra/validation/types/__init__.py
  • src/omnibase_infra/validation/types/type_application_database_function_signature.py
  • tests/ci/test_application_database_acl_contract.py
  • tests/fixtures/application_database_acl/acl-policy-postgres16.yaml
  • tests/fixtures/application_database_acl/acl-policy.yaml
  • tests/fixtures/application_database_acl/inventory.yaml
  • tests/fixtures/application_database_acl/principal-inventories-external.yaml
  • tests/fixtures/application_database_acl/principal-inventory-postgres16.yaml
  • tests/fixtures/application_database_acl/principal-inventory.yaml
  • tests/fixtures/application_database_acl/topology.yaml
  • tests/fixtures/application_relation_ownership/blocked-service.yaml
  • tests/fixtures/application_relation_ownership/conflicting-location.yaml
  • tests/fixtures/application_relation_ownership/duplicate-owner.yaml
  • tests/fixtures/application_relation_ownership/false-complete-census.yaml
  • tests/fixtures/application_relation_ownership/incomplete-census.yaml
  • tests/fixtures/application_relation_ownership/inventory-unknown-schema.yaml
  • tests/fixtures/application_relation_ownership/inventory-with-missing.yaml
  • tests/fixtures/application_relation_ownership/inventory-without-delegation.yaml
  • tests/fixtures/application_relation_ownership/inventory.yaml
  • tests/fixtures/application_relation_ownership/node-owner.yaml
  • tests/fixtures/application_relation_ownership/node-reader.yaml
  • tests/fixtures/application_relation_ownership/parallel-location.yaml
  • tests/fixtures/application_relation_ownership/rich-inventory.yaml
  • tests/fixtures/application_relation_ownership/service-owner.yaml
  • tests/fixtures/application_relation_ownership/topology.yaml
  • tests/fixtures/application_relation_ownership/unknown-schema.yaml
  • tests/fixtures/omn15547/application-acl-prechange-fixture.json.captured
  • tests/fixtures/omn15547/application-acl-source-lock.yaml.captured
  • tests/helpers/application_db_topology.py
  • tests/helpers/projection_tenant_authority.py
  • tests/incident_replays/registry.yaml
  • tests/integration/db/test_projection_writer_tenant_rls_omn15301.py
  • tests/integration/projectors/test_handler_wiring_projection_dispatch.py
  • tests/integration/projectors/test_projection_terminal_event_emission.py
  • tests/integration/runtime/test_projection_dispatch_tenant_authority_context.py
  • tests/integration/runtime/test_projection_handler_db_injection_integration.py
  • tests/integration/test_application_acl_postgres16_proof.py
  • tests/integration/test_projection_handler_wiring_runtime_dispatch.py
  • tests/integration/test_sync_db_adapter_composite_conflict_key.py
  • tests/unit/contracts/test_protocol_ownership.py
  • tests/unit/runtime/auto_wiring/test_db_table_validator.py
  • tests/unit/runtime/auto_wiring/test_handler_wiring_db_injection.py
  • tests/unit/runtime/auto_wiring/test_projection_domain_adapters.py
  • tests/unit/runtime/auto_wiring/test_typed_db_io_loading.py
  • tests/unit/runtime/test_handler_wiring_state_io.py
  • tests/unit/runtime/test_health_config_prefetch_status.py
  • tests/unit/runtime/test_kafka_contract_source.py
  • tests/unit/runtime/test_kafka_contract_source_materialization.py
  • tests/unit/runtime/test_live_contract_materialization.py
  • tests/unit/runtime/test_message_dispatch_engine.py
  • tests/unit/runtime/test_service_kernel_database_topology_wiring.py
  • tests/unit/scripts/test_prove_application_database_acl.py
  • tests/unit/validation/test_application_database_acl.py
  • tests/unit/validation/test_application_relation_ownership.py
💤 Files with no reviewable changes (1)
  • .onex_ratchets/noncanonical_class_allowlist.yaml

Comment on lines +80 to +90
domain-adapter-proof:
name: Projection Domain Adapter Proof (OMN-15421)
runs-on: >-
${{
(github.event_name == 'pull_request' &&
github.event.pull_request.head.repo.full_name != github.repository)
&& fromJSON(vars.OMNI_PUBLIC_PR_RUNS_ON_JSON || '["ubuntu-latest"]')
|| fromJSON(vars.OMNI_DOCKER_CI_RUNS_ON_JSON || vars.OMNI_TRUSTED_CI_RUNS_ON_JSON || '["self-hosted","omnibase-ci"]')
}}
timeout-minutes: 15

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check the top-level and per-job permissions declared in docker-build.yml
rg -n -B2 -A2 'permissions:' .github/workflows/docker-build.yml

Repository: OmniNode-ai/omnibase_infra

Length of output: 527


🏁 Script executed:

#!/bin/bash
# Inspect workflow structure and permission scope around the affected jobs.
sed -n '1,155p' .github/workflows/docker-build.yml
printf '\n--- permission declarations ---\n'
rg -n '^[[:space:]]{2}permissions:|^[[:space:]]{4}permissions:|^[[:space:]]{6}permissions:' .github/workflows/docker-build.yml
printf '\n--- comparable workflow permissions ---\n'
rg -n -B3 -A5 'permissions:' .github/workflows/application-acl-postgres16-proof.yml

Repository: OmniNode-ai/omnibase_infra

Length of output: 6415


🏁 Script executed:

#!/bin/bash
sed -n '1,155p' .github/workflows/docker-build.yml
printf '\n--- permission declarations ---\n'
rg -n '^[[:space:]]{2}permissions:|^[[:space:]]{4}permissions:|^[[:space:]]{6}permissions:' .github/workflows/docker-build.yml
printf '\n--- comparable workflow permissions ---\n'
rg -n -B3 -A5 'permissions:' .github/workflows/application-acl-postgres16-proof.yml

Repository: OmniNode-ai/omnibase_infra

Length of output: 6415


Add explicit GITHUB_TOKEN permissions to domain-adapter-proof.

docker-build.yml has no workflow-level permissions: block. Add permissions: contents: read to this job so it does not inherit broader repository defaults.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/docker-build.yml around lines 80 - 90, Add a job-level
permissions configuration to domain-adapter-proof granting only contents: read,
ensuring the job does not inherit broader repository permissions. Keep the
existing runner and timeout settings unchanged.

Comment on lines +23 to +30
dlq_topics: tuple[str, ...] = Field(
default_factory=tuple,
description="Contract-declared dead-letter topics",
)
consumer_group: str | None = Field(
default=None,
description="Optional contract-declared consumer group identifier",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Collect every key used under `event_bus:` in contract YAML files and compare with the model fields.
fd -t f -e yaml -e yml . | xargs -r rg -l '^\s*event_bus\s*:' | while IFS= read -r f; do
  python - "$f" <<'PY'
import sys, yaml
path = sys.argv[1]
try:
    doc = yaml.safe_load(open(path, encoding="utf-8"))
except Exception:
    sys.exit(0)
if isinstance(doc, dict) and isinstance(doc.get("event_bus"), dict):
    print(path, sorted(doc["event_bus"]))
PY
done

# Show the declared field set for comparison.
fd -t f 'model_event_bus_wiring.py' -x cat -n {}

Repository: OmniNode-ai/omnibase_infra

Length of output: 10892


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- ModelEventBusWiring ---'
cat -n src/omnibase_infra/runtime/auto_wiring/models/model_event_bus_wiring.py
printf '%s\n' '--- kafka_contract_source validation sites ---'
rg -n -C 12 'ModelEventBusWiring|event_bus' src/omnibase_infra/runtime/kafka_contract_source.py
printf '%s\n' '--- discovery event_bus parsing ---'
rg -n -C 12 'event_bus|subscribe_topics|publish_topics' src/omnibase_infra/runtime/auto_wiring/discovery.py
printf '%s\n' '--- representative contract shapes ---'
for f in \
  src/omnibase_infra/nodes/node_build_loop_projection_compute/contract.yaml \
  src/omnibase_infra/nodes/node_runtime_orchestrator/contract.yaml \
  contracts/runtime/runtime_config.yaml \
  contracts/runtime/event_bus_wiring_effect.yaml
do
  if [ -f "$f" ]; then
    echo "--- $f"
    cat -n "$f" | sed -n '1,100p'
  fi
done
printf '%s\n' '--- all event_bus mappings, including nested mappings ---'
python3 - <<'PY'
from pathlib import Path
import yaml

def walk(value, path=()):
    if isinstance(value, dict):
        for key, child in value.items():
            if key == "event_bus" and isinstance(child, dict):
                yield path + (key,), child
            yield from walk(child, path + (str(key),))
    elif isinstance(value, list):
        for i, child in enumerate(value):
            yield from walk(child, path + (f"[{i}]",))

for path in sorted(Path(".").rglob("*.yaml")) + sorted(Path(".").rglob("*.yml")):
    try:
        data = yaml.safe_load(path.read_text(encoding="utf-8"))
    except Exception:
        continue
    for location, mapping in walk(data):
        print(f"{path}:{'.'.join(location)}\t{','.join(sorted(map(str, mapping)))}")
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 40041


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- References to strict event_bus validation and contract loading ---'
rg -n -C 8 'on_contract_registered|contract_data|contract_config|runtime_config|_parse_contract|ModelEventBusWiring' \
  src/omnibase_infra/runtime src/omnibase_infra/service_kernel.py tests 2>/dev/null || true

printf '%s\n' '--- ModelEventBusWiring tests and direct validation tests ---'
rg -n -C 10 'ModelEventBusWiring|auto_offset_reset|event_bus\.(version|type|environment)|event_bus:' \
  tests src/omnibase_infra | head -n 1200

printf '%s\n' '--- Event-bus key blocks in checked-in YAML files ---'
python3 - <<'PY'
from pathlib import Path
import re

fields = {
    "subscribe_topics", "publish_topics", "dlq_topics", "consumer_group",
    "consumer_purpose", "plugin_managed", "tenant_scoped_ingress",
    "terminal_event",
}
for path in sorted(list(Path(".").rglob("*.yaml")) + list(Path(".").rglob("*.yml"))):
    lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
    in_event_bus = False
    event_indent = None
    keys = []
    for line_no, line in enumerate(lines, 1):
        if not line.strip() or line.lstrip().startswith("#"):
            continue
        indent = len(line) - len(line.lstrip())
        match = re.match(r"^(\s*)event_bus\s*:\s*(?:#.*)?$", line)
        if match:
            in_event_bus = True
            event_indent = len(match.group(1))
            keys = []
            continue
        if in_event_bus:
            if indent <= event_indent:
                if keys:
                    extra = sorted(set(keys) - fields)
                    if extra:
                        print(f"{path}: event_bus keys={sorted(set(keys))}; extra={extra}")
                in_event_bus = False
                event_indent = None
            else:
                key_match = re.match(r"^\s+([A-Za-z_][A-Za-z0-9_-]*)\s*:", line)
                if key_match and indent == event_indent + 2:
                    keys.append(key_match.group(1))
    if in_event_bus and keys:
        extra = sorted(set(keys) - fields)
        if extra:
            print(f"{path}: event_bus keys={sorted(set(keys))}; extra={extra}")
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- Kafka registration validation and failure handling ---'
sed -n '220,335p' src/omnibase_infra/runtime/kafka_contract_source.py
rg -n -C 18 'def on_contract_registered|on_contract_registered\(' src/omnibase_infra/runtime/kafka_contract_source.py src/omnibase_infra/runtime tests/unit/runtime | head -n 500

printf '%s\n' '--- Targeted tests that include extra event_bus keys ---'
rg -l 'event_bus.*version|version:.*major|auto_offset_reset|consumer_purpose' \
  tests/unit/runtime tests/integration 2>/dev/null | while IFS= read -r f; do
    echo "--- $f"
    rg -n -C 6 'event_bus|auto_offset_reset|consumer_purpose|version:' "$f" | head -n 120
  done

printf '%s\n' '--- Checked-in node contracts with known extra event_bus keys ---'
for f in \
  src/omnibase_infra/nodes/node_build_loop_projection_compute/contract.yaml \
  src/omnibase_infra/nodes/node_ledger_projection_compute/contract.yaml \
  src/omnibase_infra/nodes/node_validation_ledger_projection_compute/contract.yaml
do
  if [ -f "$f" ]; then
    echo "--- $f"
    sed -n '/^event_bus:/,/^[^ #].*:/p' "$f" | head -n 30
  fi
done

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


Add all contract-declared event_bus fields before enabling extra="forbid".

Checked-in node contracts and existing tests declare event_bus.version and auto_offset_reset, but ModelEventBusWiring does not. Kafka registration validates the raw mapping and rejects these contracts, while filesystem discovery ignores the extra keys. Align the model with the contract schema, or strip unsupported fields before validation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/auto_wiring/models/model_event_bus_wiring.py`
around lines 23 - 30, Update ModelEventBusWiring to declare every
contract-supported event_bus field, including version and auto_offset_reset,
before strict extra-field validation runs. Match the existing contract
types/defaults and preserve validation of genuinely unsupported keys; do not
strip declared fields from the raw mapping.

Comment on lines +3454 to +3472
accepted = materialization.status in {
EnumMaterializationStatus.MATERIALIZED,
EnumMaterializationStatus.ALREADY_MATERIALIZED,
}
if not accepted:
logger.warning(
"Typed db_io contract materialization rejected",
extra={
"node_name": node_name,
"status": materialization.status.value,
"reason": (
materialization.reason.value
if materialization.reason is not None
else None
),
"correlation_id": str(correlation_id),
},
)
return accepted

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find consumers of CAPABILITY_CHANGE and of registered_handlers to size the behavior change.
rg -nP --type=py -C3 'CAPABILITY_CHANGE' -g '!**/tests/**'
rg -nP --type=py -C3 '\bregistered_handlers\b'
rg -nP --type=py -C5 '_publish_capability_change|_announced_capabilities'

Repository: OmniNode-ai/omnibase_infra

Length of output: 164


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- candidate file ---'
wc -l src/omnibase_infra/runtime/runtime_host_process.py
ast-grep outline src/omnibase_infra/runtime/runtime_host_process.py | rg -n 'publish|capability|handler|health|material|dispatch|register' || true
printf '%s\n' '--- relevant symbols and references ---'
rg -n -C4 'CAPABILITY_CHANGE|registered_handlers|_publish_capability_change|_announced_capabilities|db_io|dispatch.engine|dispatch_engine' src/omnibase_infra/runtime/runtime_host_process.py src -g '*.py' -g '*.yaml' || true
printf '%s\n' '--- all tracked paths containing likely consumers ---'
git ls-files | rg -i 'capabil|health|dispatch|handler|introspect' | head -200

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- runtime_host_process.py target ---'
sed -n '3360,3505p' src/omnibase_infra/runtime/runtime_host_process.py
printf '%s\n' '--- exact capability symbols ---'
rg -n -C5 'CAPABILITY_CHANGE|registered_handlers|_publish_capability_change|_announced_capabilities' src/omnibase_infra/runtime/runtime_host_process.py src --glob '*.py' --glob '*.yaml' | head -300
printf '%s\n' '--- dispatch registration and report symbols ---'
rg -n -C4 'register_dispatch|register.*dispatcher|dispatcher.*register|ModelContractWiringResult|wired.*handler|handler.*wired|health_check' src/omnibase_infra/runtime src/omnibase_infra --glob '*.py' | head -400

Repository: OmniNode-ai/omnibase_infra

Length of output: 50384


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- materialize_cached_contract definition and callers ---'
rg -n -C10 'def materialize_cached_contract|materialize_cached_contract\(' src --glob '*.py' | head -250
printf '%s\n' '--- db_io commit registration ---'
rg -n -C15 'def _commit_handler_wiring|def _commit_contract_wiring|dispatcher_id|route_ids|db_io' src/omnibase_infra/runtime/auto_wiring/handler_wiring.py | head -350
printf '%s\n' '--- health and dispatch-engine projections ---'
sed -n '5280,5505p' src/omnibase_infra/runtime/runtime_host_process.py
rg -n -C5 'dispatch_engine|dispatchers|routes|wired_contract|wiring_details|registered_handlers' src/omnibase_infra/runtime/runtime_host_process.py src/omnibase_infra/services/health_checker.py --glob '*.py' | head -300
printf '%s\n' '--- focused tests and contract expectations ---'
rg -n -C4 'CAPABILITY_CHANGE|materialize_cached_contract|db_io.*material|registered_handlers|dispatch.*engine' tests src --glob '*.py' | head -400

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- KafkaContractSource.materialize_cached_contract ---'
sed -n '1320,1495p' src/omnibase_infra/runtime/kafka_contract_source.py
printf '%s\n' '--- commit path ---'
sed -n '6159,6295p' src/omnibase_infra/runtime/auto_wiring/handler_wiring.py
printf '%s\n' '--- dynamic registration authorization ---'
sed -n '6990,7075p' src/omnibase_infra/runtime/auto_wiring/handler_wiring.py
printf '%s\n' '--- focused test filenames and matching lines ---'
rg -l 'CAPABILITY_CHANGE|materialize_cached_contract|db_io.*material|registered_handlers|EnumMaterializationStatus' tests src --glob '*.py' | sort
rg -n -C3 'CAPABILITY_CHANGE|materialize_cached_contract|db_io.*material|EnumMaterializationStatus' tests --glob '*.py' | head -300

Repository: OmniNode-ai/omnibase_infra

Length of output: 49645


Preserve capability and health projections for live db_io materialization. The dispatch engine registers the dispatcher and routes, but the early return skips _publish_capability_change() and leaves self._handlers unchanged. Therefore, CAPABILITY_CHANGE consumers and health_check()["registered_handlers"] do not observe the materialized contract. Add an equivalent capability and health projection for this path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/runtime_host_process.py` around lines 3454 - 3472,
The typed db_io materialization path returns before updating capability and
handler projections. In the dispatch flow around the shown accepted-status
check, publish the equivalent capability change via _publish_capability_change()
and update self._handlers consistently with the normal materialization path
before returning, while preserving rejection logging and the accepted result.

Comment on lines +373 to +379
profile = os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE")
if profile is None:
return None

from omnibase_infra.topology import load_topology_profile

return load_topology_profile(profile)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Treat a blank profile value as unset.

os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE") returns "" when the variable is exported empty, which is common in compose and CI environment injection. The function then calls load_topology_profile("") and bootstrap fails with a profile-resolution error instead of the clear "profile is not set" path. Normalize the value first.

🐛 Proposed fix
-    profile = os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE")
-    if profile is None:
+    profile = (os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE") or "").strip()
+    if not profile:
         return None
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
profile = os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE")
if profile is None:
return None
from omnibase_infra.topology import load_topology_profile
return load_topology_profile(profile)
profile = (os.environ.get("ONEX_DATABASE_TOPOLOGY_PROFILE") or "").strip()
if not profile:
return None
from omnibase_infra.topology import load_topology_profile
return load_topology_profile(profile)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/runtime/service_kernel.py` around lines 373 - 379,
Normalize the value read in the profile-loading function before checking it,
treating an empty or whitespace-only ONEX_DATABASE_TOPOLOGY_PROFILE as unset and
returning None. Only call load_topology_profile with a nonblank normalized
profile value.

Comment on lines +2466 to +2474
def _quote_identifier(identifier: str) -> str:
if _SQL_IDENTIFIER.fullmatch(identifier) is None:
raise ValueError(f"Unsafe or non-canonical SQL identifier {identifier!r}")
return f'"{identifier}"'


def _quote_sql_literal(value: str) -> str:
"""Quote one trusted typed value as a PostgreSQL string literal."""
return "'" + value.replace("'", "''") + "'"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate every name that is interpolated into rendered SQL.

_quote_identifier rejects a non-canonical identifier, but the renderer bypasses it for many string literals and for name lists:

  • Line 2720 and the surrounding guard blocks embed role_name, schema_name, object_ref, and physical_database directly in single quotes with an f-string.
  • Lines 2861, 2942, 3028, 3029, and 3080 build SQL literals with Python repr(). repr() escapes an embedded quote as \', which PostgreSQL does not accept as an escaped quote in a standard-conforming string. _quote_sql_literal exists for exactly this and doubles the quote instead.

A name that contains ', a backslash, or a newline therefore produces a broken or attacker-shaped script that runs with owner privileges. The evidence YAML is checked in, so this is a posture gap rather than a live exploit, but the generated artifact is privileged SQL.

The cheapest complete fix is to validate every role, schema, and object name once while building the matrix, and to replace each repr() literal with _quote_sql_literal.

🔒️ Sketch of the validation and quoting fix
+def _assert_canonical_name(kind: str, name: str) -> str:
+    if _SQL_IDENTIFIER.fullmatch(name) is None:
+        raise ValueError(f"Unsafe or non-canonical {kind} name {name!r}")
+    return name
-    member_literals = ", ".join(repr(name) for name in membership_members)
-    parent_literals = ", ".join(repr(name) for name in governed_parents)
+    member_literals = ", ".join(_quote_sql_literal(name) for name in membership_members)
+    parent_literals = ", ".join(_quote_sql_literal(name) for name in governed_parents)
-    database_literals = ", ".join(
-        repr(database) for database in matrix.required_connect_databases
-    )
+    database_literals = ", ".join(
+        _quote_sql_literal(database) for database in matrix.required_connect_databases
+    )

Also applies to: 2716-2724, 3028-3029, 3079-3081

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/omnibase_infra/validation/application_database_acl.py` around lines 2466
- 2474, Validate every role, schema, object, and physical database name when
constructing the matrix, reusing _quote_identifier or the appropriate canonical
validation before rendering. In the SQL renderer and surrounding guard blocks,
replace direct single-quoted f-string interpolation of role_name, schema_name,
object_ref, and physical_database, plus every repr()-generated SQL literal
around the identified rendering sites, with _quote_sql_literal; preserve the
existing generated SQL structure while ensuring all interpolated names are
safely escaped.

Comment on lines +31 to +61
result = subprocess.run(
[
*command,
"up",
"--build",
"--abort-on-container-exit",
"--exit-code-from",
"proof",
],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=1_500,
check=False,
)
try:
assert result.returncode == 0, result.stdout + result.stderr
output = result.stdout + result.stderr
assert "acl_phase=scaffold_wrong_database_guard status=PASS" in output
assert "acl_phase=scaffold_fresh_additive_round_trip status=PASS" in output
assert "acl_phase=rollback_atomic_failure" in output
assert "acl_status=PASS postgres_major=16" in output
finally:
subprocess.run(
[*command, "down", "--volumes", "--remove-orphans"],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=120,
check=False,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

A timeout on up skips the compose cleanup.

subprocess.run(... "up" ...) runs outside the try block. If the build and proof exceed timeout=1_500, subprocess.run raises TimeoutExpired before the try is entered, so the finally never runs docker compose down --volumes --remove-orphans. The containers, network, and volumes of project application-acl-proof-<pid> then survive the failed run. The project name embeds the PID, so a later run does not reclaim them. Move the up call inside the try.

🐛 Proposed fix
-    result = subprocess.run(
-        [
-            *command,
-            "up",
-            "--build",
-            "--abort-on-container-exit",
-            "--exit-code-from",
-            "proof",
-        ],
-        cwd=_ROOT,
-        capture_output=True,
-        text=True,
-        timeout=1_500,
-        check=False,
-    )
     try:
+        result = subprocess.run(
+            [
+                *command,
+                "up",
+                "--build",
+                "--abort-on-container-exit",
+                "--exit-code-from",
+                "proof",
+            ],
+            cwd=_ROOT,
+            capture_output=True,
+            text=True,
+            timeout=1_500,
+            check=False,
+        )
         assert result.returncode == 0, result.stdout + result.stderr
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
result = subprocess.run(
[
*command,
"up",
"--build",
"--abort-on-container-exit",
"--exit-code-from",
"proof",
],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=1_500,
check=False,
)
try:
assert result.returncode == 0, result.stdout + result.stderr
output = result.stdout + result.stderr
assert "acl_phase=scaffold_wrong_database_guard status=PASS" in output
assert "acl_phase=scaffold_fresh_additive_round_trip status=PASS" in output
assert "acl_phase=rollback_atomic_failure" in output
assert "acl_status=PASS postgres_major=16" in output
finally:
subprocess.run(
[*command, "down", "--volumes", "--remove-orphans"],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=120,
check=False,
)
try:
result = subprocess.run(
[
*command,
"up",
"--build",
"--abort-on-container-exit",
"--exit-code-from",
"proof",
],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=1_500,
check=False,
)
assert result.returncode == 0, result.stdout + result.stderr
output = result.stdout + result.stderr
assert "acl_phase=scaffold_wrong_database_guard status=PASS" in output
assert "acl_phase=scaffold_fresh_additive_round_trip status=PASS" in output
assert "acl_phase=rollback_atomic_failure" in output
assert "acl_status=PASS postgres_major=16" in output
finally:
subprocess.run(
[*command, "down", "--volumes", "--remove-orphans"],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=120,
check=False,
)
🧰 Tools
🪛 ast-grep (0.45.0)

[error] 53-60: Command coming from incoming request
Context: subprocess.run(
[*command, "down", "--volumes", "--remove-orphans"],
cwd=_ROOT,
capture_output=True,
text=True,
timeout=120,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/test_application_acl_postgres16_proof.py` around lines 31 -
61, Move the `subprocess.run` invocation for the compose `"up"` command inside
the existing `try` block in the test flow, so `TimeoutExpired` and other
execution failures still reach the `finally` cleanup. Preserve the current
assertions and ensure the compose `"down" --volumes --remove-orphans"` call
always executes.

output = result.stdout + result.stderr
assert "acl_phase=scaffold_wrong_database_guard status=PASS" in output
assert "acl_phase=scaffold_fresh_additive_round_trip status=PASS" in output
assert "acl_phase=rollback_atomic_failure" in output

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert a verdict for the rollback phase.

Lines 49-50 assert status=PASS for their phases. Line 51 asserts only that the phase name appears, so the rollback proof passes even when that phase reports a failure verdict. Add the expected status suffix if the proof emits one for this phase.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/integration/test_application_acl_postgres16_proof.py` at line 51,
Update the rollback-phase assertion near the existing status checks to require
the proof’s expected success verdict, not just the phase name. Extend the
assertion for `acl_phase=rollback_atomic_failure` with the emitted `status=PASS`
suffix, preserving the existing phase identifier.

Comment on lines +193 to +215
def test_structural_security_context_is_not_tenant_authority() -> None:
tenant_id = uuid4()
envelope = ModelEventEnvelope[dict[str, object]](
payload={"tenant_id": str(tenant_id)},
security_context=ModelSecurityContext(
user_id=uuid4(),
auth_method="oidc",
auth_timestamp=datetime.now(UTC),
security_labels={"tenant_id": str(tenant_id)},
),
)
target = projection_database_target("tenant_events", schema="tenant")
conn, _ = _connection("tenant_projection_writer")

with patch("psycopg2.connect", return_value=conn):
adapter = _adapter(target, authority=None)
with pytest.raises(ProjectionTenantContextError, match="verified authority"):
adapter.upsert("tenant_events", "event_id", {"event_id": uuid4()})

conn.cursor.assert_not_called()
assert (
envelope.security_context is not None
) # proves the rejected shape was present

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

The structural-security-context test never gives the context to the adapter.

The test builds envelope with a ModelSecurityContext that carries security_labels["tenant_id"], but line 208 passes authority=None and no tenant_event. The adapter never sees that envelope. The test therefore proves only that a missing authority is rejected. The final assertion at lines 213-215 restates a local construction and cannot fail.

The stated guarantee is that a structural security context is not accepted as tenant authority. To cover that guarantee, pass the envelope as the dispatch event while authority stays None.

🐛 Proposed fix
     target = projection_database_target("tenant_events", schema="tenant")
     conn, _ = _connection("tenant_projection_writer")
 
     with patch("psycopg2.connect", return_value=conn):
-        adapter = _adapter(target, authority=None)
+        adapter = _adapter(target, authority=None, tenant_event=envelope)
         with pytest.raises(ProjectionTenantContextError, match="verified authority"):
             adapter.upsert("tenant_events", "event_id", {"event_id": uuid4()})
 
     conn.cursor.assert_not_called()
-    assert (
-        envelope.security_context is not None
-    )  # proves the rejected shape was present
+    # The rejected envelope did carry a structurally valid tenant label.
+    assert envelope.security_context is not None
+    assert envelope.security_context.security_labels["tenant_id"] == str(tenant_id)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def test_structural_security_context_is_not_tenant_authority() -> None:
tenant_id = uuid4()
envelope = ModelEventEnvelope[dict[str, object]](
payload={"tenant_id": str(tenant_id)},
security_context=ModelSecurityContext(
user_id=uuid4(),
auth_method="oidc",
auth_timestamp=datetime.now(UTC),
security_labels={"tenant_id": str(tenant_id)},
),
)
target = projection_database_target("tenant_events", schema="tenant")
conn, _ = _connection("tenant_projection_writer")
with patch("psycopg2.connect", return_value=conn):
adapter = _adapter(target, authority=None)
with pytest.raises(ProjectionTenantContextError, match="verified authority"):
adapter.upsert("tenant_events", "event_id", {"event_id": uuid4()})
conn.cursor.assert_not_called()
assert (
envelope.security_context is not None
) # proves the rejected shape was present
def test_structural_security_context_is_not_tenant_authority() -> None:
tenant_id = uuid4()
envelope = ModelEventEnvelope[dict[str, object]](
payload={"tenant_id": str(tenant_id)},
security_context=ModelSecurityContext(
user_id=uuid4(),
auth_method="oidc",
auth_timestamp=datetime.now(UTC),
security_labels={"tenant_id": str(tenant_id)},
),
)
target = projection_database_target("tenant_events", schema="tenant")
conn, _ = _connection("tenant_projection_writer")
with patch("psycopg2.connect", return_value=conn):
adapter = _adapter(target, authority=None, tenant_event=envelope)
with pytest.raises(ProjectionTenantContextError, match="verified authority"):
adapter.upsert("tenant_events", "event_id", {"event_id": uuid4()})
conn.cursor.assert_not_called()
# The rejected envelope did carry a structurally valid tenant label.
assert envelope.security_context is not None
assert envelope.security_context.security_labels["tenant_id"] == str(tenant_id)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/auto_wiring/test_projection_domain_adapters.py` around
lines 193 - 215, Update test_structural_security_context_is_not_tenant_authority
to pass the constructed envelope as the adapter’s dispatch event (tenant_event)
while keeping authority=None. Remove the redundant final assertion that only
rechecks the locally constructed security context, and retain the expectation
that ProjectionTenantContextError is raised without opening a cursor.

Comment on lines +66 to +86
def test_cold_boot_wiring_receives_resolved_topology() -> None:
keyword = _keyword_for_call("wire_from_manifest", "topology")

assert keyword is not None
assert isinstance(keyword.value, ast.Name)
assert keyword.value.id == "deployment_topology"


def test_dynamic_runtime_receives_the_same_resolved_topology() -> None:
keyword = _keyword_for_call("RuntimeHostProcess", "deployment_topology")

assert keyword is not None
assert isinstance(keyword.value, ast.Name)
assert keyword.value.id == "deployment_topology"


def test_db_io_boot_requires_explicit_profile() -> None:
source = SERVICE_KERNEL_PATH.read_text(encoding="utf-8")

assert "if db_io_contracts and deployment_topology is None:" in source
assert "ONEX_DATABASE_TOPOLOGY_PROFILE is not set" in source

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Locate real startup tests that invoke wire_from_manifest and check for the new topology argument.
set -uo pipefail

echo "=== wire_from_manifest usage in tests ==="
rg -nP -C 8 '\bwire_from_manifest\s*\(' tests

echo "=== wire_from_manifest signature ==="
ast-grep run --pattern 'async def wire_from_manifest($$$):
  $$$' --lang python src/omnibase_infra/runtime/auto_wiring
ast-grep run --pattern 'def wire_from_manifest($$$):
  $$$' --lang python src/omnibase_infra/runtime/auto_wiring

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


🏁 Script executed:

#!/bin/bash
set -u

echo "=== topology references in tests ==="
rg -n -C 4 '\b(topology|deployment_topology|ONEX_DATABASE_TOPOLOGY_PROFILE|_load_runtime_database_topology)\b' tests/unit/runtime tests/integration/runtime tests/integration 2>/dev/null | head -n 1200

echo "=== topology references in runtime source ==="
rg -n -C 3 '\b(topology|deployment_topology|ONEX_DATABASE_TOPOLOGY_PROFILE|wire_from_manifest)\b' src/omnibase_infra/runtime/auto_wiring src/omnibase_infra/runtime/service_kernel.py | head -n 1000

echo "=== candidate tests by filename ==="
git ls-files 'tests/**/*.py' | rg -i '(startup|boot|kernel|wiring|manifest|topology|database)'

echo "=== exact topology keyword call contexts ==="
rg -n -U -P -C 8 'wire_from_manifest\s*\([^)]*\btopology\s*=' tests || true

Repository: OmniNode-ai/omnibase_infra

Length of output: 50384


🏁 Script executed:

#!/bin/bash
set -u

echo "=== live contract materialization test outline ==="
ast-grep outline tests/unit/runtime/test_live_contract_materialization.py

echo "=== live contract materialization focused source ==="
sed -n '1,235p' tests/unit/runtime/test_live_contract_materialization.py

echo "=== wire_from_manifest definition and topology handling ==="
rg -n -C 10 'def wire_from_manifest|topology:|deployment_topology|_prepare_handler_wiring' src/omnibase_infra/runtime/auto_wiring src/omnibase_infra/runtime/service_kernel.py | head -n 1200

echo "=== AST inventory of test calls passing topology ==="
python3 - <<'PY'
import ast
from pathlib import Path

for path in Path("tests").rglob("*.py"):
    try:
        tree = ast.parse(path.read_text(encoding="utf-8"))
    except Exception:
        continue
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            name = (
                node.func.id if isinstance(node.func, ast.Name)
                else node.func.attr if isinstance(node.func, ast.Attribute)
                else ""
            )
            if name == "wire_from_manifest":
                topology = [kw for kw in node.keywords if kw.arg == "topology"]
                if topology:
                    print(f"{path}:{node.lineno}: topology argument present")
                    print(ast.get_source_segment(path.read_text(encoding="utf-8"), node))
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 48720


🏁 Script executed:

#!/bin/bash
set -u

echo "=== live contract materialization test outline ==="
ast-grep outline tests/unit/runtime/test_live_contract_materialization.py

echo "=== live contract materialization focused source ==="
sed -n '1,235p' tests/unit/runtime/test_live_contract_materialization.py

echo "=== wire_from_manifest definition and topology handling ==="
rg -n -C 10 'def wire_from_manifest|topology:|deployment_topology|_prepare_handler_wiring' src/omnibase_infra/runtime/auto_wiring src/omnibase_infra/runtime/service_kernel.py | head -n 1200

echo "=== AST inventory of test calls passing topology ==="
python3 - <<'PY'
import ast
from pathlib import Path

for path in Path("tests").rglob("*.py"):
    text = path.read_text(encoding="utf-8")
    try:
        tree = ast.parse(text)
    except Exception:
        continue
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            name = (
                node.func.id if isinstance(node.func, ast.Name)
                else node.func.attr if isinstance(node.func, ast.Attribute)
                else ""
            )
            if name == "wire_from_manifest" and any(
                kw.arg == "topology" for kw in node.keywords
            ):
                print(f"{path}:{node.lineno}: topology argument present")
                print(ast.get_source_segment(text, node))
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 48720


🏁 Script executed:

#!/bin/bash
set -u

echo "=== real manifest startup test ==="
sed -n '1,180p' tests/integration/runtime/test_auto_wiring_real_manifest.py

echo "=== runtime boot tests ==="
for f in \
  tests/integration/runtime/test_build_loop_auto_wiring_boot.py \
  tests/integration/runtime/test_pr_state_auto_wiring_boot.py \
  tests/integration/runtime/test_ledger_write_effect_dispatch_seam.py
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    sed -n '1,145p' "$f"
  fi
done

echo "=== contract discovery/loading and handler assertions in startup candidates ==="
rg -n -C 3 'discover_contracts|discover_contracts_from_paths|contract_path|handler|total_wired|dispatcher_count|registered' \
  tests/integration/runtime/test_auto_wiring_real_manifest.py \
  tests/integration/runtime/test_build_loop_auto_wiring_boot.py \
  tests/integration/runtime/test_pr_state_auto_wiring_boot.py \
  tests/integration/runtime/test_ledger_write_effect_dispatch_seam.py | head -n 1000

echo "=== all wire_from_manifest calls with topology keyword or keyword unpacking ==="
python3 - <<'PY'
import ast
from pathlib import Path

for path in Path("tests").rglob("*.py"):
    text = path.read_text(encoding="utf-8")
    try:
        tree = ast.parse(text)
    except SyntaxError:
        continue
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            fn = node.func
            name = fn.id if isinstance(fn, ast.Name) else fn.attr if isinstance(fn, ast.Attribute) else None
            if name == "wire_from_manifest":
                kws = [kw.arg for kw in node.keywords]
                unpacked = [ast.unparse(kw.value) for kw in node.keywords if kw.arg is None]
                print(f"{path}:{node.lineno}: keywords={kws}; unpacked={unpacked}")
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 50382


🏁 Script executed:

#!/bin/bash
set -u

echo "=== db_io declarations in checked-in contracts ==="
rg -l -n '(^|[[:space:]])db_io:' src --glob 'contract.yaml' | sort | head -n 200

echo "=== database declarations in boot-test contracts ==="
for f in \
  src/omnibase_infra/nodes/node_build_loop_projection_compute/contract.yaml \
  src/omnibase_infra/nodes/node_build_loop_write_effect/contract.yaml \
  src/omnibase_infra/nodes/node_pr_state_projection_compute/contract.yaml \
  src/omnibase_infra/nodes/node_pr_state_write_effect/contract.yaml
do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    rg -n -C 3 'db_io|db_tables|database_ref|schema:' "$f" || true
  fi
done

echo "=== tests that use disk db_io contracts or topology with real wiring ==="
rg -n -U -P -C 5 \
  'discover_contracts(?:_from_paths)?\s*\([^)]*|wire_from_manifest\s*\([^)]*' \
  tests/integration tests/unit/runtime 2>/dev/null \
  | rg -n -C 2 'db_io|db_tables|topology|discover_contracts|wire_from_manifest' \
  | head -n 1200

Repository: OmniNode-ai/omnibase_infra

Length of output: 50383


Add startup coverage for topology.

The existing disk-contract startup tests call wire_from_manifest and verify handler wiring, but none passes topology. Extend one test to pass a resolved topology and exercise a db_io contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/runtime/test_service_kernel_database_topology_wiring.py` around
lines 66 - 86, Extend an existing disk-contract startup test that calls
wire_from_manifest to pass a resolved topology argument and include a db_io
contract in the startup scenario. Verify the resulting handler wiring still
succeeds, ensuring the test exercises topology propagation through db_io startup
rather than only asserting AST argument names.

Source: Coding guidelines

Comment on lines +101 to +115
def test_prechange_capture_pins_durable_acl_drift_predicate(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setenv("EXPECTED_PRECHANGE", str(_PRECHANGE_CAPTURE))
proof = _load_proof(monkeypatch)
expected_path = cast("Path", proof.EXPECTED_PRECHANGE)

expected = json.loads(expected_path.read_text(encoding="utf-8"))
observed = json.loads(_PRECHANGE_CAPTURE.read_text(encoding="utf-8"))
assert expected == observed

drifted = dict(observed)
drifted["roles"] = observed["roles"][1:]
with pytest.raises(AssertionError, match="durable pre-change ACL artifact drift"):
assert expected == drifted, "durable pre-change ACL artifact drift"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Locate the real pre-change drift comparison in the proof script so the test can target it.
fd -t f 'prove_application_database_acl.py' | while IFS= read -r f; do
  echo "== $f"
  ast-grep outline "$f" --items all
  rg -n -C6 'EXPECTED_PRECHANGE|prechange|drift' "$f"
done

Repository: OmniNode-ai/omnibase_infra

Length of output: 13691


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '== production drift-check context =='
sed -n '2280,2315p' scripts/ci/prove_application_database_acl.py

printf '%s\n' '== test context =='
sed -n '1,125p' tests/unit/scripts/test_prove_application_database_acl.py

printf '%s\n' '== fixture shape =='
python3 - <<'PY'
import json
from pathlib import Path

path = Path("tests/fixtures/omn15547/application-acl-prechange-fixture.json.captured")
data = json.loads(path.read_text(encoding="utf-8"))
roles = data.get("roles")
print("top_level_keys:", sorted(data))
print("roles_type:", type(roles).__name__)
print("roles_count:", len(roles) if isinstance(roles, list) else None)
PY

printf '%s\n' '== AST call/compare summary =='
python3 - <<'PY'
import ast
from pathlib import Path

for name in (
    "scripts/ci/prove_application_database_acl.py",
    "tests/unit/scripts/test_prove_application_database_acl.py",
):
    tree = ast.parse(Path(name).read_text(encoding="utf-8"), filename=name)
    print(name)
    for node in ast.walk(tree):
        if isinstance(node, ast.Assert):
            print(
                " assert",
                node.lineno,
                ast.unparse(node.test),
                "message=" + (ast.unparse(node.msg) if node.msg else "None"),
            )
        elif isinstance(node, ast.Call) and isinstance(node.func, ast.Name):
            if node.func.id in {"main", "_load_proof"}:
                print(" call", node.lineno, node.func.id)
PY

Repository: OmniNode-ai/omnibase_infra

Length of output: 11100


Test the production drift predicate.

This test reads EXPECTED_PRECHANGE and observed from the same fixture, then checks only Python’s assert behavior. It does not execute the inline predicate in main() at scripts/ci/prove_application_database_acl.py:2310. Extract that comparison into a pure helper and test the helper with an explicitly valid roles payload and a drifted payload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/scripts/test_prove_application_database_acl.py` around lines 101 -
115, Extract the inline durable pre-change ACL comparison from main() into a
pure helper, preserving the “durable pre-change ACL artifact drift” failure
behavior. Update test_prechange_capture_pins_durable_acl_drift_predicate to call
this helper with an explicitly valid roles payload, then verify it rejects the
payload with one role removed instead of testing only Python assert semantics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants