Repository navigation
build-skill-references.ts still picks the first JSDoc block anywhere in the file — the defect build-docs.ts fixed, publishing a private constant's comment to customers #12094
Description
Activity
yinlianghui-tw commented
on Aug 25, 2026 CollaboratorMore actionsTriage:
pm:queue+domain:spec, type Bug — a customer-facing published surface (skills/**, loaded whole into customer agent context) currently opens a core-schema entry with a private constant's comment, with a live named victim and a confirmed worked fix on the docs side. Scope per the card: (1) converge on the shared selector —findModuleDocBlock()+renderFileDescription()— one selector, two consumers, ⛔ no second port of the rule; (2) regenerate and read the_index.mddiff as a census, line by line; (3) the fallback-vs-loud-refusal question for docblock-less.zod.tsfiles is the seat's to price in the PR — either answer is acceptable if stated.⚠️ Governed surface: the PR stays draft for human merge, and the whole-package value-density question applies at review. Serial note: same generator family as in-flight #11930 (spec seat) — fold-or-serial answered at claim.
Generated by Claude Code
Claim: PM loop round R6 (wave 2 backfill)
Session:session_01NDGG54XF5gbTLdQzCtnaVV
Branch:claude/issue-12094-skill-refs-module-docblock
Worktree:objectstack-issue-12094
Domain:domain:spec
File surface:packages/spec/scripts/build-skill-references.ts(converge on the sharedfindModuleDocBlock()+renderFileDescription()selector — one selector, two consumers, no second port) + regeneratedskills/*/references/_index.mdartifacts (census-reviewed line by line) + tests/self-checks as the generator carries them + changeset per repo convention for generator fixes (stop on breach; explain in the report)
Container & model: M,mode:subagent,model: opus— dispatch-gates 2026-08-25 @8619f95: "no path-derived mandate … The tier stays the PM's per-card judgment call (floor sonnet · default opus · ceiling fable)"; generator-correctness fix with a census judgment ⇒ default opus
Clause-②: no (docs generator; no contract accept/reject surface)
Serial constraints cleared: the fold-or-serial answer recorded at grading is now RESOLVED — the same-generated-artifacts sibling PR (#11930's) MERGED 2026-08-25 ~12:0xZ, so the_index.mdregen surface is free; this claim re-bases on post-merge main. Sole writer of build-skill-references.ts this batch. Governed surface (skills/**artifacts) ⇒ PR stays draft for human merge; net-line budget: skills/** regenerated only (no hand edits), net change reported per file in the census. No pin assertions on sibling behavior.
Generated by Claude Code
os-dev-report
{ "issue": 12094, "status": "done", "branch": "claude/issue-12094-skill-refs-module-docblock", "pr": "https://github.com/objectstack-ai/objectstack/pull/12202", "premise_still_valid": true, "summary": "All three PM mechanism assumptions verified on post-#12097 main (base 22c42c9). extractDescription() in build-skill-references.ts was still selecting the first JSDoc block anywhere in the file; findModuleDocBlock() in scripts/lib/file-description.ts is the docs-side shared selector; system/translation.zod.ts is a live victim publishing its private TRANSLATION_HISTORY const's comment to skills/objectstack-i18n. Fix is scope clause (1) exactly: the generator now IMPORTS findModuleDocBlock() rather than porting the rule a second time — the functional diff is the import plus the two lines that call it, +19 net lines in scripts/ (budget 20), and lib/file-description.ts is NOT modified, so the docs side is untouched (check:docs green inside check:generated is the negative control). Census: 13 pointer rows across 7 skills, 11 distinct source files, 13 insertions / 13 deletions — pure description-line replacement, no pointer rows added or removed and no id reflow, which is the positive confirmation the base was the post-#12097 tree. 12 rows corrected from a wrong block to the Exports: fallback (including the named i18n victim), 1 row gained a real module description (shared/metadata-types.zod.ts), matching what the docs site already publishes for that file. Clause (3) priced in the PR as instructed: fallback KEPT, no loud refusal, with the reasoning and the rejected alternative stated. I did NOT hit the PM's stop condition — the Exports: line states a true fact about the file where the wrong block asserted a false one about its subject, so it is degraded-but-honest, not misleading; the one real caveat (source-order ranking surfaces DEPRECATED_/NON_AUTHORABLE_/LEGACY_ constants as headline content) is filed as a finding rather than re-judged here. Governed surface: PR is draft, not queued, not armed.", "tests": "All gates run on the final commit 4013d77 (git rev-parse --short HEAD from that run); exit codes captured before any pipe, verdicts quoted from each gate's own printed line. Gate family re-derived from actual changed paths via `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (26 matched families; the dispatch list was a subset). GREEN: check:skill-refs '9 generated files in sync with packages/spec'; check:generated 'All 14 generated artifacts are up to date' (includes check:docs — proves docs side unperturbed); check:scripts-typecheck 'tsc --noEmit -p tsconfig.scripts.json' exit 0; check:doc-authoring '390 files clean' + '48 published skill files clean — no internal issue-id references'; check:skills-token-ratchet '11 published SKILL.md within their ceilings'; check:skill-compatibility '11 SKILL.md reconciled against 78 workspace packages'; check:skill-frame-sync '4 copies of the decision frame are structurally isomorphic across 3 files'; check:agent-test-spelling '0 violations — 377 file(s)'; check:role-word 'no new occurrences of the reserved word'; check-empty-changeset '1 declaring changeset(s) added'; check-changeset-no-major 'introduces no major bump'; check-adr-0087-registration 'no declared-breaking changeset'; check:objectui-changeset and check:changeset-gate-self-tests self-tests pass. Heavy work serialized through scripts/pm/os-verify-lock.sh: spec build 'VERDICT command-exit 0 · held 157s · waited 28s', check:generated 'VERDICT command-exit 0 · held 58s · waited 285s', check:scripts-typecheck 'VERDICT command-exit 0 · held 18s · waited 62s'. CENSUS CROSS-CHECK (in place of a reverse verification, which would only re-derive the diff's own before-column): an independent reimplementation of the new selection was run over all 208 .zod.ts sources BEFORE the change and predicted 17 files would change repo-wide; 11 are reachable from SKILL_MAP and all 11 changed, and the other 6 were each verified to appear in zero skill indexes — so nothing changed that was not predicted and nothing predicted was silently missed. No ablation was performed: nothing here required proving a gate can fail. DECLARED NARROWING: repo-wide scans matched only via the packages/spec/** path (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, docs-audit pair) were not run locally — the change is to a build script, not spec source, and CI runs the farm in full. CI not awaited, per the standing contract.", "open_questions": [], "out_of_scope_findings": [ "filed as #12201: the skill-reference `Exports:` fallback ranks by source order with no notion of public authorable surface, so DEPRECATED_APPROVER_TYPES, NON_AUTHORABLE_APPROVER_TYPES and LEGACY_OBJECT_FIRST_KEYS now headline customer-facing rows on an authoring surface — honest but badly ranked (finding + domain:skills, unassigned, no pm:queue)", "not filed (pre-existing, already recorded by another seat as #12123 / #12111): this seat has no direct GitHub REST channel — GITHUB_TOKEN returns 'GitHub access is not enabled for this session' and gh is absent — so the mandated REST-list dedupe search before filing was substituted with ONE bounded label-filtered MCP list_issues call (state OPEN, labels finding, fields trimmed). Declaring the channel substitution rather than filing blind or duplicating an existing finding." ] }
Generated by Claude Code
ACCEPT — PR #12202 (R6 W2 backfill, reviewer of record: spec seat, session
session_01NDGG54XF5gbTLdQzCtnaVV).Checklist conclusion (verified against GitHub, census diff read line by line): draft ✓ · base
main✓ ·Fixes #12094✓ · 9 files = the generator (+24/−5, an IMPORT offindModuleDocBlock— one selector two consumers, no second port;lib/file-description.tsuntouched, docs side proven unperturbed bycheck:docsgreen insidecheck:generated) + 7 regenerated_index.md(13 rows, 13 ins/13 del — pure 1:1 description replacement, zero id reflow = post-#12097 base positively confirmed) + patch changeset ✓ · scripts net +19 ≤ budget 20; skills net lines 0 ✓ · clause-(3) priced in the PR as dispatched (fallback kept, reasoning stated) ✓ · census cross-check accepted in place of ablation — an independent reimplementation predicted 17 repo-wide movers, all 11 SKILL_MAP-reachable moved, 6 unreachable verified zero-index; prediction↔observation closed both directions ✓.Whole-package value-density (the governed-surface mandatory question, answered from the loading customer's seat): the 13 before-texts were WRONG-block prose — a private constant's comment, mid-sentence truncations ("…a
StandardErrorCodemember or"), single-enum labels posing as module descriptions. After: 12 honestExports:lines + 1 real module description that now agrees with the docs page. Some rows got longer, but a true export list beats a false description on a surface agents trust verbatim — density of TRUTH went up. The residual ranking caveat (retired/deprecated constants headliningExports:lines) is correctly filed as #12201 rather than smuggled into this diff.No contract-review chain: the diff touches
packages/spec/scripts/**+skills/**only — neither clause-② leg fires.Path fork:
skills/**= governed surface. Terminal four-piece: this PR stays draft and is never enqueued by this seat; review requested from os-zhuang; listed under "awaiting a human merge" in the round report. Human merge is the review record.
Generated by Claude Code
Filed unassigned, measured while stripping the projected issue-ids in #11930 (out of that card's scope — that one strips ids, this is about which doc block gets published at all).
What
packages/spec/scripts/build-skill-references.tsderives each_index.mdentry's description with its ownextractDescription():That is the first JSDoc block anywhere in the file, verbatim — a rule about ordering, not about descriptions. Whichever declaration happens to sit nearest the top donates its comment to a customer-facing page.
This is the same defect that was measured and fixed on the docs-site side.
build-docs.tsno longer does this: it callsfindModuleDocBlock()frompackages/spec/scripts/lib/file-description.ts, which follows TSDoc's own rule read back — the block must start at column 0 and precede the first declaration.packages/spec/CHANGELOG.mdrecords the original measurement (six victim pages) and the reasoning:The fix landed in the docs generator only. The skill-references generator was never converted, and it publishes to a surface with a strictly higher cost curve:
skills/**is loaded whole into customer agent context windows.Live victim
packages/spec/src/system/translation.zod.tshas no module docblock. Its first JSDoc block documents a private constant,TRANSLATION_HISTORY. Soskills/objectstack-i18n/references/_index.mdcurrently opens its only core-schema entry with:"Shared history sentence for every shape in this file" describes an internal string constant used to build
.describe()text. It is not a description of the Translation protocol, and it is meaningless to the customer reading it. The docs site does not have this problem for the same file —findModuleDocBlock()correctly declines that block — which is the cleanest possible demonstration that the two generators disagree.Note this is exactly the file the CHANGELOG names as a victim of the original defect ("The Translation protocol reference opened with
Shared history sentence for every shape in this file"), so the docs-side repair is confirmed and the skills-side one is confirmed missing.Why no gate catches it
check:skill-refscompares the generated file against what the generator produces — it reproduces the wrong block faithfully, so there is no drift to report. Same green-through-the-defect shape the docs side had.What a card here would do
extractDescription()inbuild-skill-references.tswith the sharedfindModuleDocBlock()+renderFileDescription()path, rather than porting the rule a second time — one selector, two consumers._index.mdline that changes is a file that was donating the wrong block. Some will fall through to theExports: …fallback, which is a separate authoring question (does that file want a real module docblock?) and may want its own follow-up..zod.tswith no module docblock should be a loud refusal instead of a quietExports:line.skills/**is a governed surface — whatever lands here is draft + human merge, and the regeneration diff should be reviewed line by line rather than accepted wholesale.