Uh oh!
There was an error while loading. Please reload this page.
fix(spec): render a nested item shape as a table so its describe text reaches the reference page - #12309
Merged
Merged
Conversation
… reaches the reference page `build-docs.ts` collapsed an inline object property into a one-line signature cell that has no description column, so every `.describe()` on a key of that shape was unreachable from the page. Measured: 1208 property rows across 566 published schemas carry 7502 described nested keys (~473 KB of prose) that reached no page, and adding such a describe produced a zero-line `gen:docs` diff. `nestedShapeOf` (beside `renderType`, so the two agree about what one shape level is) names the single shape a cell opens and the TypeScript indexed accessor that selects it. `renderSchemaSection` renders it as a `### Nested Shape:` table directly under the Properties table, in the position and grammar `### Allowed Values:` has used since #6225. Bounded: one level; only where a key carries describe text; never for a union of two or more object shapes; and a nested table elides vocabularies instead of relocating them. Regenerated output is purely additive. 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): |
This was referenced Aug 25, 2026
…sted-describe-rendering
Discharges the os-regen deferral recorded by the merge commit. `main` gained `SearchAllResponseSchema` / `SearchAllHitSchema` / `CloneDataResponseSchema` (#12203) while this branch was open, so the pages this branch regenerated at its fork point described a source the merged tree no longer has — which is what `check:docs` reported on the merge ref. Regenerated with `gen:schema && gen:docs` from the merged tree, never by hand. `api/protocol.mdx` gains the three new schema sections plus one nested-shape table this branch's renderer produces for the new array-of-object property, `SearchAllResponse.hits[number]`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
os-litant
marked this pull request as ready for review
August 25, 2026 19:49
Uh oh!
There was an error while loading. Please reload this page.
os-litant pushed a commit
that referenced
this pull request
Aug 26, 2026
…rging origin/main The merge took origin/main's side of every os-regen artifact (per scripts/pm/os-regen-merge.sh); this commit re-derives them from the merged tree — gen:schema + gen:docs + gen:strictness-ledger — so main's nested-shape reference tables (#12309) and this branch's retirement both survive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NDGG54XF5gbTLdQzCtnaVV
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#11601
The defect
build-docs.tsrenders a property whose type is an inline object as a one-line signature in the Type cell — and that cell has no description column. Every.describe()an author wrote on a key of that shape was therefore unreachable from the reference page: not truncated, not marked, absent.The card's specimen,
content/docs/references/ui/component.mdx:An empty Description cell — while
packages/spec/src/ui/component.zod.ts:699gives that item-levelvisibleWhena ~600-character contract note whose whole point is that its evaluation environment is not the page-componentvisibleWhenof the same name.The loss was invisible from both sides.
check:docscompares generated output with committed output, so it is green forever on prose neither side contains — measured onmain@0b478e1, adding a.describe()to a nested item key produced a zero-linegen:docsdiff.Population, enumerated before a rendering was chosen
Measured over the 1585 emitted JSON Schema documents, counting property rows the section renderer actually emits (main object table plus union-variant tables), and shapes at the one depth level a cell opens:
The population is large enough that a sub-table (rather than expandable rows or inline prose) is the only shape that stays inside the page grammar this renderer already has.
What is rendered now
A property that opens exactly one shape, and whose shape has at least one described key, gets a
### Nested Shape:table directly under the Properties table — the same position, addressing and heading level### Allowed Values:has used since #6225, so the page gains no second grammar.The heading names the shape with a TypeScript indexed accessor —
items[number]for an array element,[string]for aRecordvalue, composed left to right for a wrapper stack. That is a real spelling of the type, not a sigil invented for the docs, which matters in a table that already carries two omission markers (…and… +N more).Tombstoned keys are rendered in a nested table, unlike in the cell above it:
retiredKey()puts the whole[REMOVED]migration prescription indescription, and a signature has no column to carry it.format-type.tssays as much where it drops them from{ … }— this table is the row such a shape never had.Four bounds, each measured rather than chosen
SHAPE_DEPTH_LIMITbudget a cell already spends. A nested table opens no table of its own, so page depth stays a fact about the renderer rather than about how deeply an author happened to nest a schema.formatPropertyTyperefuses to relocate a vocabulary out ofEnum<…>[]. 28 of 1293 rows are in that state.{ … }summary does (INLINE_ENUM_WIDTH_LIMIT, bare…). It is a second position for those keys, and gen:docs 顶层长枚举仍是单个 6092 字符的表格单元格 ——### Allowed Values项目符号只对「整个 schema 是枚举」生效,对「某个属性是枚举」从不生效 #6225's relocation budget is only spendable where the vocabulary's authoritative copy lives. Measured by regenerating without this rule: the 288-memberApiError.codevocabulary was re-listed under every nestederrorshape — 20,260 bullet lines across the tree,api/metadata.mdxalone +6097 — for a vocabulary already published in full onapi/errors.mdx. Every PR that registers an error code regenerates the same 11 reference pages — the ledger is a serialization point, and a PR carrying a new code is in a race it keeps losing #9182 took the count out of this position for a smaller version of the same cost.The regenerated tree is purely additive
143 files, +14195 / -118 lines. Every one of the 38177 pre-existing lines is still present byte for byte — proved by a line-multiset comparison of the tree at
origin/mainagainst the regenerated tree (comm -23over both sorted: 0 lines present before and absent after). The 118 are re-ordering around the inserted sections, not removal. The## SchemaNameheading multiset is unchanged (identical md5).Largest movers:
ui/view.mdx+1422,api/protocol.mdx+968,data/data-engine.mdx+653,ui/component.mdx+276.Considered and not taken
Deduplicating identical sub-tables within a page (render once, point later occurrences at the first). Measured: 192 of the 1180 emitted blocks are same-page duplicates and a dedupe would save 2926 of the 14195 added lines — 21%. Rejected because it costs a second addressing notation ("see the shape of X") and breaks the adjacency rule the
### Allowed Values:relocation established: a relocation lands immediately under the table whose cells it completes.Linking a nested shape to the published schema it structurally matches. 860 of the 1293 occurrences fingerprint-match a schema that has its own section elsewhere, and linking instead of re-tabling would cut the added rows from 7502 to 1435. Rejected for this card: matching on key names plus describe text is not schema identity, and a confident link to the wrong schema is the defect #4696 was filed on. It is a bigger design with its own correctness risk, worth its own card if the tree growth ever becomes a problem.
Verification — all at
044ceb1Every command below was run through
scripts/pm/os-verify-lock.sh; the verdict quoted is the gate's own line, never a bare$?.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2Test Files 428 passed | 1 skipped (429)·Tests 11416 passed | 1 skipped (11417)pnpm --filter @objectstack/spec run check:docs✅ 229 generated files in sync with packages/specpnpm --filter @objectstack/spec run check:generated✓ All 14 generated artifacts are up to date.pnpm --filter @objectstack/spec typecheckcheck:test-typecheck: OK — … 55 file(s) / 263 error(s) held in test-typecheck-debt.json(unchanged, shrink-only)pnpm lint(eslint . --no-inline-config, whole repo)VERDICT command-exit 0 · held the lock 98spnpm --filter @objectstack/spec run check:skill-examples✅ 256 prose examples type-check across 3 surface(s)Plus the derived gate union for this change set —
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived from the real diff after the final commit — all exit 0:check:cross-package-test-inputs,check:doc-anchors,check:doc-authoring,check:doc-formula-expressions,check:doc-security-posture,check:docs-audit-scope,check:docs-redirects,check:empty-state,check:liveness,check:merge-driver,check:published-files,check:published-readme-links,check:quick-reference-counts,check:react-page-adapter-contract,check:role-word,check:slot-lookup,check:strictness-ledger,check:test-source-alias,check:type-source-resolution,check:variant-docs,check-ci-filter-parity,check-doc-frontmatter,check-doc-route-spelling,check-docs-section-name,check-plugin-teardown-shape,check-section-landing-index,docs-audit/check-affected-docs,check:engine-double-contract,check:where-matcher,check:query-options-erasure,check:type-check-coverage,check:nul-bytes, and the six changeset families.Two gates were not measured locally and are declared rather than claimed:
check:dev-prereqsandcheck:type-check-debt --re-measureboth refuse on an unbuilt workspace closure (60+ packages), and CI builds before it gates.Reverse verification
Run from the committed state, with a restore trap, and with the mutation proved on disk before anything was read:
nestedShapeOfneutered to returnnull(the pre-fix answer) with every other line of the fix in place.git diff --stat1 insertion.scripts/nested-shape.test.ts→Tests 14 failed | 8 passed (22). The 8 survivors are exactly the refusal cases (a leaf, a tombstone, a named/self ref, a cycle, a two-object union) — they answernulleither way, and that asymmetry is why the pins are written on both directions.check:docs→ exit 1,content/docs/references/ is out of date with packages/spec. The card's zero-diff measurement is reversed: the pages now depend on this renderer.Tests 22 passed (22),check:docsback to✅ 229 generated files in sync.Changeset
@objectstack/spec: patch— the reference pages are user-visible and gain ~473 KB of authored documentation. Precedent: the two priorbuild-docs.tschangesets (#11260, #11482) are both spec patches.skip-changesetwould have been wrong here: this PR changes what the docs site publishes.Generated by Claude Code