Repository navigation
fix(quality): score non-mapping metadata instead of crashing - #226
Conversation
The quality check's SKILL_SPEC field check read the frontmatter with
`frontmatter.get("metadata") or {}`, so only a falsy value became an empty
mapping, and then ran `field_name in metadata` and `metadata[field_name]` on
whatever was left. A `metadata` value that is not a mapping is either not
iterable (`true`, `1.5`, an unquoted date) or passes the membership test and
cannot be indexed by a string (a list or string containing `author` or
`tags`), so the check raised TypeError. Nothing caught it, so `validate`,
`tier1` and `quality-check` ended in a traceback and wrote no report, hiding
the schema finding that already describes the malformed field.
Score any non-mapping `metadata` as absent metadata. `metadata.author` and
`metadata.tags` then count as missing, which is how null, empty and other
non-mapping values such as `metadata: Jane Doe` were already scored. Mapping
values score as before.
Signed-off-by: Max Freedom Pollard <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
chrisknvidia
left a comment
There was a problem hiding this comment.
LGTM. I checked that the 6 new tests fail against main's quality_score.py (TypeError on list, scalar and date metadata) and pass with this change. test_quality_score.py passes in full. Treating non-dict metadata as empty keeps the quality check running, and the schema check still reports the malformed field. version.py already guards the same way.
Say that a non-mapping metadata value is invalid per the schema rather than that the schema check reports it, which only holds when the schema check runs too. Signed-off-by: Max Freedom Pollard <[email protected]> Co-Authored-By: Claude Opus 5.5 <[email protected]>
rng1995
left a comment
There was a problem hiding this comment.
Automated review: 0 findings (0 P1, 0 P2, 0 P3); 0 posted inline.
Reviewed at e99a58a. No findings. The isinstance(dict) guard covers every non-mapping shape PyYAML produces (list, string, int, float, bool, date, set, binary), and the other Tier 1 readers of metadata already guard. I ran validate --tiers 1 --no-llm, tier1 --no-llm and quality-check on 26 metadata variants at main and at this head. On main, a list or string that contains author, a number, a bool, a date, a set or a binary value ends in a traceback with no report. At this head each one scores the same as missing metadata, and the schema check reports one HIGH finding. The 6 new tests fail on main and pass here. The two wording threads are addressed by the applied suggestion and can be resolved.
Not caused by this PR, for a separate issue: an impossible calendar date anywhere in the frontmatter (for example metadata: 2026-02-30) makes yaml.safe_load raise ValueError. schema.py and quality_score._parse_frontmatter catch only yaml.YAMLError, so validate still ends in a traceback on both main and this head.
|
Thanks, I used your suggested wording in e99a58a. |
* fix(quality): score non-mapping metadata instead of crashing * fix(quality): reword the non-mapping metadata comment Signed-off-by: Max Freedom Pollard <[email protected]>
Summary
A
SKILL.mdwhosemetadatais not a mapping crashes the quality check, and the whole Tier 1 run with it:metadata: true,metadata: 1.5, an unquoted date, and any list or string containingauthorortagsfail the same way.validate,tier1andquality-checkstop with a traceback and write no report (a catalog run lists the skill as anunexpected error), so the user never sees the schema finding that already describes the problem:Field 'metadata': Input should be a valid dictionary or instance of SkillMetadata.Cause.
_check_spec_fieldsreplaced only falsy values with{}(frontmatter.get("metadata") or {}), then ranfield_name in metadataandmetadata[field_name]on whatever was left. No other Tier 1 check that reads frontmatter crashes on these values.Fix. A
metadatavalue that is not a mapping is scored as absent metadata:metadata.authorandmetadata.tagscount as missing, as they already did for null, empty and other non-mapping values such asmetadata: Jane Doe. Mapping values score exactly as before.Verification
make lintmake testmake buildNew tests in
tests/validators/test_quality_score.py: one runs the quality check on list, string, boolean, float and datemetadatavalues, and one runsrun_validation(checks="schema,quality")and checks that the run completes and reports the schema finding. All six raiseTypeErrorwithout the fix and pass with it.make teston this branch, run with a 60 s per-test timeout because a few process-cleanup tests hang in my sandbox: 14,441 passed, 25 skipped, 107 failed. The failures are environmental. 106 of them fail the same way on unpatchedmain(the Seatbelt and Docker process tests my sandboxed machine can't run, parallel catalog workers, sockets and writes under/tmp, a Python 3.9python3onPATH, and a pip TLS error in the packaging test). The last one is the OSS boundary scan hitting the 60 s limit under load; it passes on its own.make lintpasses, andpython -m buildbuilds the sdist and wheel (with--installer uv, for the same pip TLS reason). The quality tests also pass on Python 3.13 with only thedevextra.Release Impact
CHANGELOG.md🤖 Generated with Claude Code