Skip to content

feat(OMN-1783): Implement PostgresRepositoryRuntime for contract-driven database access - #225

Merged
jonahgabriel merged 7 commits into
mainfrom
jonah/omn-1783-postgres-repository-runtime
Feb 1, 2026
Merged

jonahgabriel merged 7 commits into
mainfrom
jonah/omn-1783-postgres-repository-runtime

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Feb 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds a generic contract executor for ModelDbRepositoryContract from omnibase_core, enabling contract-driven database access with safety constraints and determinism guarantees.

Key Features:

  • Typed exception hierarchy (RepositoryConfigError, RepositoryExecutionError, RepositoryTimeoutError, RepositoryContractError, RepositoryValidationError)
  • ModelRepositoryRuntimeConfig for runtime configuration (timeouts, limits, operation modes)
  • PostgresRepositoryRuntime core implementation with:
    • Read/write operation mode support
    • Determinism enforcement via ORDER BY injection (or hard error if no PK)
    • LIMIT injection for multi-row queries
    • Positional parameter binding ($1, $2, ...)
    • Timeout enforcement via asyncio.wait_for()

Files Changed:

  • src/omnibase_infra/errors/repository/ - New typed exception hierarchy
  • src/omnibase_infra/runtime/db/ - Runtime implementation and config
  • tests/unit/runtime/db/test_postgres_repository_runtime.py - 24 unit tests
  • tests/integration/runtime/db/test_postgres_repository_runtime_integration.py - 10 integration tests

Dependencies:

  • Bumps omnibase-core to ^0.12.0 for ModelDbRepositoryContract
  • Bumps version to 0.2.9

Linear Ticket

OMN-1783

Test Plan

  • All 24 unit tests passing (pytest tests/unit/runtime/db/)
  • All 10 integration tests passing against real PostgreSQL (pytest -m postgres tests/integration/runtime/db/)
  • Pre-commit hooks passing (ruff, yamlfmt, ONEX validators)
  • Type checking passing (mypy)
  • CI pipeline passes

Summary by CodeRabbit

  • New Features

    • PostgreSQL repository runtime: safe, deterministic DB ops with ORDER BY/LIMIT injection, timeouts, and configurable runtime controls.
    • New repository error types for contract, validation, execution, and timeout scenarios.
    • Runtime configuration model to control determinism, limits, timeouts, and observability.
  • Tests

    • Extensive unit and integration tests covering determinism, LIMIT injection, timeouts, modes, argument validation, error wrapping, and metrics.
  • Chores

    • Bump core dependency to v0.12.0.
    • Stricter infra validation defaults, added validation exemptions, and per-file lint ignore.

✏️ Tip: You can customize this high-level summary in your review settings.

…en database access

Adds a generic contract executor for ModelDbRepositoryContract from omnibase_core.

Key Features:
- Typed exception hierarchy (RepositoryConfigError, RepositoryExecutionError, etc.)
- ModelRepositoryRuntimeConfig for runtime configuration
- PostgresRepositoryRuntime core implementation with:
  - Read/write operation mode support
  - Determinism enforcement via ORDER BY injection
  - LIMIT injection for multi-row queries
  - Positional parameter binding ($1, $2, ...)
  - Timeout enforcement via asyncio.wait_for()

Testing:
- 24 unit tests covering all behaviors
- 10 integration tests against real PostgreSQL

Dependencies:
- Bumps omnibase-core to ^0.12.0 for ModelDbRepositoryContract
- Bumps version to 0.2.9
@coderabbitai

coderabbitai Bot commented Feb 1, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a Postgres repository runtime and runtime config, a repository-specific error hierarchy, validation constant updates and exemptions, an omnibase-core dependency bump, lint ignore entries, and extensive unit and integration tests.

Changes

