# Todo 46.1 Mode Parity and Duplicate Call Safety Plan **Status:** done ## Result Added pre-side-effect duplicate ID rejection, ordered concurrent direct execution, and symmetric event-budget enforcement for direct and dual modes. Specification and quality gates passed with no Critical/Important findings. ## Goal Remove three review-confirmed sources of unsafe or unfair comparison behavior between `dual_agent` and `chat_agent_tools`. ## Scope - Detect provider tool-call IDs already declared in active direct-mode history before creating a new assistant transcript or executing handlers. - Prevent duplicate IDs within a batch and across rounds from causing repeated side effects. - Execute direct-mode batches concurrently while preserving provider call order in returned tool messages. - Apply `max_event_loops` acceptance to dual text events as well as direct provider calls. ## Boundaries - A duplicate provider call ID should fail the current runtime before the duplicate handler runs; do not invent a second invalid assistant/tool transcript. - Use ordinary `asyncio.gather` parity for this todo; bounded concurrency, conflict classes, terminal barriers, and timeout policy remain Todo 48. - Preserve visible reply streaming that occurred before a duplicate is detected. ## Files - Modify: `src/agent_lab/application/runtime.py` - Modify: `tests/test_debug_runtime.py` ## Requirement Execution Loop ### Plan 1. Add RED one-shot and session tests for duplicate provider IDs across rounds; handler call count must remain one. 2. Add a timing/overlap RED test proving two direct async handlers start before either finishes and replies retain input order. 3. Add RED dual-mode tests proving events after budget exhaustion are ignored and the loop terminates. 4. Implement pre-execution ID validation, concurrent direct execution, and symmetric budget acceptance. 5. Run focused/full verification and renewed reviews. ### Observe / Update Close Todo 46 only when both modes differ only in orchestration protocol, not duplicate safety, event budget, or handler scheduling semantics. ## Verification - `UV_CACHE_DIR=.uv-cache uv run pytest tests/test_debug_runtime.py -q` - `UV_CACHE_DIR=.uv-cache uv run pytest` - `git diff --check`