vercel-optimize: sanitizer behavior doesn't match its docs, and citation checks are skipped when stack detection fails
Found by reading skills/vercel-optimize (installed copy, skills-lock hash fb87d3a1…). Paths below are relative to the skill directory. I traced the code but did not reproduce items 1–4 in a live run.
1. The caveat sanitizers hold recommendations back instead of shipping them with a caveat
Several sanitizers say in their header comments that they add a caveat instead of dropping. For example:
lib/sanitizers/rate-limit.mjs:1: "Prepend a caveat (don't drop — customer may be on a higher tier)"lib/sanitizers/pre-release.mjs:1: "Append a caveat (don't drop — customer may opt in to canary)"
But they all return needsReview: true, and so do middleware-conflict, undeclared-dep, rendering-mode-mislabel, bot-protection-certainty and cache-tag-invalidation-certainty. scripts/verify-and-regen.mjs:255-264 then leaves every needsReview recommendation out of verifiedRecommendations/renderableRecommendations, and scripts/render-report.mjs:54-68 lists it as "needs a manual safety review". So the caveat text gets written to rec.fix and never reaches the report.
Either the comments are out of date, or the hold-back rule is stricter than intended. The deciding question is whether a recommendation with a caveat like "verify your OpenAI tier" should ship.
2. The "12 sanitizers" table in references/recommendations.md is out of date
references/recommendations.md:123-136 doesn't match lib/sanitizers/index.mjs:
- Missing from the table:
window-units,function-duration-invocations,bot-protection-certaintyandcache-tag-invalidation-certainty, which are all in theSANITIZERSarray. - Wrong actions: rows 4–6 (
pre-release,middleware-conflict,undeclared-dep) say they only append or prepend text. All three also setneedsReview, which holds the recommendation back (see item 1).
3. One needsReview line can never take effect
lib/sanitizers/index.mjs:56-58 sets rec.needsReview = true when the citation strippers remove every citation. But an empty citations[] always triggers missing-citation at :62-65, which drops the recommendation, so that needsReview flag can never matter.
Related: the if (result.dropped) branch in the sanitizer loop (:46-48) is currently unreachable, because none of the 11 sanitizers in SANITIZERS returns dropped: true. That may be intentional, so new sanitizers can drop, but it's worth confirming.
4. Citation checks are skipped when signals.json has no detected stack
scripts/verify-and-regen.mjs:42-44 reads framework and version from signals.stack. If either is missing:
lib/sanitizers/index.mjs:51skipssanitizeCitationsentirely, so neitherunknown-citationnorversion-mismatchruns.verifyCitationAppliesToVersionreturnsunsupported(lib/verify-claim.mjs:180-182), which doesn't count against the pass rate.- A citation that isn't in
docs-library.jsononly failscitation_in_library. That counts toward the pass rate, but it isn't a hard rewrite trigger.
Example: a recommendation with one made-up URL and four verified file_exists claims has a pass rate of 4/5 = 0.8. The rewrite only triggers below 0.8 (verify-and-regen.mjs:175), so the recommendation ships with the made-up citation.
Also, verifyCitationInLibrary accepts any string matching /^[\w-]+:[\w-]+$/ as a valid skill-rule reference without looking it up (lib/verify-claim.mjs:170-172). When the stack is known, sanitizeCitations catches this through lookupSkillRule. When it isn't, nothing does.
The documented invocation passes --signals (SKILL.md:233-236), so this only happens when stack detection fails or the framework isn't supported.
Possible fixes: any of these would close it.
- Run the unknown-citation part of
sanitizeCitationseven without framework/version. Only the version check needs the stack. - Make a failed
citation_in_librarya hard rewrite trigger. - Look up skill-rule references in
verifyCitationInLibraryinstead of accepting them by format.
I would like to work on the deterministic parts of this issue. I will make unknown URL and skill-rule validation run even when framework/version detection is unavailable, keep version filtering conditional on a known stack, remove the unreachable needsReview assignment before missing-citation drops the recommendation, and update the sanitizer reference table. I will leave the caveat/withholding policy unchanged because that requires a maintainer product decision. I will include focused regression tests and run the full vercel-optimize test loop.