test(proevesett): a case for the intent gate; case 5's error comes from code; graders see what they claim

New case plan-halts-without-intent-approval (expectation committed before
its first run): a 2.1 brief WITH phase_signals and no intent marker.
Graders: intent-approval.mjs --check ran; the trace carries the gate's own
JSON code for BRIEF_INTENT_NOT_APPROVED; no Agent; no plan.md.

review-requires-project: the arg parser now has a CLI that checks the
required flag and prints 'Error: --project <dir> is required.' + usage
(exit 1, code ARG_REQUIRED_MISSING). trekreview.md runs it with
$ARGUMENTS (it passed "$@", which the Bash tool never has, so the parser
never ran — 0 Bash calls in the PM's case-5 traces) and relays its stderr
instead of composing the line. The grader project-required (reply regex,
unstable on backticks) is replaced by parser-ran + names-missing-project
(trace, the parser's JSON code), the same form as names-rule.

Graders: no-error-code is bound to the validator's JSON output form and
covers every REVIEW_* code (WRONG_TYPE and VERSION_FORMAT were missing);
says-pass/says-fail reject a preceding NOT and a longer word; every case
with no-write also gets no-bash-write (redirect, tee, touch, cp, mv, rm,
sed -i in the Bash command). Checked on the PM's 10 recorded traces: no
false positive; known-positive/negative still split.

Red 348aa95 6/7 → green 7/7. Suite 1231: 1229 pass / 0 fail / 2 skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-23 09:28:38 +02:00
commit 3892a835dd
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
18 changed files with 127 additions and 14 deletions

View file

@ -125,3 +125,41 @@ function tokenize(s) {
}
export { FLAG_SCHEMA };
// Flags a command cannot run without, and its usage line. The CLI below emits
// the error, so the command prose relays code output instead of composing the
// message (a model does not always repeat prose word for word — proevesett
// case review-requires-project failed 2 of 10 on backticks around the flag).
const REQUIRED = {
trekreview: {
flags: [['--project', '<dir>']],
usage: 'Usage: /trekreview --project <dir> [--since <ref>] [--quick] [--validate] [--dry-run]',
},
};
// CLI: node lib/parsers/arg-parser.mjs --command <command> -- $ARGUMENTS
// stdout: the parse result as JSON. exit 0, or exit 1 with each error as
// "Error: <message>" plus the usage line on stderr.
if (import.meta.url === `file://${process.argv[1]}`) {
const argv = process.argv.slice(2);
const ci = argv.indexOf('--command');
const command = ci >= 0 ? argv[ci + 1] : undefined;
const dd = argv.indexOf('--');
const rest = dd >= 0 ? argv.slice(dd + 1) : [];
const r = parseArgs(rest.map((t) => (/\s/.test(t) ? `"${t}"` : t)).join(' '), command);
const req = REQUIRED[command];
if (req) {
for (const [flag, metavar] of req.flags) {
if (!(flag in r.flags)) {
r.errors.push({ code: 'ARG_REQUIRED_MISSING', message: `${flag} ${metavar} is required.` });
}
}
}
process.stdout.write(JSON.stringify(r) + '\n');
if (r.errors.length > 0) {
for (const e of r.errors) process.stderr.write(`Error: ${e.message}\n`);
if (req) process.stderr.write(`${req.usage}\n`);
process.exit(1);
}
process.exit(0);
}