Repository navigation
Refuse Skill Frontmatter That Parses to a List or a Scalar - #3847
Conversation
skill_description mapped every non-mapping frontmatter to "no description", so a SKILL.md whose frontmatter parsed to a list or a scalar skipped the description length gate. That frontmatter is now refused as unmeasurable, as an unclosed or invalid one already is. Empty frontmatter still reads as no description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues are recorded for the change, supporting its progression.
No open issues 🎉
What changed in this PR
This PR strengthens skill frontmatter validation so non-mapping YAML cannot bypass the description-length gate, while preserving empty frontmatter as having no description.
Changes:
- Reject list and scalar frontmatter with a mapping error.
- Preserve the existing empty-frontmatter behavior.
- Add regression coverage for list and empty frontmatter.
This pull request requires changes.
| File | Summary |
|---|---|
scripts/build_dist.py |
Validates non-mapping frontmatter, but explicit YAML null or ~ can still bypass refusal. [P1, moderate] |
tests/test_build_dist.py |
Covers list and empty frontmatter, but lacks an explicit scalar refusal case. [P2, nit] |
Review effort: Lite
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #3847 +/- ##
========================================
Coverage 83.29% 83.30%
========================================
Files 29 29
Lines 9933 9937 +4
========================================
+ Hits 8274 8278 +4
Misses 1659 1659
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…rge on a Running Hosted Review, and Gate Skill Description Length (#3843) Promotes the changes merged into `develop` since promotion #3797 to `main`, the end of an away-mode backlog burndown. - [#3803](#3803) exempts the Roslyn embedded-language marker (`// lang=json`, `language=`) from the prose gate's comment rules as a tool directive. - [#3807](#3807) has `local_review.py record` take `--report`, the file the reviewer wrote, bind the pass to its sha256, and derive the finding count from it. `status` gains `reportPath`. - [#3809](#3809) holds `pr_review.py merge` while a hosted review is still running on the head, and routes a declined Qodo finding to a dismiss request. - [#3811](#3811) dates an anchored `intentRef` by the section its anchor names, and lets a `driftNote` acknowledge a verified intent advisory. - [#3816](#3816) moves the null GraphQL node check into the shared `gh_graphql` transport as `NullNodeError`. - [#3818](#3818) explains the workspace-edit default in `GOVERNANCE.md` and names the aggregator's expression form. - [#3822](#3822) moves the abandon discard to the `backlog-burndown` orchestrator, aligns the abandoned-branch delete, and holds a grown agent-safety set. - [#3823](#3823) scopes the Husky prose gate to staged paths and adds `--skip-generated` so a named file inside a generated tree is skipped. - [#3828](#3828) reads Copilot's `Open findings:` label, drops the duplicate `null_node`, and matches `scripts/README.md` to the Merge Gate. - [#3829](#3829) bumps the two stale hub caller snippet pins and documents the fallback's mixed-pair refusal. - [#3831](#3831) keeps an inherited `GIT_DIR` from rerooting the prose gate's subdirectory git reads. - [#3832](#3832) gives `backlog-burndown` a disposition for a worker's standalone clone and keeps the agent-safety hold past a park. - [#3835](#3835) makes `carry.py check-sections` refuse what `apply-sections` would, and name an open fence. - [#3836](#3836) pins the reusable-workflow stubs by placeholder and ticks the PlexCleaner gates item. - [#3838](#3838) has the `runtime-secrets` audit dimension detect a bare `secrets/` directory from the tracked files that name it. - [#3839](#3839) gates skill descriptions at the 1024-character limit and trims every one over it. - [#3846](#3846) fixes an adjacent doc, an in-file pre-existing defect, and an edge case on new code in the open pull request instead of filing an issue for each, and keeps filing for code that runs elsewhere. - [#3847](#3847) refuses skill frontmatter that parses to a list or a scalar, so the description length gate cannot be bypassed. Fixes #3770 Fixes #3699 Fixes #3705 Fixes #3789 Fixes #1819 Fixes #727 Fixes #3710 Fixes #3706 Fixes #3623 Fixes #3687 Fixes #3617 Fixes #3757 Fixes #3790 Fixes #3786 Fixes #3785 Fixes #3772 Fixes #1657 Fixes #3443 Fixes #3824 Fixes #3817 Fixes #3805 Fixes #1666 Fixes #3700 Fixes #3821 Fixes #3771 Fixes #3794 Fixes #3825 Fixes #3690 Fixes #1472 Fixes #3813 Fixes #3719 Fixes #1592 Fixes #3845 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
Fixes a finding Copilot raised on promotion PR #3843, against the description length gate #3839 added.
skill_descriptioninscripts/build_dist.pyreturned None ("states no description") for any frontmatter that was not a mapping. ASKILL.mdwhose frontmatter parsed to a list or a scalar was therefore never measured, and it got past the 1024-character gate.skill-lifecycleandscripts/README.mdboth say the gate refuses "frontmatter too malformed to measure one". The code now does the same: frontmatter that is not a mapping raisesfrontmatter is not a mapping, as unclosed and invalid frontmatter already did. Empty frontmatter still reads as stating no description.scripts/build_dist.py: refuse non-mapping frontmatter, and keep returning None for empty frontmatter.tests/test_build_dist.py: a refusal case for list frontmatter, and a not-measured case for empty frontmatter.Verification
python -m unittest discover -s tests -p test_build_dist.py: 99 tests OK.ruff checkandruff format --checkon both files: clean.scripts/build_dist.py --check: generated distributions are current.SKILL.mdunder.agents/skills/opens with mapping frontmatter, so no existing skill newly fails the build.frontiertier. The first raised one finding (no test covered the empty-frontmatter branch), fixed in ce00bf3. The second raised none. The receipt covers the pushed head.🤖 Generated with Claude Code