Put the last 14 files under the type gate, and fix what they were hiding - #418
Merged
Conversation
A coverage check of [tool.mypy].files against the tree found three directories with Python in them that nothing was checking: plugins/ (8 files), mutation_tests/ (5) and tests_e2e/ (1). The gate said "339 source files" and meant it, but "all of them" was never verified - so this checks. mutation_tests/ and tests_e2e/ were already clean. plugins/ was not. plugins/system_prompt/plugin.py had six errors, of two kinds: root = document.get_branch_root(parent_node_id) ... edge.target == root.id get_branch_root returns SceneNode | None - None for an id it does not know. It cannot be None here, because the guard fifteen lines up already returned early for a parent_node_id that is not in document.nodes. Rather than assert that with an ignore, the None branch now returns _create_pending() - the answer this plugin already has for "no usable parent", and the difference between an AttributeError and a sensible fallback if that guard ever changes. The other four were the familiar unnarrowed node state, in a generator that read `document.nodes[edge.source]` three separate times. A checker cannot tie a kind check on one subscript expression to a field read on another, and neither can a reader. It is a plain loop over one bound candidate now, with the same result: first match in edge order, or None. Two mypy settings come with plugins/: namespace_packages and explicit_package_bases. plugins/ is eight sibling directories each holding a plugin.py with no __init__.py anywhere - the layout the loader discovers by path - and without those two mypy maps all eight onto one module name and refuses to check any of them. Verified they change nothing for the existing files: the run is clean before and after. The gate now covers 353 source files and the coverage check reports no uncovered directory and no uncovered root module. Verified it still bites by injecting a deliberate type error into a plugin, a mutation test and api_provider - caught in all three. Test plan: full suite 3,285 passed / 20 skipped; the System Prompt plugin's own 23 tests pass. ruff clean. mypy clean across 353 files. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Problem
The gate said "339 source files" and meant it — but "all of them" was never
verified. Checking
[tool.mypy].filesagainst the tree found three directorieswith Python in them that nothing was checking:
plugins/mutation_tests/tests_e2e/What
plugins/was hidingplugins/system_prompt/plugin.py, two kinds of error:get_branch_rootreturnsSceneNode | None—Nonefor an id it does notknow. It cannot be
Nonehere: the guard fifteen lines up already returnsearly for a
parent_node_idthat is not indocument.nodes. Rather than assertthat with an ignore, the
Nonebranch now returns_create_pending()— theanswer this plugin already has for "no usable parent", and the difference
between an
AttributeErrorand a sensible fallback if that guard ever changes.The other four were the familiar unnarrowed node state, in a generator that read
document.nodes[edge.source]three separate times. A checker cannot tie a kindcheck on one subscript expression to a field read on another — and neither can a
reader. It is a plain loop over one bound candidate now, with the same result:
first match in edge order, or
None.Two settings come with
plugins/namespace_packagesandexplicit_package_bases.plugins/is eight siblingdirectories each holding a
plugin.pywith no__init__.pyanywhere — thelayout the loader discovers by path — and without those two, mypy maps all eight
onto one module name and refuses to check any of them ("Duplicate module named
'plugin'"). Verified they change nothing for the existing files: the run is
clean before and after.
Result
module.
mutation test and
api_provider— caught in all three.Test plan
ruff check .clean.mypyclean across 353 files.🤖 Generated with Claude Code