fix(spec): gen:schema io:'input' fallback + disappearance ratchet — restore PageTabsProps (#2978)#3012
Merged
Conversation
…hemas (#2978) PageTabsProps vanished from json-schema/ when #2967 added an ExpressionInputSchema (.transform) field — zod's toJSONSchema cannot represent transforms in the default output mode, and build-schemas.ts silently skipped it, so the next gen:docs run would have deleted the published PageTabsProps reference section. Two-part fix: 1. io:'input' fallback — when output-mode conversion fails on a transform, retry with io:'input'. These JSON Schemas describe what authors WRITE, and the input side of a transform pipe is plain data, so it is representable (for PageTabsProps.visibleWhen it emits the correct `anyOf: [string, expression envelope]` authoring shape). Rescued schemas are marked `x-io: "input"`. This restores PageTabsProps and 149 other transform-blocked public contracts (ObjectSchema, FieldSchema, FlowSchema, PageSchema, ActionSchema, …); only 18 truly unrepresentable schemas (function/Date/BigInt/custom) remain skipped. 2. Disappearance ratchet — json-schema/ is gitignored, so the committed json-schema.manifest.json records every schema key ever emitted. A key present in the manifest but absent from a build now fails gen:schema loudly with remediation steps; deliberate retirements must remove the key in the same PR. Silent skip remains only for types that have never been representable. Also escape literal `|` in the description cell of generated property tables (build-docs.ts) — rescued schemas surfaced descriptions with pipes that split GFM table rows. Closes #2978 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB
gen:docs over the post-fix json-schema/ output. PageTabsProps keeps its section (now including the visibleWhen items shape from #2967), and the 149 schemas rescued by the io:'input' fallback gain reference sections — previously delivered-but-undeclared contracts (Prime Directive #10). Existing table rows with literal pipes in descriptions are re-emitted with GFM escaping. Verified: `pnpm docs:build` compiles all regenerated MDX. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 97 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
- build-schemas.ts: read the ratchet manifest directly and treat ENOENT as first-run bootstrap instead of existsSync-then-read (TOCTOU). - build-docs.ts: escape backslashes before pipes in table-cell descriptions — an existing `\|` would otherwise decay into an escaped backslash followed by a live pipe, splitting the GFM cell. No output changes: regenerated json-schema/ and references/ are byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB
os-zhuang
marked this pull request as ready for review
July 16, 2026 04:50
os-zhuang
pushed a commit
that referenced
this pull request
Jul 16, 2026
Conflict resolution: content/docs/references/ui/view.mdx (auto-generated) regenerated via gen:docs on the merged tree; api-surface.json auto-merge verified identical to regenerated output; json-schema.manifest.json (disappearance ratchet, #3012, new on main) picks up +ui/FormButtonConfig. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Ue47V8zZ5QhcYMPiRQDA7
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 #2978.
Problem
#2967 added an
ExpressionInputSchemafield (items[].visibleWhen) toPageTabsProps. That schema contains a.transform(string shorthand →{dialect, source}envelope), which zod'stoJSONSchemacannot represent in the default output mode, sobuild-schemas.tssilently skipped it.json-schema/ui/PageTabsProps.jsondisappeared, and the next fullgen:docsrun would have deleted the published PageTabsProps section fromcontent/docs/references/ui/component.mdx.It turned out to be a whole class, not a one-off: 150 schemas (ObjectSchema, FieldSchema, FlowSchema, PageSchema, ActionSchema, …) were already transform-blocked and absent from
json-schema/— delivered but not declared.Fix (
packages/spec/scripts/build-schemas.ts)io: 'input'fallback — when output-mode conversion fails on a transform, retry withio: 'input'. These JSON Schemas describe what authors write, and the input side of a transform pipe is plain data, so it is representable. ForPageTabsProps.visibleWhenthis emits the correct authoring shape:anyOf: [string (CEL shorthand), expression envelope]. Rescued schemas carry anx-io: "input"marker (author-time shape: parse-time transforms/defaults not applied). Result: 1849 schemas generated (150 as input shape); only 18 truly unrepresentable ones (function/Date/BigInt/custom) remain skipped.Disappearance ratchet —
json-schema/is a gitignored build artifact, so a new committedpackages/spec/json-schema.manifest.jsonrecords every schema key ever emitted (mirrors thespec-livenessratchet pattern). A key present in the manifest but not emitted by a build now failsgen:schemaloudly with remediation steps; deliberate retirements must remove the key in the same PR. New schemas are auto-appended (commit the manifest change). Silent skip is now reserved for types that have never been representable — exactly the boundary gen:schema silently drops PageTabsProps since #2967 — references regen would delete real docs #2978 asked for.build-docs.tspipe escaping — rescued schemas surfaced descriptions containing literal|, which split GFM table cells (the type column already escaped pipes; the description column didn't). Descriptions in property tables are now escaped.Docs regen (
content/docs/references/)Full
gen:docsover the fixed output (the regen that was unsafe before this fix):PageTabsPropskeeps its section — the regression the issue predicted is gone;automation/control-flow,integration/connector-auth,integration/mapping,shared/mapping);Verification
pnpm --filter @objectstack/spec gen:schema→Generated: 1849 (150 as input shape),json-schema/ui/PageTabsProps.jsonpresent withanyOfauthoring shape forvisibleWhen;pnpm --filter @objectstack/spec gen:openapiunaffected;pnpm docs:buildcompiles all regenerated MDX.🤖 Generated with Claude Code
https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB
Generated by Claude Code