Skip to content

Three lint hooks are red in full-repo mode: blocking-IO, LLMResponse dict access, local schemas #15505

Open

Description

@mrveiss

Three tools/lint/ hooks exit 1 when run in full-repo mode on Dev_new_gui. Measured on the base of PR #15504, and unchanged by it — every path they flag is git-tracked and outside the excluded directories, so the previous rglob enumeration reached them identically. This is standing debt, surfaced by #14896's floor work rather than caused by it.

Hook Full-repo verdict
tools/lint/check_no_blocking_io_in_async.py 208 blocking-I/O calls inside async def bodies (#7444)
tools/lint/check_no_llm_response_dict_access.py 2 dict accesses on LLMResponse, both in autobot-backend/agents/base_modality_agent.py (lines 117, 126)
tools/lint/check_no_local_schemas.py Local BaseModel subclasses, first at autobot-backend/api/admin_pricing.py:23

None of the three is invoked full-repo by any workflow, and all three use pre-commit's default pass_filenames, so nothing merges on this today. That is exactly why it has accumulated: the staged-file path only ever sees the lines a PR touched.

Acceptance criteria

  • python3 tools/lint/check_no_llm_response_dict_access.py exits 0 on the full tree
  • python3 tools/lint/check_no_local_schemas.py exits 0 on the full tree
  • python3 tools/lint/check_no_blocking_io_in_async.py exits 0 on the full tree, or the remaining sites carry the documented NOQA_TOKEN with a per-site reason
  • Each hook that reaches 0 gets a full-repo invocation somewhere that can block a merge — a guard nothing runs at full scope drifts straight back

Activity

  1. added this to the v0.10.0 milestone on Sep 12, 2026
  2. mrveiss commented on Sep 27, 2026

    @mrveiss
    OwnerAuthor

    Status of AC3 after #17647, measured rather than estimated

    python3 tools/lint/check_no_blocking_io_in_async.py exits 0 on the full tree, or the remaining sites carry the documented NOQA_TOKEN with a per-site reason

    Still red, and this PR does not change that. Full-repo verdict at PR #17647's head, broken out by kind:

    kind count
    Path.read/write_text/bytes 192
    requests.* 0
    subprocess.* / sqlite3.connect / time.sleep / os.system 0 enforced

    So the whole remaining backlog is one kind. That is worth recording because it changes what AC3 costs: it is not 192 heterogeneous migrations, it is one mechanical substitution — aiofiles or await asyncio.to_thread(p.read_text, ...) — repeated across 192 sites, which can be batched by directory rather than triaged individually.

    Two things about the number that would otherwise mislead

    The 208 in the issue table is not comparable to 192. It was measured on Dev_new_gui at the time of filing, and the tree has moved since. I have not established how much of the difference is migration versus churn, and I am not claiming credit for the delta.

    The detector is now wider than when 208 was measured, so a count taken today looks at a larger class. #17647 added subprocess.run/call/check_call/check_output/Popen, sqlite3.connect, time.sleep, os.system, matched on (module, attr) with the receiver resolved through the file's imports. It found 4 production sites the narrower version had passed clean over, all now fixed — which is why the stdlib row reads 0 rather than being absent.

    A scope decision AC3 will have to take a position on

    The widened kinds are not enforced in test files: 18 hits live there, and a blocked loop in an async test is the test's own. A full-repo run prints that skipped count rather than hiding it, so 0 enforced and nothing there are distinguishable. If AC3 means "exits 0 including test files", those 18 are in scope and the exemption has to be revisited as an explicit decision; if it means production, the stdlib half is already met. The issue predates the distinction, so it does not say.

    AC4 is the one that matters most and is untouched

    Each hook that reaches 0 gets a full-repo invocation somewhere that can block a merge — a guard nothing runs at full scope drifts straight back

    Still true and still unaddressed. check_no_blocking_io_in_async.py uses pre-commit's default pass_filenames, so nothing runs it at full scope on a merge path. Reaching 0 without AC4 buys a number that decays.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions