The release skill described a v2 release as three steps and left four
things a release actually depends on implicit or absent: that it is two
pull requests against two different bases, the production smoke of the
release candidate, the ledger artifact the maintainers review, and where
a smoke finding gets fixed. It also gave only the `git tag` path, which
is the fallback rather than the norm.
Restructure it around PR 1 -> PR 2 -> Release:
- a "The shape" table contrasting the two PRs by branch, base, contents,
verification and merge condition, plus why they must not be folded
together and why PR 1 merges before PR 2 is opened;
- step 2 broken into the tree-hash check and production smoke, the
ledger's structure, and the fix-on-`v2/main` rule that keeps the merge
tree byte-identical to `origin/v2/main`;
- step 3 leading with the GitHub UI path, keeping the CLI commands as the
by-hand equivalent.
Docs only. The `npm audit fix`, `--no-git-tag-version`, tag-`origin/main`,
no-`v`-prefix and #2010 warnings are all preserved.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RsmR1iQstcrEzJFmgZXGLi
Signed-off-by: cliffhall <cliff@futurescale.com>
Five findings, all valid.
`runOutdated` accepted every exit status and returned `result.stdout ?? ""`.
A failed `npm outdated` (exit 2 on a registry or config error) also prints
nothing, so the empty string parsed to an empty package list — and across five
installs a total outage produced output byte-identical to a clean sweep. It now
throws on any status other than the documented 0/1.
`main()` was untested, which is how that reached review: the helper-only suite
passed while the silent-success path was live. It now takes its spawn function
as a parameter and is driven by a fake, covering npm failure, create vs. edit,
milestone handling, both no-op paths and the missing-repo guard.
The no-op path returned before looking for the marker issue, so once every
install caught up, a still-open tracking issue kept its obsolete package table
indefinitely — contradicting the body's own promise to update in place. It now
rewrites through `buildClearedBody()`. It deliberately does not close the
issue: the sweep takes no board actions, and closing one whose card a
maintainer may have moved would make the board assert work shipped that this
script cannot verify shipped.
The release step mandated `npm audit fix`, which AGENTS.md forbids. The reason
is not `--force`: plain `audit fix` resolves an advisory with no upward escape
in range by silently downgrading, as it did to esbuild across three installs in
#2058, and `local:gate` has no version-regression check to catch it. The step
is now `npm audit` report-only, with fixes applied deliberately via a direct
bump or an `overrides` entry.
An unmilestoned issue is swept into Incoming, not Todo — Todo asserts a
maintainer signed off. Message corrected and pinned by a test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RWMJENjs1mExXE5XPJTEei
Signed-off-by: cliffhall <cliff@futurescale.com>
Adds npm audit fix (root + every client) as the first sub-step of the
release skill's bump step, before npm version, so a release is never
gated on remembering to check separately. Never --force; anything
audit fix can't resolve is left to the dependabot-alert pipeline
(#2229) or a follow-up issue.
Disables Dependabot npm version updates in dependabot.yml (a
version-update PR carries no issue and no board card) and replaces
them with a monthly scheduled sweep that runs npm outdated across the
root install and every client, filing or updating one idempotent
tracking issue instead of an auto-generated PR.
Closes#2231
Part of #2229
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017N9ha27Qg6LHpBQP7G7zPY
Signed-off-by: cliffhall <cliff@futurescale.com>
- board-ops: write board dumps to a temp dir, not the repo root. The boards are
private, so a snapshot is a full export of item IDs and every card's Status
and Priority — and the recipe left three such files in the worktree, one
`git add -A` from being published in a PR. All three now go to `$BOARD_TMP`,
and the snapshot step prints the path, since recovery needs it.
- release: branch from `origin/v2/main` after fetching, and read the version
once you are on it. A default clone has only `main` checked out, so the local
ref may not exist and `package.json` was `main`'s — the released version
rather than the one being bumped from. Added the one-liner for reading it
before branching, since the branch name needs it.
Signed-off-by: cliffhall <cliff@futurescale.com>
- Enrol both skill gates in the repo's gate-integrity vouch cycle. A gate that
stops being invoked fails silently with every fixture test green, which is the
failure the existing cycle exists to prevent. `verify:format-coverage` now
vouches for `verify:skills`, `verify:skills` vouches back, and it additionally
asserts the two links nothing else could see: `verify:skills:cli` present in
`local:gate` and in the workflow — neither is reachable from `validate` or
from any test. `checkWiring` is pure and unit-tested, with a live case against
the real package.json and workflow so the fixtures cannot drift. All four
links verified by mutation.
- The existing sibling-vouch fixture is now a table over every sibling, so
adding a fourth guard later does not need a new test.
- release skill: stop hard-coding `2.3.0`, which has already shipped — the tag
command aborted on an existing tag and the branch template named the wrong
release. Both now read the version from `package.json` (the tag from
`origin/main`'s), with a warning never to copy a version out of the file.
Signed-off-by: cliffhall <cliff@futurescale.com>
Closes#2163
`AGENTS.md` was one 1,223-line contract loaded in full on every turn, whether
the task was a one-line CSS fix or a release cut. This splits it: rules stay
resident, procedures move to `.claude/skills/`.
- Ten skills under `.claude/skills/`, seven `disable-model-invocation: true`
(invoked by name only, so they cost no listing context and have no trigger
question) and three model-invoked with committed eval cases.
- `AGENTS.md` 1,223 → 380 lines: rules, a skills index, and a project tree
reduced to one line per entry. The removed recipes are not duplicated.
- `README.md` 811 → 105 lines, split into `docs/{architecture,quality-gate,
test-servers,publishing,docker}.md`, and dropped from `CLAUDE.md`'s auto-load.
- `.github/copilot-instructions.md` and its mirroring rule removed — Copilot
reads `AGENTS.md`.
- `npm run verify:skills` (in `validate`, so in `local:gate` and CI) parses each
SKILL.md the way Claude Code does, requires an explicit invocation mode and
eval cases for model-invoked skills, and budgets the listing.
- `npm run skills:eval` runs the committed trigger cases headless.
Signed-off-by: cliffhall <cliff@futurescale.com>