Skip to content

docs(skills): split multi-document JSON fences, drop the two elisions, opt every parsing fence in - #7608

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-7474-skills-json-fences-parse
Sep 4, 2026
Merged

docs(skills): split multi-document JSON fences, drop the two elisions, opt every parsing fence in#7608
os-zhuang merged 1 commit into
mainfrom
claude/issue-7474-skills-json-fences-parse

Conversation

@os-steve

@os-steve os-steve commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Fixes #7474

After the jsonc retag (PR #7473), ten JSON blocks under skills/objectui/ parsed under no dialect — eight multi-document listings and two [...] elisions — and seven retagged jsonc fences parsed but carried no opt-in marker, so check-skill-examples reached none of them. This splits each listing into one fence per document, replaces both elisions with the real value the surrounding prose is about, and opts every parsing fence in. The enforced JSON population moves 39 -> 70 of 70.

Marker spelling. The opt-in marker is an HTML comment, so it is deliberately NOT written literally anywhere in this body: this repository has measured GitHub's body sanitizer eating tag-shaped fragments even inside backticks. Its exact bytes are the MARKER constant in scripts/check-skill-examples.mjs; the diff is the authority.

Verification head: 2ba20df (git rev-parse --short HEAD). Every gate below ran on that tree, with the worktree clean.

Census, re-measured at this branch's base 24e027e with the repository's own parseJsonFence

skills/objectui/ before after
json + jsonc fences 56 (40 json / 16 jsonc) 70 (41 json / 29 jsonc)
parse under json 39 41
parse under jsonc 46 70
parse under their OWN tag 46 70
marked 39 70
parse under NO dialect 10 0
parseable under their own tag but unmarked 7 0

The site list at the base is exactly the one the card filed at ec67429 — nothing moved in between. The card's title says 11 because guides/schema-expressions.md line 206 is counted twice there (once as a listing, once as the kept json); the card's own table states the block count as 10, and 10 is what the base measures.

The gate's own lines, before and after

Before (the three guides and the script reverted to the base inside the worktree, measured, then restored — git diff HEAD empty afterwards and all four blob hashes equal to HEAD's):

Scanned 20 guide(s) under skills, .claude/skills: 121 ts/tsx/typescript fence(s), 56 json/jsonc fence(s).
Marked: 13 ts fence(s) (floor 13), 39 json fence(s) (floor 39) - the floor is SHRINK-ONLY. Unmarked fences are ignored by design (opt-in).
JSON phase:     39 fence(s) parsed, 0 failed.

After:

Scanned 20 guide(s) under skills, .claude/skills: 121 ts/tsx/typescript fence(s), 70 json/jsonc fence(s).
Marked: 13 ts fence(s) (floor 13), 70 json fence(s) (floor 70) - the floor is SHRINK-ONLY. Unmarked fences are ignored by design (opt-in).
JSON phase:     70 fence(s) parsed, 0 failed.

Both runs exit 0, and that is the point: before this change the ten unparseable blocks were UNMARKED, so the gate never read them. The green was silence, not coverage.

Per site

Splits — one fence per document, retagged by content (json when the document is strict, jsonc when a comment stays):

site (fence opener at the base) before after
guides/schema-expressions.md 32 1 jsonc fence, 4 documents 4 jsonc fences, each keeping its own // line
guides/schema-expressions.md 170 1 jsonc fence, 3 documents (one per line) 3 jsonc fences
guides/schema-expressions.md 206 1 json fence, 2 documents (one per line) 2 json fences — no comment in either, so both stay strict json
guides/schema-expressions.md 447 1 jsonc fence, 3 documents 3 jsonc fences
guides/schema-expressions.md 463 1 jsonc fence, 2 documents 2 jsonc fences
guides/schema-expressions.md 479 1 jsonc fence, 3 documents 3 jsonc fences
guides/schema-expressions.md 492 1 jsonc fence, 2 documents 2 jsonc fences
rules/protocol.md 177 1 jsonc fence, 3 documents (one per line) 3 jsonc fences

Where a listing put several documents on consecutive lines with their comments column-aligned, the alignment run collapses to a single space once each document owns a fence — the padding only ever aligned them against each other.

Elisions — ... is legal under no dialect, and the value it stood for is the one the rule is about, so both become real:

site before after
rules/protocol.md 157 "fields": [...], // spec uses "columns" "fields": [{ "header": "Name", "accessorKey": "name" }], // spec uses "columns"
rules/protocol.md 166 "columns": [...] // declared by DataTableSchema "columns": [{ "header": "Name", "accessorKey": "name" }] // declared by DataTableSchema

Markers added to fences that already parsed: guides/schema-expressions.md 328, 355, 365, 374, 391; rules/protocol.md 187; rules/styling.md 170. Markers added to every fence the splits and the elision fixes made parseable: the other 24. 31 marker lines in total, which is the whole of the 39 -> 70 move.

Why one fence per document rather than one array

The four axes of the dispatch frame all point the same way for this corpus. A reader copies ONE node — no author ever writes an array of contrasting cases, so an array serves no measured use. Contract-first, one fence is one document is exactly what the gate's parser assumes, so the shape matches the check rather than working around it. Most of these listings are pass/fail pairs (a wrong spelling beside the right one); wrapping them in one array puts a deliberately-wrong document inside a copyable structure, which is the failure mode this repository keeps closing — an AI copies the whole block. And it adds no machinery: the edit is re-fencing existing text, not new prose. No listing in this set is read by its prose as a set of documents, so the array route is not taken anywhere here.

MARKED_FLOOR

scripts/check-skill-examples.mjs is touched for its json row only: 39 -> 70, with the measurement written beside it. That is the ADD direction the ratchet's own docblock names ("raise the number here in the pull request that adds the markers"); the row's shrink-only property is untouched, and the committed floors are MET by the corpus in this checkout (its suite's own pin) holds at 70 of 70.

Line and byte arithmetic

file lines before -> after bytes before -> after
skills/objectui/guides/schema-expressions.md 518 -> 569 (+51) 20664 -> 21210 (+546)
skills/objectui/rules/protocol.md 320 -> 332 (+12) 13553 -> 13758 (+205)
skills/objectui/rules/styling.md 319 -> 320 (+1) 10794 -> 10812 (+18)
whole published bundle, every .md under skills/ 4431 -> 4495 (+64) 153386 -> 154155 (+769)
every SKILL.md under skills/ 137 -> 137 (0) 6973 -> 6973 (0)

The +64 lines are fence scaffolding and nothing else: 31 marker lines plus the opener/closer/blank of 14 new fences. No sentence of prose was added; the only new CONTENT bytes are the two real columns values that replaced the elisions. There is no token or line ratchet over skills/** in this repository — confirmed here by enumerating the check:* scripts: check-skill-eval-tokens.mjs grades eval must_contain tokens against the guides, not guide size, and no other gate reads a size of this surface.

Gates (exit captured before any pipe; each line below is the gate's own verdict)

command exit verdict line
pnpm check:skill-examples 0 JSON phase: 70 fence(s) parsed, 0 failed. / Every marked skill example holds up against the built types.
node scripts/check-skill-examples.mjs --self-test 0 check-skill-examples self-test: 52 cases pass (marker adjacency both directions, orphans, nested illustration, json/jsonc, ...)
pnpm exec vitest run scripts/__tests__/check-skill-examples.test.ts scripts/__tests__/check-skill-eval-tokens.test.ts 0 Test Files 2 passed (2) / Tests 120 passed (120)
pnpm check:skills-paths 0 check-skills-paths: OK (88/89 stated path(s) resolve across 20 guide file(s); 1 baselined).
pnpm check:skill-eval-tokens 0 Every must_contain token is taught by its own skill bundle.
pnpm check:doc-fences 0 check:doc-fences - every TypeScript block in 227 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) ...
pnpm check:control-bytes 0 check-control-bytes: OK (scanned 6227 tracked text file(s); skipped 85 binary).
node scripts/check-changeset-presence.mjs 0 No source or published contract of a released package changed in this range, so no changeset is owed.
pnpm lint 0 Tasks: 47 successful, 47 total (0 errors; the warning counts are pre-existing)
pnpm check:shell-escape-residue 0 check-shell-escape-residue: OK (5/5 root(s) resolved ... 206 file(s) and 1307 fenced block(s) examined ...)
pnpm check:doc-types 0 Every documented component type is registered.
pnpm check:doc-snippets 0 Every covered documentation snippet compiles against the built types.
pnpm check:governed-queue-guard 0 OK check-governed-queue-guard self-test: 132 cases pass ...
node scripts/check-governed-queue-guard.mjs --test over the four changed paths 3 GOVERNED - 3 of 4 path(s) are on a governed surface

check:doc-snippets first exited 2 (PRECONDITION NOT MET — five packages unbuilt, which is "could not run", not a verdict); the run above is after building what its own --build-filter names.

Changeset: none owed, per the verdict quoted above. This repository has no skip-changeset mechanism, so no label is applied.

Governed surface

skills/objectui/** is governed, and the guard confirms it over this exact file list. This PR stays a DRAFT: not flipped ready, no auto-merge, no merge queue, no reviewers requested from here — the seat requests os-zhuang and hotlong at the contract tier, and a human merge is the review record.

Session for durable attribution: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox


Generated by Claude Code

…ns, mark every parsing fence

The 8 multi-document listings under `skills/objectui/` become one fence per
document, retagged by content (`json` when strict, `jsonc` when a comment
stays), and the two `...` elisions in `rules/protocol.md` become the real
`columns` value the surrounding prose is about. Every fence that parses now
carries the `os:check` marker, so the enforced JSON population moves from 39 to
70 of 70 fences and `MARKED_FLOOR`'s json row is raised to the new count.

Census under the repository's own `parseJsonFence`, `skills/objectui/`:
before 56 fences (40 json / 16 jsonc), 46 parsing, 39 marked; after 70 fences
(41 json / 29 jsonc), 70 parsing, 70 marked.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
@os-zhuang
os-zhuang marked this pull request as ready for review September 4, 2026 10:44
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 89d6adf Sep 4, 2026
31 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-7474-skills-json-fences-parse branch September 4, 2026 10:58
os-steve pushed a commit that referenced this pull request Sep 4, 2026
`parseJsonFence`'s docblock said "There are zero `jsonc` fences in the
corpus today" as the reason the dialect is recognised. That stopped being
true at PR #7473 (16 comment-carrying fences retagged `jsonc`) and PR
#7608 moved it further (41 `json` / 29 `jsonc` today, confirmed with
`node scripts/check-skill-examples.mjs --measure`). The sentence read as
"this branch has never run in anger" — the opposite of the truth, and a
risk that a reader deletes or weakens the branch as dead code.

Rewritten to a count-free statement, in the same convention the file's
own header uses for its other counts ("Re-derive it with `--measure`"):
the branch is exercised by fences already in the corpus, not merely
reserved for a hypothetical one. No behaviour change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

3 participants