Skip to content

refactor: group queue, owner, project and agents into packages (#863 M3) - #877

Merged
0xfauzi merged 2 commits into
mainfrom
refactor/863-m3-queue-owner-project-agents
Oct 13, 2026
Merged

0xfauzi merged 2 commits into
mainfrom
refactor/863-m3-queue-owner-project-agents

Conversation

@0xfauzi

@0xfauzi 0xfauzi commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Result

Slice M3 of #863. 16 modules move into the packages kstrl/queue/ (3), kstrl/owner/ (4), kstrl/project/ (7) and kstrl/agents/ (2 new: agent_output.py and sandbox.py). The 10 modules that were in kstrl/agents/ stay there. This PR merges into main at 5f6b22b1, which holds #876 (M2).

The interfaces in __all__ have these counts of names: queue 17, owner 28, project 43 and agents 26. Code in a different package imports only these names, and no shim stays at a previous path. kstrl/write_guard.py stays at the top level and imports no M3 package.

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 this branch.

  1. A first commit moves get_agent and UnknownAgentTypeError from kstrl/agents/__init__.py to the new module kstrl/agents/select.py, because a package __init__.py holds only its re-exports. The agents interface keeps its 7 previous names.
  2. move_slice.sh with the M3 map: git mv, the codemod, the pin re-sort, ruff and mypy.
  3. The interface step on the 4 packages: 184 imports in 76 files.
  4. A hand patch in 6 test files (below).

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

  • A binding table. loop.py reads DEFAULT_PROMPT in a function, and the interface step changed that import to the kstrl.project binding. test_delivered_prompts.py replaced the constant in scaffold_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.
  • A test with no subject. A B4 test in test_state_dir_scope.py imported Path from kstrl.agents, which re-exported pathlib.Path. After step 1, the resolver gives kstrl.agents.Path, and the test stayed green when Claude removed the edge of the package that it guards. At this time, it imports annotations, which comes from __future__. It is red when the edge goes.
  • A name list. The codemod changed the permitted text feedforward.py of test_retired_config_names.py to project/feedforward.py. Thus 7 lines that name the file were red. The file name did not change, thus the permitted text is feedforward.py again.
  • Census pins. project/__init__.py gets a row in 2 pins (the loader and the prompt names). One pin is sorted again, and 3 long lines are divided.

Measured

  • 10 plants against the changed code and guards: 10 caught, 0 hung, 0 could not plant.
  • Guard census: an audit hook recorded the 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__.py files and agents/select.py.
  • tools/back_edges.py: 0 before and 0 after. Each of the 230 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 **/kstrl/owner/waivers.py, 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. It wrote 53 records to events.jsonl and left no process. A claude session (haiku) wrote hello.txt through the write guard, and the guard stopped its write to a directory that is not in the worktree.
  • Import time (median of 15, three series): import kstrl.cli is 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/select and queue/workqueue. import kstrl.write_guard is 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 7922 passed, 81 skipped and 106 xfailed, 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.py changed their text, because their census labels changed (stack.py::_refusal is project/stack.py::_refusal).

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 10 of these guards.

🤖 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.

0xfauzi and others added 2 commits October 13, 2026 20:28
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
0xfauzi marked this pull request as ready for review October 13, 2026 20:53
@0xfauzi
0xfauzi merged commit 6309368 into main Oct 13, 2026
6 checks passed
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant