docs: address Copilot review round 8 on #2203

Ask the YAML parser what it discarded instead of re-deriving it from the raw
frontmatter text. `yaml` hangs the comment it stripped on the scalar node, so
`parseDocument(...).get(field, true).comment` IS the truncation signal: a plain
scalar that lost text has one, a quoted or block scalar never does, and
`Issue#28` (no preceding space, so no comment) keeps its full value.

That closes both findings at once. The line-locating regex only ever matched
the canonical `description:` key, so `"description":` and `description :`
populated the mapping while the guard skipped them and left verify:skills green
on a truncated listing; and the continuation scan stopped at the first blank
line, inspecting only the opening paragraph of a plain scalar that YAML happily
continues past one.

It also retires the scanning itself — three rounds of regex here each fixed one
shape and missed the next (tags and anchors, then indented continuations, now
key forms and blank lines). The node carries all of them for free, so 65 lines
of hand-rolled parsing come out. Parsing once with `parseDocument` keeps the
node view and the value view from ever disagreeing.

Tests cover the three noncanonical key forms, the blank-line continuation, and
the standalone comments that must NOT read as truncation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SyBPs7caoMcyvnp9ArMBhV
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
cliffhall 2026-09-01 12:46:22 -04:00
commit c66793bfd8

View file

@ -601,3 +601,72 @@ test("the positive floor counts distinct prompts, not entries", () => {
[],
);
});
test("the truncation guard covers noncanonical key forms", () => {
// `"description":` and `description :` both populate the mapping, so a guard
// that located the field by matching a `^description:` LINE skipped them
// entirely and left `verify:skills` green on a truncated listing (Copilot).
const mk = (key) =>
[
"---",
"name: alpha",
`${key} Covers board #28 and the hazard.`,
"disable-model-invocation: false",
"---",
"body",
].join("\n");
for (const key of ['"description":', "'description':", "description :"]) {
const parsed = parseSkill("alpha", mk(key));
assert.equal(parsed.description, "Covers board", `key form: ${key}`);
assert.match(
parsed.errors.join(" "),
/`description` is truncated/,
`key form: ${key}`,
);
}
});
test("the truncation guard spans a blank line inside a plain scalar", () => {
// A plain scalar continues across empty lines too, so a scan that stopped at
// the first blank one inspected only the opening paragraph and reported no
// loss (Copilot).
const parsed = parseSkill(
"alpha",
[
"---",
"name: alpha",
"description: Covers boards",
"",
" #28 and #11 and the hazard.",
"disable-model-invocation: false",
"---",
"body",
].join("\n"),
);
assert.equal(parsed.description, "Covers boards");
assert.match(parsed.errors.join(" "), /`description` is truncated/);
});
test("a standalone comment line is not read as truncation", () => {
// The guard keys on the comment the parser hung on the SCALAR. A comment on
// its own line belongs to the document, not to the description, and flagging
// it would fail a frontmatter that loses nothing.
for (const frontmatter of [
["# leading", "name: alpha", "description: Covers boards"],
["name: alpha", "description: Covers boards", "# standalone"],
["name: alpha", "description: Issue#28 needs no quoting"],
]) {
const parsed = parseSkill(
"alpha",
[
"---",
...frontmatter,
"disable-model-invocation: false",
"---",
"body",
].join("\n"),
);
assert.deepEqual(parsed.errors, [], frontmatter.join(" | "));
}
});