Uh oh!
There was an error while loading. Please reload this page.
fix(spec): publish each skill reference's own module doc block, not the first block in the file - #12202
Merged
Merged
Conversation
build-skill-references.ts derived every _index.md pointer description from the first doc block anywhere in the source file — a rule about ORDERING, not about descriptions. Whichever declaration happened to sit nearest the top of a .zod.ts donated its comment to a customer-facing page. Converge on the shared findModuleDocBlock() selector that build-docs.ts already uses, imported rather than restated: one selector, two consumers. The column-0 / precedes-first-declaration / documents-no-symbol rule now governs both surfaces, so the two generators stop disagreeing about the same sources. Thirteen pointer rows across seven skills change; skills/** artifacts are regenerated, not hand-edited. The docblock-less fallback to the existing "Exports: ..." line is kept deliberately. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
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): |
os-litant
marked this pull request as ready for review
August 25, 2026 13:28
os-litant
marked this pull request as draft
August 25, 2026 13:28
os-trump
marked this pull request as ready for review
August 25, 2026 15:25
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#12094
build-skill-references.tsderived every_index.mdpointer description from the first doc block anywhere in the source file. That is a rule about ORDERING, not about descriptions: whichever declaration happened to sit nearest the top of a.zod.tsdonated its comment to a customer-facing page, and moving a helper up a file silently rewrote published text.This is the defect the docs-site generator already fixed by converging on
findModuleDocBlock()— the block must start at column 0, precede the first declaration, and document no symbol. The skill-references generator was never converted, so the two generators disagreed about the same sources. It now imports that selector rather than restating it: one selector, two consumers, no second port of the rule. The diff in the generator is the import plus the two lines that call it; everything else is the docblock explaining why.skills/**is loaded whole into customer agent context windows, so it was paying the higher price for the same defect.Census — every changed
_index.mdline, read line by line13 pointer rows across 7 skills, covering 11 distinct source files (
data/hook-body.zod.tsappears in 3 skills). No pointer row was added or removed and no ids reflowed — this diff is description text only.Corrected: wrong block →
Exports:fallback (12 rows, 10 files)ai/tool.zod.tsToolSchemakeys — the rejection carries the upgrade prescription,"Exports: ToolSchemaapi/realtime.zod.tsExports: TransportProtocol, RealtimeEventType, …api/contract.zod.tsStandardErrorCodemember or" — a doc nested insideApiErrorSchemaExports: ApiErrorSchema, BaseResponseSchema, …automation/approval.zod.tsExports: ApproverType, DEPRECATED_APPROVER_TYPES, …data/hook-body.zod.ts(×3)HookBodyCapabilityExports: HookBodyCapability, ExpressionBodySchema, …system/translation.zod.tsTRANSLATION_HISTORYconstExports: LocaleSchema, FieldTranslationSchema, …kernel/manifest.zod.tsExports: PluginPermissionsSchema, …kernel/plugin.zod.tsExports: PluginContextSchema, CORE_PLUGIN_TYPES, …ui/widget.zod.tsExports: FieldWidgetPropsSchemaui/responsive.zod.tsExports: StyleMapSchema, ResponsiveStylesSchemaThe i18n row is the live victim named on the issue, and it is the cleanest case: the sentence described an internal string constant used to build
.describe()text, not the Translation protocol.Gained:
Exports:→ a real module description (1 row)shared/metadata-types.zod.tsExports: MetadataFormatSchema, BaseMetadataRecordSchemaIts block was previously invisible to the old selector, which required a newline immediately after the opening delimiter and so never matched a one-line block. Worth noting for review: the shared selector accepts it because an
importline sits between the block and the schema, and imports do not close the header zone. That is the shared rule's existing, documented behaviour and the docs site already publishes this exact sentence for the same file (content/docs/references/shared/metadata-types.mdx), so this row makes the two surfaces agree rather than inventing a third answer.Census completeness — cross-checked, not asserted
An independent reimplementation of the new selection was run across all 208
.zod.tssources before the change and predicted 17 files would change repo-wide. 11 of those are reachable fromSKILL_MAPand all 11 changed here; the other 6 (ai/solution-blueprint,api/protocol,api/router,data/mapping,shared/error-map,system/notification) were each verified to appear in zero skill indexes. Nothing changed that was not predicted, and nothing predicted was silently missed.The fallback-vs-loud-refusal question (issue scope item 3) — priced
This PR keeps the
Exports:fallback and does not introduce a loud refusal.The reasoning is the shared lib's own principle, 宁可缺,不要错: an export list states a true fact about the file, where the wrong block asserted a false one about its subject. Every one of the 12 corrected rows is therefore a net improvement even though 12 rows lose prose and only 1 gains it — the prose they lost was wrong.
A loud refusal was considered and rejected for this card: it would make "write a module doc block" an implicit prerequisite of a generator fix, red the gate on ~9 source files, and convert a contained repair into an authoring sweep. Whether a
.zod.tson this surface should be required to carry a module doc block is a real question and a separate decision — the census above names every file that reaches the fallback, which is exactly the input that decision needs.One measured caveat on the fallback, filed rather than fixed here: its export list ranks by source order with no notion of public authorable surface, so
DEPRECATED_APPROVER_TYPES,NON_AUTHORABLE_APPROVER_TYPESandLEGACY_OBJECT_FIRST_KEYSnow appear as headline content on an authoring surface. That is honest but badly ranked. Filed as #12201 (observation, unassigned) — out of scope here, and #12094 anticipated it as its own follow-up.Whole-package value density (governed surface)
Line counts are unchanged everywhere — this is a 1:1 description-line replacement (13 insertions, 13 deletions).
_index.mdfiles — lines_index.mdfiles — tokensSKILL.md(thecheck:skills-token-ratchetsurface) — linesSKILL.md— tokensskills/**— linesskills/**— tokensTokens counted as
ceil(utf8 bytes / 4), the conventionscripts/check-skills-token-ratchet.mjsdefines. The +123 tokens buys the removal of 12 false statements from a surface loaded whole into every customer session; the ratchet's own surface (SKILL.md) is untouched.Per-file: ai −14, api +30, automation +25, data +10, i18n +21, platform +35, ui +16 tokens.
Verification
All gates below were run on the final commit,
4013d77, and each verdict is the gate's own printed line (exit codes captured before any pipe).Gate family re-derived from the actual changed paths with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(which reads the change set from the merge base itself), not from the dispatch list.check:docspassing insidecheck:generatedis the load-bearing negative result: the sharedlib/file-description.tsis not modified, so the docs side is provably unperturbed by this convergence.Declared narrowing: repo-wide scans that matched only because a file under
packages/spec/**was touched (check:liveness,check:empty-state,check:strictness-ledger,check:variant-docs,check:slot-lookup,check:published-files,check:type-source-resolution,check:test-source-alias,check:merge-driver,check:dev-prereqs,check:plugin-teardown-shape, the docs-audit pair) were not run locally — the change is to a build script, not to spec source, and CI runs the farm in full regardless.Notes for review
skills/**artifacts are regenerated only — zero hand edits. Reproduce withpnpm --filter @objectstack/spec gen:skill-refs.@objectstack/specpatch, following the convention docs(spec): strip the internal issue-ids projected into the published skill catalog, and drop the gate exemption that hid them #12097 used for the same class of change (generator fix plus regenerated catalog artifacts).Generated by Claude Code