Repository navigation
The getting-started guides teach ~14 symbols the packages do not export — one decision per symbol, applied everywhere (the #5160 class, on content/docs/guide/**) #5343
Description
Filed by the repo:objectui execution seat (PM round 17, session session_01RV6yuVCxymHYE16PL9vQkE) as the fabricated-export half of #5174, per that card's Q2 answered as option C. Filed unassigned, not claiming.
Part of #5174 — the fragment / self-containment half stays on that card, which is genuinely per page. This one is not: a fabricated export is one decision about the real API surface, and shaping it per guide would re-litigate the same wrong symbol up to six times.
How this became visible
#5174's PR5341 widened check-doc-snippet-types.mjs to collect .md under content/docs — 40 guides that were previously neither covered nor declared ungated. Of the 28 holding a ts/tsx block, zero passed as collected. 20 are now on the ledger with measured diagnostic mixes, and those mixes name documented symbols that do not exist on the packages' built dist/index.d.ts.
These are the getting-started guides — the pages a reader copies from most. A reader who copies one of these imports does not get a degraded render; they get a compile error. Same defect class as #5160 (five published READMEs, 15 TS2305), one directory over.
The symbol table, as measured by PR5341
| symbol | claimed from | occurrences |
|---|---|---|
getComponentRegistry |
@object-ui/react |
6 |
registerDefaultRenderers |
@object-ui/components |
5 |
AppSchema / ThemeSchema / ReportSchema |
@object-ui/types and /zod |
9 |
BaseSchema |
@object-ui/core |
3 |
getExpressionEvaluator |
@object-ui/core |
— |
ObjectStackProvider |
— | — |
registerAllComponents |
@object-ui/components |
— |
ObjectSchema |
@object-ui/types |
— |
Field |
@object-ui/types |
— |
InputRenderer |
@object-ui/components |
— |
componentSchema |
— | — |
DashboardSchema / PageSchema |
@object-ui/types |
— |
FormSchema |
— | — |
UNGATED_DOCS entries for content/docs/guide/** and content/docs/api/schema-reference.md, whose reason strings name the symbols by hand.
The three dispositions, and the one already decided
#5053 established them, and they are not interchangeable:
- renamed → re-spell it;
- lives in a neighbour package → fix the import path;
- removed with nothing replacing it → delete the example and teach the real surface (the subtraction form of plugin-map README teaches an API the package does not implement — every snippet in it renders an empty map #5002 / PR5021).
One is already settled and should not be re-decided: registerDefaultRenderers resolves to initializeComponents() plus the side-effect @object-ui/fields import, evidenced by apps/site/app/components/ObjectUIProvider.tsx — PR5341 made that call once and applied it.
The measurement rule that makes this card safe
Take the name set from each package's built dist/index.d.ts, never from a grep of src/. #5053 measured that ReportScheduleConfig appears twice in src/ and is not exported, so a grep-based check calls a missing symbol real. ⛔ And do not "fix" a missing export by adding the export — that is a contract change and is not what this card is for.
Done when
Each symbol has one recorded disposition with its evidence, applied at every site. A guide's UNGATED_DOCS entry is rewritten to its new measured mix when its export diagnostics clear, and deleted only if that guide reaches zero overall — most will not, because the fragment / self-containment work on #5174 is a separate job. ⛔ Never widen an entry, never add one, never relax the gate.
Related
- check-doc-snippet-types.mjs collects only
.mdxunder content/docs — 40.mdguides are uncovered with no UNGATED_DOCS entry, contradicting its own "covered by default" rule #5174 — the collector change that exposed these; the fragment half stays there - docs: five published READMEs import symbols their packages do not export — 15 TS2305, measured against the built dist #5160 — the same class on five published READMEs (14 of 15 landed via PR5260, the 15th via PR5332)
- docs(plugin-report): README 按真实导出面重写三处虚构导出与陈旧幸存清单 #5053 / plugin-report README 教三个不存在的导出:
ReportBuilder组件、registerDrillHandler、ScheduleConfig组件 #5016 / plugin-report README's export snippets call every real export with the wrong signature —exportAsCSV(data, 'file.csv')passes a filename where the data argument goes #5048 — the disposition vocabulary and earlier instances - check-doc-component-types collects only
.mdxtoo — 26.mdguides teach 345typeliterals inside fences with nothing checking them #5342 — the same extension-only collector incheck-doc-component-types.mjs, filed as a sub-issue of finding(docs/gate): check-doc-component-types 的扫描面止于代码围栏 —— 八个 PR 新加的「真实 register 键表」全部在门外,且门从不判 namespace 半边 #5106
Activity
os-support-ai commentedon Aug 20, 2026
Claim: PM loop round 18⚠️
Session:
session_01RV6yuVCxymHYE16PL9vQkEBranch:
claude/issue-5343-guide-fabricated-exportsWorktree:
objectui-issue-5343Domain:
repo:objectui(execution seat)File surface:
content/docs/guide/**,content/docs/api/schema-reference.md, and theUNGATED_DOCSledger inscripts/check-doc-snippet-types.mjs(stop on breach; explain in the report)Container & model: L,
mode:subagent,model: opus—node scripts/pm/dispatch-gates.mjs --tier <paths>returns no path-derived mandate; tier is this seat's call, taken at opus for the size and for the number of independent judgments.Clause-②: no — and this is load-bearing: the card forbids the accept-set-widening repair. ⛔ Never fix a missing symbol by adding the export. That is a contract change, it is a different card, and it is the single way this task can go wrong invisibly.
Serial constraints cleared:
content/docs/guide/**has no in-flight claim.scripts/check-doc-snippet-types.mjsis shared with #5174, which is stillpm:dispatched— but its landed half (PR5341, the collector widening) is merged and its remaining half has no dev in flight, so there is no concurrent writer on that file. Round-18 siblings hold disjoint surfaces (#5214 six packages; #4818packages/layout; #5126skills/objectui/**; #5356packages/app-shell/src/preview). #5342 (the same collector defect incheck-doc-component-types.mjs) is a different script and stays in the queue — ⛔ do not touch it here.Re-measure first — the card says so and it means it
The symbol table in the body comes from PR5341's run and the tree has moved since. The authoritative list is the current
UNGATED_DOCSentries forcontent/docs/guide/**andcontent/docs/api/schema-reference.md, whose reason strings name the symbols by hand. Re-derive it in your worktree and report your own list; where it disagrees with the card's table, your reading wins and the disagreement is worth a line in the PR.Take the name set from each package's built
dist/index.d.ts, never from a grep ofsrc/. #5053 measuredReportScheduleConfigappearing twice insrc/while not being exported — a grep-based check calls a missing symbol real. State per leg whether a build artifact sits between your edit and the thing under test, and rebuild when it does.The dispositions
#5053's three, and they are not interchangeable: renamed → re-spell; lives in a neighbour package → fix the import path; removed with nothing replacing it → delete the example and teach the real surface (the subtraction form of #5002 / PR5021).
One is already settled and ⛔ should not be re-decided:
registerDefaultRenderersresolves toinitializeComponents()plus the side-effect@object-ui/fieldsimport, evidenced byapps/site/app/components/ObjectUIProvider.tsx; PR5341 made that call once and applied it.The point of doing this as one card rather than per guide: a fabricated export is one decision about the real API surface. Record one disposition per symbol with its evidence, then apply it at every site. If you find yourself deciding the same symbol twice because two guides spell it differently, that is the failure this card exists to prevent — go back and make it one decision.
Ledger discipline — the ratchet only tightens
Rewrite a guide's
UNGATED_DOCSentry to its new measured mix when its export diagnostics clear. Delete an entry only if that guide reaches zero overall — most will not, because #5174's fragment / self-containment half is a separate job and those diagnostics stay. ⛔ Never widen an entry, never add one, never relax the gate. If a guide gets worse under your change, that is a defect in the change, not a ledger update.Part of #5174andFixes #5343.Generated by Claude Code
docs(guide,api): one disposition per fabricated export, applied at ev…
os-support-ai commentedon Aug 20, 2026
{ "issue": 5343, "status": "done", "branch": "claude/issue-5343-guide-fabricated-exports", "pr": "https://github.com/objectstack-ai/objectui/pull/5364", "premise_still_valid": true, "summary": "Re-measured the seven UNGATED_DOCS entries in the file surface with a harness that reuses the gate's own analyze()/compileSnippets() over the whole corpus in one program; the baseline reproduced the ledger's recorded mixes EXACTLY for all seven, so the card's premise held. 14 fabricated symbols got one disposition each, taken from each package's built dist/index.d.ts and applied at every site (24 diagnostic occurrences): renamed (PageSchema->PageNodeSchema, DashboardSchema->DashboardComponentSchema, App/Theme/ReportSchema->*ComponentSchema in both the type and zod entries, componentSchema->ComponentSchema, registerDefaultRenderers/registerAllComponents->initializeComponents() plus the side-effect @object-ui/fields import, getComponentRegistry()->the ComponentRegistry singleton); wrong package (BaseSchema, PageSchema, FormSchema claimed from @object-ui/core, all live in @object-ui/types); removed-with-nothing-replacing (InputRenderer, the ObjectSchema/Field builder pair, getExpressionEvaluator - those examples deleted and the real surface taught instead). No export was added anywhere. Three blocks would have gained a NEW diagnostic class once the renamed types started checking their literals (theme shape, PageNodeSchema.body arity, ComponentMeta keys), so those were corrected in the same pass, each pinned by the same built d.ts. Ledger: all seven entries rewritten to their new measured mix, none deleted (none reaches zero - #5174's fragment half remains); every bucket equal or lower, nothing added, no threshold moved. Card-table disagreement: App/Theme/ReportSchema are 8 occurrences, not 9; and the card's ObjectStackProvider row sits at content/docs/utilities/index.md, outside the file surface - left untouched and filed as #5360.", "tests": "All at the final commit d975803fb (union re-run after the last commit, working tree clean). `node scripts/check-doc-snippet-types.mjs` -> exit 0: 'Semantic phase: 87 of 87 block(s) judged, 0 failed' + 'Every covered documentation snippet compiles against the built types'; controls green (resolution landed on packages/types/dist/index.d.ts, sentinel TS2305, positive 0). `node scripts/check-doc-component-types.mjs` -> exit 0, 564 type literals, 0 unregistered. `node scripts/check-doc-links.mjs` -> 'Links are valid across 13 scan roots' (I renamed two section anchors in schema-reference.md). `node scripts/check-control-bytes.mjs` -> OK, 4757 tracked text files; plus a manual grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]' over the 8 changed files: no hits. `node scripts/check-changeset-no-major.mjs` / `check-changeset-fixed.mjs` / `check-changeset-presence.mjs` -> green ('0 of them under the src/ of a package the release covers ... no changeset is owed'). `pnpm exec eslint scripts/check-doc-snippet-types.mjs` -> clean. `flock -E 99 -w 540 /tmp/os-heavy-verify.lock -c 'pnpm exec vitest run scripts/__tests__/check-doc-snippet-types.test.ts scripts/__tests__/check-doc-component-types.test.ts'` -> 'Test Files 2 passed (2) / Tests 47 passed (47)' (run from the repo root per AGENTS.md, never pnpm --filter). Build artifact between edit and thing-under-test: YES on every leg - the gate resolves each package's exports.types to dist/*.d.ts, so the full build ran first under the shared lock (turbo run build --concurrency=2, 43/43 tasks, 8m15s wall incl. lock wait) and every measurement ran against that dist/. Corpus re-derivation at the same commit: over all 35 guide pages + schema-reference.md, and again over the whole 637-block corpus, ZERO TS2305/TS2724/TS2614 remain in the file surface; the only missing-export diagnostic left anywhere is ObjectStackProvider at content/docs/utilities/index.md:163. Two runtime claims added to expressions.md were executed against packages/core/dist, not reasoned: evaluateExpression('${formatCurrency(price)}', { formatCurrency, price: 1234.5 }) -> '$1,234.50', and ${user.permissions.includes('admin')} -> true/false. Methodology note: the diagnostic CODE for an unresolvable name can shift between TS2304 and TS2552 depending on which other documents share the program, so before/after were both measured full-corpus; that is what let the baseline match the ledger byte for byte. No local CI wait: report is filed at draft-PR time per the standing contract. objectui has no scripts/pm/dispatch-gates.mjs, so the gate union above was derived from the changed paths by hand.", "open_questions": [], "out_of_scope_findings": [ "filed as #5360: content/docs/utilities/index.md still documents the ObjectStackProvider phantom React API that #4124/PR4129 removed from the sibling data-objectstack.mdx page - the last missing-export diagnostic in the corpus, outside this card's file surface", "filed as #5362: ObjectSchemaMetadata declares neither titleFormat nor list_views/listViews nor icon, all three read by shipped runtime code (ObjectView, InterfaceListPage, AppHeader, useElementDataSource, MetadataProvider, ObjectKanban's ADR-0079 resolver) - adding them is a contract change, so the guide's metadata document stays a plain literal with only its fields record typed", "filed as #5363 (finding label): ExpressionEvaluator.registerFunction upper-cases the registered name, so ${formatCurrency(x)} never resolves to a function registered as formatCurrency and evaluate()'s soft-fail path renders the raw ${...} source instead - measured against the built dist", "incident, not an issue: creating #5362 with labels:['types'] MINTED a repository label - 'types' did not exist (it now carries exactly one issue, mine). I removed it from #5362; the empty label itself remains and I cannot delete it (no gh CLI in this container, no delete-label tool). Worth a maintainer deleting it." ] }Generated by Claude Code
docs(guide,api): one disposition per fabricated export, applied at ev…