From 45bac749024a67e8176d176d358a23ac691470dc Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Mon, 25 May 2026 05:52:20 -0400 Subject: [PATCH 1/4] fix(OMN-11994): handler_wiring psycopg2 list adaptation for text[] columns Only apply psycopg2.extras.Json() to dict values, not list values. Lists intended for Postgres text[] columns (models_used, machines_used) were being wrapped in Json() producing malformed array literals. --- src/omnibase_infra/runtime/auto_wiring/handler_wiring.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/omnibase_infra/runtime/auto_wiring/handler_wiring.py b/src/omnibase_infra/runtime/auto_wiring/handler_wiring.py index 8ca03f5259..0ba695e528 100644 --- a/src/omnibase_infra/runtime/auto_wiring/handler_wiring.py +++ b/src/omnibase_infra/runtime/auto_wiring/handler_wiring.py @@ -805,9 +805,7 @@ def upsert(self, table: str, conflict_key: str, row: dict[str, object]) -> bool: ) conflict_columns = ", ".join(f'"{key}"' for key in conflict_keys) adapted_row = { - key: psycopg2.extras.Json(value) - if isinstance(value, (dict, list)) - else value + key: psycopg2.extras.Json(value) if isinstance(value, dict) else value for key, value in row.items() } # table/conflict_key/cols validated by _TABLE_NAME_RE — not raw user input From 2fafb2917b013d3f42e943e276e1bd48efa42692 Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Mon, 25 May 2026 06:13:25 -0400 Subject: [PATCH 2/4] test(OMN-11994): cover psycopg2 text array adaptation --- ...ection_handler_db_injection_integration.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tests/integration/runtime/test_projection_handler_db_injection_integration.py b/tests/integration/runtime/test_projection_handler_db_injection_integration.py index eac60d9df9..8c7a89962f 100644 --- a/tests/integration/runtime/test_projection_handler_db_injection_integration.py +++ b/tests/integration/runtime/test_projection_handler_db_injection_integration.py @@ -12,12 +12,15 @@ from __future__ import annotations import asyncio +import sys +import types from pathlib import Path from unittest.mock import MagicMock, patch import pytest from omnibase_infra.runtime.auto_wiring.handler_wiring import ( + _build_sync_db_adapter, _make_projection_dispatch_callback, _read_db_io_tables, ) @@ -404,3 +407,61 @@ def handle(self, input_data: dict) -> dict: assert result is None assert call_count[0] == 0 + + +@pytest.mark.integration +def test_sync_psycopg2_adapter_preserves_text_array_lists(monkeypatch: pytest.MonkeyPatch) -> None: + """The sync adapter must not JSON-wrap Postgres text[] values.""" + + captured_execute: dict[str, object] = {} + + class FakeJson: + def __init__(self, value: object) -> None: + self.value = value + + class FakeCursor: + def __enter__(self) -> FakeCursor: + return self + + def __exit__(self, *args: object) -> None: + return None + + def execute(self, sql: str, params: object) -> None: + captured_execute["sql"] = sql + captured_execute["params"] = params + + class FakeConnection: + closed = False + autocommit = False + + def cursor(self, *args: object, **kwargs: object) -> FakeCursor: + return FakeCursor() + + fake_extras = types.SimpleNamespace(Json=FakeJson, RealDictCursor=object) + fake_psycopg2 = types.SimpleNamespace( + connect=lambda dsn: FakeConnection(), + extras=fake_extras, + ) + + monkeypatch.setitem(sys.modules, "psycopg2", fake_psycopg2) + monkeypatch.setitem(sys.modules, "psycopg2.extras", fake_extras) + + adapter = _build_sync_db_adapter("postgresql://example") + result = adapter.upsert( + "swarm_runs", + "run_id", + { + "run_id": "run-1", + "models_used": ["qwen3", "gpt-5"], + "machines_used": ["worker-a", "worker-b"], + "metadata": {"source": "integration-test"}, + }, + ) + + assert result is True + params = captured_execute["params"] + assert isinstance(params, dict) + assert params["models_used"] == ["qwen3", "gpt-5"] + assert params["machines_used"] == ["worker-a", "worker-b"] + assert isinstance(params["metadata"], FakeJson) + assert params["metadata"].value == {"source": "integration-test"} From 824f33f355d5595c898ecf5f36f4a5add711f0bb Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Mon, 25 May 2026 06:34:04 -0400 Subject: [PATCH 3/4] chore(OMN-11994): rerun gates after OCC merge From d5d678775c7fb981ed468f088da7a1a971644bae Mon Sep 17 00:00:00 2001 From: jonahgabriel Date: Mon, 25 May 2026 06:43:31 -0400 Subject: [PATCH 4/4] style(OMN-11994): format handler wiring integration test --- .../test_projection_handler_db_injection_integration.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/runtime/test_projection_handler_db_injection_integration.py b/tests/integration/runtime/test_projection_handler_db_injection_integration.py index 8c7a89962f..2aad7d8132 100644 --- a/tests/integration/runtime/test_projection_handler_db_injection_integration.py +++ b/tests/integration/runtime/test_projection_handler_db_injection_integration.py @@ -410,7 +410,9 @@ def handle(self, input_data: dict) -> dict: @pytest.mark.integration -def test_sync_psycopg2_adapter_preserves_text_array_lists(monkeypatch: pytest.MonkeyPatch) -> None: +def test_sync_psycopg2_adapter_preserves_text_array_lists( + monkeypatch: pytest.MonkeyPatch, +) -> None: """The sync adapter must not JSON-wrap Postgres text[] values.""" captured_execute: dict[str, object] = {}