fix(spec): the @module marker line is machinery, not the opening line of a reference page - #14464
Merged
Merged
Conversation
The `@module <path>` tag selects a module's doc block (#13334) but is machinery for the selector, not prose. `renderFileDescription` emitted it verbatim, so fourteen published reference pages opened on the literal text `@module ui/sharing` instead of on their first sentence. `check:docs` could not see it: it compares the artifact against the source, and the artifact reproduced the marker faithfully. Mirrors the existing `os:check` marker drop in the same function — a prose-level filter applied before the render classification — rather than inventing a second convention, and matches the filter `build-skill-references.ts` has always had on the skill-index surface. The marker stays in the source and `findModuleDocBlock` still reads it. Scope is `@module` alone, not `^@\w+`: `@example <caption>` and `@category <value>` carry prose a line-drop would take off the page. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
`pnpm --filter @objectstack/spec gen:docs` after the renderer fix. Every page loses exactly two lines — its `@module <path>` marker and the blank line under it — and none gains any, so no page loses prose. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 2, 2026
os-zhuang
marked this pull request as ready for review
September 2, 2026 08:30
os-zhuang
enabled auto-merge
September 2, 2026 08:30
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13796
The
@module PATHtag tellsfindModuleDocBlockwhich doc block describes themodule. It is machinery for the selector — but
renderFileDescriptionemittedit like any other prose line, so it became the opening line of every published
reference page whose source carries it.
content/docs/references/ui/sharing.mdxopened on the literal text
@module ui/sharinginstead of onSharing & Embedding Protocol.Emit site
packages/spec/scripts/lib/file-description.ts, inrenderFileDescription— theprose-line filter applied to the gutter-stripped block before the render
classification. Selection is untouched:
findModuleDocBlockandhasModuleMarkerstill read the marker, and the marker stays in the source.Mechanism mirrored, not invented
The same function already drops one machinery line at exactly this point: the
check:skill-examplesopt-in marker (SKILL_EXAMPLE_MARKER). This addsMODULE_MARKERbeside it and routes both through oneisMarkerLinepredicate, sothere is one convention and one call site, not two. The sibling surface has never
had the defect —
packages/spec/scripts/build-skill-references.tsfilters@-opening lines before taking a module's one-line description, which is why theskill index already reads
Sharing & Embedding Protocolfor the same file.The marker is judged with the same untrimmed
^@module\btest the selectoruses, and only on lines classified as prose, so a mid-sentence mention and one
shown inside a fenced example both survive.
Scope:
@moduleonly, deliberatelyNot
^@\w+at large. The two other block tags that reach a page carry a payloada reader needs —
@example Basic field mappingis the caption of the fencebeneath it,
@category Securityis a classification — so a blanket line-dropwould take that prose off the page, which is the one thing this fix may not do.
@seeshows the shape those two want instead:renderProserewrites it intoSee also: …rather than dropping it. Those two leaks are filed separately as#14455 (not addressed here).
Page count, before and after
The issue body says 16 pages; the measured number on
origin/mainis 14.The two-page delta is not a page that kept the marker: 16 spec sources carry the
tag, and two of them —
shared/retry-policy.zod.tsandshared/metadata-collection.zod.ts— publish no reference page at all, so theynever leaked and nothing about them changes here.
Every changed page is
0 added, 2 deleted— the marker line and the blankline under it — and the union of all removed lines across the 14 pages is exactly
the 14
@modulelines, with zero added lines. No page loses non-tag prose:shared/mappingandsystem/cacheare on the list because PR #13794 added themarker to those two sources; the other twelve carried it already.
Tests
packages/spec/scripts/file-description.test.ts— a unit block pinning bothhalves together (selection still reads the marker, the page never shows it), the
bare
@modulewith no path, the fenced and mid-sentence negatives, and a scopecase asserting
@example/@categorysurvive; plus a corpus invariantre-derived from the real
packages/spec/srctree, so a source that acquires themarker tomorrow cannot re-acquire the defect with it.
Reverse verification (renderer reverted to its pre-fix bytes from
HEAD~1,mutation confirmed on disk by blob hash before the run, restored by
git checkout HEAD -- PATHand confirmed byte-identical afterwards): 4 failed,89 passed — the three drop-asserting unit cases and the corpus invariant, with
the two scope negatives green in both legs by design. Restored: 93 passed.
Gates
Derived union at
b0e155aa7—node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,63 commands, all run:
check:docs(229 generated files in sync),check:generated(all 15 artifacts up to date),check:skill-refs,check:docs-single-h1,check:doc-anchors,check:corpus-claim-drift,check:cross-package-test-inputs,check:test-source-alias,check:empty-changeset.check:skill-examplesneeded@objectstack/client-reactbuilt first; with theclosure built it is green — 263 prose examples type-check across 3 surfaces.
a finding):
check-test-completeness,check:doc-formula-expressions,check:doc-security-posture,check:dual-build-cjs-loads,check:type-check-debt.check-dev-prereqsexits 1 for the same reason andsays so in its own words ("1 unmet precondition, not a list of problems").
pnpm --filter @objectstack/spec typecheckgreen, and--listFilesconfirmsits program really includes both edited files.
An earlier
check:generatedrun reportedapi-surface/stale; that was thephantom the gate itself warns about (it reads a dist that did not exist yet in a
fresh worktree). Re-run after
pnpm --filter @objectstack/spec build: green.Changeset
A
@objectstack/specpatch changeset, not theskip-changesetlabel — matchingPR #13794, the immediate predecessor on this same file, which shipped the same
"no schema behavior changes" shape with a patch changeset.
🤖 Generated with Claude Code
https://claude.ai/code/session_01GDA48PuRFrHyRfdkBz8m21
Generated by Claude Code