[BUG] design-sync truncation marker points to unshipped component docs
Environment
- Claude Code: 2.1.238
- Bundled skill:
design-sync - Affected module:
lib/docs.mjs - Pristine module SHA-256:
bb0465b065d9f29722a9453c869b70c73f85337b748d1be28800e2999be4626e
Problem
The bundled /design-sync converter caps every matched per-component documentation body at 8,000 JavaScript characters before it emits <Name>.prompt.md:
export const DOC_BODY_CAP = 8000;
if (body.length > DOC_BODY_CAP) {
const orig = body.length;
const cut = body.slice(0, DOC_BODY_CAP).replace(/\s+\S*$/, '');
body = (cut.length > DOC_BODY_CAP - 500 ? cut : body.slice(0, DOC_BODY_CAP)) +
`\n\n_(truncated — see ${basename(path)} for full)_`;
}
The marker is unusable in the published artifact. The upload contract ships each component's .prompt.md, .d.ts, .html, and .jsx, but it does not ship the matched source <Name>.md. The generated prompt therefore tells the design agent to read a file that does not exist in the Claude Design project.
In one 379-component bundle, a count-independent marker scan found 15 affected prompts:
- Attachments
- ButtonGroup
- ChainOfThought
- Confirmation
- Conversation
- HoverCard
- InlineCitation
- InputGroup
- Message
- Popover
- Queue
- SchemaDisplay
- SearchableList
- TestResults
- Tool
Their transformed source bodies range up to 16,299 characters. Each published prompt ends around 8 KB and loses the remaining usage guidance.
Why the cap itself deserves re-evaluation
The source comment says the design agent reads every .prompt.md, so one large document would crowd out the others. The generated project README instead directs the agent to read a single component prompt on demand:
For a specific component, read_file("components/<group>/<Name>/<Name>.prompt.md").
No platform file ceiling was encountered by the larger source documents. The fixed cap's rationale therefore appears inconsistent with the current on-demand read contract. The dangling marker remains a defect even if a cap is retained.
Reproduction
After running the bundled package converter, scan the output:
rg -l '^_\(truncated — see .* for full\)_$' ds-bundle/components
For any result, confirm that the referenced basename is absent from the upload tree:
find ds-bundle -type f -name '<Name>.md'
The only matching component guidance is the already-truncated <Name>.prompt.md.
Expected behavior
Truncation must never silently discard the only shipped copy of component guidance.
Any of these would satisfy the contract:
- Keep the full per-component body in the on-demand
.prompt.md. - Make the body budget configurable and allow a project to select a bounded value that preserves its complete documents.
- If a hard cap remains, ship the full source at a stable path and make the marker point to that actual uploaded path.
The converter should also validate that every truncation marker resolves inside the final bundle.
Related but distinct issues
- #88268 covers seven card-scaffold findings in
lib/emit.mjsandlib/preview-rebuild.mjs. - #83670 covers the separate 120-character prop JSDoc truncation in
lib/dts.mjs.
This report concerns lib/docs.mjs, the per-component .prompt.md body, and a dangling recovery reference. The three issues should remain independently verifiable and independently removable.