* [420e5e68] Fix mypy errors in tests/unit/ and create tests/__init__.py (#154)
* [420e5e68] fix(tests): resolve all mypy errors in tests/unit/ and create tests/__init__.py
- Create tests/__init__.py as empty package marker
- Add Any import and fix list type annotation in test_flow_server_intent_public_mapping.py
- Move AsyncIterator to TYPE_CHECKING block and fix m.cls.__name__ attr error in test_app.py
- Add return type annotations to _stub_get_optimal, _source, and factory functions
- Implement abstract methods (index_type, prepare_metadata, build_source_uri) in _FakePlugin
- Add pyproject.toml per-file-ignore for ARG002 on test_optimal_grounding.py stub
- Remove 4 stale # type: ignore comments from test_rate_limit_tracker.py
- Fix method-assignment patterns in test_rate_limit_sweep.py via patch.object
- All 487 source files pass mypy with 0 errors; 2312 unit tests pass
* [420e5e68] fix(tests): move stdlib/third-party imports to TYPE_CHECKING blocks across tests/unit/
Resolves 6 remaining ruff TC002/TC003 errors from the quality gate:
- test_handlers.py: Iterator → TYPE_CHECKING
- test_quality_gate.py: pathlib → TYPE_CHECKING
- test_board_dispatch.py: AsyncIterator + httpx → TYPE_CHECKING
- test_streaming.py: Iterator → TYPE_CHECKING
- test_notification.py: AsyncIterator → TYPE_CHECKING
All files have from __future__ import annotations so annotations are strings
at runtime; no runtime NameError risk from moving to TYPE_CHECKING.
* [420e5e68] fix(tests): use forward-ref cast() and drop unused TYPE_CHECKING import in 4 test files
* [420e5e68] chore(Makefile): scope lint mypy target to roboco/ to match gate and quality targets
---------
* [b0c9d41b] Fix mypy errors in tests/integration/ tests/foundation/ tests/property/ and update Makefile quality gates (#155)
* [b0c9d41b] fix(tests): resolve all mypy errors in tests/integration/, tests/foundation/, tests/property/
- Add missing type annotations to inner functions (_override_db, _override_agent_id, _req, etc.)
- Use cast("UUID", ...) to fix SQLAlchemy UUID vs uuid.UUID arg-type mismatches
- Remove stale # type: ignore comments from test_full_lifecycle_real_db.py and test_task_service_lifecycle_misc.py
- Update Makefile quality/quality-fast targets to run mypy on roboco/ tests/
- No runtime logic changed — annotations and cast() only
* [b0c9d41b] fix(tests): apply ruff TC006 quoted-cast and AsyncGenerator[T] fixes to complete mypy gate
- Quote all cast() type arguments per ruff TC006 rule (cast("T", x))
- Change AsyncGenerator[T, None] to AsyncGenerator[T] (Python 3.12 form)
- Move runtime-only imports to TYPE_CHECKING blocks (Path, Table, Generator, etc.)
- No runtime logic changed — annotation-only changeset
* [b0c9d41b] fix(Makefile): align lint target mypy scope with gate target (roboco/ only)
The lint target used `uv run mypy .` (all files) while gate uses `uv run mypy
roboco/`. This inconsistency caused the pre-submit gate to fail on 161 pre-existing
tests/unit/ errors (being fixed by sibling task 420e5e68). The quality/quality-fast
targets already check `roboco/ tests/` — the lint target now matches gate scope.
---------
---------
Co-authored-by: Backend Developer 1 <be-dev-1@agents.roboco.dev>
Co-authored-by: Backend Developer 2 <be-dev-2@agents.roboco.dev>
#170 made the closure dispatcher auto-resume a `paused` parent before
respawning its PM, but only `paused`. A parent that is `blocked` at
closure (every descendant already terminal) is an errant/stale block —
a child's i_am_blocked propagated, or a PM blocked it and never
unblocked — the real dependency is already done. #170 left it as-is, so
the respawned PM landed on a blocked parent it cannot submit_up /
complete and had to manually `unblock` it first (needs journal:decision)
— which models do not reliably do, wedging the whole closure chain
forever (observed end-to-end this run: leaf stuck awaiting_pm_review,
cell parent blocked, root paused, PMs cycling indefinitely).
Add `_auto_recover_blocked_parent` (mirrors `_auto_resume_paused_parent`)
and recover `blocked` symmetrically to `paused` in
`_maybe_spawn_pm_closure`. `blocked -> in_progress` is lifecycle-valid —
it is exactly what `unblock(restore=True)` performs. Scoped to the
closure-spawn point (descendants terminal) so a live dependency block is
never auto-cleared. Best-effort, like the paused path. 4 new tests
mirror the #170 suite (recovered-before-spawn, mutual exclusivity with
paused, patch shape, error-swallowing). make quality green.
A PM auto-pauses its owned parent on i_am_idle (by design — so the
closure dispatcher knows to respawn it when subtasks finish).
Pre-gateway the parent was resumed at respawn so the PM landed
actionable; the gateway refactor dropped that, so the respawned PM had
to issue resume() itself. minimax reliably failed to (called resume on
the leaf / unblock on the paused root), wedging smoke-15 — the leaf
stayed awaiting_pm_review and the chain never completed.
Restore the pre-gateway behaviour: _maybe_spawn_pm_closure now calls
new _auto_resume_paused_parent (paused -> in_progress via the same
PATCH path _auto_block_task uses) immediately before spawning the PM,
but only when the parent is actually `paused` (awaiting_pm_review /
in_progress parents untouched). Best-effort: a resume failure is
logged and swallowed so it never blocks the spawn (the PM can still
resume manually). The parent stays assigned to the PM, so it lands on
its own in_progress task able to submit_up / complete / escalate
directly — no reliance on the weak model issuing resume().
Combined with 4090397 (exact-complete remediate), this closes the
smoke-15 PM-completion wedge end to end.