refactor: remove testing agent claim mechanism for concurrent testing

Remove the testing_in_progress claim/release mechanism from the testing
agent architecture. Multiple testing agents can now test the same feature
concurrently, simplifying the system and eliminating potential stale lock
issues.

Changes:
- parallel_orchestrator.py:
  - Remove claim_feature_for_testing() and release_testing_claim() methods
  - Remove _cleanup_stale_testing_locks() periodic cleanup
  - Replace with simple _get_random_passing_feature() selection
  - Remove startup stale lock cleanup code
  - Remove STALE_TESTING_LOCK_MINUTES constant
  - Remove unused imports (timedelta, text)

- api/database.py:
  - Remove testing_in_progress and last_tested_at columns from Feature model
  - Update to_dict() to exclude these fields
  - Convert _migrate_add_testing_columns() to no-op for backwards compat

- mcp_server/feature_mcp.py:
  - Remove feature_release_testing tool entirely
  - Remove unused datetime import

- prompts.py:
  - Update testing prompt to remove feature_release_testing instruction
  - Testing agents now just verify and exit (no cleanup needed)

- server/websocket.py:
  - Update AgentTracker to use composite keys (feature_id, agent_type)
  - Prevents ghost agent creation from ambiguous [Feature #X] messages
  - Proper separation of coding vs testing agent tracking

Benefits:
- Eliminates artificial bottleneck from claim coordination
- No stale locks to clean up after crashes
- Simpler crash recovery (no testing state to restore)
- Reduced database writes (no claim/release transactions)
- Matches intended design: random, concurrent regression testing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Auto
2026-01-23 15:30:31 +02:00
parent 874359fcf6
commit 486979c3d9
5 changed files with 83 additions and 247 deletions

View File

@@ -57,10 +57,6 @@ class Feature(Base):
# Dependencies: list of feature IDs that must be completed before this feature
# NULL/empty = no dependencies (backwards compatible)
dependencies = Column(JSON, nullable=True, default=None)
# Regression testing: prevent concurrent testing of the same feature
testing_in_progress = Column(Boolean, nullable=False, default=False, index=True)
# Last time this feature was tested (for session-based regression tracking)
last_tested_at = Column(DateTime, nullable=True, default=None)
def to_dict(self) -> dict:
"""Convert feature to dictionary for JSON serialization."""
@@ -76,9 +72,6 @@ class Feature(Base):
"in_progress": self.in_progress if self.in_progress is not None else False,
# Dependencies: NULL/empty treated as empty list for backwards compat
"dependencies": self.dependencies if self.dependencies else [],
# Regression testing fields
"testing_in_progress": self.testing_in_progress if self.testing_in_progress is not None else False,
"last_tested_at": self.last_tested_at.isoformat() if self.last_tested_at else None,
}
def get_dependencies_safe(self) -> list[int]:
@@ -240,23 +233,18 @@ def _migrate_add_dependencies_column(engine) -> None:
def _migrate_add_testing_columns(engine) -> None:
"""Add testing_in_progress and last_tested_at columns for regression testing.
"""Legacy migration - no longer adds testing columns.
These columns support atomic claiming of features for regression testing
and tracking when features were last tested in a session.
The testing_in_progress and last_tested_at columns were removed from the
Feature model as part of simplifying the testing agent architecture.
Multiple testing agents can now test the same feature concurrently
without coordination.
This function is kept for backwards compatibility but does nothing.
Existing databases with these columns will continue to work - the columns
are simply ignored.
"""
with engine.connect() as conn:
# Check existing columns
result = conn.execute(text("PRAGMA table_info(features)"))
columns = [row[1] for row in result.fetchall()]
if "testing_in_progress" not in columns:
conn.execute(text("ALTER TABLE features ADD COLUMN testing_in_progress BOOLEAN DEFAULT 0"))
conn.commit()
if "last_tested_at" not in columns:
conn.execute(text("ALTER TABLE features ADD COLUMN last_tested_at DATETIME DEFAULT NULL"))
conn.commit()
pass
def _is_network_path(path: Path) -> bool: