skill-size-check: a boundary clause naming a dotted filename is invisible to the gate #110
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found during the #99 ADR-0020 retrofit, wave 2 (
pc-author).What happens
scripts/skill-size-check.shdetects a boundary clause with:The
[^.;]character class cannot cross a.or;. So any boundary clause that names a dotted filename between "Not" and the arrow is invisible to the gate:Why it matters
The failure is silent and misdiagnosing. The clause is present and correct for a human reader, but the gate reports a missing boundary clause SUGGESTION. An author reading that finding has no way to know the clause exists and simply was not matched — the reported problem and the actual problem are different things.
In wave 2 this cost real time: the first
pc-authordraft carried the clause above, the gate reported it as missing, and the cause was only found by reading the regex. The workaround was rewording to "the pre-commit config" — which is fine here, but the gate should not be dictating prose to avoid a parsing artifact.Scope of the bite
Narrow but real. It only fires when the dotted token sits between
Notand the arrow. A dotted filename after the arrow, or in an earlier sentence, is unaffected — confirmed on the finalpc-authordescription, where.pre-commit-config.yamlappears before "Not" and the clause matches normally.Suggested fix
Sentence segmentation rather than a character-class exclusion, or at minimum exempt a
.that is part of a backticked token. Whatever the approach, the gate should distinguish "no boundary clause" from "boundary clause I could not parse" — the second deserves its own message.Related
Sibling gate defects from the same retrofit: #107, #108, #109.
Two more independent hits during #99 wave 3, from agents that had no knowledge of this issue or of each other. That makes three occurrences in two waves, and it moves this from "latent defect" to "reliably distorts authored output."
Both agents wrote a correct boundary clause, watched
validate.shreportdescription has no boundary clause, and — because the gate is hot — reworded the clause to satisfy the regex. Neither wrote the clause they judged best.The two hits
vale-run. Clause named.vale.ini. The dots ended clause detection before the arrow. Workaround: strip the filename entirely.Cost: the router-facing text no longer names the file that is the actual discriminator between this skill and
vale-config.agentsmd-audit. Every one of its boundary clauses names a dotted file —CLAUDE.md,AGENTS.md— so this was unavoidable, not incidental. Workaround: insert a word soBOUNDARY_MARKERmatches instead ofBOUNDARY_ARROW.Cost: a stray "for" whose only purpose is to route around a regex, in a skill whose whole domain is dotted filenames.
What this sharpens about the diagnosis
Three details worth adding to the original report:
2 of 2 boundary target(s) resolve. Only the presence heuristic breaks. So the failure is a false SUGGESTION on a clause that is present and working, not a routing failure.BOUNDARY_MARKERis the escape hatch and it is undocumented.agentsmd-auditfound it by trial. Whatever the fix, the two matchers' relationship should be stated somewhere an author reads.Bearing on the fix
The original recommendation — allow the pattern to cross a
.when it is not sentence-terminating — still looks right. The wave-3 evidence adds one constraint: dotted filenames in boundary clauses are common and often unavoidable, since a large share of this corpus exists to route between named files. Any fix that merely documents a workaround leaves the distortion in place.Both wave-3 clauses should be rewritten to name their files once the regex is fixed. Recording that here so the revert is not forgotten.
Related
Found during #99 wave 3, alongside #109 (resolved) and #114.
Severity escalation: for a bare target the clause is not misreported, it is unchecked
Found during a third independent review of #99's branch. The issue body frames the impact as a misdiagnosis — the clause is present but the gate reports missing boundary clause. That holds when the target is backticked. When the target is bare, the failure is worse and silent: the target is never extracted, so the dangling-route check never runs on it.
Reproduced by executing the extracted resolver against a synthetic
knownset:So a boundary clause naming a non-existent skill after a dotted filename ships green with no finding of any kind — not a SUGGESTION, not a dangling-target report. That is a different failure class from the one this issue describes: the misdiagnosis is noisy and eventually gets read, this one produces silence.
The two live clauses of this shape are rescued by their backticks, not by luck of wording
Measured on the current corpus:
BOUNDARY_ARROWhitsagentsmd-auditNot writing AGENTS.md -> `agentsmd-author`.agentsmd-author,provider-adapter-authoragentsmd-authorNot for CLAUDE.md -> `provider-adapter-author`.agentsmd-audit,provider-adapter-authoragentsmd-auditis the clear case:BOUNDARY_ARROWscores zero hits on that description — the.inAGENTS.mdblocks it exactly as this issue describes — and the targets survive only because they are backticked, which routes extraction through the backtick rule instead. Rewrite that same clause with a bare target and the route silently stops being checked.No current skill is actually dangling this way, so nothing is broken today. But the protection is incidental: it depends on an authoring convention (backtick your targets) that nothing enforces, rather than on the gate.
Bearing on the suggested fix
This strengthens the issue's existing recommendation rather than changing it. "Distinguish no boundary clause from boundary clause I could not parse" is still the right shape — but the bare-target case shows the parse failure must also be surfaced when the clause yields zero targets, not only when the boundary heuristic returns false. A clause that matches nothing and extracts nothing currently produces no output at all.
Worth noting alongside #107, which is the adjacent recall hole in the same notation (only the first target after an arrow is resolved). Both matter more after #99 than before it: the retrofit standardised roughly 30 of 39 descriptions on the compressed arrow form, so the notation with the two blind spots is now the corpus default.
Related: #107, #117, #118, and the
validate-provenance.shbullet-form parser defect fixed in484357aonrefactor/adr0020-skill-retrofit— three of the four gate blind spots found so far are "the check silently did not run", not "the check was wrong".Fixed on
refactor/adr0020-skill-retrofit(not yet pushed — the PR body will carry the close), including the severity escalation in comment 2The regex
[^.;]became a namedCLAUSE_BODY:A dot inside a filename is followed by non-space; a sentence-ending dot is followed by whitespace or end-of-string. Both
ARROW_BOUNDARY(target extraction) andBOUNDARY_ARROW(presence heuristic) are built from it, so the two matchers cannot diverge on this again.Three outcomes, as this issue asked for
boundary_clause_status()now returnspresent/absent/unparsed, and the two failure modes get different messages. Theunparsedtext says the clause is present, that this is a parse failure and not a missing clause, that the dangling-target check did not run on it, and names the most common cause (a bare single-word target, deliberately unmatched becauseresearch,triageandforgeare all ordinary English).The bare-target case from comment 2 is genuinely checked now
Not inferred — executed against a synthetic package:
So the protection no longer depends on the incidental backtick convention comment 2 identified. Bare, after a dotted filename, is extracted, resolved, and blocking.
All three hosts carry the change:
scripts/skill-size-check.sh,skill-audit/scripts/validate.sh,agent-audit/scripts/validate.sh.Remaining work — the wave-3 revert has NOT been done
Comment 1 asked that both workaround clauses be rewritten to name their files once the regex was fixed. They have not been. Current state on the branch:
vale-runNot setting up Vale config or styles -> `vale-config`..vale.iniagentsmd-auditNot converting a provider file -> `provider-adapter-author`.CLAUDE.mdThe gate no longer forces either wording, so both can now say what their authors judged best. Leaving this issue open on that basis.
Fixed by #129, squash-merged to
mainas598a7c3.Verified against the merged tree on the exact clause from this issue's report:
The target
git-commitsis now extracted and carried into resolution. No "missing boundary clause" SUGGESTION — the misdiagnosing finding this issue is about is gone, and the gate no longer dictates prose to avoid a parsing artifact.The related ask — that the gate distinguish "no boundary clause" from "boundary clause I could not parse" — also landed: an unparsable arrow clause now reports explicitly that the clause is present and this is a PARSE failure, so the dangling-target check did not run on it.
Stayed open after the merge because Gitea's closing-keyword parser consumed only the first reference in
Closes #99, #107, …. Closing manually.