Commit Graph
4 Commits
Author SHA1 Message Date
Renn F dba4a378ad fix(gate): make the work-session invariant fix pass the full gate
Two failures the full make-quality flagged after 06adf978 landed on master:
- mypy: _second_agent (test helper) now returns the agent's UUID, so
  WorkSessionCreate(agent_id=...) receives a real uuid.UUID rather than the
  ORM column type.
- xenon: the single-active-per-task supersede is extracted out of
  _create_work_session_if_needed into _supersede_other_active_sessions,
  bringing the former back under complexity rank B.

No behavior change; 1566 work-session/gateway/service tests green.
2026-06-24 05:58:42 +02:00
Renn F 06adf9782d fix(run-hardening): enforce one active work session per task
A task re-claimed by a different agent (pool release, reaper unclaim,
escalation redirect) left the prior holder's active work session open.
WorkSessionService.get_active_for_task then ran a one-row query over the
duplicates and raised MultipleResultsFound; the caught failure surfaced
as the cryptic "'NoneType' object has no attribute 'id'" that crashed the
claim/plan/start flow — so the task could never advance, the orchestrator
re-spawned its PM every ~30s forever, and its dependents stayed blocked.

Fixed at three layers:
- active-session lookups return the most-recent session instead of raising
- claiming a task supersedes any other agent's stale active session
  (the single-active-per-task invariant), in both WorkSessionService.create
  and TaskService._create_work_session_if_needed
- a partial unique index (migration 047, which de-duplicates existing rows
  keeping the most recent) enforces it at the DB level; mirrored on the model

Verified: 1614 tests green (work_session + gateway + services), ruff/mypy
clean, migration chain applies + reverses, dedup proven on the real schema.
2026-06-24 05:35:15 +02:00
Renn F 9aa30fb945 100% Coverage 2026-05-06 21:02:31 +02:00
Renn F b6903490f1 + tests 2026-05-05 05:50:01 +02:00