Finding qwen-code Simplifications
AGENTS.md § Simplicity First — "Minimum code that solves the problem.
Nothing speculative." This skill hunts what that principle already rejected
but that shipped anyway. It owns correct code nobody needs, repo-wide,
with no diff to anchor on.
Every candidate names the surface, names every consumer, and says what
breaks when it goes. A candidate whose consumers cannot all be named is
dropped — not downgraded, dropped.
Read this file, then the one document for your phase. Do not survey or land
from this file alone; if the phase document cannot be read, stop and say so.
| Phase |
Document |
| Survey (default): find and file |
references/survey.md |
| Land: turn ONE approved candidate into a PR |
references/land.md |
Issue First, PR Second
A run's deliverable is a comment on the tracking issue, not a PR.
Survey → file candidates on the tracking issue → maintainer says yes to one
→ land that one → one PR, one candidate.
This is not ceremony. AGENTS.md § Core Infrastructure ends "When in doubt,
escalate. Better to wrongly escalate than to wrongly approve," and an
unrequested batch of deletions is the shape that gets closed. It also makes
the ledger free: the issue that carries the proposals is the same object the
next run reads to avoid re-proposing them.
A maintainer asking for a PR in this session counts as assent — record it on
the ledger before opening the PR.
Boundaries
| Skill |
Owns |
Why not this one |
bundled /simplify |
The diff you just wrote; stops when there is no diff |
Cannot see surface accumulated across releases |
/repo-hygiene |
Wrong code — a defect provable by evidence; bans "cleaner / more modern / more consistent" edits |
Its six angles are all defect classes |
bundled /review |
Judging a change that exists |
Your change does not exist yet |
/create-issue |
Filing an issue well |
Use it to create the ledger issue when missing — it cannot comment; post run comments with gh issue comment |
/prepare-pr |
pr-title.txt / pr-body.md from the repo template |
Call it in the land phase; do not reinvent PR rules |
/verify-pr |
Behavioral A/B evidence for a PR |
A deletion has no behavior to demo |
/bugfix, /feat-dev, /deflake, /docs-* |
A defect, a feature, a flaky test, prose |
None of them remove surface |
Territory
The split is not taste. packages/core/package.json exports "./src/*" and
"./dist/*", and packages/core/src/index.ts carries ~179 export * from
lines, so every file under packages/core/src is reachable from outside
this repo. The release workflow npm-publishes @qwen-code/audio-capture
and the eight @qwen-code/channel-* packages with --access public, so a
symbol re-exported by their package entry is reachable the same way. No grep
inside this repo can prove such a symbol has no consumer. The same is true
of two surfaces whose consumers are not imports at all:
packages/core/vendor/** and packages/web-shell ship inside
the published @qwen-code/qwen-code tarball — packages/core/package.json
lists vendor in files, and scripts/copy_bundle_assets.js copies both
vendor/ and web-shell/dist into the bundle, where qwen serve hands the
latter to browsers. Their consumers are registry-, tarball-, or browser-side,
so an in-repo grep for them returns zero hits and the consumer proof passes
vacuously — getBuiltinRipgrep() even assembles the vendor path from
segments, so no literal path exists to grep for. Import reachability is the
floor, not the definition: consumption also happens through runtime reads,
loaders, manifests, and tool configs that never appear as imports. The
consumer proof must name the mechanism that consumes the surface; a grep
blind to that mechanism proves nothing, and the rows below mark every such
path this repo ships or loads. A path named by more than one row takes the
most restrictive outcome: Never-a-target beats Report-only, which beats
Landable.
| Territory |
Outcome |
packages/cli/src — the whole package (generated/ stays under the Never-a-target row below; **/*.sb stays under the Report-only row below; i18n/locales/** and commands/extensions/examples/** stay under the Report-only row below; **/*.test.ts(x), **/*.spec.ts(x), **/__snapshots__/** are never targets, always searched as consumers) |
Landable |
scripts/, esbuild.config.js, eslint.legacy-filenames.mjs, root manifests |
Landable |
Whole files or directories nothing consumes by any mechanism named above — no import and no runtime read, loader, manifest, or tool config — anywhere outside packages/core/src, packages/audio-capture, packages/channels, packages/sdk-*, packages/acp-bridge, packages/vscode-ide-companion, packages/chrome-extension, packages/zed-extension, packages/web-shell, packages/core/vendor, .github, and the Never-a-target row below |
Landable |
docs/users/**, docs/developers/**, docs/index.md, docs/_meta.ts, packages/cli/src/i18n/locales/**, packages/cli/src/commands/extensions/examples/** — as whole files or directories |
Report-only — copied into the published tarball (scripts/prepare-package.js copies the locales and extension examples; scripts/copy_bundle_assets.js copies docs/users/ for qc-helper) and consumed by the published docs site (docs-site/scripts/link-public-docs.mjs symlinks docs/users/ and docs/developers/ into the Nextra build per PUBLIC_DOC_ROOTS and copies docs/index.md and docs/_meta.ts; the site discovers pages by walking that tree); consumers are runtime reads — qc-helper's doc paths, the i18n loader's segment-assembled import(), /extensions new scaffolds — never imports. Individual orphan locale keys stay class-4 candidates: their proof greps the literal key, naming its mechanism |
docs-site/ |
Report-only — standalone published-site app, not a workspace member; route files are consumed by Next.js filesystem routing and an out-of-repo deploy, never imports, and no in-repo CI builds it |
Tracked .qwen/skills/**, .qwen/agents/**, .qwen/e2e-tests/**, docs/design/**, docs/plans/** |
Report-only — consumed by the skill loader, agent definitions, and process readers (including AGENTS.md itself), never imports |
AGENTS.md, CLAUDE.md, SECURITY.md, CONTRIBUTING.md, .prettierrc.json, .prettierignore, .editorconfig, .nvmrc, .npmrc, .yamllint.yml |
Report-only — consumed by external tooling through filename convention (agent harnesses, GitHub's security-policy UI, prettier and yamllint config auto-discovery, nvm, editors); never imports, and an in-repo grep for them measures only prose |
Anything under packages/core/src |
Report-only — published |
packages/audio-capture, packages/channels |
Report-only — npm-published (--access public) |
packages/core/vendor/**, packages/web-shell |
Report-only — shipped inside the published @qwen-code/qwen-code tarball / served to browsers by qwen serve; consumers are bundled or browser-side, never imports |
packages/cli/src/utils/**/*.sb |
Report-only — copied into the published bundle by extension glob (scripts/copy_bundle_assets.js copies packages/**/*.sb, scripts/prepare-package.js lists '*.sb') and read at runtime through a segment-assembled path (resolveSeatbeltProfileFile() builds sandbox-macos-${profile}.sb); consumers are never imports, and a basename grep measures zero |
Any key in packages/cli/src/config/settingsSchema.ts |
Report-only — see below |
packages/sdk-*, packages/acp-bridge, protocol/wire shapes |
Report-only — out-of-repo consumers |
packages/vscode-ide-companion, packages/chrome-extension, packages/zed-extension |
Report-only — shipped as store manifests; the store is the consumer |
.github/ — workflows, actions, CODEOWNERS |
Report-only — consumed GitHub-side: triggers, required checks, cross-repo uses: |
package.json dependencies |
Report-only — bundlers and postinstall hide consumers |
| Comments, JSDoc, commented-out code |
Out of scope — AGENTS.md says do not delete existing comments as cleanup |
packages/desktop-shell, packages/cua-driver, packages/mobile-mcp, **/generated/**, **/*.test.ts(x), **/*.spec.ts(x), **/__snapshots__/** |
Never a target; always searched as consumers — vitest discovers tests by filename glob, nothing imports them, so an import-based orphan detector matches every live test vacuously |
A settings key with zero read sites is still not cleanup. The key is likely
documented under docs/users/ and completed from the generated schema;
removing it withdraws a documented, user-settable option and turns an
accepted setting into a silently ignored one — warned nowhere, since the
unknown-key check compares top-level keys only and its output is a
session-gated debug-log append, never the terminal. That is a deprecation
decision. File it; never land it.
Report-only does not mean worthless — a named, proven, un-landable finding is
exactly what a maintainer needs to make the call. It means the run stops at
the issue comment.
Decision Table
| Situation |
Do |
| Landable territory, every consumer named, maintainer said yes |
Land it. One candidate, one PR |
| Landable territory, no assent yet |
File on the tracking issue and stop |
| Several strong candidates in one run |
File them all; land at most one |
| Report-only territory |
File with evidence, marked report-only. Never a PR |
| Path or symbol younger than ~90 days |
Drop silently — unwired new feature, not rot |
| A never-called migrator, validator, guard, or dropped wire-up |
Not cleanup. It may be a defect → /bugfix or /review |
| Any consumer cannot be named |
Drop |
| Correct but tiny (one dead import, a typo) |
Reject on the ledger: below both skills' intake bar |
| Branch would remove 500+ production logic lines under core paths |
Stop. docs/design/yyyy-mm-dd-topic.md, then a maintainer |
AGENTS.md § Core Infrastructure Is Maintainer-Only governs
packages/core/src/**, packages/*/src/ under auth, providers,
models, config, tools, services, and any cross-package change:
500+ production logic lines of refactor there is a hard block for
non-maintainer PRs (excluding *.test.ts(x), *.spec.ts(x),
__tests__/**, *.schema.{ts,json}, *.generated.ts, **/generated/**),
and anything smaller "must be 100% confident … name every downstream
consumer; if it cannot, escalate." Breadth alone is not size: a sweep
touching many files with a line or two each is judged on confidence, not
file count.
Recurring-Run Design
Rotation
Survey one slice per run, picked by the calendar, plus at most one other if
the first comes up empty. Rotation is what stops the third run from
re-searching the same hot directories.
git fetch origin || exit 1
# Fetch only updates the ref, but every grep below reads the working tree —
# survey fresh code from a throwaway worktree at origin/main. Never switch
# the user's checkout: the survey is read-only and must leave the checkout
# exactly as it found it.
SURVEY_PARENT="${TMPDIR:-/tmp}/find-simplifications-survey"
SURVEY="$SURVEY_PARENT/main"
# Clear any leftover from a failed or interrupted earlier run first. The
# fixed path (not mktemp) lets every call re-derive the worktree with no
# shared state, so at most one leftover can ever exist. There is no EXIT
# trap: the consuming harness spawns a fresh shell per command, so a trap
# fires when THIS call ends — before any survey command runs — and its
# variables do not survive to the call that would need to clear it.
# Delete the directory, never `git worktree remove --force` on the fixed
# path: remove resolves symlinks, so a planted link to another registered
# worktree of this repo would force-delete that foreign tree, uncommitted
# work included. rm -rf unlinks a symlink without following it; prune
# then clears the stale registration. Fail closed on removal errors: a
# leftover that cannot be deleted is owned by someone else, and the
# checkout must never go into a parent this user does not control.
rm -rf "$SURVEY_PARENT" || exit 1
# Close the create side too: `git worktree add` accepts a planted EMPTY
# directory (exit 0, the planter keeps ownership and mode) and a symlink to
# an empty directory (exit 0, the checkout written through the link), so
# recreate the parent as a fresh 0700 dir owned by the running user — no
# other local user can then plant the worktree path. mkdir, not install -d:
# install -d exits 0 adopting an existing directory and following a planted
# symlink, so no exit-status check could tell creation from adoption; mkdir
# fails when anything is still at the path, aborting the block instead.
mkdir -m 0700 "$SURVEY_PARENT" || exit 1
git worktree prune
git worktree add --detach "$SURVEY" origin/main || exit 1
# Slice from the month, not the ISO week: a monthly run advances ISO weeks
# by ~4, so week % 4 repeated the same slice for 3–6 monthly runs at a
# time. POSIX slice computation: the `10#` radix prefix is bash/ksh-only
# and is a hard syntax error under /bin/sh (dash), hence the leading-zero
# strip.
M=$(date -u +%m); SLICE=$(( ${M#0} % 4 ))
echo "SURVEY=$SURVEY SLICE=$SLICE"
Each fenced block in this skill is ONE command: the consuming harness spawns
a fresh shell per command, so environment variables, cwd, and traps set here
do not survive to later calls. Every later call that needs the worktree
re-derives the same fixed path
(${TMPDIR:-/tmp}/find-simplifications-survey/main) and runs its commands
from there (cd "$SURVEY" && …, or by setting the call's working
directory).
| Slice |
Territory |
| 0 |
packages/cli/src/ui/components, ui/hooks, ui/contexts |
| 1 |
packages/cli/src/ui/commands, packages/cli/src/commands |
| 2 |
packages/cli/src/utils, packages/cli/src/i18n, packages/cli/src/services |
| 3 |
scripts/, esbuild.config.js, eslint.legacy-filenames.mjs, root manifests, everything else under packages/cli/src, plus whole-file orphans anywhere in landable territory |
Skip a slice the ledger shows was surveyed in the last three runs; the
fallback is the lowest-numbered slice NOT surveyed in those runs — a skip
with no fallback surveys nothing, and three empty runs in a row trip the
stop-loss below without any sweep having happened. Survey a report-only
territory only when a human asks for it by name.
Check churn per candidate rather than trusting a static list — it moves:
git log --since='3 months ago' --name-only --pretty=format: -- <dir> \
| grep -v '^$' | wc -l
A candidate sitting in a directory the team touches constantly loses the
merge race on any slow cadence, and its test files are exactly where conflicts
land. File those; do not try to land them.
The ledger
State lives in ONE long-lived GitHub issue, [find-simplifications] candidate ledger, and nowhere else. Do not commit a state file: a ledger in the repo
turns "found nothing" into a diff, conflicts across bot branches, and is
deleted by the autofix branch sweep.
Read it before surveying, append to it after. If the search returns no issue,
create it first through /create-issue, with exactly the title
[find-simplifications] candidate ledger — a first run has nowhere else to
post, and an improvised title splits the state this section keeps in one
issue:
gh issue list --state all --search '"find-simplifications" ledger in:title'
gh issue comment <number> --body-file <comment>.md
- Each candidate gets an
id derived from the surface, never from prose:
slug(<primary symbol, file, or directory>) — enum-selector,
locale-orphans-auth-subcommand. A prose-derived id reappears forever.
- One line per candidate:
id — territory — status — date. Statuses:
filed, landed, declined, dropped-recency, dropped-consumers.
- An id on the ledger with status
declined is a permanent tombstone.
Never re-propose it, however good the new evidence looks. A
closed-unmerged simplify/* PR tombstones its id only when it closed on
the finding's merits — the same test the stop-loss rule below uses. Read
the closing comment and the id's ledger line; when neither records a
merits decline, treat the close as operational. A PR closed for
operational reasons (a stale base, conflicts, an infrastructure retry, a
superseding re-file) is not a tombstone: re-survey the id and, if it still
survives the proof protocol, re-file it. Search with --state all — the
default open filter never returns the closed-unmerged PRs this rule targets
— and quote the marker: GitHub tokenizes on hyphens, so
gh pr list --state all --search 'enum-selector in:body' returns unrelated
PRs, while --search '"find-simplifications:id=enum-selector" in:body'
does not.
- Append only. Never rewrite, reorder, prune, or summarize it. A maintainer
removing a line is the only supported retraction.
- Record what a run rejected and why, not only what it filed. That is the
whole anti-churn mechanism: without it the next run re-derives and
re-rejects the same hundred symbols.
- If the ledger cannot be read, stop and say so in the run's output — no
candidates this run. The ledger is the only copy of the permanent
tombstones and the recent-slice rotation this section keeps, so surveying
through a read failure can re-propose a permanently declined id or re-sweep
a slice the last run already covered. Fail closed; there is no equally
authoritative snapshot to fall back on. In headless mode (§ Output) the
read is a file, not
gh: the caller supplies the ledger text as
<workdir>/ledger.md before the run, and a missing or unreadable file is
exactly this read failure.
Never treat a previous run's finding as evidence. Evidence is code: a call
site, a file:line, a git log result.
Stopping
Finding nothing is a successful run, and in a repo this skill has already
swept it is the expected outcome most of the time. Do not lower the evidence
bar to produce output. On an empty run: open nothing, le
…(truncated)
1---2name: find-simplifications3description: Use for a periodic repo-wide sweep of qwen-code for accumulated excess surface — dead components and files, orphaned locale keys, exports nothing consumes, added-then-removed scaffolding — filing candidates on a tracking issue and landing only what a maintainer has said yes to. Repo-wide and evidence-first; every consumer is named before anything is deleted. Not for tidying a diff you just wrote (that is bundled `/simplify`) and not for defects (that is `/review`).4---5
6# Finding qwen-code Simplifications
7
8`AGENTS.md` § Simplicity First — "Minimum code that solves the problem.
9Nothing speculative." This skill hunts what that principle already rejected
10but that shipped anyway. It owns **correct code nobody needs**, repo-wide,
11with no diff to anchor on.
12
13Every candidate names the surface, names **every** consumer, and says what
14breaks when it goes. A candidate whose consumers cannot all be named is
15dropped — not downgraded, dropped.
16
17Read this file, then the one document for your phase. Do not survey or land
18from this file alone; if the phase document cannot be read, stop and say so.
19
20| Phase | Document |
21| ------------------------------------------- | ---------------------- |
22| Survey (default): find and file | `references/survey.md` |
23| Land: turn ONE approved candidate into a PR | `references/land.md` |
24
25## Issue First, PR Second
26
27A run's deliverable is a comment on the tracking issue, **not** a PR.
28
29```
30Survey → file candidates on the tracking issue → maintainer says yes to one
31 → land that one → one PR, one candidate.
32```
33
34This is not ceremony. `AGENTS.md` § Core Infrastructure ends "When in doubt,
35escalate. Better to wrongly escalate than to wrongly approve," and an
36unrequested batch of deletions is the shape that gets closed. It also makes
37the ledger free: the issue that carries the proposals is the same object the
38next run reads to avoid re-proposing them.
39
40A maintainer asking for a PR in this session counts as assent — record it on
41the ledger before opening the PR.
42
43## Boundaries
44
45| Skill | Owns | Why not this one |
46| --------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
47| bundled `/simplify` | The diff you just wrote; stops when there is no diff | Cannot see surface accumulated across releases |
48| `/repo-hygiene` | **Wrong** code — a defect provable by evidence; bans "cleaner / more modern / more consistent" edits | Its six angles are all defect classes |
49| bundled `/review` | Judging a change that exists | Your change does not exist yet |
50| `/create-issue` | Filing an issue well | Use it to create the ledger issue when missing — it cannot comment; post run comments with `gh issue comment` |
51| `/prepare-pr` | `pr-title.txt` / `pr-body.md` from the repo template | Call it in the land phase; do not reinvent PR rules |
52| `/verify-pr` | Behavioral A/B evidence for a PR | A deletion has no behavior to demo |
53| `/bugfix`, `/feat-dev`, `/deflake`, `/docs-*` | A defect, a feature, a flaky test, prose | None of them remove surface |
54
55## Territory
56
57The split is not taste. `packages/core/package.json` exports `"./src/*"` and
58`"./dist/*"`, and `packages/core/src/index.ts` carries ~179 `export * from`
59lines, so **every file under `packages/core/src` is reachable from outside
60this repo**. The release workflow npm-publishes `@qwen-code/audio-capture`
61and the eight `@qwen-code/channel-*` packages with `--access public`, so a
62symbol re-exported by their package entry is reachable the same way. No grep
63inside this repo can prove such a symbol has no consumer. The same is true
64of two surfaces whose consumers are not imports at all:
65`packages/core/vendor/**` and `packages/web-shell` ship inside
66the published `@qwen-code/qwen-code` tarball — `packages/core/package.json`
67lists `vendor` in `files`, and `scripts/copy_bundle_assets.js` copies both
68`vendor/` and `web-shell/dist` into the bundle, where `qwen serve` hands the
69latter to browsers. Their consumers are registry-, tarball-, or browser-side,
70so an in-repo grep for them returns zero hits and the consumer proof passes
71vacuously — `getBuiltinRipgrep()` even assembles the vendor path from
72segments, so no literal path exists to grep for. Import reachability is the
73floor, not the definition: consumption also happens through runtime reads,
74loaders, manifests, and tool configs that never appear as imports. The
75consumer proof must name the mechanism that consumes the surface; a grep
76blind to that mechanism proves nothing, and the rows below mark every such
77path this repo ships or loads. A path named by more than one row takes the
78most restrictive outcome: Never-a-target beats Report-only, which beats
79Landable.
80
81| Territory | Outcome |
82| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
83| `packages/cli/src` — the whole package (`generated/` stays under the Never-a-target row below; `**/*.sb` stays under the Report-only row below; `i18n/locales/**` and `commands/extensions/examples/**` stay under the Report-only row below; `**/*.test.ts(x)`, `**/*.spec.ts(x)`, `**/__snapshots__/**` are never targets, always searched as consumers) | Landable |
84| `scripts/`, `esbuild.config.js`, `eslint.legacy-filenames.mjs`, root manifests | Landable |
85| Whole files or directories nothing consumes by any mechanism named above — no import and no runtime read, loader, manifest, or tool config — anywhere outside `packages/core/src`, `packages/audio-capture`, `packages/channels`, `packages/sdk-*`, `packages/acp-bridge`, `packages/vscode-ide-companion`, `packages/chrome-extension`, `packages/zed-extension`, `packages/web-shell`, `packages/core/vendor`, `.github`, and the Never-a-target row below | Landable |
86| `docs/users/**`, `docs/developers/**`, `docs/index.md`, `docs/_meta.ts`, `packages/cli/src/i18n/locales/**`, `packages/cli/src/commands/extensions/examples/**` — as whole files or directories | **Report-only** — copied into the published tarball (`scripts/prepare-package.js` copies the locales and extension examples; `scripts/copy_bundle_assets.js` copies `docs/users/` for qc-helper) and consumed by the published docs site (`docs-site/scripts/link-public-docs.mjs` symlinks `docs/users/` and `docs/developers/` into the Nextra build per `PUBLIC_DOC_ROOTS` and copies `docs/index.md` and `docs/_meta.ts`; the site discovers pages by walking that tree); consumers are runtime reads — qc-helper's doc paths, the i18n loader's segment-assembled `import()`, `/extensions new` scaffolds — never imports. Individual orphan locale keys stay class-4 candidates: their proof greps the literal key, naming its mechanism |
87| `docs-site/` | **Report-only** — standalone published-site app, not a workspace member; route files are consumed by Next.js filesystem routing and an out-of-repo deploy, never imports, and no in-repo CI builds it |
88| Tracked `.qwen/skills/**`, `.qwen/agents/**`, `.qwen/e2e-tests/**`, `docs/design/**`, `docs/plans/**` | **Report-only** — consumed by the skill loader, agent definitions, and process readers (including `AGENTS.md` itself), never imports |
89| `AGENTS.md`, `CLAUDE.md`, `SECURITY.md`, `CONTRIBUTING.md`, `.prettierrc.json`, `.prettierignore`, `.editorconfig`, `.nvmrc`, `.npmrc`, `.yamllint.yml` | **Report-only** — consumed by external tooling through filename convention (agent harnesses, GitHub's security-policy UI, prettier and yamllint config auto-discovery, nvm, editors); never imports, and an in-repo grep for them measures only prose |
90| Anything under `packages/core/src` | **Report-only** — published |
91| `packages/audio-capture`, `packages/channels` | **Report-only** — npm-published (`--access public`) |
92| `packages/core/vendor/**`, `packages/web-shell` | **Report-only** — shipped inside the published `@qwen-code/qwen-code` tarball / served to browsers by `qwen serve`; consumers are bundled or browser-side, never imports |
93| `packages/cli/src/utils/**/*.sb` | **Report-only** — copied into the published bundle by extension glob (`scripts/copy_bundle_assets.js` copies `packages/**/*.sb`, `scripts/prepare-package.js` lists `'*.sb'`) and read at runtime through a segment-assembled path (`resolveSeatbeltProfileFile()` builds `sandbox-macos-${profile}.sb`); consumers are never imports, and a basename grep measures zero |
94| Any key in `packages/cli/src/config/settingsSchema.ts` | **Report-only** — see below |
95| `packages/sdk-*`, `packages/acp-bridge`, protocol/wire shapes | **Report-only** — out-of-repo consumers |
96| `packages/vscode-ide-companion`, `packages/chrome-extension`, `packages/zed-extension` | **Report-only** — shipped as store manifests; the store is the consumer |
97| `.github/` — workflows, actions, CODEOWNERS | **Report-only** — consumed GitHub-side: triggers, required checks, cross-repo `uses:` |
98| `package.json` dependencies | **Report-only** — bundlers and postinstall hide consumers |
99| Comments, JSDoc, commented-out code | **Out of scope** — `AGENTS.md` says do not delete existing comments as cleanup |
100| `packages/desktop-shell`, `packages/cua-driver`, `packages/mobile-mcp`, `**/generated/**`, `**/*.test.ts(x)`, `**/*.spec.ts(x)`, `**/__snapshots__/**` | Never a target; always searched as consumers — vitest discovers tests by filename glob, nothing imports them, so an import-based orphan detector matches every live test vacuously |
101
102A settings key with zero read sites is still not cleanup. The key is likely
103documented under `docs/users/` and completed from the generated schema;
104removing it withdraws a documented, user-settable option and turns an
105accepted setting into a silently ignored one — warned nowhere, since the
106unknown-key check compares top-level keys only and its output is a
107session-gated debug-log append, never the terminal. That is a deprecation
108decision. File it; never land it.
109
110Report-only does not mean worthless — a named, proven, un-landable finding is
111exactly what a maintainer needs to make the call. It means the run stops at
112the issue comment.
113
114## Decision Table
115
116| Situation | Do |
117| ---------------------------------------------------------------- | ---------------------------------------------------------- |
118| Landable territory, every consumer named, maintainer said yes | Land it. One candidate, one PR |
119| Landable territory, no assent yet | File on the tracking issue and stop |
120| Several strong candidates in one run | File them all; land at most one |
121| Report-only territory | File with evidence, marked report-only. Never a PR |
122| Path or symbol younger than ~90 days | Drop **silently** — unwired new feature, not rot |
123| A never-called migrator, validator, guard, or dropped wire-up | Not cleanup. It may be a defect → `/bugfix` or `/review` |
124| Any consumer cannot be named | Drop |
125| Correct but tiny (one dead import, a typo) | Reject on the ledger: below both skills' intake bar |
126| Branch would remove 500+ production logic lines under core paths | Stop. `docs/design/yyyy-mm-dd-topic.md`, then a maintainer |
127
128`AGENTS.md` § Core Infrastructure Is Maintainer-Only governs
129`packages/core/src/**`, `packages/*/src/` under `auth`, `providers`,
130`models`, `config`, `tools`, `services`, and any cross-package change:
131500+ production logic lines of `refactor` there is a hard block for
132non-maintainer PRs (excluding `*.test.ts(x)`, `*.spec.ts(x)`,
133`__tests__/**`, `*.schema.{ts,json}`, `*.generated.ts`, `**/generated/**`),
134and anything smaller "must be 100% confident … name every downstream
135consumer; if it cannot, escalate." Breadth alone is not size: a sweep
136touching many files with a line or two each is judged on confidence, not
137file count.
138
139## Recurring-Run Design
140
141### Rotation
142
143Survey one slice per run, picked by the calendar, plus at most one other if
144the first comes up empty. Rotation is what stops the third run from
145re-searching the same hot directories.
146
147```bash
148git fetch origin || exit 1
149# Fetch only updates the ref, but every grep below reads the working tree —
150# survey fresh code from a throwaway worktree at origin/main. Never switch
151# the user's checkout: the survey is read-only and must leave the checkout
152# exactly as it found it.
153SURVEY_PARENT="${TMPDIR:-/tmp}/find-simplifications-survey"
154SURVEY="$SURVEY_PARENT/main"
155# Clear any leftover from a failed or interrupted earlier run first. The
156# fixed path (not mktemp) lets every call re-derive the worktree with no
157# shared state, so at most one leftover can ever exist. There is no EXIT
158# trap: the consuming harness spawns a fresh shell per command, so a trap
159# fires when THIS call ends — before any survey command runs — and its
160# variables do not survive to the call that would need to clear it.
161# Delete the directory, never `git worktree remove --force` on the fixed
162# path: remove resolves symlinks, so a planted link to another registered
163# worktree of this repo would force-delete that foreign tree, uncommitted
164# work included. rm -rf unlinks a symlink without following it; prune
165# then clears the stale registration. Fail closed on removal errors: a
166# leftover that cannot be deleted is owned by someone else, and the
167# checkout must never go into a parent this user does not control.
168rm -rf "$SURVEY_PARENT" || exit 1
169# Close the create side too: `git worktree add` accepts a planted EMPTY
170# directory (exit 0, the planter keeps ownership and mode) and a symlink to
171# an empty directory (exit 0, the checkout written through the link), so
172# recreate the parent as a fresh 0700 dir owned by the running user — no
173# other local user can then plant the worktree path. mkdir, not install -d:
174# install -d exits 0 adopting an existing directory and following a planted
175# symlink, so no exit-status check could tell creation from adoption; mkdir
176# fails when anything is still at the path, aborting the block instead.
177mkdir -m 0700 "$SURVEY_PARENT" || exit 1
178git worktree prune
179git worktree add --detach "$SURVEY" origin/main || exit 1
180# Slice from the month, not the ISO week: a monthly run advances ISO weeks
181# by ~4, so week % 4 repeated the same slice for 3–6 monthly runs at a
182# time. POSIX slice computation: the `10#` radix prefix is bash/ksh-only
183# and is a hard syntax error under /bin/sh (dash), hence the leading-zero
184# strip.
185M=$(date -u +%m); SLICE=$(( ${M#0} % 4 ))
186echo "SURVEY=$SURVEY SLICE=$SLICE"
187```
188
189Each fenced block in this skill is ONE command: the consuming harness spawns
190a fresh shell per command, so environment variables, cwd, and traps set here
191do not survive to later calls. Every later call that needs the worktree
192re-derives the same fixed path
193(`${TMPDIR:-/tmp}/find-simplifications-survey/main`) and runs its commands
194from there (`cd "$SURVEY" && …`, or by setting the call's working
195directory).
196
197| Slice | Territory |
198| ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
199| 0 | `packages/cli/src/ui/components`, `ui/hooks`, `ui/contexts` |
200| 1 | `packages/cli/src/ui/commands`, `packages/cli/src/commands` |
201| 2 | `packages/cli/src/utils`, `packages/cli/src/i18n`, `packages/cli/src/services` |
202| 3 | `scripts/`, `esbuild.config.js`, `eslint.legacy-filenames.mjs`, root manifests, everything else under `packages/cli/src`, plus whole-file orphans anywhere in landable territory |
203
204Skip a slice the ledger shows was surveyed in the last three runs; the
205fallback is the lowest-numbered slice NOT surveyed in those runs — a skip
206with no fallback surveys nothing, and three empty runs in a row trip the
207stop-loss below without any sweep having happened. Survey a report-only
208territory only when a human asks for it by name.
209
210Check churn per candidate rather than trusting a static list — it moves:
211
212```bash
213git log --since='3 months ago' --name-only --pretty=format: -- <dir> \
214 | grep -v '^$' | wc -l
215```
216
217A candidate sitting in a directory the team touches constantly loses the
218merge race on any slow cadence, and its test files are exactly where conflicts
219land. File those; do not try to land them.
220
221### The ledger
222
223State lives in ONE long-lived GitHub issue, `[find-simplifications] candidate
224ledger`, and nowhere else. Do not commit a state file: a ledger in the repo
225turns "found nothing" into a diff, conflicts across bot branches, and is
226deleted by the autofix branch sweep.
227
228Read it before surveying, append to it after. If the search returns no issue,
229create it first through `/create-issue`, with exactly the title
230`[find-simplifications] candidate ledger` — a first run has nowhere else to
231post, and an improvised title splits the state this section keeps in one
232issue:
233
234```bash
235gh issue list --state all --search '"find-simplifications" ledger in:title'
236gh issue comment <number> --body-file <comment>.md
237```
238
239- Each candidate gets an `id` derived from the **surface**, never from prose:
240 `slug(<primary symbol, file, or directory>)` — `enum-selector`,
241 `locale-orphans-auth-subcommand`. A prose-derived id reappears forever.
242- One line per candidate: `id — territory — status — date`. Statuses:
243 `filed`, `landed`, `declined`, `dropped-recency`, `dropped-consumers`.
244- An id on the ledger with status `declined` is a **permanent tombstone.
245 Never re-propose it**, however good the new evidence looks. A
246 closed-unmerged `simplify/*` PR tombstones its id only when it closed on
247 the finding's merits — the same test the stop-loss rule below uses. Read
248 the closing comment and the id's ledger line; when neither records a
249 merits decline, treat the close as operational. A PR closed for
250 operational reasons (a stale base, conflicts, an infrastructure retry, a
251 superseding re-file) is not a tombstone: re-survey the id and, if it still
252 survives the proof protocol, re-file it. Search with `--state all` — the
253 default open filter never returns the closed-unmerged PRs this rule targets
254 — and quote the marker: GitHub tokenizes on hyphens, so
255 `gh pr list --state all --search 'enum-selector in:body'` returns unrelated
256 PRs, while `--search '"find-simplifications:id=enum-selector" in:body'`
257 does not.
258- Append only. Never rewrite, reorder, prune, or summarize it. A maintainer
259 removing a line is the only supported retraction.
260- Record what a run **rejected** and why, not only what it filed. That is the
261 whole anti-churn mechanism: without it the next run re-derives and
262 re-rejects the same hundred symbols.
263- If the ledger cannot be read, stop and say so in the run's output — no
264 candidates this run. The ledger is the only copy of the permanent
265 tombstones and the recent-slice rotation this section keeps, so surveying
266 through a read failure can re-propose a permanently declined id or re-sweep
267 a slice the last run already covered. Fail closed; there is no equally
268 authoritative snapshot to fall back on. In headless mode (§ Output) the
269 read is a file, not `gh`: the caller supplies the ledger text as
270 `<workdir>/ledger.md` before the run, and a missing or unreadable file is
271 exactly this read failure.
272
273Never treat a previous run's finding as evidence. Evidence is code: a call
274site, a `file:line`, a `git log` result.
275
276### Stopping
277
278**Finding nothing is a successful run**, and in a repo this skill has already
279swept it is the expected outcome most of the time. Do not lower the evidence
280bar to produce output. On an empty run: open nothing, le
281
282…(truncated)