Cohort / File(s) Summary
Project config
pyproject.toml
Bumps omnibase-core from ^0.11.0 → ^0.12.0; adds per-file Ruff ignore for S608 on an integration test (duplicate entry present).
Repository errors
src/omnibase_infra/errors/__init__.py, src/omnibase_infra/errors/repository/__init__.py, src/omnibase_infra/errors/repository/errors_repository.py
New repository error module and five exported classes: RepositoryError, RepositoryContractError, RepositoryValidationError, RepositoryExecutionError, RepositoryTimeoutError with repo-specific fields (op_name, table, sql_fingerprint, retriable) and predefined error codes/retriability.
DB runtime public API
src/omnibase_infra/runtime/db/__init__.py, src/omnibase_infra/runtime/db/models/__init__.py
New package initializers re-exporting DB runtime models and PostgresRepositoryRuntime as the db subpackage public API.
Runtime config model
src/omnibase_infra/runtime/db/models/model_repository_runtime_config.py
New frozen Pydantic ModelRepositoryRuntimeConfig with fields and validators for max_row_limit, timeout_ms, allowed_modes, allow_write_operations, primary_key_column, default_order_by, and SQL identifier safety checks.
Postgres runtime implementation
src/omnibase_infra/runtime/db/postgres_repository_runtime.py
New PostgresRepositoryRuntime implementing contract-driven execution: operation/arg validation, ORDER BY and LIMIT injection, max-row enforcement, asyncio timeout handling, error wrapping into repository errors, metrics hooks, and result shaping.
Validation constants & exemptions
src/omnibase_infra/validation/infra_validators.py, src/omnibase_infra/validation/validation_exemptions.yaml
Bumps INFRA_MAX_UNIONS 115→117; adds INFRA_MAX_VIOLATIONS, INFRA_PATTERNS_STRICT, INFRA_UNIONS_STRICT; adds two identical pattern exemptions for PostgresRepositoryRuntime (OMN-1783).
Unit tests
tests/unit/runtime/db/__init__.py, tests/unit/runtime/db/test_postgres_repository_runtime.py
Adds unit tests with extensive fixtures/mocks covering validation, determinism/order injection, LIMIT handling, timeouts, error wrapping, metrics emission, and configuration.
Integration tests
tests/integration/runtime/db/test_postgres_repository_runtime_integration.py
Adds integration tests exercising PostgresRepositoryRuntime against a live Postgres instance for read/write flows, determinism, LIMIT injection, argument checks, and timeouts.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Runtime as PostgresRepositoryRuntime
    participant Contract as ModelDbRepositoryContract
    participant SQL as SQLBuilder
    participant DB as Database
    participant Err as ErrorHandler

    Client->>Runtime: call(op_name, *args)
    Runtime->>Contract: fetch_operation(op_name)
    Contract-->>Runtime: ModelDbOperation

    Runtime->>Runtime: validate_mode(operation)
    Runtime->>Runtime: validate_arg_count(*args)

    Runtime->>SQL: ensure_order_by_and_limit(sql, config)
    SQL-->>Runtime: sql_with_order_and_limit

    Runtime->>DB: execute_with_timeout(sql, *args)
    alt Timeout
        DB-->>Err: TimeoutError
        Err-->>Runtime: RepositoryTimeoutError
    else Execution Error
        DB-->>Err: DatabaseError
        Err-->>Runtime: RepositoryExecutionError
    else Success
        DB-->>Runtime: rows
    end

    Runtime->>Runtime: shape_result(rows, operation)
    Runtime-->>Client: list[dict] | dict | None
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through SQL with contract in paw,
I injected ORDER BY so rows keep their law,
I chased down timeouts and kept fingerprints near,
I wrapped errors kindly so callers need not fear,
A tiny runtime — rabbit celebrates the new gear.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature being implemented: PostgresRepositoryRuntime for contract-driven database access, with OMN-1783 ticket reference.
Docstring Coverage ✅ Passed Docstring coverage is 81.61% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jonah/omn-1783-postgres-repository-runtime

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

@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: 5

🤖 Fix all issues with AI agents
In `@src/omnibase_infra/runtime/db/__init__.py`:
- Around line 34-53: Update the docstring example to use the correct
ModelDbOperation API: change mode="select" to mode="read" (or "write" where
appropriate) and replace params=["user_id"] with a mapping of parameter names to
ModelDbParam instances (e.g., params={"user_id": ModelDbParam(...)}), keeping
ModelDbReturn as-is; ensure the example still demonstrates creating
ModelDbRepositoryContract, initializing PostgresRepositoryRuntime, and calling
runtime.call("find_by_id", 123) so it matches the actual constructors/types
(ModelDbRepositoryContract, ModelDbOperation, ModelDbParam, ModelDbReturn,
PostgresRepositoryRuntime.call).

In `@src/omnibase_infra/runtime/db/models/__init__.py`:
- Around line 9-15: Update the module docstring for ModelRepositoryRuntimeConfig
to reference the actual field names (allowed_modes and allow_write_operations)
instead of the nonexistent allow_raw_operations and allow_delete_operations;
adjust the brief descriptions to match the semantics of allowed_modes (operation
allowlisting) and allow_write_operations (write/delete permission flag) and
ensure any other listed fields (e.g., max_row_limit, timeout_ms,
primary_key_column, default_order_by, metrics config) remain accurate and
consistent with the ModelRepositoryRuntimeConfig definition.

In `@src/omnibase_infra/runtime/db/models/model_repository_runtime_config.py`:
- Around line 21-31: Update the module docstring example for
ModelRepositoryRuntimeConfig to use the actual model fields: replace uses of
allowed_ops with allowed_modes and allow_raw_operations with emit_metrics (or
set emit_metrics to appropriate boolean), and ensure any membership checks
reference valid modes (e.g., "read" or "write") rather than "delete"; keep
max_row_limit and timeout_ms as shown and show correct printed values for the
real fields so the example matches the ModelRepositoryRuntimeConfig class
definition.

