diff --git a/NEXT_SESSION_PROMPT.md b/NEXT_SESSION_PROMPT.md index 90db89b5..69964072 100644 --- a/NEXT_SESSION_PROMPT.md +++ b/NEXT_SESSION_PROMPT.md @@ -1,155 +1,186 @@ -# Next session: keep splitting, tests first +# Next session: shell splits, tests first > **Paste this whole file into a fresh Claude session opened in `~/testsAndMisc`.** > It is self-contained. Do not go looking for the previous session's context. ## Where things stand -Over-cap: **41 → 37** (29 shell, 4 python, 2 kotlin, 1 dart, 1 markdown — the -markdown is this file). 12 commits, `6713ef3..ff1a1b6`, all pushed. +Over-cap: **37 → 25** (21 shell, 2 kotlin, 1 dart, 1 markdown — the markdown is +this file). 15 commits, `0cf487b..HEAD`, all pushed. -The C++ category is empty and the `system-maintenance/bin/` python is done: -every module there is under the cap at 100% line+branch coverage. +**Python is done.** Every `.py` in the repo is under the cap, at 100% line and +branch coverage where the gate measures it. The remaining work is shell, plus +three files in other languages. -## The method, which worked six times +## Tooling built last session — use it, don't rebuild it -1. **Measure coverage of the block you intend to move, first.** The failure - this catches is real: `_usage_report_parsing.py` was 39% covered and the - uncovered 61% was almost exactly the half a split would extract. Splitting - that first would have proved nothing. -2. **Tests land in their own commit, before the split.** Not negotiable — a - split verified by tests written alongside it is verified against the - post-split shape. -3. **Move code verbatim, then prove it.** Write a throwaway script that parses - HEAD and the new modules with `ast`, normalises each top-level def through - `ast.dump(ast.parse(ast.unparse(node)))`, and asserts identity. It caught a - literal `×` typed where the original had a `×` escape. Formatting-blind, - logic-sensitive; ~40 lines, worth rewriting each time. -4. **Rewrite import sites to name the owning module.** No re-export barrels. - Check the _whole_ graph: one split shipped with `usage_report.py` still - importing `_fmt_h` through the render module, and the commit message claimed - otherwise. -5. **Run the actual program.** Every unit test here stubs subprocesses, so only - a real run proves the import graph resolves. Run every entry point the split - touched, not just one. -6. Re-run every gate, commit one split at a time, with evidence. +Two scripts do the mechanical half. Both were validated before use; don't +re-derive them. -## Traps that cost time this session, in order of cost +**`meta/scripts/extract_shell_functions.py`** moves functions into a library: -- **`monkeypatch.setattr` must target the module whose namespace resolves the - name** — the caller's, not the one the function moved to. Getting this wrong - on `_run_since` made `main()` call the real function, which read the - machine's actual atop logs and **hung the suite** rather than failing. If a - pytest run stalls after a split, this is why. -- **Splitting a test file can put it over the cap.** Two commits added - over-cap files while fixing something else (`DropZone.test.tsx` 250 → 256 on - a lint fix; two new test files at 373 and 272). Check - `check_file_length.sh --all` _before_ committing, not after. -- **Don't move too much at once.** The `usage_report.py` split needed two - functions relocated after their first placement made an import cycle, plus - four modules' worth of patch targets re-pointed. Smaller slices are cheaper. -- **`TYPE_CHECKING` imports bite when code moves.** `Path`, `_fmt_h` and - `dataclass` each ended up importable only for type checking while used at - runtime. All three failed at first call; 100% coverage surfaced them at once. -- **A backgrounded `git push | tail` hides failure.** One push reported exit 0 - while printing `error: failed to push some refs`. Verify with - `git status -sb` showing no `[ahead N]`. +```bash +python3 meta/scripts/extract_shell_functions.py