diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index 64612e2..dcceedc 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -16,6 +16,7 @@ out dozens of times. """ import asyncio +import hashlib import os import socket import subprocess @@ -54,9 +55,23 @@ TEST_TABLES = ( ) BACKEND_DIR = Path(__file__).resolve().parents[1] -_COMPOSE_PROJECT = "agp-pytest" -_EPHEMERAL_PG_PORT = 25432 -_EPHEMERAL_REDIS_PORT = 26379 + +# A hardcoded project name/port here would mean every concurrent checkout +# running `pytest` (e.g. several Claude Agent-tool subagents, each in their +# own ~/agp/workspace/task_ clone) fights over the exact same Docker +# Compose project and host ports -- one run's pytest_unconfigure teardown +# can yank the ephemeral Postgres out from under a completely unrelated +# concurrent run, surfacing as "connection was closed in the middle of +# operation" with no obvious cause. Confirmed live 2026-09-15 running 3 +# parallel subagents. Same root cause and fix pattern as the agent_core +# workspace/Docker-Compose collision documented in project_agp memory -- +# derive both the project name and the port from a hash of the checkout +# directory, so different concurrent checkouts land on different projects/ +# ports while the same checkout is stable across repeated runs. +_WORKSPACE_HASH = hashlib.sha256(str(BACKEND_DIR.parent).encode()).hexdigest()[:10] +_COMPOSE_PROJECT = f"agp-pytest-{_WORKSPACE_HASH}" +_EPHEMERAL_PG_PORT = 25400 + (int(_WORKSPACE_HASH, 16) % 100) +_EPHEMERAL_REDIS_PORT = 26300 + (int(_WORKSPACE_HASH, 16) % 100) # Set by pytest_configure() when it starts container(s) it owns; torn down in # pytest_unconfigure.