In `@src/omnibase_infra/runtime/db/postgres_repository_runtime.py`:
- Around line 29-49: Update the docstring example to use the real API: change
ModelDbOperation's mode from "select" to "read" and supply params as a dict
rather than a list (e.g., use params={"user_id": ...}), and ensure the
ModelDbReturn and PostgresRepositoryRuntime usage (and the
runtime.call("find_by_id", ...)) match the actual signatures; adjust the example
invocation and parameter shape accordingly so it compiles with ModelDbOperation,
ModelDbReturn, and PostgresRepositoryRuntime.

In
`@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`:
- Around line 46-54: The get_dsn function currently embeds hardcoded sensitive
defaults (POSTGRES_HOST and POSTGRES_PASSWORD); change its default values to
non-sensitive placeholders (e.g., POSTGRES_HOST default to "localhost" or "" and
POSTGRES_PASSWORD default to an obvious placeholder like "REQUIRED_OVERRIDE" or
empty string) and update the docstring or comment to state that these
environment variables must be provided for tests; ensure you only read
environment variables POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DATABASE,
POSTGRES_USER, POSTGRES_PASSWORD and construct the DSN the same way so CI/devs
must explicitly override the placeholders when running tests.
🧹 Nitpick comments (3)
tests/integration/runtime/db/test_postgres_repository_runtime_integration.py (1)

72-102: Test table not cleaned up after test run.

The test table is created but never dropped, leaving test artifacts in the database. Consider adding a module-level teardown or autouse fixture to clean up.

🧹 Proposed cleanup fixture
`@pytest.fixture`(scope="module", autouse=True)
async def cleanup_test_table(db_pool: asyncpg.Pool):
    """Clean up test table after all tests in module complete."""
    yield
    async with db_pool.acquire() as conn:
        await conn.execute(f"DROP TABLE IF EXISTS {_TEST_TABLE_NAME}")
src/omnibase_infra/runtime/db/postgres_repository_runtime.py (2)

78-80: SQL regex patterns have edge-case limitations.

The regex patterns won't correctly handle ORDER BY or LIMIT inside subqueries, string literals, or comments. Since contract SQL is developer-authored (not user input), this is acceptable, but worth documenting in the class docstring for awareness.


485-494: Docstring overstates fingerprint sanitization.

The docstring says "removes potentially sensitive values" but the implementation only truncates. Since parameter values aren't in the SQL (uses $1 placeholders), this is fine, but the docstring should be clarified.

📝 Proposed docstring fix
     def _fingerprint_sql(self, sql: str) -> str:
-        """Create a safe fingerprint of SQL for logging/errors.
-
-        Truncates long SQL and removes potentially sensitive values.
-        """
+        """Create a fingerprint of SQL for logging/errors.
+
+        Truncates long SQL to a reasonable length for diagnostics.
+        Note: Parameter values are not in the SQL (uses $1 placeholders).
+        """

Comment on lines +34 to +53
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... ops={
... "find_by_id": ModelDbOperation(
... mode="select",
... sql="SELECT * FROM users WHERE id = $1",
... params=["user_id"],
... returns=ModelDbReturn(many=False),
... ),
... },
... )
>>>
>>> # Create runtime with pool
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring example uses incorrect API.

The example shows mode="select" and params=["user_id"], but the actual ModelDbOperation expects mode="read" (or "write") and params as a dict[str, ModelDbParam]. This will cause errors if users copy-paste this example.

📝 Proposed fix
     >>> # Define contract
     >>> contract = ModelDbRepositoryContract(
     ...     name="users",
     ...     database_ref="primary",
+    ...     engine="postgres",
+    ...     tables=["users"],
+    ...     models={"User": "dict"},
     ...     ops={
     ...         "find_by_id": ModelDbOperation(
-    ...             mode="select",
+    ...             mode="read",
     ...             sql="SELECT * FROM users WHERE id = $1",
-    ...             params=["user_id"],
+    ...             params={"user_id": ModelDbParam(name="user_id", param_type="integer")},
     ...             returns=ModelDbReturn(many=False),
     ...         ),
     ...     },
     ... )
