Repository navigation
refactor: group queue, owner, project and agents into packages (#863 M3) - #877
Merged
Merged
Conversation
Rule 1 of the #863 package rule: a package __init__.py holds only its re-exports. get_agent and UnknownAgentTypeError move without change to a new module in the agents package. The package interface keeps the same seven names. The B4 test of a re-export from outside kstrl read the pathlib.Path that this __init__.py imported. It reads the __future__ binding now, because with Path the resolver gives a kstrl name and the test was green without the edge that it guards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RexDjjKvNJRfe6yxbyuhdf
The codemod moves 16 modules into kstrl/queue/, kstrl/owner/, kstrl/project/ and kstrl/agents/ and rewrites each reference. agent_output.py and sandbox.py go to agents. The interface pass gives each of the four packages an __init__.py with its interface in __all__, and code in a different package imports only those names. The agents interface keeps its seven previous names. No shim stays at an old path. The hand edits: loop.py reads DEFAULT_PROMPT in a function from the kstrl.project interface, thus the binding table of test_delivered_prompts.py names the package. Three long lines are divided, and one pin is sorted again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RexDjjKvNJRfe6yxbyuhdf
0xfauzi
marked this pull request as ready for review
October 13, 2026 20:53
0xfauzi
added a commit
that referenced
this pull request
Oct 18, 2026
…es (#863 M4) (#878) ## Result Slice M4 of #863. 37 modules move into the packages `kstrl/verify/` (11), `kstrl/knowledge/` (4), `kstrl/learning/` (12) and `kstrl/architect/` (10). The branch has one commit on `main` at `63093687`, which holds #877 (M3). The interfaces in `__all__` have these counts of names: `verify` 44, `knowledge` 8, `learning` 36 and `architect` 15. Code in a different package imports only these names. No shim stays at a previous path. No prompt body changes. ## Method The tools of the plan made the diff. `regen.sh` in the lane notes makes it again from `origin/main`, and it gave the same tree as the tested tree. 1. `move_slice.sh` with the M4 map: `git mv`, the codemod, the pin re-sort, ruff and mypy. 2. The interface step on the 4 packages: 151 imports in 53 files. 3. A hand patch in 10 files (below). The codemod rewrote 544 imports, 352 strings, 42 module aliases, 21 comments, 4 attribute chains, 194 census labels and 76 tokens in 16 text files. Claude examined each of its 40 UNCERTAIN and 205 REVIEW lines. ## Defects that the move caused - **A test with no subject.** `ks check` imports `run_mechanical_verification` in a function from the `kstrl.verify` interface. The codemod changed the patch string of two tests in `test_check_baseline_cli.py` to `kstrl.verify.verify.run_mechanical_verification`. The spy then counted 0 uses, and each test asserts 0, thus the tests stayed green. A plant that operates the checks before the digest refusal stayed green with the codemod string. At this time, the patch names the package binding, and the plant is red. - **A binding.** `ks evolve` reads `EvolutionJournal` with the same procedure. `test_config_control_plane.py` replaced it in `evolution.py` and was red. At this time, it replaces the package binding. - **A name list.** The codemod changed `NOT_WRITERS` of `test_ladder_inputs_have_writers.py` to package labels, but the guard compares it with `path.name`. The list holds file names again. - **A snippet label.** The journal guard lets only `learning/evolution.py` write the journal, but a snippet in `tmp_path` gets the label `evolution.py`. At this time, the guard labels a snippet relative to the root that the test gives. - **Pins.** `test_spec_reads_pinned.py` gets 2 rows for `architect/__init__.py`. A planted pin in `test_census_pins_have_no_line_numbers.py` names `verify/verify.py`. CLAUDE.md names the 3 role modules that moved. 4 long lines are divided. ## Measured - 9 plants against the changed code and guards: 9 caught, 0 hung, 0 could not plant. The demonstration plant above stayed green with the codemod string. - Prompts: the sha256 of each of the 51 enrolled prompt bodies and the 6 `SCAFFOLDED_TEMPLATES` rows are the same before and after. - Guard census: an audit hook recorded the `kstrl/` files that each test opens, in the full suite before and after. The only new files are the 4 new `__init__.py` files. One test read no file in the second full suite, because the parse cache of its worker was full. Alone, it reads 235 files (231 before, plus the 4 new files). - The import closure of `kstrl.loop` in `test_state_dir_scope.py` holds more modules, because an import of `kstrl.verify` loads its interface. It gets to no writer. - `tools/back_edges.py`: 0 before and 0 after. Each of the 234 modules imports alone in a new process. - complexipy and the cyclomatic values: the same for each of the 2435 and 2483 functions before and after. - `policy.ENFORCEMENT_MACHINERY_PATHS` names the 9 moved machinery files with their new paths, and the test of the rows finds each file. - `ks --help`, `python -m kstrl --help` and `python -I -m kstrl.write_guard --ready` operate. - A `ks factory` subprocess with a stub engineer on a scratch project completed its component. Verification operated the `[stack]` check `stack:tests`. The factory wrote 53 records to `events.jsonl` and left no process. - Import time (median of 15, three series): `import kstrl.cli` is 103.1, 103.0 and 103.3 ms before and 107.6, 104.4 and 107.0 ms after, with 199 and 206 kstrl modules. The 7 new modules are the 4 packages and 3 modules of the `learning` interface (`autonomy_replay`, `evolve_report` and `health`, which also loads `statistics`). `import kstrl.write_guard` stays at 9 kstrl modules (8.5, 8.4 and 8.7 ms before, 8.5, 8.4 and 8.6 ms after). ## Tests The full suite (`-n 4`) on the last tree gave 7922 `passed`, 81 `skipped` and 106 `xfailed`, with 0 failures. Before the move it gave the same counts, and each test has the same outcome (`junit_diff.py`). The collected tests stay at 8109. 14 parametrized ids changed their text, because their census labels or source snippets changed: 7 in `test_config_guard.py` and 7 in `test_inbox_write_guards.py`. ## Limits - complexipy and the cyclomatic ratchet read a moved function as new. The commit used `SKIP=complexipy,cyclomatic-ratchet` after Claude compared the values above. - The census of reads does not show a guard that reads the same files but compares a changed text. The plants examine 9 of these guards. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01RexDjjKvNJRfe6yxbyuhdf Merge gate, tree merged with main 6309368: mypy strict, ruff, pre-commit and gen_docs pass on the Mac. CI runs the full suite on Linux on this tree before merge.
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.
Result
Slice M3 of #863. 16 modules move into the packages
kstrl/queue/(3),kstrl/owner/(4),kstrl/project/(7) andkstrl/agents/(2 new:agent_output.pyandsandbox.py). The 10 modules that were inkstrl/agents/stay there. This PR merges intomainat5f6b22b1, which holds #876 (M2).The interfaces in
__all__have these counts of names:queue17,owner28,project43 andagents26. Code in a different package imports only these names, and no shim stays at a previous path.kstrl/write_guard.pystays at the top level and imports no M3 package.Method
The tools of the plan made the diff.
regen.shin the lane notes makes it again fromorigin/main, and it gave the same tree as this branch.get_agentandUnknownAgentTypeErrorfromkstrl/agents/__init__.pyto the new modulekstrl/agents/select.py, because a package__init__.pyholds only its re-exports. Theagentsinterface keeps its 7 previous names.move_slice.shwith the M3 map:git mv, the codemod, the pin re-sort, ruff and mypy.The codemod rewrote 408 imports, 258 strings, 14 module aliases, 16 comments, 124 census labels and 25 tokens in 11 text files. Claude examined each of its 17 UNCERTAIN and 127 REVIEW lines.
Defects that the move caused
loop.pyreadsDEFAULT_PROMPTin a function, and the interface step changed that import to thekstrl.projectbinding.test_delivered_prompts.pyreplaced the constant inscaffold_templates, thus it was red for the engineer role. At this time, its table names the package. Claude examined each of the 80 function-level imports that the interface step changed. No other test replaces one of their names through a different binding.test_state_dir_scope.pyimportedPathfromkstrl.agents, which re-exportedpathlib.Path. After step 1, the resolver giveskstrl.agents.Path, and the test stayed green when Claude removed the edge of the package that it guards. At this time, it importsannotations, which comes from__future__. It is red when the edge goes.feedforward.pyoftest_retired_config_names.pytoproject/feedforward.py. Thus 7 lines that name the file were red. The file name did not change, thus the permitted text isfeedforward.pyagain.project/__init__.pygets a row in 2 pins (the loader and the prompt names). One pin is sorted again, and 3 long lines are divided.Measured
kstrl/files that each test opens, in the full suite before and after. Each test reads each file that it read before. The only new files are the 3 new__init__.pyfiles andagents/select.py.tools/back_edges.py: 0 before and 0 after. Each of the 230 modules imports alone in a new process.policy.ENFORCEMENT_MACHINERY_PATHSnames**/kstrl/owner/waivers.py, and the test of the rows finds each file.ks --help,python -m kstrl --helpandpython -I -m kstrl.write_guard --readyoperate.ks factorysubprocess with a stub engineer on a scratch project completed its component. It wrote 53 records toevents.jsonland left no process. A claude session (haiku) wrotehello.txtthrough the write guard, and the guard stopped its write to a directory that is not in the worktree.import kstrl.cliis 107.4, 105.5 and 106.0 ms before and 105.0, 108.7 and 106.6 ms after, with 194 and 199 kstrl modules. The 5 new modules are the 3 packages,agents/selectandqueue/workqueue.import kstrl.write_guardis 8.9, 8.8 and 8.8 ms before and 8.5, 9.0 and 8.4 ms after, with 9 kstrl modules.Tests
The full suite (
-n 4) on the last tree gave 7922passed, 81skippedand 106xfailed, with 0 failures. Before the move it gave the same counts. Each test has the same outcome before and after (junit_diff.py).The collected tests stay at 8109. 7 parametrized ids in
test_inbox_write_guards.pychanged their text, because their census labels changed (stack.py::_refusalisproject/stack.py::_refusal).Limits
SKIP=complexipy,cyclomatic-ratchetafter Claude compared the values above.🤖 Generated with Claude Code
https://claude.ai/code/session_01RexDjjKvNJRfe6yxbyuhdf
Merge gate, tree merged with main 5f6b22b: mypy strict, ruff, pre-commit and gen_docs pass on the Mac. CI runs the full suite on Linux on this tree before merge.