v0.67.0
feder-cr/invisible_dotsv0.67.0Sep 15, 2026by github-actions[bot]
Upgrading?
AI Summary
This release focuses on a comprehensive code audit to identify and remove dead code and unused functions. It introduces a new structural 'Gate' to ensure all top-level definitions in the source code are actually used by the product rather than just the test suite.
Key Highlights
- Introduced a structural 'Gate' to verify that top-level definitions in `src/aihawk` are registered or used by the product.
- Refactored `AGENT.RUN_TASK` to `tests/_loop.py` as it was only used by tests.
- Removed unused helper functions `CLEAN.RELEVANCE`, `CLEAN.CLEAN_STATS`, and `CLEAN.BLOCK_TAGS`.
- Refactored `SESSIONS.AROUND` and `SESSIONPLAN.DESCRIBE` to remove test-only artifacts.
- Fixed duplicate facts in storage handling by centralizing path logic.
Breaking Changes
- Moved `AGENT.RUN_TASK` from the main product to the test suite.
- Removed `SESSIONS.AROUND` and `SESSIONS._OPEN_LINK` entry points.
- Removed `CLEAN.RELEVANCE` and `CLEAN.CLEAN_STATS` functions.
- Modified `SESSIONPLAN.DESCRIBE` to align with the product's execution path.
New Features
- New structural 'Gate' mechanism to prevent adding dead surface code.
Full Release Notes
An audit for code that exists only because the tests grew up around it. Seven surfaces came out of src/aihawk and every one had the same shape: zero callers in the product, and enough callers in the suite to look load-bearing. AGENT.RUN_TASK WAS A SECOND WAY TO RUN THE AGENT LOOP. Its own docstring said so: "not called by the product - kept because the suite drives the loop through it, about twenty-five tests". Worse than unused, it took an object with list_tools and call_tool, which is the shape from before Link existed, while the product passes link.call and link.tools to Conversation.run. A reader of agent.py met two entry points with two different ideas of how a tool is reached, and one of them was imaginary. The convenience was real, so it moved to tests/_loop.py rather than being deleted. The e2e test that drove a real server through it now goes through Conversation.run, which is the path the product takes. SESSIONS.AROUND OFFERED ITSELF TO "ANYTHING EMBEDDING THIS", a user that does not exist: this is an application, and the only importer of sessions.py is cli.py. Eleven callers, all in two test modules. The argument it was written for is good and survives in tests/_sessions.py, because it is a rule about the suite: a test driving ONE conversation should still go through build_app and the routes, so the single case is exercised by the same code the many case uses. SESSIONS._OPEN_LINK WAS A SEAM NOTHING DECLARED. It was assigned in __init__ and reassigned from outside by two test modules - a convention a reader of the signature could not see and a reader of the assignment could not tell from an accident. It is a keyword argument now, so how a connection is made is part of the interface and the default is the product's one way. SESSIONPLAN.DESCRIBE WAS A SECOND MAPPING OF A PLAN ONTO THE SENTENCE a caller is told, beside the one in work.open, and the two were free to disagree the day a fifth field joined the sentence. It also described something that does not happen: between planning and launching, work.open can rewrite the settings and the exit note - that is how the helper browser comes to share main's exit - so the sentence is read from what was LAUNCHED and never from what was planned. A method on the plan quietly offered the other thing. Its six callers were all in one test file and now go through the function the product goes through. CLEAN.RELEVANCE AND CLEAN.CLEAN_STATS ARRIVED DEAD and stayed that way. Fifty seven lines scoring how much a model needs an element, and seven figures about what the cleaning saved, both imported with the server on 2026-09-06 and named by no commit since. clean_stats was in __all__ and had a test; relevance had neither, and the module docstring described it as part of how the file works - "the relevance score below orders and annotates" - so the file's own account of itself named a pass that does not run. What those two were really carrying is kept: that nothing here may drop an element, and that a reduction figure says nothing about whether the result is still usable. Both are the invariant at the top of the module, which is where a rule can act. CLEAN.BLOCK_TAGS was a tuple nothing read. TWO PLACES ALSO STOPPED HOLDING THE SAME FACT TWICE. storage.file_for owns the rule that turns a session id into a path, so chats.py and mcp/store.py each name only their own directory and neither spells the join. And a test migrated off the store.home re-export onto aihawk.storage.home, which is where home lives. THE GATE IS ON THE CLASS, NOT ON THE SEVEN NAMES. A list would stop those seven; the defect is that a surface can be added, be used only by its own tests, and look exactly like one the product depends on. So it asks the general question: every top-level function, class and constant in src/aihawk must be named somewhere in src/aihawk. Being registered excuses it, and that is structural - a decorator spelled .tool, .command or .group hands the object to FastMCP or to click, where the call happens over a wire or from a shell. Wrapping does not: dataclass and contextmanager hand the object straight back, so it is still called by name. Exporting it in __all__ does not count either, because __all__ is the claim under audit rather than evidence for it, and that is precisely where clean_stats was hiding. WHAT THE GATE DOES NOT SEE IS WRITTEN INTO IT. 178 definitions across 25 modules, with floors asserted so a scan that goes blind fails instead of printing the same clean line. Methods are out of scope: a method reaches the code as an attribute, and plan.describe and SessionPlan.describe are the same attribute name, so no scan can tell the dead one from the live one beside it. That one was found by reading, and this gate would not have found it. Suite 654 green, from a 642 baseline: one test went with clean_stats and thirteen arrived with the gate. Six known-bad inputs and five cases that must not fire, plus a mutation against the real tree - relevance put back into clean.py, which the gate names by file and line. The first three must-not-fire cases failed on the first run and the gate was right: a toy module whose own outermost function has no caller has a dead surface, so each fixture ends at a registered entry point, exactly as the package does.
Related Repositories
The AI that really does things. Any OS. Any Platform. The lobster way. 🦞
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
Reverse engineer anything with agents, from app behavior down to native binaries.
The open source coding agent.
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.