📝 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
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... ops={
... "find_by_id": ModelDbOperation(
... mode="select",
... sql="SELECT * FROM users WHERE id = $1",
... params=["user_id"],
... returns=ModelDbReturn(many=False),
... ),
... },
... )
>>>
>>> # Create runtime with pool
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
"""
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... engine="postgres",
... tables=["users"],
... models={"User": "dict"},
... ops={
... "find_by_id": ModelDbOperation(
... mode="read",
... sql="SELECT * FROM users WHERE id = $1",
... params={"user_id": ModelDbParam(name="user_id", param_type="integer")},
... returns=ModelDbReturn(many=False),
... ),
... },
... )
>>>
>>> # Create runtime with pool
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
🤖 Prompt for AI Agents
In `@src/omnibase_infra/runtime/db/__init__.py` around lines 34 - 53, Update the
docstring example to use the correct ModelDbOperation API: change mode="select"
to mode="read" (or "write" where appropriate) and replace params=["user_id"]
with a mapping of parameter names to ModelDbParam instances (e.g.,
params={"user_id": ModelDbParam(...)}), keeping ModelDbReturn as-is; ensure the
example still demonstrates creating ModelDbRepositoryContract, initializing
PostgresRepositoryRuntime, and calling runtime.call("find_by_id", 123) so it
matches the actual constructors/types (ModelDbRepositoryContract,
ModelDbOperation, ModelDbParam, ModelDbReturn, PostgresRepositoryRuntime.call).

Comment on lines +9 to +15
Exports:
ModelRepositoryRuntimeConfig: Configuration for PostgresRepositoryRuntime
- Safety constraints (max_row_limit, timeout_ms)
- Operation allowlisting (select, insert, update, upsert)
- Feature flags (allow_raw_operations, allow_delete_operations)
- Determinism controls (primary_key_column, default_order_by)
- Metrics emission configuration

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring references non-existent fields.

Lines 13-14 mention allow_raw_operations and allow_delete_operations, but the actual ModelRepositoryRuntimeConfig has allowed_modes and allow_write_operations.

📝 Proposed fix
 Exports:
     ModelRepositoryRuntimeConfig: Configuration for PostgresRepositoryRuntime
         - Safety constraints (max_row_limit, timeout_ms)
-        - Operation allowlisting (select, insert, update, upsert)
-        - Feature flags (allow_raw_operations, allow_delete_operations)
+        - Operation mode allowlisting (read, write)
+        - Feature flags (allow_write_operations)
         - Determinism controls (primary_key_column, default_order_by)
         - Metrics emission configuration
📝 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
Exports:
ModelRepositoryRuntimeConfig: Configuration for PostgresRepositoryRuntime
- Safety constraints (max_row_limit, timeout_ms)
- Operation allowlisting (select, insert, update, upsert)
- Feature flags (allow_raw_operations, allow_delete_operations)
- Determinism controls (primary_key_column, default_order_by)
- Metrics emission configuration
Exports:
ModelRepositoryRuntimeConfig: Configuration for PostgresRepositoryRuntime
- Safety constraints (max_row_limit, timeout_ms)
- Operation mode allowlisting (read, write)
- Feature flags (allow_write_operations)
- Determinism controls (primary_key_column, default_order_by)
- Metrics emission configuration
🤖 Prompt for AI Agents
In `@src/omnibase_infra/runtime/db/models/__init__.py` around lines 9 - 15, Update
the module docstring for ModelRepositoryRuntimeConfig to reference the actual
field names (allowed_modes and allow_write_operations) instead of the
nonexistent allow_raw_operations and allow_delete_operations; adjust the brief
descriptions to match the semantics of allowed_modes (operation allowlisting)
and allow_write_operations (write/delete permission flag) and ensure any other
listed fields (e.g., max_row_limit, timeout_ms, primary_key_column,
default_order_by, metrics config) remain accurate and consistent with the
ModelRepositoryRuntimeConfig definition.

Comment on lines +21 to +31
Example:
>>> config = ModelRepositoryRuntimeConfig(
... max_row_limit=100,
... timeout_ms=5000,
... allowed_ops={"select", "insert"},
... )
>>> print(config.allow_raw_operations)
False
>>> print("delete" in config.allowed_ops)
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.

⚠️ Potential issue | 🟡 Minor

Module docstring example references non-existent fields.

The example shows allowed_ops and allow_raw_operations, but the actual model defines allowed_modes and emit_metrics. This will confuse users.

📝 Proposed fix for the docstring example
 Example:
-    >>> config = ModelRepositoryRuntimeConfig(
-    ...     max_row_limit=100,
-    ...     timeout_ms=5000,
-    ...     allowed_ops={"select", "insert"},
-    ... )
-    >>> print(config.allow_raw_operations)
-    False
-    >>> print("delete" in config.allowed_ops)
-    False
+    >>> config = ModelRepositoryRuntimeConfig(
+    ...     max_row_limit=100,
+    ...     timeout_ms=5000,
+    ...     allowed_modes=frozenset({"read", "write"}),
+    ... )
+    >>> print(config.emit_metrics)
+    True
+    >>> print("write" in config.allowed_modes)
+    True
📝 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
Example:
>>> config = ModelRepositoryRuntimeConfig(
... max_row_limit=100,
... timeout_ms=5000,
... allowed_ops={"select", "insert"},
... )
>>> print(config.allow_raw_operations)
False
>>> print("delete" in config.allowed_ops)
False
"""
Example:
>>> config = ModelRepositoryRuntimeConfig(
... max_row_limit=100,
... timeout_ms=5000,
... allowed_modes=frozenset({"read", "write"}),
... )
>>> print(config.emit_metrics)
True
>>> print("write" in config.allowed_modes)
True
"""
🤖 Prompt for AI Agents
In `@src/omnibase_infra/runtime/db/models/model_repository_runtime_config.py`
around lines 21 - 31, Update the module docstring example for
ModelRepositoryRuntimeConfig to use the actual model fields: replace uses of
allowed_ops with allowed_modes and allow_raw_operations with emit_metrics (or
set emit_metrics to appropriate boolean), and ensure any membership checks
reference valid modes (e.g., "read" or "write") rather than "delete"; keep
max_row_limit and timeout_ms as shown and show correct printed values for the
real fields so the example matches the ModelRepositoryRuntimeConfig class
definition.

Comment on lines +29 to +49
>>> # Create contract
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... ops={
... "find_by_id": ModelDbOperation(
... mode="select",
... sql="SELECT * FROM users WHERE id = $1",
... params=["user_id"],
... returns=ModelDbReturn(many=False),
... ),
... },
... )
>>>
>>> # Create runtime (with pool)
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring example uses incorrect API.

Similar to the package __init__.py, this example shows mode="select" and params=["user_id"] which don't match the actual API (mode="read" and params as a dict).

📝 Proposed fix
     >>> # Create contract
     >>> contract = ModelDbRepositoryContract(
     ...     name="users",
     ...     database_ref="primary",
+    ...     engine="postgres",
+    ...     tables=["users"],
+    ...     models={"User": "dict"},
     ...     ops={
     ...         "find_by_id": ModelDbOperation(
-    ...             mode="select",
+    ...             mode="read",
     ...             sql="SELECT * FROM users WHERE id = $1",
-    ...             params=["user_id"],
-    ...             returns=ModelDbReturn(many=False),
+    ...             params={"user_id": ModelDbParam(name="user_id", param_type="integer")},
+    ...             returns=ModelDbReturn(model_ref="User", many=False),
     ...         ),
     ...     },
     ... )
📝 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
>>> # Create contract
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... ops={
... "find_by_id": ModelDbOperation(
... mode="select",
... sql="SELECT * FROM users WHERE id = $1",
... params=["user_id"],
... returns=ModelDbReturn(many=False),
... ),
... },
... )
>>>
>>> # Create runtime (with pool)
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
"""
>>> # Create contract
>>> contract = ModelDbRepositoryContract(
... name="users",
... database_ref="primary",
... engine="postgres",
... tables=["users"],
... models={"User": "dict"},
... ops={
... "find_by_id": ModelDbOperation(
... mode="read",
... sql="SELECT * FROM users WHERE id = $1",
... params={"user_id": ModelDbParam(name="user_id", param_type="integer")},
... returns=ModelDbReturn(model_ref="User", many=False),
... ),
... },
... )
>>>
>>> # Create runtime (with pool)
>>> pool = await asyncpg.create_pool(...)
>>> runtime = PostgresRepositoryRuntime(pool, contract)
>>>
>>> # Execute operation
>>> user = await runtime.call("find_by_id", 123)
"""
🤖 Prompt for AI Agents
In `@src/omnibase_infra/runtime/db/postgres_repository_runtime.py` around lines 29
- 49, Update the docstring example to use the real API: change
ModelDbOperation's mode from "select" to "read" and supply params as a dict
rather than a list (e.g., use params={"user_id": ...}), and ensure the
ModelDbReturn and PostgresRepositoryRuntime usage (and the
runtime.call("find_by_id", ...)) match the actual signatures; adjust the example
invocation and parameter shape accordingly so it compiles with ModelDbOperation,
ModelDbReturn, and PostgresRepositoryRuntime.

…RepositoryRuntime

- Change primary_key_column default from "pattern_id" to None (fail-fast)
- Change default_order_by default from "score DESC, pattern_id ASC" to None
- Add cleanup fixture to drop test table after integration tests complete
- Change db_pool fixture to module scope to support cleanup fixture

@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: 1

🤖 Fix all issues with AI agents
In
`@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`:
- Around line 403-438: The test
TestLearnedPatternsTable.test_query_learned_patterns_empty should not assume the
learned_patterns table is empty; instead, modify the assertion to validate
invariants about the returned rows from runtime.call("find_validated") — e.g.,
assert results is a list and for each row (returned model type from
ModelDbReturn "LearnedPattern") that row["status"] == "validated" (and
optionally other invariants like keys/id types or length <=
config.max_row_limit); alternatively, seed or clean the table before running the
test using the db_pool fixture so the test has a deterministic state.

Comment on lines +403 to +438
class TestLearnedPatternsTable:
"""Test against the real learned_patterns table schema."""

async def test_query_learned_patterns_empty(self, db_pool: asyncpg.Pool):
"""Test querying the actual learned_patterns table."""
contract = ModelDbRepositoryContract(
name="learned_patterns_repo",
engine="postgres",
database_ref="omninode_bridge",
tables=["learned_patterns"],
models={"LearnedPattern": "dict"},
ops={
"find_validated": ModelDbOperation(
mode="read",
sql="""
SELECT id, pattern_signature, domain_id, confidence, status
FROM learned_patterns
WHERE status = $1
ORDER BY confidence DESC, id ASC
""",
params={"status": ModelDbParam(name="status", param_type="string")},
returns=ModelDbReturn(model_ref="LearnedPattern", many=True),
safety_policy=ModelDbSafetyPolicy(),
),
},
)

config = ModelRepositoryRuntimeConfig(max_row_limit=10)
runtime = PostgresRepositoryRuntime(db_pool, contract, config)

# Query for validated patterns (table is empty, so expect empty list)
results = await runtime.call("find_validated", "validated")

assert isinstance(results, list)
# Table is empty based on our earlier check
assert len(results) == 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid assuming learned_patterns is empty.

This assertion will fail in any environment where the table already has data. Prefer asserting invariants (e.g., all returned rows are status == "validated") or seed/cleanup the table in the test DB.

✅ Suggested assertion change
-        # Table is empty based on our earlier check
-        assert len(results) == 0
+        assert all(r["status"] == "validated" for r in results)
📝 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
class TestLearnedPatternsTable:
"""Test against the real learned_patterns table schema."""
async def test_query_learned_patterns_empty(self, db_pool: asyncpg.Pool):
"""Test querying the actual learned_patterns table."""
contract = ModelDbRepositoryContract(
name="learned_patterns_repo",
engine="postgres",
database_ref="omninode_bridge",
tables=["learned_patterns"],
models={"LearnedPattern": "dict"},
ops={
"find_validated": ModelDbOperation(
mode="read",
sql="""
SELECT id, pattern_signature, domain_id, confidence, status
FROM learned_patterns
WHERE status = $1
ORDER BY confidence DESC, id ASC
""",
params={"status": ModelDbParam(name="status", param_type="string")},
returns=ModelDbReturn(model_ref="LearnedPattern", many=True),
safety_policy=ModelDbSafetyPolicy(),
),
},
)
config = ModelRepositoryRuntimeConfig(max_row_limit=10)
runtime = PostgresRepositoryRuntime(db_pool, contract, config)
# Query for validated patterns (table is empty, so expect empty list)
results = await runtime.call("find_validated", "validated")
assert isinstance(results, list)
# Table is empty based on our earlier check
assert len(results) == 0
class TestLearnedPatternsTable:
"""Test against the real learned_patterns table schema."""
async def test_query_learned_patterns_empty(self, db_pool: asyncpg.Pool):
"""Test querying the actual learned_patterns table."""
contract = ModelDbRepositoryContract(
name="learned_patterns_repo",
engine="postgres",
database_ref="omninode_bridge",
tables=["learned_patterns"],
models={"LearnedPattern": "dict"},
ops={
"find_validated": ModelDbOperation(
mode="read",
sql="""
SELECT id, pattern_signature, domain_id, confidence, status
FROM learned_patterns
WHERE status = $1
ORDER BY confidence DESC, id ASC
""",
params={"status": ModelDbParam(name="status", param_type="string")},
returns=ModelDbReturn(model_ref="LearnedPattern", many=True),
safety_policy=ModelDbSafetyPolicy(),
),
},
)
config = ModelRepositoryRuntimeConfig(max_row_limit=10)
runtime = PostgresRepositoryRuntime(db_pool, contract, config)
# Query for validated patterns (table is empty, so expect empty list)
results = await runtime.call("find_validated", "validated")
assert isinstance(results, list)
assert all(r["status"] == "validated" for r in results)
🤖 Prompt for AI Agents
In `@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`
around lines 403 - 438, The test
TestLearnedPatternsTable.test_query_learned_patterns_empty should not assume the
learned_patterns table is empty; instead, modify the assertion to validate
invariants about the returned rows from runtime.call("find_validated") — e.g.,
assert results is a list and for each row (returned model type from
ModelDbReturn "LearnedPattern") that row["status"] == "validated" (and
optionally other invariants like keys/id types or length <=
config.max_row_limit); alternatively, seed or clean the table before running the
test using the db_pool fixture so the test has a deterministic state.

Remove all default values for database configuration including the
production password that was exposed in source code. All PostgreSQL
environment variables are now required with no fallback defaults.

Changes:
- Add _check_postgres_env_vars() helper for validation
- Remove hardcoded host, port, database, user, and password defaults
- Use os.environ[] (raises KeyError) instead of os.getenv() with defaults
- Skip tests gracefully when env vars not configured

@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: 2

🤖 Fix all issues with AI agents
In
`@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`:
- Around line 249-250: Remove the explicit isinstance check for `results` in the
test; instead rely on duck typing by deleting the line `assert
isinstance(results, list)` so the existing `assert len(results) == 3` and
subsequent indexing of `results` in
test_postgres_repository_runtime_integration.py will naturally fail if `results`
doesn't behave like a sequence, keeping the test concise and according to the
coding guideline that forbids isinstance checks.
- Around line 26-29: Replace any direct ValueError raises from get_dsn() with
raising RepositoryConfigError and chain the original KeyError using "from e";
specifically locate get_dsn() in test_postgres_repository_runtime_integration.py
(and similar occurrences around lines 65-90) and change patterns like "raise
ValueError(...)" to "raise RepositoryConfigError(... ) from e" so the raised
exception is an OnexError subclass and preserves the causal context; ensure you
import/use RepositoryConfigError (instead of ValueError) and keep the original
exception variable (e) when chaining.

Comment on lines +26 to +29
from omnibase_infra.errors.repository import (
RepositoryContractError,
RepositoryValidationError,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use RepositoryConfigError with chaining instead of ValueError.
get_dsn() raises ValueError, which violates the OnexError-only policy and loses causal context. Prefer raising RepositoryConfigError chained from the underlying KeyError.

🔧 Suggested fix
 from omnibase_infra.errors.repository import (
     RepositoryContractError,
     RepositoryValidationError,
+    RepositoryConfigError,
 )
@@
-    is_configured, error_msg = _check_postgres_env_vars()
-    if not is_configured:
-        raise ValueError(error_msg)
-
-    host = os.environ["POSTGRES_HOST"]
-    port = os.environ["POSTGRES_PORT"]
-    database = os.environ["POSTGRES_DATABASE"]
-    user = os.environ["POSTGRES_USER"]
-    password = os.environ["POSTGRES_PASSWORD"]
+    try:
+        host = os.environ["POSTGRES_HOST"]
+        port = os.environ["POSTGRES_PORT"]
+        database = os.environ["POSTGRES_DATABASE"]
+        user = os.environ["POSTGRES_USER"]
+        password = os.environ["POSTGRES_PASSWORD"]
+    except KeyError as e:
+        _, error_msg = _check_postgres_env_vars()
+        raise RepositoryConfigError(error_msg) from e
     return f"postgresql://{user}:{password}@{host}:{port}/{database}"

As per coding guidelines, "Only raise OnexError or its subclasses - always use raise OnexError(...) from e pattern for error chaining".

Also applies to: 65-90

🤖 Prompt for AI Agents
In `@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`
around lines 26 - 29, Replace any direct ValueError raises from get_dsn() with
raising RepositoryConfigError and chain the original KeyError using "from e";
specifically locate get_dsn() in test_postgres_repository_runtime_integration.py
(and similar occurrences around lines 65-90) and change patterns like "raise
ValueError(...)" to "raise RepositoryConfigError(... ) from e" so the raised
exception is an OnexError subclass and preserves the causal context; ensure you
import/use RepositoryConfigError (instead of ValueError) and keep the original
exception variable (e) when chaining.

Comment on lines +249 to +250
assert isinstance(results, list)
assert len(results) == 3

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the test file and the specific lines mentioned
cat -n tests/integration/runtime/db/test_postgres_repository_runtime_integration.py | sed -n '240,260p'

Repository: OmniNode-ai/omnibase_infra

Length of output: 986


🏁 Script executed:

# Also check the full test function to understand context
cat -n tests/integration/runtime/db/test_postgres_repository_runtime_integration.py | sed -n '230,270p'

Repository: OmniNode-ai/omnibase_infra

Length of output: 2029


🏁 Script executed:

# Check if there are protocol definitions in omnibase_spi related to results/list
find . -path "*/omnibase_spi*" -name "*.py" -type f | head -20

Repository: OmniNode-ai/omnibase_infra

Length of output: 52


🏁 Script executed:

# Search for similar isinstance checks in test files to understand the pattern
rg "isinstance.*list" tests/integration/runtime/db/test_postgres_repository_runtime_integration.py -B 2 -A 2

Repository: OmniNode-ai/omnibase_infra

Length of output: 443


🏁 Script executed:

# Find the PostgresRepositoryRuntime class and its call method signature
rg "class PostgresRepositoryRuntime" -A 20 --type py

Repository: OmniNode-ai/omnibase_infra

Length of output: 2234


🏁 Script executed:

# Search for the call method in PostgresRepositoryRuntime
rg "def call\(" --type py -A 5 | grep -A 5 "PostgresRepositoryRuntime\|class\|def call"

Repository: OmniNode-ai/omnibase_infra

Length of output: 682


🏁 Script executed:

# Check the return type of the call method
fd "\.py$" -type f | xargs grep -l "PostgresRepositoryRuntime" | head -5

Repository: OmniNode-ai/omnibase_infra

Length of output: 240


🏁 Script executed:

# Get more context on what the call method returns
rg "async def call" --type py -B 2 -A 8 | head -100

Repository: OmniNode-ai/omnibase_infra

Length of output: 4408


Remove the explicit isinstance check and rely on duck typing.

Per the coding guidelines, isinstance checks should not be used. The subsequent assertions (len(results) == 3 and list indexing) will fail naturally with appropriate errors if results is not a list, validating the contract without an explicit type check.

♻️ Suggested cleanup
-        assert isinstance(results, list)
         assert len(results) == 3
🤖 Prompt for AI Agents
In `@tests/integration/runtime/db/test_postgres_repository_runtime_integration.py`
around lines 249 - 250, Remove the explicit isinstance check for `results` in
the test; instead rely on duck typing by deleting the line `assert
isinstance(results, list)` so the existing `assert len(results) == 3` and
subsequent indexing of `results` in
test_postgres_repository_runtime_integration.py will naturally fail if `results`
doesn't behave like a sequence, keeping the test concise and according to the
coding guideline that forbids isinstance checks.

…itations

Security hardening and documentation improvements from code review:

- Add Pydantic field validators for primary_key_column and default_order_by
  to ensure only safe SQL identifiers are accepted (prevents misconfiguration)
- Document regex-based SQL parsing limitations in postgres_repository_runtime.py
  including known edge cases (string literals, subqueries, comments)
- Add recommendations for handling complex queries in contracts
- Use explicit asyncio.TimeoutError instead of bare TimeoutError
- Add S608 suppression documentation explaining SQL injection safety
- Add return type annotations to MockAsyncRecord test helper methods
Resolve conflicts:
- pyproject.toml: Keep omnibase-core ^0.12.0 (includes v0.11.0 features)
- poetry.lock: Regenerated with updated dependencies
- Add module-scoped event_loop fixture to integration tests
  - Fixes pytest-asyncio ScopeMismatch error when db_pool (module-scoped)
    tries to use function-scoped event_loop
- Update INFRA_MAX_UNIONS test assertion from 115 to 117
  - Reflects 2 new union types in PostgresRepositoryRuntime:
    - call() return type: list[dict] | dict | None
    - _execute_with_timeout() return type: same pattern

@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: 1

🤖 Fix all issues with AI agents
In `@tests/unit/validation/test_validator_defaults.py`:
- Around line 100-102: The assertion for INFRA_MAX_UNIONS currently expects 117
but its failure message still mentions 115; update the assertion message
attached to the assert of INFRA_MAX_UNIONS to reflect the new expected value
(117) and keep the explanatory text (e.g., "INFRA_MAX_UNIONS should be 117
(non-optional unions only, X | None excluded)"), ensuring the assert for
INFRA_MAX_UNIONS and its message are consistent.

Comment on lines +100 to 102
assert INFRA_MAX_UNIONS == 117, (
"INFRA_MAX_UNIONS should be 115 (non-optional unions only, X | None excluded)"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update failure message to match the new expected constant.

The assertion now expects 117, but the message still says 115, which will confuse failures.

🔧 Proposed fix
-        assert INFRA_MAX_UNIONS == 117, (
-            "INFRA_MAX_UNIONS should be 115 (non-optional unions only, X | None excluded)"
-        )
+        assert INFRA_MAX_UNIONS == 117, (
+            "INFRA_MAX_UNIONS should be 117 (non-optional unions only, X | None excluded)"
+        )
📝 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
assert INFRA_MAX_UNIONS == 117, (
"INFRA_MAX_UNIONS should be 115 (non-optional unions only, X | None excluded)"
)
assert INFRA_MAX_UNIONS == 117, (
"INFRA_MAX_UNIONS should be 117 (non-optional unions only, X | None excluded)"
)
🤖 Prompt for AI Agents
In `@tests/unit/validation/test_validator_defaults.py` around lines 100 - 102, The
assertion for INFRA_MAX_UNIONS currently expects 117 but its failure message
still mentions 115; update the assertion message attached to the assert of
INFRA_MAX_UNIONS to reflect the new expected value (117) and keep the
explanatory text (e.g., "INFRA_MAX_UNIONS should be 117 (non-optional unions
only, X | None excluded)"), ensuring the assert for INFRA_MAX_UNIONS and its
message are consistent.

@jonahgabriel
jonahgabriel merged commit 9979ec0 into main Feb 1, 2026
19 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-1783-postgres-repository-runtime branch February 1, 2026 19:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant