fix: round 4 of the release review of 6.3.0

Round 4 (v6.2.0..41ea8fc, WARN: 9 MAJOR, 3 MINOR); the nine MAJOR fixed,
each behind a test that failed first (operator 2026-10-10). Three were
regressions from round 3's shared Files: reader.

- fieldPaths keeps a backticked path with punctuation after it and one
  inside a note, a directory (docs/) and a glob (src/*.mjs) in plain text,
  and app/(auth)/x.ts whole; a bare word counts only alone and capitalised
  (Makefile), so "format" or "v6.3.0" in a description is no path. The K6
  sweep plans what v6.2.0 planned for `a.mjs`: and `b.mjs`.
- skill frontmatter: a quoted value may carry a YAML comment after it.
- criteria runner: no word with a leading ~ (sh expands it), and nothing
  after `make test` (another target would run).
- release-check: scope_sha_end must be a commit sha (a ref name passed
  coverage whatever was reviewed), and README lines changed after the review
  may differ only in the badge's version. The round-3 leading-zero example
  is 7 characters now, the shortest sha accepted.

The three MINOR (one word screen for git, the exec copy in regression-check,
a shared isMain helper) are not in this round.

Suite 2175 (2173/0/2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-10 23:48:52 +02:00
commit ab6dcd838e
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 137 additions and 33 deletions

View file

@ -295,8 +295,9 @@ const PLAIN_WORD = /^(?:[A-Za-z0-9_@%^~:.,=+/-]+|[A-Za-z0-9_./][A-Za-z0-9_@%^~:.
// `only` the ones whose value must be one of a few words: a built-in node test
// reporter only formats, a reporter path would load code),
// whether `--` may hand the rest to the repo's own script (`dashDash`: then
// only paths follow), and whether a plain word may carry `=` (make reads
// `VAR=value` as an override). The lists hold options that only read.
// only paths follow), and whether nothing may follow the fixed words at all
// (`noWords`: make reads a word as one more target, or `VAR=value` as an
// override). The lists hold options that only read.
const RUNNER_ARGS = {
npm: { fixed: (t) => (t[1] === 'run' ? 3 : 2), opts: [], dashDash: true },
node: {
@ -310,7 +311,7 @@ const RUNNER_ARGS = {
pytest: { fixed: 1, opts: ['-q', '-qq', '-v', '-vv', '-x', '-s', '--quiet', '--verbose', '--exitfirst', '--tb', '--maxfail'] },
cargo: { fixed: 2, opts: ['--release', '--workspace', '--all', '--lib', '--doc', '-q', '--quiet', '--no-fail-fast'] },
go: { fixed: 2, opts: ['-v', '-short', '-race', '-failfast', '-cover', '-count', '-run'], value: ['-count', '-run'] },
make: { fixed: 2, opts: [], noAssign: true },
make: { fixed: 2, opts: [], noWords: true },
};
RUNNER_ARGS.python = RUNNER_ARGS.python3 = RUNNER_ARGS.uv = { ...RUNNER_ARGS.pytest, fixed: 3 };
@ -318,6 +319,8 @@ function screenArgs(t, spec) {
const fixed = typeof spec.fixed === 'function' ? spec.fixed(t) : spec.fixed;
for (let i = fixed, paths = false; i < t.length; i++) {
const w = t[i];
// `make test install` runs the install target too: make takes nothing more.
if (spec.noWords) return deny(`\`${t.slice(0, fixed).join(' ')}\` with more after it (${w})`);
if (paths) {
if (w.startsWith('-')) return deny(`an option after \`--\` (${w}): only paths may follow it`);
continue;
@ -334,7 +337,6 @@ function screenArgs(t, spec) {
}
continue;
}
if (spec.noAssign && w.includes('=')) return deny(`\`${t[0]}\` with a variable override (${w})`);
}
return permit();
}
@ -431,6 +433,10 @@ function screenShape(command, opts, writeTime) {
const tokens = text.trim().split(/\s+/);
if (!Object.hasOwn(RUNNERS, tokens[0])) return deny(`\`${tokens[0]}\` is not a known test runner`);
// /bin/sh expands a tilde at the start of a word (and after = or : in an
// assignment), so such a word is not one the shell passes on unchanged.
const tilde = tokens.find((w) => /(^|[=:])~/.test(w));
if (tilde !== undefined) return deny(`a word the shell would rewrite (${tilde}): a leading ~ is expanded`);
const form = RUNNERS[tokens[0]](tokens, cwd, writeTime);
if (!form.allowed || tokens[0] === 'git') return form;
const odd = tokens.find((w) => !PLAIN_WORD.test(w));