chore: address Copilot review round 11
- skill-manifest: accept CRLF on the opening fence. A Windows checkout with `core.autocrlf` has `---\r\n`, the fence is still the first line, and the authoritative validator accepts it — so `npm run validate` was failing a valid manifest, and failing it *before* that validator ever ran. The closing fence now strips a preceding CR too, so the YAML handed to the parser is clean. Regression cases for CRLF, mixed endings, and CRLF-with-no-body, plus cases proving the first-line rule and the whole-line terminator rule still hold with CRLF. Verified by mutation. - docs/quality-gate: `verify:skills` requires eval cases only from model-invoked skills; the seven name-only ones intentionally have none, and the summary read as an instruction to add them everywhere. - docs/quality-gate: the `test:scripts` inventory said four new suites; `claude-cli.test.mjs` makes five. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
23c59d7a17
commit
97122b508b
1 changed files with 58 additions and 5 deletions
|
|
@ -254,3 +254,50 @@ test("listingCost counts when_to_use too", () => {
|
|||
7,
|
||||
);
|
||||
});
|
||||
|
||||
test("a CRLF manifest is valid — the fence is still the first line", () => {
|
||||
// A Windows checkout with `core.autocrlf` produces these. Rejecting one would
|
||||
// fail `npm run validate` on a manifest the authoritative validator accepts,
|
||||
// and would fail it *before* that validator ever ran.
|
||||
const crlf =
|
||||
"---\r\nname: x\r\ndescription: d\r\ndisable-model-invocation: true\r\n---\r\n\r\nBody\r\n";
|
||||
assert.equal(
|
||||
splitFrontmatter(crlf).frontmatter,
|
||||
"name: x\r\ndescription: d\r\ndisable-model-invocation: true",
|
||||
);
|
||||
assert.deepEqual(parseSkill("x", crlf).errors, []);
|
||||
|
||||
// Mixed endings are still fine, and so is a CRLF file with no trailing body.
|
||||
assert.deepEqual(
|
||||
parseSkill(
|
||||
"x",
|
||||
"---\r\nname: x\ndescription: d\r\ndisable-model-invocation: true\n---\r\n",
|
||||
).errors,
|
||||
[],
|
||||
);
|
||||
assert.deepEqual(
|
||||
parseSkill(
|
||||
"x",
|
||||
"---\r\nname: x\r\ndescription: d\r\ndisable-model-invocation: true\r\n---",
|
||||
).errors,
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
test("CRLF does not weaken the first-line rule", () => {
|
||||
// The point of the opening check is that anything before the fence turns the
|
||||
// whole file into body — accepting CRLF must not start accepting those.
|
||||
for (const text of [
|
||||
"\r\n---\r\nname: x\r\n---\r\n",
|
||||
"---\r\nname: x\r\n---\r\n",
|
||||
"# Title\r\n---\r\nname: x\r\n---\r\n",
|
||||
"--- \r\nname: x\r\n---\r\n".replace("--- ", "---x"),
|
||||
]) {
|
||||
assert.match(splitFrontmatter(text).error ?? "", /first line|never closed/);
|
||||
}
|
||||
// And `---oops` is still not a terminator with CRLF endings either.
|
||||
assert.match(
|
||||
splitFrontmatter("---\r\nname: x\r\n---oops\r\nbody\r\n").error ?? "",
|
||||
/never closed/,
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue