fix: round 2 of the release review of 6.3.0
Round 2 (v6.2.0..0d044f6, BLOCK: 2 BLOCKER, 11 MAJOR, 1 MINOR), each fixed behind a test that failed first. - The git runner checks only words /bin/sh passes through unchanged (no quote, backslash, $, glob or brace) and refuses --output and its abbreviations: round 1's --output refusal was bypassed by quoting. - fieldPaths: backticked paths are kept as written, parentheses and all; in plain text every path-like word counts, and a parenthesised note does not. - plan-validator --steps-from reads the plan's ## Verification for an appended End-to-end step, and warns instead of failing under --soft. - regression-check prints progress_status, the value progress.json takes; /trekexecute copies it. - release-check: a plugin in a subdirectory is checked in its own directory, the suite is not run when a cheaper check already makes the answer exit 2, and a bad argument or a crash is exit 2. - Skill routing looks a skill up among skills only, and builds the corpus vectors once. - /trekexecute Phase 7.2 says plainly that remediation steps in the review template's own form stop with a re-plan; making them runnable is a later order (operator 2026-10-10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0d044f6b6f
commit
ed87cc668d
10 changed files with 263 additions and 70 deletions
|
|
@ -85,55 +85,57 @@ const DOORS = `### Doors
|
|||
function fixture({
|
||||
suiteExit = 0, doors = DOORS, verdict = 'ALLOW', writeReview = true,
|
||||
reviewSha = 'work', afterRelease = null, dirty = false, version = '1.0.1',
|
||||
testScript = null, files = {}, attributes = null,
|
||||
testScript = null, files = {}, attributes = null, sub = null,
|
||||
} = {}) {
|
||||
const base = mkdtempSync(join(tmpdir(), 'release-check-'));
|
||||
const repo = join(base, 'repo');
|
||||
mkdirSync(join(repo, '.claude-plugin'), { recursive: true });
|
||||
// sub: the plugin lives in a subdirectory of a larger repo (release review of 6.3.0, round 2).
|
||||
const dir = sub ? join(repo, sub) : repo;
|
||||
mkdirSync(join(dir, '.claude-plugin'), { recursive: true });
|
||||
git(repo, 'init', '-q', '-b', 'main');
|
||||
git(repo, 'config', 'user.email', 't@example.invalid');
|
||||
git(repo, 'config', 'user.name', 't');
|
||||
git(repo, 'config', 'commit.gpgsign', 'false');
|
||||
|
||||
const pkg = (v) => JSON.stringify({ name: 'fx', version: v, scripts: { test: testScript ?? `node -e "process.exit(${suiteExit})"` } }, null, 2) + '\n';
|
||||
writeFileSync(join(repo, 'package.json'), pkg('1.0.0'));
|
||||
writeFileSync(join(repo, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx', version: '1.0.0' }) + '\n');
|
||||
writeFileSync(join(repo, 'README.md'), '# fx\n\n\n\nText.\n');
|
||||
writeFileSync(join(repo, 'CHANGELOG.md'), '# Changelog\n\n## v1.0.0 — 2026-10-01 — first\n\n- first\n');
|
||||
writeFileSync(join(repo, 'a.mjs'), 'export const a = 1;\n');
|
||||
for (const [rel, text] of Object.entries(files)) writeFileSync(join(repo, rel), text);
|
||||
writeFileSync(join(dir, 'package.json'), pkg('1.0.0'));
|
||||
writeFileSync(join(dir, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx', version: '1.0.0' }) + '\n');
|
||||
writeFileSync(join(dir, 'README.md'), '# fx\n\n\n\nText.\n');
|
||||
writeFileSync(join(dir, 'CHANGELOG.md'), '# Changelog\n\n## v1.0.0 — 2026-10-01 — first\n\n- first\n');
|
||||
writeFileSync(join(dir, 'a.mjs'), 'export const a = 1;\n');
|
||||
for (const [rel, text] of Object.entries(files)) writeFileSync(join(dir, rel), text);
|
||||
if (attributes) writeFileSync(join(repo, '.git', 'info', 'attributes'), attributes);
|
||||
git(repo, 'add', '-A');
|
||||
git(repo, 'commit', '-q', '-m', 'feat: first');
|
||||
writeFileSync(join(repo, 'a.mjs'), 'export const a = 2;\n');
|
||||
git(repo, 'add', 'a.mjs');
|
||||
git(repo, 'commit', '-q', '-m', 'fix: the work');
|
||||
const workSha = git(repo, 'rev-parse', 'HEAD');
|
||||
git(dir, 'add', '-A');
|
||||
git(dir, 'commit', '-q', '-m', 'feat: first');
|
||||
writeFileSync(join(dir, 'a.mjs'), 'export const a = 2;\n');
|
||||
git(dir, 'add', 'a.mjs');
|
||||
git(dir, 'commit', '-q', '-m', 'fix: the work');
|
||||
const workSha = git(dir, 'rev-parse', 'HEAD');
|
||||
|
||||
if (version !== null) {
|
||||
writeFileSync(join(repo, 'package.json'), pkg(version));
|
||||
writeFileSync(join(repo, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx', version }) + '\n');
|
||||
writeFileSync(join(dir, 'package.json'), pkg(version));
|
||||
writeFileSync(join(dir, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx', version }) + '\n');
|
||||
} else {
|
||||
writeFileSync(join(repo, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx' }) + '\n');
|
||||
writeFileSync(join(repo, 'package.json'), JSON.stringify({ name: 'fx', scripts: { test: 'node -e "process.exit(0)"' } }) + '\n');
|
||||
writeFileSync(join(dir, '.claude-plugin', 'plugin.json'), JSON.stringify({ name: 'fx' }) + '\n');
|
||||
writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'fx', scripts: { test: 'node -e "process.exit(0)"' } }) + '\n');
|
||||
}
|
||||
writeFileSync(join(repo, 'README.md'), `# fx\n\n\n\nText.\n`);
|
||||
writeFileSync(join(repo, 'CHANGELOG.md'),
|
||||
writeFileSync(join(dir, 'README.md'), `# fx\n\n\n\nText.\n`);
|
||||
writeFileSync(join(dir, 'CHANGELOG.md'),
|
||||
`# Changelog\n\n## v${version ?? '9.9.9'} — 2026-10-08 — fixture\n\n${doors ?? ''}\n### Fixed\n\n- the work\n\n## v1.0.0 — 2026-10-01 — first\n\n- first\n`);
|
||||
git(repo, 'add', '-A');
|
||||
git(repo, 'commit', '-q', '-m', 'chore(release): fixture');
|
||||
git(dir, 'add', '-A');
|
||||
git(dir, 'commit', '-q', '-m', 'chore(release): fixture');
|
||||
|
||||
if (afterRelease) {
|
||||
for (const [rel, text] of Object.entries(afterRelease)) writeFileSync(join(repo, rel), text);
|
||||
git(repo, 'add', '-A');
|
||||
git(repo, 'commit', '-q', '-m', 'after the review');
|
||||
for (const [rel, text] of Object.entries(afterRelease)) writeFileSync(join(dir, rel), text);
|
||||
git(dir, 'add', '-A');
|
||||
git(dir, 'commit', '-q', '-m', 'after the review');
|
||||
}
|
||||
if (dirty) writeFileSync(join(repo, 'a.mjs'), 'export const a = 3;\n');
|
||||
if (dirty) writeFileSync(join(dir, 'a.mjs'), 'export const a = 3;\n');
|
||||
|
||||
const review = join(base, 'review.md');
|
||||
const sha = reviewSha === 'work' ? workSha : reviewSha;
|
||||
if (writeReview) writeFileSync(review, reviewText({ verdict, sha }));
|
||||
return { base, repo, review, cleanup: () => rmSync(base, { recursive: true, force: true }) };
|
||||
return { base, repo: dir, review, cleanup: () => rmSync(base, { recursive: true, force: true }) };
|
||||
}
|
||||
|
||||
function run(fx, extra = []) {
|
||||
|
|
@ -360,3 +362,29 @@ test('release-check — a red suite is red when the check itself runs under node
|
|||
assert.match(r.stdout, /npm test exited/);
|
||||
} finally { fx.cleanup(); }
|
||||
});
|
||||
|
||||
// ---- round 2 of the release review (2026-10-10) --------------------------------
|
||||
|
||||
test('release-check — a plugin in a subdirectory of a larger repo is checked there → 0', () => {
|
||||
const fx = fixture({ sub: 'voyage' });
|
||||
try {
|
||||
const r = run(fx);
|
||||
assert.equal(r.status, 0, r.stdout + r.stderr);
|
||||
} finally { fx.cleanup(); }
|
||||
});
|
||||
|
||||
test('release-check — no review: the suite is not run, exit 2 at once', () => {
|
||||
const fx = fixture({ writeReview: false, testScript: 'node -e "require(\'fs\').writeFileSync(\'suite-ran\', \'\')"' });
|
||||
try {
|
||||
const r = run(fx);
|
||||
assert.equal(r.status, 2, r.stdout + r.stderr);
|
||||
assert.equal(existsSync(join(fx.repo, 'suite-ran')), false, 'the suite did not run');
|
||||
assert.match(r.stdout, /suite\s+not run/);
|
||||
} finally { fx.cleanup(); }
|
||||
});
|
||||
|
||||
test('release-check — a flag with no value is exit 2, not 1', () => {
|
||||
const r = spawnSync(process.execPath, [CHECK, '--repo'], { encoding: 'utf8' });
|
||||
assert.equal(r.status, 2, r.stdout + r.stderr);
|
||||
assert.match(r.stdout + r.stderr, /not measured|NOT MEASURED/i);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue