The user has decided all three of the questions the previous brief left open: fix the _VENDOR_KW Intel bug, split the phone_focus_mode scripts despite the deployment coupling, and restructure the three parked files. Records them as instructions rather than open questions, with the specific facts each needs. For the phone splits, accepting the risk does not mean skipping the copy lists: deploy.sh has two hardcoded per-file lists and never deploys lib/, so the brief now spells out that both must grow and that the seam is a sibling file. dns_enforcer.sh and lib/monitor.sh are called out first because both have runnable tests, so those splits can be proved the way tether_enforcer was. config.sh is flagged separately - focus_policy/loader.py parses it. For the restructuring, notes that verify_shell_split.sh no longer applies once code stops being a verbatim move, so each of the three needs a test or a real run instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
12 KiB
Next session: three explicit asks, then keep splitting
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.
Over-cap: 37 → 24 (20 shell, 2 kotlin, 1 dart, 1 markdown — this file).
17 commits pushed. Python is done: every .py is under the cap at 100%
line+branch coverage where the gate measures it.
The user has given three direct instructions. Do them in this order, each as its own commit. They are already decided — do not re-litigate them.
1. Fix the _VENDOR_KW Intel bug
python_pkg/vscode_optimizer/_hardware.py:22:
_VENDOR_KW = {"nvidia": "NVIDIA", "amd": "AMD", "ati": "AMD", "intel": "Intel"}
_detect_gpu does for kw, vendor in _VENDOR_KW.items(): if kw in low:.
Every real lspci display line contains "VGA compatible controller", so
"ati" matches unconditionally and "intel" is unreachable. Intel iGPUs are
reported as AMD, which switches on the GPU-accelerated terminal and AMD-only
Electron flags. This machine is unaffected only because "nvidia" is checked
first.
Do:
- Fix it so vendor detection keys on the device description rather than the
whole line — the text after the last
:is already extracted intohw.gpu_modelone line above. Match against that, notlow. - Delete the
strict=Truexfailtest_detect_gpu_should_recognise_an_intel_igpuinpython_pkg/vscode_optimizer/tests/test_gpu_disk.pyand make it a normal passing test. The xfail isstrict=True, so a fix without removing the marker fails the suite — that is deliberate. - The parametrised
test_detect_gpu_maps_each_vendor_keywordcurrently characterises the bug: two of its cases assert"AMD"for an Intel line and for an unknown vendor. Update both to the correct expectations. - Verify with a real run:
python3 -m python_pkg.vscode_optimizer --dry-runmust still detect this machine's RTX 3090 as NVIDIA and propose the same 18 changes. Then confirm the repo gate: barepytest(memory-capped) at 100%.
2. Split the phone_focus_mode scripts anyway
The user has accepted the deployment risk. This does not mean skip the copy lists — it means proceed with the splits, doing them correctly.
deploy.sh has two hardcoded per-file lists and never deploys lib/:
- an
adb_cmd push "$DEPLOY_DIR/<f>" "/data/local/tmp/focus_stage/<f>"(~line 381) - an
adb_root "cp /data/local/tmp/focus_stage/<f> $REMOTE_DIR/<f>"(~line 497)
Every new sibling must be added to BOTH, in the same commit. Missing the
push leaves the copy pointing at a file that was never staged. Use a sibling
file beside the entry script, never a lib/ member — these scripts source
"$SCRIPT_DIR/<name>.sh" and lib/ does not exist on the phone.
tether_enforcer.sh was done last session and is the worked example — read that
commit before starting.
Targets, cheapest first, with what can verify each:
| file | lines | verifiable by |
|---|---|---|
dns_enforcer.sh |
325 | lib/tests/test_dns_enforcer.sh — runnable |
phone_backup.sh |
333 | no test; not in deploy.sh's lists at all |
curfew_enforcer.sh |
367 | no test |
hosts_enforcer.sh |
421 | no test |
lib/monitor.sh |
449 | lib/tests/test_monitor.sh — runnable; already a lib, not deployed by deploy.sh |
focus_daemon.sh |
543 | no test |
config.sh |
571 | python_pkg/focus_policy/loader.py parses it — see below |
deploy.sh |
835 | not deployed itself; entry+lib/ IS safe here |
focus_ctl.sh |
1091 | no test |
Start with dns_enforcer.sh and lib/monitor.sh: both have real test scripts,
so you can prove the split the way tether_enforcer was proved (run the test
before and after; the count must match exactly).
config.sh is special. python_pkg/focus_policy/loader.py is a
mini-interpreter that parses it as the live source of truth. Splitting it breaks
that loader unless the parser follows. focus_policy has 100% tests that will
catch it — run them. Plan the two changes together, or do config.sh last.
3. Restructure the three parked files
Last session parked these because a verbatim function move cannot get them under the cap. The user has authorised restructuring. Restructuring means the verbatim harness no longer applies, so each one needs a test or a real run instead — say plainly which you used.
install_plagiarism_tools.sh(534, only 3 tiny functions). ~500 lines of top-level code. Wrap coherent stages in functions, then move those. This is the most mechanical of the three; do it first.libre_translate.sh(488, 18 funcs). After the clean seams are taken,parse_args(111 lines),write_env_file,detect_container_userandmainall assign and read the same configuration globals. Four attempts were spent relocating them; that does not work. Restructureparse_args— e.g. split the case body into per-flag helpers, or move the whole config-globals cluster into one lib that owns both writes and reads.diagnose_pacman_hook_stall.sh(493, 15 funcs). Same shape:run_onewritesLAST_ELAPSED,mainreads it. Also emits SC2153 (PACMAN_BINvsPACMAN_PID) once split — that is a real shellcheck finding to resolve, not to suppress.
Tooling — use it, don't rebuild it
meta/scripts/extract_shell_functions.py — moves functions into a library.
Walks brace-by-brace and lifts only function blocks. Never slice by line
range: these scripts interleave top-level commands between function
definitions, and a range slice sweeps those into the library where they run at
source time and out of order. It refuses to guess when there is no set -e
anchor (as in the #!/system/bin/sh phone scripts) — place the source line by
hand there, after the existing . "$SCRIPT_DIR/config.sh".
python3 meta/scripts/extract_shell_functions.py <script> <lib> \
--functions name1,name2 --header '#!/usr/bin/env bash
# What this library is for.'
meta/scripts/verify_shell_split.sh — proves a move was verbatim by
normalising each function through shfmt -mn and comparing hashes. Sees through
reformatting, catches a one-character logic change, names the function.
bash meta/scripts/verify_shell_split.sh HEAD <old-path> <new-path>...
Re-run it after pre-commit autofixes — it caught export edits that lint had
accepted but that changed two function bodies. It does not apply to task 3,
where the code is deliberately being restructured.
The rule that decides where a shell seam can fall
A file must not assign a global it never reads. That is SC2034; the repo
forbids suppressions; the pre-commit hook runs shellcheck with no -x, so
a # shellcheck source= directive will not make it follow the link. Each file
stands alone — check with shellcheck <lib> before committing.
The precedent at install_pacman_wrapper.sh:29 is about definitions-only libs.
It does not mean "assignments stay in the entry script" — it means writer and
readers must sit in the same file. steam_compatibility.sh split cleanly only
once detect_system moved next to score_game and load_cache_map next to
main. This is the shell analogue of the monkeypatch.setattr target trap.
Still-live deployment trap (task 2 does not cancel this)
install_leechblock.sh (485) and block_compulsive_opening.sh (705) are
copied to /usr/local/…, and pacman_wrapper.sh:831 prefers the deployed copy
on every pacman invocation. Split them naively and every pacman -S on this
machine fails. Teach the installer to deploy the directory first, in its own
commit, then re-baseline, then split. Do these last. Note you cannot run
sudo pacman -S from the Bash tool — it deadlocks on db.lck; hand the user a
! pacman -S <pkg> line and state the expected output.
Rules that will bite you
- No suppressions, ever. No
# noqa,# type: ignore,# shellcheck disable, no lowered coverage threshold. Every time this came up last session the seam was wrong, not the linter. - Run the actual thing.
steam_compatibility.sh --helpexiting 0 is what proved four source lines resolved. For scripts too dangerous to run (main.shinstalls packages;setup_passwordless_system.shwrites sudoers), say so and rely onbash -nplus sourcing each library in a subshell to prove it has no side effects. - Check
check_file_length.sh --allbefore committing — a split that fixes one file while pushing a new library over the cap is a net zero. It happened twice last session. - Every commit touching code needs evidence in
docs/superpowers/evidence/<slug>-<date>.json(copytemplate.json). Staging ≥4 code files also needs a freshdocs/superpowers/contracts/*.json. Validate withmeta/scripts/validate_{evidence,contract}.py. - New sourced libs need a shebang and the executable bit. The
check-shebang-scripts-are-executablehook reads the git index — stage the mode withgit add --chmod=+x. pre-commit run --files <changed>before committing.prettierandci-mirrorrun on pre-push, not pre-commit.npx prettier --writeany.mdyou touch, including this one.- Work directly on
main.git stashand branch creation are blocked by hooks. Verify a push landed withgit status -sbshowing no[ahead N]. - Do not wire the file-length pre-commit hook. It lands last, once
check_file_length.sh --allexits 0. 24 files are still over. - Cap pytest memory:
systemd-run --user --scope -p MemoryMax=2G -p MemorySwapMax=0.
Known pre-existing state — not yours, do not fix silently
bash linux_configuration/tests/test_security_hardening.shexits 1 with❌ FAIL: Compulsive block wrappers installed. Belongs toblock_compulsive_opening.sh.bucket_catch/packages/frontendhas 4 eslint errors, documented with measured reasoning indocs/superpowers/evidence/bucket-catch-eslint-2026-08-17.json.usePuzzleGameLoop.ts:129'sMap.get(...)!cannot be fixed with?? Infinity— tried, measured at 99.54%, because the default side is unreachable.npm run coverageis green: 145 tests, 100%.- Repo-wide
jscpdreports ~2.5% from the working tree but 1.47% at HEAD in a clean worktree — the excess is vendored.venvsite-packages. Don't chase it. - The
tether_enforcer.shsplit is unverified on the phone. Its test passes (17/17), and bothdeploy.shlists were updated, but no deploy has run. If tether enforcement misbehaves after the next deploy, look there first.
Testing notes specific to this repo
linux_configuration/testsis in CI, but never by name:pyproject.tomlsetstestpaths, so barepytestcollects it. Behaviour is gated; coverage is not (--cov=python_pkgonly).- Non-
python_pkgmodules are tested vialinux_configuration/tests/, whoseconftest.pyputs standalone script dirs onsys.path. Add a directory there rather than moving code intopython_pkg/— that move drags the file under afail_under = 100gate and breaks any by-path caller. name-tests-testrequires every.pyundertests/to betest_*.py. Shared helpers go inconftest.pyas fixtures —conftestis not importable by module name.- For a test-file split the discriminating check is the test count, not a green run: a file outside the runner's glob is silently never collected. That caught a real breakage last session.
phone_focus_mode's shell tests are not in CI —shell-tests.ymluses an explicit list coveringlinux_configuration/tests/only. Run them by hand.focus_ownergradle needsJAVA_HOME=/usr/lib/jvm/java-21-openjdkand--rerun-tasks; a plaingradlew testreportsUP-TO-DATEand proves nothing.