From 672fd1f7e48005c4c4ba5b7554d1aabb33db0bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 8 Sep 2026 23:01:49 +0200 Subject: [PATCH] :recycle: Adopt setup: prefix and retire the stray use: script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a setup: prefix for one-time clone configuration (mutates the local environment, never a hook or CI step) with setup as its umbrella aggregator. Move use:git-commit-message to setup:git-commit-message as its first member, retiring use: — the undocumented prefix tracked in the backlog. Update both CONTRIBUTING.md prefix lists, the bare-command inventory, and the stale use: reference in branch.sh. --- CONTRIBUTING.md | 9 +++++---- backlog.tasks | 6 +++--- package.json | 3 ++- scripts/branch.sh | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 599d727..9253d01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ This document is for maintainers and contributors working on the project itself. CI and review will bounce these even though `npm run check` and the linters don't catch them. They're the high-frequency things a contributor (or an agent) reaches for by default: - **Source imports use `.ts` extensions, never `.js`.** `node --strip-types` resolves the `.ts` form at test time; `rewriteRelativeImportExtensions` emits `.js` in `dist/`. "Pre-fixing" an import to `.js` breaks the inner loop. (rationale: README § Tooling decisions) -- **A new `npm run` script must reuse an existing prefix** (`create:` / `check:` / `fix:` / `test:` / `watch:` / `maintain:` / `publish:`). If none fits, that's a signal the script doesn't belong in the pipeline — not a reason to invent a new prefix. If it genuinely does belong, add the prefix to both lists here in the same commit; an undocumented prefix becomes invisible and quietly accrues members. (see [Script prefix convention](#script-prefix-convention)) +- **A new `npm run` script must reuse an existing prefix** (`create:` / `check:` / `fix:` / `test:` / `watch:` / `maintain:` / `publish:` / `setup:`). If none fits, that's a signal the script doesn't belong in the pipeline — not a reason to invent a new prefix. If it genuinely does belong, add the prefix to both lists here in the same commit; an undocumented prefix becomes invisible and quietly accrues members. (see [Script prefix convention](#script-prefix-convention)) - **`oxlint-disable` directives live in source, not `.oxlintrc.json`.** The trade-off must sit next to the code it silences. This is a _human_ last-resort convention; agents must not add these — see [AGENTS.md § Never do](./AGENTS.md#never-do). (rationale: README § Tooling decisions) - **Don't put slow / network / whole-project scans in `check` or pre-commit.** Advisory scans are not correctness gates; they belong under `maintain:`. (see [Feedback tiers](#feedback-tiers) and [Script prefix convention](#script-prefix-convention)) - **New work starts with `npm run create:branch`, never a hand-written `git switch -c`/`git checkout -b`.** The command carries the branch precondition; branching around it skips the clean-tree, current-`main` and green-baseline checks, and the skip is invisible until a failure can no longer be attributed. (see [Branching model](#branching-model)) @@ -15,7 +15,7 @@ CI and review will bounce these even though `npm run check` and the linters don' ## Commit messages -Gitmoji subject, imperative mood, 50/72 wrapping. The template is `commit-message-template`; run `npm run use:git-commit-message` once after cloning to register it as git's `commit.template`. +Gitmoji subject, imperative mood, 50/72 wrapping. The template is `commit-message-template`; run `npm run setup:git-commit-message` once after cloning to register it as git's `commit.template` (or `npm run setup` to run every one-time clone step). Examples from history: `:sparkles: Add watch tier with watch:test child`, `:recycle: Move type-aware config to .oxlintrc.json; use source-level disable directives`, `:memo: Restore unique maintainer content as CONTRIBUTING.md`. The body explains _what and why_, not _how_; link issues with `Resolves #...`. @@ -30,10 +30,11 @@ Script names in `package.json` use a prefix that signals _when_ the script is in - `watch:*` — long-running watchers for the manual inner dev loop. Aggregated by `watch`; currently a single child (`watch:test`), and a future `watch:oxlint` / `watch:tsc` would run concurrently under that umbrella. - `maintain:*` — advisory repo-maintenance scans: read-only, but whole-project and/or network-bound, so never a correctness gate. Aggregated by `npm run maintain`. - `publish:*` — validates the _publishable artifact_ (e.g. `dist/`) rather than the source, so it needs a fresh build. (see [Rules the tools don't enforce](#rules-the-tools-dont-enforce) and [Publishing workflow](#publishing-workflow)) +- `setup:*` — one-time configuration of a fresh clone; mutates the local environment (git config, editor settings) rather than the repo source, so it is never part of a hook or CI step. Aggregated by `npm run setup` (the umbrella), run once after cloning. -A new script should pick the prefix that matches its lifecycle, not invent a new one. If no existing prefix fits, that's a signal the script doesn't belong in the standard pipeline. When it genuinely does belong, a new prefix is allowed — but it enters both lists in this file in the same commit as its first member, otherwise the rule "reuse an existing prefix" silently develops an exception (`use:` is tracked as exactly that in `backlog.tasks`). +A new script should pick the prefix that matches its lifecycle, not invent a new one. If no existing prefix fits, that's a signal the script doesn't belong in the standard pipeline. When it genuinely does belong, a new prefix is allowed — but it enters both lists in this file in the same commit as its first member, otherwise the rule "reuse an existing prefix" silently develops an exception (the old `use:` prefix was exactly that; it is now retired into `setup:`). -Separately, some top-level scripts are **bare** (no prefix): the entry points that either run a single tool (`build`, `clean`) or aggregate a `prefix:*` family (`check`, `fix`, `test`, `watch`, `maintain`), plus one convenience that composes across tiers: `verify` — composing `check` + `test:unit` into one whole-project correctness gate (it deliberately uses `test:unit` rather than `test` because `check` already runs `check:tsc`, so the type checker runs exactly once). Bare commands are how you invoke a tier; the `prefix:*` scripts are what those tiers are made of. +Separately, some top-level scripts are **bare** (no prefix): the entry points that either run a single tool (`build`, `clean`) or aggregate a `prefix:*` family (`check`, `fix`, `test`, `watch`, `maintain`, `setup`), plus one convenience that composes across tiers: `verify` — composing `check` + `test:unit` into one whole-project correctness gate (it deliberately uses `test:unit` rather than `test` because `check` already runs `check:tsc`, so the type checker runs exactly once). Bare commands are how you invoke a tier; the `prefix:*` scripts are what those tiers are made of. ## Feedback tiers diff --git a/backlog.tasks b/backlog.tasks index b0942a9..317ab16 100644 --- a/backlog.tasks +++ b/backlog.tasks @@ -18,9 +18,9 @@ Setup: - maybe skills? → resolved: adopted @spences10/pi-lsp@0.0.46 as a project-local pi extension (`.pi/settings.json`). It auto-detects the repo's TypeScript 7 (no `lib/tsserver.js`) and spawns `tsc --lsp --stdio` — the same tsgo binary VS Code's native-preview uses. Read-only: hover / definition / references / symbols / diagnostics. No skill; skills don't own persistent processes. -☐ Adopt a `setup:` prefix for one-time clone configuration - ☐ Register `use:git-commit-message` as its first member (and retire `use:` — it is in no prefix list) - ☐ Create an umbrella 'setup' task that runs all setup tasks - currently one +✔ Adopt a `setup:` prefix for one-time clone configuration @done + ✔ Register `use:git-commit-message` as its first member (and retire `use:` — it is in no prefix list) @done + ✔ Create an umbrella 'setup' task that runs all setup tasks - currently one @done v1.0: ☐ API surface is stable and fully typed diff --git a/package.json b/package.json index a9737e6..e7d36c4 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,8 @@ "watch:test": "node --test --watch --strip-types \"src/**/*.test.ts\"", "publish:attw": "attw . --pack --profile esm-only", "publish:publint": "publint", - "use:git-commit-message": "git config commit.template commit-message-template" + "setup": "npm run setup:git-commit-message", + "setup:git-commit-message": "git config commit.template commit-message-template" }, "devDependencies": { "@arethetypeswrong/cli": "^0.18.5", diff --git a/scripts/branch.sh b/scripts/branch.sh index 0b01696..26d5f0b 100755 --- a/scripts/branch.sh +++ b/scripts/branch.sh @@ -26,7 +26,7 @@ set -eu # `create:` was kept because both members really do create something: a branch, # a release. It was added to both prefix lists in CONTRIBUTING.md in the same # commit as its first members, because a prefix missing from those lists is -# invisible — which is the `use:` mistake this repo now carries in backlog.tasks. +# invisible — which was the `use:` mistake this repo carried in backlog.tasks (since retired into `setup:`). # There is deliberately no bare `create` aggregator: "run all the workflows" # describes nothing anyone wants, and `publish:*` already sets the precedent for # a prefix without one.