github.com/kuhyx/phone-focus-mode The two halves go as one repo: focus_policy parses phone_focus_mode's config.sh into the typed policy that focus-owner consumes, and nothing else references it. 77 commits of history, plus the two Python suites from linux_configuration/tests/ and the six mutation fixtures from meta/scripts/fixtures/, all of which named phone_focus_mode paths. Running the suites -- not reading them -- turned up a real defect the extraction would otherwise have inherited. config.sh sources the untracked config_secrets.sh, and ctl_libs_harness.sh never pinned HOME_LAT/HOME_LON, so the distance assertions were checking against whatever real coordinates that file happened to hold. The suite passed on this machine and could not run anywhere else, and a real home location was load-bearing in a pass/fail condition. The harness now pins a pair 4300 m south of the coordinate its own case seeds, and config.sh sources the secrets file only when it exists. 136/136 pass with no secrets file present. Before making the repo public I scanned the whole history for the known home coordinates and for any committed config_secrets.sh: zero hits, and the file was never tracked. The new repo also gained a .gitignore, since none came across in the filter-repo pass. test_magisk_service.sh hangs. It hangs identically in the pre-extraction baseline worktree and appears in no CI list here, so the new repo's CI skips it with that reason rather than pretending it passes. check_python_location.sh loses its phone_focus_mode exception now that the directory is gone; every tracked .py still passes it. The .gitignore rules for config_secrets.sh and the keystore STAY -- the working copy is still on this machine and still holds a real location. Depth 262 -> 248. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
7.0 KiB
testsAndMisc
Mixed-language monorepo: Python packages, Bash automation, and several apps.
Repository Layout
| Path | Description |
|---|---|
python_pkg/ |
Python packages — every .py in the repo belongs here or in an allowlisted dir |
meta/ |
Repo-wide tooling: pyproject.toml, requirements.txt, run.sh, lint_python.sh, .fvmrc, scripts/ |
linux_configuration/ |
Arch setup, i3 config, system maintenance, and the tracked git hooks |
billsplit/ |
Receipt bill-splitting Flutter app (Dart) |
bottles/ |
Small standalone project |
docs/ |
Reference docs; docs/superpowers/ holds AI workflow artifacts |
third_party/ |
Vendored upstream skills/agents |
Root pyproject.toml, requirements.txt, run.sh, lint_python.sh and
.fvmrc are symlinks into meta/ — edit the files in meta/, not the
symlinks.
Extracted to their own repos: steam-backlog-enforcer,
screen-locker,
diet-guard,
wake-alarm,
dufs-cloud,
build-your-x (lives at ~/build_your_x),
reverse-survivors,
kcd2-dice-solver (lives at ~/kcd2-dice-solver),
focus-owner,
mtk-root,
system-maintenance (lives at
~/system-maintenance),
android-guardian (lives at
~/android-guardian),
phone-focus-mode (with
python_pkg/focus_policy).
Archived work: testsAndMisc-archive.
Adding a Flutter app
billsplit/ is currently the only one, and the only place binaries are
committed. To add another, repeat both halves or the icons fail silently:
- Add the icon globs to
.binary-allowlist. - Add matching
!overrides at the end of.gitignore— an ignored file fails silently ongit addrather than erroring.
Icons come from the shared generator in python_pkg/app_icons/. Dart style is
gated by CI only (.github/workflows/billsplit-ci.yml), not by a local hook.
Keep app dirs free of Python: the check-python-location hook requires every
.py to sit under python_pkg/ (or linux_configuration/, meta/scripts/). billsplit/'s coverage gate therefore lives at
python_pkg/billsplit_coverage/.
Git Workflow
Work directly on main; commit and push straight there.
core.hooksPath points at the tracked linux_configuration/.githooks/, so
hooks travel with the repo. .git/hooks/ is unused — never run
pre-commit install.
- pre-commit: shfmt + shellcheck + jscpd (fails above 2% duplication),
then
pre-commit run --hook-stage pre-commit. - pre-push:
pre-commit run --hook-stage pre-push—prettierandci-mirror.ci-mirrorruns a clean-venv install,pre-commit runover all files, and pytest for changed packages.
Bootstrap a clone or new machine:
./meta/scripts/install_hooks.sh # wire hooks + install missing tools
./meta/scripts/install_hooks.sh --check # verify only; exit 1 if incomplete
Both hooks fail closed: every external binary is verified each run and
auto-installed via pacman where possible. A missing tool aborts the commit —
it never means "skip the check". Extend REQUIRED_TOOLS in
linux_configuration/.githooks/lib/common.sh when adding a language: system
hook. common.sh also warns when local shellcheck/prettier/shfmt/zsh drift
from the versions pinned in .github/workflows/pre-commit.yml.
Development Workflow
- Do NOT run tests unless instructed, or before committing.
- If tests fail on the same issue twice in a row, STOP and ask.
- Confirm a change works by running the program and inspecting output — not by running tests. Then ask the user to confirm the behaviour.
- Fix coverage gaps; do not ignore them.
AI evidence (enforced)
Every commit touching code needs an evidence artifact:
- Copy
docs/superpowers/evidence/template.json→docs/superpowers/evidence/<task-slug>-<date>.json. - Fill in intent, scope, changes, verification, risks, rollback.
- Stage it with the code.
validate_evidence.py rejects empty verification[] and the phrases
"should work", "probably fine", "seems right".
Staging ≥4 code files additionally requires a fresh
docs/superpowers/contracts/*.json in the same commit.
Deletions in docs/superpowers/sessions/* abort the commit (append-only).
Code Conventions
Anything already enforced by a hook is omitted here — run
pre-commit run --all-files and read .pre-commit-config.yaml for the
complete list. What follows is what a linter cannot check.
Python
from __future__ import annotationsfor forward references.- Prefix private functions/modules with
_(_smart_plug.py,_process_game_event). - Mock external calls in tests; never hit real APIs or the filesystem.
- For branch coverage: prefer an explicit
while Truewithtry/except StopIterationoverforwhen iterator exhaustion needs covering, and mock threads/subprocesses to keep tests fast.
Full linting/coverage configuration lives in meta/pyproject.toml
(ruff select = ["ALL"], mypy, pylint enable = "all", coverage
fail_under = 100 with branch coverage). Note the mypy hook disables a
number of error codes, so it is weaker than the strict = true in the config.
Shell
set -euo pipefailin every script.- Prefer
/proc,/sysand bash builtins over$(...)in hot paths — see theefficient-polling-scriptsskill. Theno-polling-antipatternshook only inspects functions named*_loop,*_daemonorpoll*, so a fork storm elsewhere passes clean. - Use
jq/yqfor JSON/YAML, notgrep/awk.
Key Files
meta/pyproject.toml— all Python tool configs.pre-commit-config.yaml— hook definitionslinux_configuration/.githooks/— the tracked git hooksmeta/requirements.txt— runtime + dev dependenciesdocs/superpowers/evidence/template.json— evidence template.github/workflows/—pre-commit,python-tests,shell-tests, and one CI workflow per app