fix: stop rejecting skills whose SKILL.md uses thematic breaks - #3297
Conversation
The quality gate stripped frontmatter with a regex carrying the `m` flag, so `^---` matched at every line start rather than only at the start of the document. Frontmatter is optional when publishing, so a SKILL.md that opens with a heading and uses `---` as an ordinary Markdown thematic break had everything between its first two rules deleted before the body was measured. The truncated body then fell under the word and character floors and the publish was rejected outright with "Skill content is too thin or templated". The same truncation also fed the structural fingerprint used for template-spam detection. The three other frontmatter parsers in the repository are all anchored to the start of the document; this one is now consistent with them.
|
@Yigtwxx is attempting to deploy a commit to the OpenClaw Foundation Team on Vercel. A member of the Team first needs to authorize it. |
|
Maintainer follow-up pushed at exact head The quality gate now gets its body from the shared SKILL.md parser instead of maintaining a second frontmatter regex. The parser only strips a delimited block when it parses as a YAML object, normalizes LF/CRLF/CR line endings, and preserves leading Markdown thematic breaks plus malformed or unterminated frontmatter-like text. Regression coverage now includes:
Validation:
The fork-only Vercel authorization status remains unrelated and non-required. The earlier long-running moderation browser lane passed on retry after the first runner experienced broad local Convex timeouts. Maintainer verdict: merge. |
|
Thanks for the follow-up — routing the gate through |
What Problem This Solves
Fixes an issue where publishing a skill fails with
even though the SKILL.md is fully documented. The trigger is a SKILL.md that has
no YAML frontmatter and uses
---as an ordinary Markdown thematic break. Thepublish is rejected outright, so the skill never reaches the catalog.
Newly created accounts are hit hardest: the reject floors are highest for the
lowtrust tier, which covers every account under 30 days old or with fewerthan 10 published skills.
Why This Change Was Made
The quality gate removes frontmatter before measuring the body:
The
mflag makes^match at every line start rather than only at the start ofthe document. Frontmatter is optional on publish —
publishSkillVersiontakes thedisplay name from its own arguments, and
parseFrontmatterreturns an emptyrecord for a document that has none — so a SKILL.md may legitimately open with a
heading and use
---as a horizontal rule. When it does, the pattern latches ontothe first rule and deletes everything up to the second one.
Dropping the flag anchors the pattern to the start of the document, which is what
the rest of the repository already does. The canonical parser
parseFrontmatterinconvex/lib/skills/index.tsguards withnormalized.startsWith("---"), and the three other frontmatter patterns(
convex/skillsShMirror.ts,packages/schema/src/clawPackage.ts,packages/clawhub/src/schema/clawPackage.ts) carry nomflag.skillQualitywas the only one reading the same document differently from the publish path that
calls it.
The truncated body also fed
toStructuralFingerprint, so template-spamsimilarity was being compared over a fragment rather than the real document. That
is corrected by the same change.
Non-goals, kept out to hold the change to one concern:
User Impact
A skill whose SKILL.md uses
---as a thematic break now publishes normallyinstead of being rejected as thin content. Spam detection also compares whole
documents rather than truncated fragments, so the fingerprint is no longer
skewed toward whatever a skill happens to place above its first horizontal rule.
Evidence
Base commit:
79ef4af1. The fix is not onmain—stripFrontmatterthere stillcarries the
mflag.Signals and the gate decision read from
computeQualitySignalsandevaluateQuality, for a 109-word SKILL.md with two headings, four bullets and two---thematic breaks, evaluated at thelowtrust tier with no similar recentpublishes:
bodyCharsbodyWordsheadingCountbulletCountscoredecisionrejectpassreason94% of the body was being discarded before measurement.
This module had no unit test.
convex/lib/skillQuality.test.tsadds three cases;two of them fail on the parent commit and pass with the fix:
The third case (
still strips real frontmatter) passes on both sides: it comparesa document carrying frontmatter against the same body without it and asserts the
measured
bodyWordsandbodyCharsmatch, so the intended stripping is stillhappening.
Consumers of the module, run together:
Gates run locally on Windows:
bunx tsc --noEmit— cleanbun run lint— cleanbun run deadcode:ci— cleanbun run format:check— the only two files it reports areCLAUDE.mdand.agents/skills/autoreview/CLAUDE.md; both report identically on an unmodifiedcheckout of
79ef4af1, so they are pre-existing and untouched here.bun run ci:unit— 5542 passed. The 24 failures are pre-existing on thisplatform: an unmodified checkout of
79ef4af1fails the same 14 files with thesame 24 tests (5539 passed there; the difference is the three tests added by
this PR). They are the
scripts/worker, CLI and security-dataset suites thatshell out to
bun, plusconvex/lib/githubAccount.test.tsandsrc/routes/-management.test.tsx. Linux CI is the authoritative signal.The Vercel preview check will need OpenClaw Foundation team authorization, as with
other fork pull requests.