From fdfdc23b7240261f385dfc7847965ba5cd4777d4 Mon Sep 17 00:00:00 2001 From: Renn F Date: Mon, 22 Jun 2026 13:12:04 +0200 Subject: [PATCH] fix(orchestrator): give agent gate containers the test-DB env so the suite runs DB-backed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An agent's make quality runs against no Postgres, so the conftest skips every integration test and coverage collapses far below the 80% threshold — a self-hosted PM read 71% on a suite that is ~96% with a DB and chased it as a code regression. _append_gate_env now injects ROBOCO_TEST_DB_* (host/port/user/password/admin-db) from the orchestrator's own DB settings into each spawn; agents share the Docker network so the host resolves, and the conftest creates throwaway test databases isolated from the live one. The app runtime reads ROBOCO_DATABASE_*, never ROBOCO_TEST_DB_*, so this only feeds the test harness. Gated on toolchain_match_enabled, the faithful-gate flag. --- roboco/runtime/orchestrator.py | 33 ++++++++++++++++++++++++ tests/unit/runtime/test_gate_env.py | 40 +++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 tests/unit/runtime/test_gate_env.py diff --git a/roboco/runtime/orchestrator.py b/roboco/runtime/orchestrator.py index 8c273a26..105a8a9c 100644 --- a/roboco/runtime/orchestrator.py +++ b/roboco/runtime/orchestrator.py @@ -2085,6 +2085,38 @@ class AgentOrchestrator: if config.git_context.branch_name: cmd.extend(["-e", f"ROBOCO_BRANCH={config.git_context.branch_name}"]) + @staticmethod + def _append_gate_env(cmd: list[str]) -> None: + """Inject the test-DB env so an agent's gate runs the real, DB-backed + suite instead of a hollow unit-only subset. + + Without a reachable Postgres the conftest skips every integration test, + so coverage collapses far below the gate threshold and a role 'gates' + against a partial run (the failure that made a PM read 71% on a suite + that is ~96% with a DB). The values come from the orchestrator's own DB + settings; agents share the Docker network, so the host resolves. The app + runtime reads ROBOCO_DATABASE_*, never ROBOCO_TEST_DB_*, so this only + feeds the test harness and never changes live behaviour. Gated on the + same faithful-gate flag as interpreter matching — both exist to make an + agent's self-gate trustworthy. + """ + if not settings.toolchain_match_enabled: + return + cmd.extend( + [ + "-e", + f"ROBOCO_TEST_DB_HOST={settings.database_host}", + "-e", + f"ROBOCO_TEST_DB_PORT={settings.database_port}", + "-e", + f"ROBOCO_TEST_DB_USER={settings.database_user}", + "-e", + f"ROBOCO_TEST_DB_PASSWORD={settings.database_password}", + "-e", + "ROBOCO_TEST_DB_ADMIN_DB=postgres", + ] + ) + @staticmethod def _default_spawn_prompt() -> str: """Fallback prompt when the caller provided none.""" @@ -2222,6 +2254,7 @@ class AgentOrchestrator: cmd = self._build_mount_args(container_name, config, hosts) self._append_agent_auth_env(cmd, config) self._append_git_context_env(cmd, config) + self._append_gate_env(cmd) self._append_image_and_claude_args(cmd, config, initial_prompt) proc = await asyncio.create_subprocess_exec( diff --git a/tests/unit/runtime/test_gate_env.py b/tests/unit/runtime/test_gate_env.py new file mode 100644 index 00000000..bbfcfb33 --- /dev/null +++ b/tests/unit/runtime/test_gate_env.py @@ -0,0 +1,40 @@ +"""Faithful-gate env injection. + +An agent's gate (`make quality` / pytest) needs a reachable Postgres or the +conftest skips every DB-backed integration test and coverage collapses far +below the threshold — a hollow gate. `_append_gate_env` injects the test-DB +connection (from the orchestrator's own settings) so the agent runs the real +suite, gated on the same faithful-gate flag as interpreter matching. +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from roboco.config import settings +from roboco.runtime.orchestrator import AgentOrchestrator + +if TYPE_CHECKING: + import pytest + + +def test_gate_env_injects_test_db_when_flag_on(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(settings, "toolchain_match_enabled", True) + monkeypatch.setattr(settings, "database_host", "roboco-postgres") + monkeypatch.setattr(settings, "database_port", 5432) + monkeypatch.setattr(settings, "database_user", "roboco") + monkeypatch.setattr(settings, "database_password", "s3cret") + cmd: list[str] = [] + AgentOrchestrator._append_gate_env(cmd) + assert "ROBOCO_TEST_DB_HOST=roboco-postgres" in cmd + assert "ROBOCO_TEST_DB_PORT=5432" in cmd + assert "ROBOCO_TEST_DB_USER=roboco" in cmd + assert "ROBOCO_TEST_DB_PASSWORD=s3cret" in cmd + assert "ROBOCO_TEST_DB_ADMIN_DB=postgres" in cmd + + +def test_gate_env_inert_when_flag_off(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(settings, "toolchain_match_enabled", False) + cmd: list[str] = [] + AgentOrchestrator._append_gate_env(cmd) + assert cmd == []