mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 17:47:05 +01:00
Adopt the four markdown namespaces and gate them
Renames this repo's markdown onto README.md / CLAUDE*.md / DOCS*.md / TODO*.md so a future session can tell a live task from a finished record without reading the file to find out. TODO files carry the literal "REMOVE ME AFTER FINISH" and are deleted when the work lands. Enforced by the md-naming pre-commit hook and CI workflow, both delegating to the shared gate in kuhyx/utils so this repo's idea of a valid name cannot drift from every other repo's. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A47aX5DJwmA3QFn3pkEWi7
This commit is contained in:
parent
69937ffda8
commit
49d82511c3
38
.github/workflows/md-naming.yml
vendored
Normal file
38
.github/workflows/md-naming.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: md-naming
|
||||
|
||||
# The four markdown namespaces, enforced on push as well as at commit time.
|
||||
# The local pre-commit hook can be skipped (a fresh clone that never ran
|
||||
# `pre-commit install` has no hooks at all), so the convention needs a second
|
||||
# gate that no one can forget to install.
|
||||
#
|
||||
# Deliberately a SEPARATE workflow from any release job: a badly named doc
|
||||
# should fail lint, not block publishing an artifact.
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
md-naming:
|
||||
name: markdown naming convention
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# The gate and its exemption list live in the shared utils repo so every
|
||||
# repo enforces the same namespaces. Checking it out beats vendoring a
|
||||
# copy here, which is exactly how a gate and a survey start disagreeing.
|
||||
- name: Check out the shared gate
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: kuhyx/utils
|
||||
path: .utils
|
||||
|
||||
- name: Enforce the naming convention
|
||||
run: bash .utils/scripts/check_md_naming.sh --all
|
||||
|
||||
# Warns only: no machine can prove a task is finished, so an old TODO
|
||||
# gets a nudge, never a failure.
|
||||
- name: Warn about stale TODOs
|
||||
run: PYTHONPATH=.utils python3 .utils/md_naming/stale.py
|
||||
@ -582,3 +582,13 @@ repos:
|
||||
# - id: commitizen
|
||||
# - id: commitizen-branch
|
||||
# stages: [push]
|
||||
|
||||
# Four markdown namespaces (README / CLAUDE* / DOCS* / TODO*), plus the
|
||||
# rule that a TODO carries "REMOVE ME AFTER FINISH" and nothing else may.
|
||||
# Shared gate in ~/utils owns the namespaces and the exemption list, so
|
||||
# one repo's idea of a valid name cannot drift from every other repo's.
|
||||
- id: md-naming
|
||||
name: markdown naming convention
|
||||
entry: scripts/check_md_naming.sh
|
||||
language: system
|
||||
files: \.(md|markdown)$
|
||||
|
||||
@ -128,3 +128,5 @@ N/A below with spot-checks noted instead.
|
||||
- **Primary structural finding**: introduce a shared token source (CSS custom properties in a `src/theme.css` imported by `index.css`, or a TS `theme.ts`) before doing any rule-by-rule fix — otherwise each violation below has to be independently re-fixed per `*.module.css` file, and new files will keep reintroducing the same drift (as the reversed-gradient-stop-order bug on `PuzzleResult.module.css:25` already shows).
|
||||
- Once tokens exist, Rules 9 and 18 become checkable as whole-palette rules and should be re-audited.
|
||||
- The 4-gray inconsistency (Rule 2) and the duplicated-gradient literals (Rule 4) are the same underlying fix — collapsing to a `theme.css` resolves both simultaneously.
|
||||
|
||||
REMOVE ME AFTER FINISH
|
||||
@ -0,0 +1,48 @@
|
||||
{
|
||||
"intent": "Rename this repo's markdown onto the four shared namespaces (README.md / CLAUDE*.md / DOCS*.md / TODO*.md) and gate them, so a future session can tell a live task from a finished record without reading the file to find out.",
|
||||
"scope": [
|
||||
"40 markdown files renamed via git mv (history preserved)",
|
||||
"scripts/check_md_naming.sh: thin shim delegating to kuhyx/utils",
|
||||
".pre-commit-config.yaml: adds the md-naming hook",
|
||||
".github/workflows/md-naming.yml: same gate on push/PR",
|
||||
"Non-goal: executing the outstanding work these TODO files describe",
|
||||
"Non-goal: any change to source code, tests or build config"
|
||||
],
|
||||
"changes": [
|
||||
"Task files became TODO-<slug>.md and gained the literal line 'REMOVE ME AFTER FINISH'; record files became DOCS-<slug>.md with no marker.",
|
||||
"Classification was by file CONTENT, not filename: RESTRUCTURE_HANDOFF.md and INSTALLER_FIX_TASK.md are settled records (DOCS), while docs/superpowers/plans/2026-05-01-phone-focus-recovery.md is still a task (TODO).",
|
||||
"Deleted refactor_claude_todo.md and refactor_claude_todo_resume.md: the 250-line gate exits 0 in this repo, so the work they describe is provably finished.",
|
||||
"Inbound references to the renamed files were rewritten in the same commit."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "bash scripts/check_md_naming.sh --all",
|
||||
"result": "pass",
|
||||
"evidence": "exit 0; 0 problems across the whole tree"
|
||||
},
|
||||
{
|
||||
"command": "pre-commit run md-naming --all-files",
|
||||
"result": "pass",
|
||||
"evidence": "markdown naming convention.....Passed"
|
||||
},
|
||||
{
|
||||
"command": "bash scripts/check_file_length.sh --all",
|
||||
"result": "pass",
|
||||
"evidence": "exit 0 -- the basis for deleting both refactor todos"
|
||||
},
|
||||
{
|
||||
"command": "python3 -m pytest md_naming/tests/ (in ~/utils)",
|
||||
"result": "pass",
|
||||
"evidence": "71 passed; 100% branch coverage on the gate"
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"A rename breaks an inbound link not caught by the reference sweep. Mitigated: the sweep covered ~/.claude/CLAUDE.md, rules/, skills/, memory/ and every tracked .md; a bare-basename match was deliberately narrowed after a dry run showed it would corrupt vendored node_modules files.",
|
||||
"A doc classified TASK is actually finished, or vice versa. Mitigated: verdicts came from content audits cross-checked against repo code, and are recorded in ~/utils/md_naming/migrate/classify.py.",
|
||||
"The gate depends on kuhyx/utils being present; CI checks it out, and the shim fails loudly with install instructions if it is missing."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit -- every rename is a git mv, so history follows and the revert restores the original names.",
|
||||
"After rollback, confirm bash scripts/check_md_naming.sh --all is no longer wired by removing the md-naming hook from .pre-commit-config.yaml and deleting .github/workflows/md-naming.yml."
|
||||
]
|
||||
}
|
||||
@ -2051,3 +2051,5 @@ git commit -m "chore(phone): final pre-commit fixes and live-verification adjust
|
||||
| `phone_focus_mode/systemd/install_pc_phone_automation.sh` | Create |
|
||||
| `phone_focus_mode/README.md` | Create |
|
||||
| `scripts/run_all/run_phone.sh` | Create |
|
||||
|
||||
REMOVE ME AFTER FINISH
|
||||
@ -52,10 +52,10 @@ This repo automates Linux desktop bootstrap, hardening, and i3 setup. It’s pri
|
||||
For in-depth understanding of specific components, see these dedicated guides:
|
||||
|
||||
- **Hosts Guard**: [./fixes/migrate_hosts_guard_to_guard_lib.sh](../fixes/migrate_hosts_guard_to_guard_lib.sh) header comment - guard-lib migration, protection layers, canonical copies, path watchers. The pre-guard-lib README is archived at github.com/kuhyx/testsAndMisc-archive.
|
||||
- **Pacman Wrapper**: [periodic_background/digital_wellbeing/pacman/README_FOR_LLM.md](../periodic_background/digital_wellbeing/pacman/README_FOR_LLM.md) - Policy files, integrity checks, challenges
|
||||
- **Midnight Shutdown**: [periodic_background/digital_wellbeing/README_MIDNIGHT_SHUTDOWN_LLM.md](../periodic_background/digital_wellbeing/README_MIDNIGHT_SHUTDOWN_LLM.md) - Schedule protection, timer system
|
||||
- **Compulsive Block**: [periodic_background/digital_wellbeing/README_COMPULSIVE_BLOCK_LLM.md](../periodic_background/digital_wellbeing/README_COMPULSIVE_BLOCK_LLM.md) - App launch limiting
|
||||
- **Security Analysis**: [docs/SECURITY_HARDENING_ANALYSIS.md](../docs/SECURITY_HARDENING_ANALYSIS.md) - Vulnerabilities and implementation roadmap
|
||||
- **Pacman Wrapper**: [periodic_background/digital_wellbeing/pacman/DOCS-pacman-wrapper-reference.md](../periodic_background/digital_wellbeing/pacman/DOCS-pacman-wrapper-reference.md) - Policy files, integrity checks, challenges
|
||||
- **Midnight Shutdown**: [periodic_background/digital_wellbeing/DOCS-midnight-shutdown-reference.md](../periodic_background/digital_wellbeing/DOCS-midnight-shutdown-reference.md) - Schedule protection, timer system
|
||||
- **Compulsive Block**: [periodic_background/digital_wellbeing/DOCS-compulsive-block-reference.md](../periodic_background/digital_wellbeing/DOCS-compulsive-block-reference.md) - App launch limiting
|
||||
- **Security Analysis**: [docs/DOCS-security-hardening-analysis.md](../docs/DOCS-security-hardening-analysis.md) - Vulnerabilities and implementation roadmap
|
||||
|
||||
## Digital Wellbeing Components Summary
|
||||
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
# Refactor TODO — enforce the 250-line file cap
|
||||
|
||||
> **This file is a ready-to-use prompt.** Paste it to Claude, or open this repo
|
||||
> and say "do refactor_claude_todo". It is self-contained: everything needed to
|
||||
> execute is below. Generated 2026-08-14 from a measured survey of every repo.
|
||||
|
||||
## Goal
|
||||
|
||||
Every file in this repo must be **at most 250 lines** — source, tests, and
|
||||
prose (`.md`/`.txt`/`.rst`/`.tex`) alike — and must **stay** that way forever,
|
||||
enforced by a gate that fails the commit, not by a note anyone can ignore.
|
||||
|
||||
Why: a file that cannot be read in one piece forces re-reads and partial edits,
|
||||
which is the single largest avoidable cost in an LLM-assisted workflow. Aim by
|
||||
churn, not size alone — refactoring pays where code is read and changed often
|
||||
(Fowler, _refactoring economic benefit_).
|
||||
|
||||
## Scope in this repo
|
||||
|
||||
- **197 files** currently exceed 250 lines (of 801 eligible files).
|
||||
- **87,393 lines** sit in violation; longest file is **2053 lines**.
|
||||
|
||||
Exempt (do NOT split these):
|
||||
|
||||
- generated files — `*.g.dart`, `*.freezed.dart`, `*.gr.dart`, `**/l10n/generated/**`,
|
||||
anything with a `GENERATED` header
|
||||
- markup — `.html`, `.css`, `.scss`
|
||||
- data files — `.json`, `.yaml`, `.csv`, wordlists and other data-ish `.txt`
|
||||
(mean line length under 25 chars)
|
||||
|
||||
## Violations, highest ROI first
|
||||
|
||||
ROI = lines x commits in the last year. Work top-down; a long file nobody edits
|
||||
has near-zero payoff and should not be first.
|
||||
|
||||
| lines | commits/yr | kind | file |
|
||||
| ----: | ---------: | :---- | :------------------------------------------------------------------------------------- |
|
||||
| 556 | 41 | code | `phone_focus_mode/config.sh` |
|
||||
| 1734 | 9 | code | `linux_configuration/periodic_background/digital_wellbeing/setup_midnight_shutdown.sh` |
|
||||
| 833 | 15 | code | `phone_focus_mode/deploy.sh` |
|
||||
| 1337 | 8 | code | `linux_configuration/periodic_background/check_and_enable_services.sh` |
|
||||
| 1091 | 9 | code | `phone_focus_mode/focus_ctl.sh` |
|
||||
| 543 | 12 | code | `phone_focus_mode/focus_daemon.sh` |
|
||||
| 929 | 6 | code | `linux_configuration/periodic_background/digital_wellbeing/pacman/pacman_wrapper.sh` |
|
||||
| 564 | 9 | code | `focus_owner/android/app/src/main/kotlin/com/kuhy/focus_owner/EnforcementRunner.kt` |
|
||||
| 918 | 5 | code | `linux_configuration/periodic_background/digital_wellbeing/setup_night_lockdown.sh` |
|
||||
| 912 | 5 | code | `linux_configuration/periodic_background/hosts/install.sh` |
|
||||
| 258 | 16 | prose | `CLAUDE.md` |
|
||||
| 698 | 5 | code | `reverse_survivors/src/core/sim.test.ts` |
|
||||
| 620 | 5 | code | `linux_configuration/lib/common.sh` |
|
||||
| 415 | 7 | code | `focus_owner/android/app/src/main/kotlin/com/kuhy/focus_owner/DevicePolicyBridge.kt` |
|
||||
| 912 | 3 | code | `linux_configuration/features/setup_searxng.sh` |
|
||||
|
||||
_(182 further files over 250 lines not listed — re-run the survey for the full set.)_
|
||||
|
||||
## How to split
|
||||
|
||||
- **Python** — extract cohesive helpers into sibling modules; keep the public
|
||||
API and imports stable.
|
||||
- **Shell** — split into `lib/*.sh` sourced by a thin entry script. Keep
|
||||
`set -euo pipefail` in each.
|
||||
- **Dart / TypeScript** — extract widgets/components into their own files.
|
||||
- **Tests** — split by test-group into sibling files
|
||||
(`foo.test.ts` -> `foo.parsing.test.ts`, `foo.render.test.ts`). Coverage must
|
||||
not drop.
|
||||
- **Docs** — split into topic files under `docs/` with an index. For an
|
||||
oversized `CLAUDE.md`, move detail into referenced docs so the
|
||||
always-loaded part shrinks.
|
||||
|
||||
**Do not** game the cap: no one-lining, no deleting tests, no moving code into
|
||||
an exempt extension, no `# noqa`-style suppressions.
|
||||
|
||||
## Make it permanent (required — this is the point)
|
||||
|
||||
A refactor without a gate silently regrows. Before this task is done:
|
||||
|
||||
1. Wire the shared gate `~/utils/scripts/check_file_length.sh` into this repo's
|
||||
`.pre-commit-config.yaml` as a local hook. If the repo has no pre-commit
|
||||
config, add a minimal one.
|
||||
2. The hook checks **files in the commit** (not the whole tree), so unrelated
|
||||
commits never break, and it **fails** — exit 1, not a warning.
|
||||
3. No baseline file and no allowlist. Those are suppressions.
|
||||
4. If this repo has CI (`.github/workflows`), add the same check there so it
|
||||
also fails on push.
|
||||
|
||||
## Done condition
|
||||
|
||||
- `bash ~/utils/scripts/check_file_length.sh --all` from this repo root exits 0.
|
||||
- The repo's own test suite and coverage bar are still green.
|
||||
- `pre-commit run --files <changed files>` passes.
|
||||
- A deliberately over-250-line test file, staged, makes `git commit` **fail**.
|
||||
- For a deployed daemon/app: the entry point still actually runs.
|
||||
|
||||
## Verify
|
||||
|
||||
Many scripts here run from systemd timers and the working tree. After splitting a script, run it directly and confirm the timer unit still resolves its path.
|
||||
@ -1,248 +0,0 @@
|
||||
# Resume: enforce the 250-line file cap
|
||||
|
||||
> **Paste this whole file to a fresh Claude session opened in `~/testsAndMisc`.**
|
||||
> It is self-contained. Continues `refactor_claude_todo.md`, which is still the
|
||||
> spec — read it too, but the decisions below override it where they differ.
|
||||
|
||||
## Where things stand
|
||||
|
||||
**57 files** over 250 lines (was 183 — 69% cleared). Everything is committed
|
||||
to `main`; see `git log` for the head.
|
||||
|
||||
`focus_owner/analysis_options.yaml` is **resolved** (2026-08-16). It was not a
|
||||
stray edit: `flutter pub get` writes that `analyzer.exclude` block itself
|
||||
("Upgrading analysis_options.yaml to exclude build and platform directories"),
|
||||
reproduced byte-identically from a clean detached worktree. It is committed, so
|
||||
it will stop reappearing. Earlier handoffs called it "not ours" — that was
|
||||
wrong, and the reason it kept coming back.
|
||||
|
||||
**`python_pkg/` is DONE — 50 violations → 0.** Do not reopen it.
|
||||
**All 12 prose files are done.** `kcd2_dice_solver` is 12 → 4, all four source
|
||||
files.
|
||||
|
||||
`git log --oneline --grep='[Ss]plit'` is the authoritative list.
|
||||
|
||||
## What is left
|
||||
|
||||
Get the real list — a per-directory table used to live here and went stale
|
||||
every session:
|
||||
|
||||
```bash
|
||||
bash ~/utils/scripts/check_file_length.sh --all
|
||||
```
|
||||
|
||||
`linux_configuration` dominates; `phone_focus_mode` (11) is last by policy.
|
||||
This handoff counts too, whenever an edit pushes it over.
|
||||
|
||||
### Pick targets by VERIFIABILITY, not by line count
|
||||
|
||||
The suggested order below sorts by cheapness. That is the wrong axis: several
|
||||
"cheap" near-miss files turned out to be unverifiable, which costs more than a
|
||||
big file that can be run. Triage each candidate first:
|
||||
|
||||
```bash
|
||||
grep -cE '^\s*(cat|tee)\s*>|>\s*"?(\$HOME|\$unit_dir|/etc|/usr|/var|/opt)' <f>
|
||||
grep -cE '\b(require_root|sudo -v|EUID -ne 0)\b' <f>
|
||||
```
|
||||
|
||||
- **Both zero → take it.** Traceable, or runnable outright.
|
||||
- **Writes > 0 → skip for now.** Shell redirections (`cat > /etc/...`) cannot
|
||||
be stubbed via `PATH`; running it mutates the system for real. This ruled out
|
||||
`nvidia_troubleshoot.sh` (writes `/etc/modprobe.d/`) and
|
||||
`install_usage_monitoring.sh` (writes `$HOME/.local/bin` + systemd units)
|
||||
after they had already been picked as "easy".
|
||||
- **Best of all: something self-verifying.** `mtk_root/tests/run_tests.sh` was
|
||||
421 lines and the easiest split of the session, because it reports
|
||||
`58 passed, 0 failed` and the full output diffs byte-identical.
|
||||
|
||||
Done this session on that basis: `disk_cleanup_check.sh` (329 → 230+124),
|
||||
`mtk_root/tests/run_tests.sh` (421 → 218+157+75), `meta/lint_python.sh`
|
||||
(353 → 175+116+96), `EnforcementLogTest.kt` (251 → 169+90).
|
||||
|
||||
**Verify the branch you actually changed.** `lint_python.sh --quick` exits
|
||||
before the block that was extracted, so an identical `--quick` output proved
|
||||
almost nothing; the full-mode run is what mattered. Same shape as the silent-
|
||||
stub trap in `docs/shell-split-verification.md`. Ask every time: did this run
|
||||
enter the code I moved?
|
||||
|
||||
### Deliberately over the cap — a NAMED blocker, not a line-count job
|
||||
|
||||
Splitting one means fixing the blocker first. **Do not suppress to land one.**
|
||||
|
||||
| File | Why |
|
||||
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `check_and_enable_services.sh` (1337) | every `check_*` writes one `SERVICE_STATUS` |
|
||||
| `steam_compatibility.sh` (663) | `CACHE_MAP` written in a lib, read by `main` |
|
||||
| `block_compulsive_opening.sh` (705) | `install_all` copies the running script to `/usr/local/bin`; an entry+lib shape ships an entry whose `SCRIPT_DIR` has no `lib/` — breaks three daily-use apps + the pacman rewrap hook |
|
||||
| `diagnose_pacman_hook_stall.sh` (493) | `LAST_ELAPSED` / `PACMAN_BIN` cross the seam |
|
||||
| `libre_translate.sh` (488) | ~19 globals cross any seam |
|
||||
| `enforce_vbox_hosts.sh` (443) | every seam falls inside a heredoc |
|
||||
| `clean_audio.sh` (419) | probe-result globals through two libs |
|
||||
| `setup_passwordless_system.sh` (374) | no `main()`; top-level block kept by hand |
|
||||
| `install_plagiarism_tools.sh` (534) | two heredocs emitting Python; extracting them pulls 22 ruff/pylint/mypy violations into the gate — a Python cleanup task, not a split |
|
||||
| `meta/scripts/optimize_vscode.py` (498) | `_apply_variant` calls back into the caller |
|
||||
|
||||
Same in TypeScript: `kcd2`'s `search.ts` and `badgeValue.ts`, and
|
||||
`reverse_survivors`' `sim.ts` (`step` ⇄ `survivorStep`) and `types.ts`.
|
||||
|
||||
`billsplit`'s last file is Flutter's generated `win32_window.cpp`.
|
||||
**Resolved 2026-08-16 — gitignore is NOT the mechanism**: it is tracked and
|
||||
`billsplit/windows/runner/CMakeLists.txt:13` lists it as a build source, so a
|
||||
`.gitignore` entry does nothing and `git rm --cached` breaks the Windows build
|
||||
for every fresh clone. (`check.py` skips git-_ignored_ files, which is what
|
||||
makes gitignore look workable — it only works for untracked ones.)
|
||||
|
||||
**Prerequisite of the gate-wiring step:** add a Flutter-runner exemption to
|
||||
`~/utils/file_length/config.py` — a _different repo_, own gate and CI —
|
||||
covering `windows/runner/`, `linux/runner/`, `macos/Runner/`, beside the
|
||||
existing `GENERATED_PATTERN` rules. Land it there before wiring the hook here.
|
||||
|
||||
## Read these BEFORE the first split
|
||||
|
||||
- `docs/shell-split-recipes.md` — how to **make** a shell split.
|
||||
- **`docs/shell-split-verification.md`** — how to find out it is **wrong**.
|
||||
New this session and the more important of the two. Read it first.
|
||||
- `docs/app-split-recipes.md` — Dart `part`, Kotlin fixture objects, the TS
|
||||
import cycle that compiles clean, per-project test baselines.
|
||||
- `docs/python-split-recipes.md` — the seam-selection rule, which generalises.
|
||||
|
||||
### The single most expensive lesson
|
||||
|
||||
**A green split can still be broken.** `analyze_repo.sh` passed `bash -n`,
|
||||
`shellcheck`, two diffs and a stubbed probe, then aborted at runtime. The two
|
||||
bugs (a `set -e` function tail, a self-referencing nameref), why
|
||||
`verify_shell_split.sh` cannot see either, how
|
||||
`meta/scripts/trace_shell_split.sh` does, and the traps in using it are all in
|
||||
**`docs/shell-split-verification.md`**. Read it before any shell split; do not
|
||||
re-derive it here.
|
||||
|
||||
Also there: why a `--skip-install` flag is not permission to run a script —
|
||||
one such "safe" baseline run installed four AUR packages.
|
||||
|
||||
## Decisions already made (do not re-ask)
|
||||
|
||||
1. **Full clearance** to `--all` exit 0. When context runs out, write a fresh
|
||||
handoff like this one rather than stopping mid-way.
|
||||
2. CI checks only files in the push/PR range, not `--all`.
|
||||
3. `docs/superpowers/plans/**` + `sessions/**` are exempt — done.
|
||||
4. `poker-stakes/` is tracked — done.
|
||||
5. Prose: automate what can be automated, delete the automated lines, keep only
|
||||
HOW, never WHY.
|
||||
6. Shell verification is `bash -n` + `shellcheck` + `systemctl cat` path checks.
|
||||
**Never execute an enforcement/installer script that mutates the live system
|
||||
or the phone.**
|
||||
7. One commit per logical unit.
|
||||
8. **Editing test files to follow moved code is allowed**, bounded by: no
|
||||
assertion changed, nothing deleted/skipped/weakened, identical pass count.
|
||||
A test harness that copies the script into a temp worktree must also copy the
|
||||
new `lib/` — that bit the `music_parallelism` split.
|
||||
9. Per-commit gate is `pre-commit run --files <changed>`; the real `git commit`
|
||||
adds jscpd. Push per directory tranche.
|
||||
10. **When a seam splits code covered by a per-file-ignore, fix the lint — do
|
||||
not copy the ignore onto the new file.** Ask only if the fix looks like it
|
||||
changes behaviour.
|
||||
11. **The named blockers get real refactors, not exemptions** (user, 2026-08-16:
|
||||
"yes, do a real refactoring, we can take risks"). Risk is accepted on the
|
||||
blocker list — but "accepted risk" means verified against stubs, not
|
||||
unverified. Pair it with 12.
|
||||
12. **Every split is verified by running, always** (user, 2026-08-16: "apply the
|
||||
full run-and-diff always"). For scripts Decision 6 forbids executing live,
|
||||
"running" means `meta/scripts/trace_shell_split.sh` — a real execution with
|
||||
mutating binaries stubbed — and a trace diff against the pre-split commit.
|
||||
Decisions 6 and 12 do not conflict; the harness is what reconciles them.
|
||||
A split verified by static checks alone is not finished.
|
||||
|
||||
## The constraint that will bite you
|
||||
|
||||
**Wire the file-length gate LAST**, only once `--all` already exits 0.
|
||||
`meta/scripts/ci_mirror.sh:109` runs `pre-commit run --all-files` as a
|
||||
**pre-push** hook, and `.github/workflows/pre-commit.yml:105` does the same in
|
||||
CI. Registering the hook while violations remain makes **every `git push` fail**.
|
||||
Do not scope around it with `exclude:`/`files:`.
|
||||
|
||||
Final commit, once and only once the tree is clean:
|
||||
|
||||
```yaml
|
||||
- id: file-length
|
||||
name: file length <= 250 lines
|
||||
entry: bash /home/kuhy/utils/scripts/check_file_length.sh
|
||||
language: system
|
||||
```
|
||||
|
||||
Plus `.github/workflows/file-length.yml` modelled on
|
||||
`~/todo/.github/workflows/file-length.yml`, scoped to changed files. Then prove
|
||||
it fails: stage a deliberately 251-line file, confirm `git commit` aborts,
|
||||
delete it.
|
||||
|
||||
## Concurrency: check for another agent FIRST
|
||||
|
||||
A past session collided with a second Claude on the same tree and lost a
|
||||
commit race to it. **Before touching the index**, run the `pgrep`/`ss` checks
|
||||
in `docs/shared-checkout-safety.md`, which also covers recovering changes
|
||||
stranded by a killed `pre-commit`.
|
||||
|
||||
## Traps that still cost time
|
||||
|
||||
- **`end-of-file-fixer` aborts commits.** Files built with `sed`/`cat` often
|
||||
lack a trailing newline. `git add` again and re-commit.
|
||||
- **`prettier` is pre-push only.** A markdown file that passes every per-commit
|
||||
gate can still fail the push. Run `npx prettier --write <file>` on new docs.
|
||||
- **`shfmt -w` deletes comment banners** it thinks are stray — it removed a
|
||||
`#====` STEP header. Re-count banners after running it. Also: 157 of 298
|
||||
`linux_configuration` shell files were **already** shfmt-dirty at the session
|
||||
start, so `run_linters` exits 1 on the full tree regardless. Do not add to it;
|
||||
do not try to fix all 157.
|
||||
- **Formatters silently revert edits.** After editing, `grep` the file to
|
||||
confirm the change survived.
|
||||
- **Contracts.** Staging **≥4 code files** requires a fresh
|
||||
`docs/superpowers/contracts/*.json` in the same commit, on top of the
|
||||
per-commit evidence JSON. Validate with
|
||||
`python3 meta/scripts/validate_contract.py <file>`.
|
||||
- **Never edit files while a push is running** — pre-commit stashes and restores
|
||||
unstaged changes; editing in that window makes the restore fail. After any
|
||||
push confirm `git status --short --branch` does not say `ahead N`; a piped
|
||||
`git push | tail` masks failure.
|
||||
- **Long commands**: background anything over ~60s.
|
||||
|
||||
## `phone_focus_mode` — highest blast radius, do it LAST
|
||||
|
||||
1. **`deploy.sh` has a hardcoded flat push list** (search `adb_cmd push`, ~lines
|
||||
374–383) with **no `lib/` subdirectory**. Every new split lib must be added
|
||||
there in the same commit, or the phone sources a missing file at runtime —
|
||||
gate green, tests green, device broken.
|
||||
2. **`config.sh` (571) is sourced by 11 scripts.** Keep it as the entry point
|
||||
that re-sources its own parts, so all 11 callers keep working untouched.
|
||||
|
||||
Static check after each split: grep `deploy.sh`'s push list and every
|
||||
`source`/`.` line in `phone_focus_mode/*.sh` and confirm each new lib appears.
|
||||
|
||||
## Suggested order
|
||||
|
||||
Run the verifiability triage above first; it outranks this list.
|
||||
|
||||
1. Anything self-verifying or read-only — test suites, linters, report
|
||||
scripts. Cheapest to prove, regardless of size.
|
||||
2. `focus_owner` (Kotlin/Dart), `kcd2_dice_solver`, `bucket_catch`,
|
||||
`reverse_survivors` — read `docs/app-split-recipes.md` first. These have
|
||||
real test baselines (40 Kotlin, 94 Dart, 288, 160).
|
||||
3. The `linux_configuration` shell scripts that write nothing.
|
||||
4. The write-to-system installers, once the harness can redirect their writes
|
||||
under a temp prefix. Not tractable before that.
|
||||
5. `phone_focus_mode` (11) — with the `deploy.sh` push-list guard above.
|
||||
6. Gate wiring + CI workflow — last, and only after the
|
||||
`~/utils/file_length/config.py` Flutter-runner exemption lands.
|
||||
|
||||
**`fresh-install/main.sh` is not the easy one it looks like**: `sudo -v` and
|
||||
package installs at top level, a `local -n` nameref in
|
||||
`all_subpackages_installed`, and it reads `aur_packages.txt` /
|
||||
`pacman_packages.txt` from the **cwd**, so a baseline must run from its own
|
||||
directory or it dies at the first read and looks like a broken split.
|
||||
|
||||
## Done condition
|
||||
|
||||
```bash
|
||||
cd ~/testsAndMisc && bash ~/utils/scripts/check_file_length.sh --all # exit 0
|
||||
pre-commit run --all-files # passes
|
||||
```
|
||||
|
||||
Plus: a staged 251-line file makes `git commit` fail.
|
||||
32
scripts/check_md_naming.sh
Executable file
32
scripts/check_md_naming.sh
Executable file
@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ============================================================================
|
||||
# Fail if any markdown file breaks the shared naming convention.
|
||||
#
|
||||
# Thin delegate to the shared gate in ~/utils, which owns the four namespaces
|
||||
# (README / CLAUDE* / DOCS* / TODO*), the "REMOVE ME AFTER FINISH" marker rule
|
||||
# and the exemption list. Copying that logic here is what lets one repo's idea
|
||||
# of a valid name drift from every other repo's -- so this script only locates
|
||||
# the shared checker and forwards its arguments.
|
||||
#
|
||||
# Usage:
|
||||
# scripts/check_md_naming.sh <file> [<file> ...] # pre-commit passes these
|
||||
# scripts/check_md_naming.sh --all # whole tree, from cwd
|
||||
# ============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
readonly SHARED_GATE="${UTILS_ROOT:-$HOME/utils}/scripts/check_md_naming.sh"
|
||||
|
||||
main() {
|
||||
if [[ ! -x "$SHARED_GATE" ]]; then
|
||||
echo "Error: shared markdown-naming gate not found at $SHARED_GATE" >&2
|
||||
echo " Clone github.com/kuhyx/utils to ~/utils, or set" >&2
|
||||
echo " UTILS_ROOT to where it lives." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec bash "$SHARED_GATE" "$@"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue
Block a user