fix(async-audit): Phase 3 cleanup — eliminate sync I/O in async routes#247
Merged
fix(async-audit): Phase 3 cleanup — eliminate sync I/O in async routes#247
Conversation
Wrap the remaining ASYNC* violations in src/ so the async-route audit hook reaches a clean state ahead of Phase 4 enforcement. src/main.py - ASYNC240 — snapshot detail route now calls a new ``_find_snapshot_file`` helper via ``asyncio.to_thread``, bundling ``exists`` + ``iterdir`` + ``stat`` into a single thread hop instead of three event-loop blocks. - ASYNC240 — snapshot create route runs ``Path.mkdir(parents=True, exist_ok=True)`` via ``asyncio.to_thread`` so a slow disk can't stall the loop. - ASYNC109 — ``api_remote_stop_workers`` keeps its ``timeout`` query parameter (it's a passthrough to the adapter, not a deadline for this handler) with a ``# noqa: ASYNC109`` and justification. src/backend/cascor_service_adapter.py - ASYNC110 — control-stream supervisor's ``while ...: await sleep(1)`` poll keeps its 1-second cadence with a ``# noqa: ASYNC110``; rewriting around ``asyncio.Event`` would require touching the stream callback chain we don't own and the 1s latency is well below any reconnect we care about. Verification: ``ruff check --select ASYNC src/`` reports "All checks passed!" The full pre-commit suite (black, isort, flake8, mypy, bandit, async-audit) is green on both files. Helper functions exercised with ad-hoc fixtures covering missing-dir, malformed-jsonl, hit, and miss paths. Refs: notes/ASYNC_ROUTE_AUDIT_HOOK_MIGRATION_PLAN.md (Phase 3) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Phase 3 of the async-route audit migration (see juniper-ml ASYNC_ROUTE_AUDIT_HOOK_MIGRATION_PLAN.md). Clears the remaining 5 ASYNC* violations in this repo so we can flip the hook from soft-fail to enforcement in Phase 4.
After this lands,
ruff check --select ASYNC src/reports All checks passed!Changes
src/main.pyGET /api/v1/snapshots/{snapshot_id}) now calls a new_find_snapshot_filehelper viaasyncio.to_thread. Previously didpath.exists()+path.iterdir()+snapshot_file.stat()inline (three sync stat-bound calls on the event loop); now bundled into a single thread hop.POST /api/v1/snapshots) wrapsPath(_snapshots_dir).mkdir(parents=True, exist_ok=True)inasyncio.to_threadso a slow disk can't stall the loop.api_remote_stop_workers'stimeout: int = 10parameter is a passthrough tobackend._adapter.stop_remote_workers, not a deadline for this handler. Silenced with# noqa: ASYNC109and a justification comment.src/backend/cascor_service_adapter.pywhile not self._shutdown and self.is_connected: await asyncio.sleep(1)keeps its 1s poll cadence with# noqa: ASYNC110. Rewriting aroundasyncio.Eventwould require touching the stream callback chain we don't own, and 1s latency is well below any reconnect we care about.New helpers in
src/main.py(added in a prior commit on this branch):_load_snapshot_history(history_file)— readssnapshot_history.jsonl; tolerates missing files and malformed lines._find_snapshot_file(snapshots_dir, snapshot_id)— bundlesexists+iterdir+statfor callers usingasyncio.to_thread.Verification
ruff check --select ASYNC src/exits clean[], malformed JSON tolerated, snapshot lookup hit/miss/missing-dir all behave correctlyTest plan
--exit-zeroandcontinue-on-erroroff after this lands)🤖 Generated with Claude Code