Uh oh!
There was an error while loading. Please reload this page.
refactor(types,core)!: retire CRUDSchema and the crud node type (ADR-0049) - #6117
Merged
Merged
Conversation
…R-0049) `crud` carried four declaration faces — the TS interface, the zod mirror, a dedicated branch in `validateSchema` that affirmatively passed it, and `CRUDBuilder` — and never had a registered renderer, so a node spelling it painted the OBJUI-001 "Unknown component type" panel while `api/schema-reference.md` published it as reference material. Per the maintainer's 2026-08-20 ruling (route 2), all four faces are removed and the spelling is now refused BY NAME: `validateSchema` returns a `RETIRED_TYPE` error on `schema.type` at any depth, naming the shapes that do render (`object-grid`, `object-form`, `detail`). The reference page is rewritten around those, and #5342's `DOC_TYPE_EXEMPTIONS` entry — which asked to be deleted when this landed — goes in the same commit. Card relation is declared once, in the PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
yinlianghui
marked this pull request as ready for review
August 24, 2026 18:19
This was referenced Aug 24, 2026
Uh oh!
There was an error while loading. Please reload this page.
yinlianghui pushed a commit
that referenced
this pull request
Aug 25, 2026
…base The measurement objectui#5392's 2026-08-22 ruling required before the A/B/C fork is decided. No generator, no drift gate, no published artifact. Re-run on origin/main @ 50d0d6c, which contains objectui#6117 (CRUDSchema retired). Converter: zod 4.4.3's built-in z.toJSONSchema (already a dependency). Population: AnyComponentSchema — 14 union members, 105 leaf node schemas. Headline: the generated artifact is a strict relaxation of the zod source. Over 475 root-type JSON files it agrees with safeValidateSchema on 461 (97.1%), is weaker on 14, and is stricter on none. 0/105 node types convert under default options; 105/105 convert lenient; 0/105 faithful. 276 of 333 objects are open because BaseSchema is .passthrough() and .strict() is called zero times, so the artifact reads closed and is not. Size: 651,908 bytes pretty / 369,028 minified, or +21.5% / +12.2% of the published dist. New since the pre-#6117 run: all 5 refinement sites isolated with passing controls (was 2 of 5); @objectstack/spec already ships generated JSON Schema (23.4 MB, 156 UI documents, 118/124 closed at the root) as both a precedent and the closedness contrast; the JSONC-only files were checked and carry no root type, so the 475 census is complete against check.ts's own reader. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
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#5373
Retires
CRUDSchemaand thetype: 'crud'node spelling under ADR-0049 enforce-or-remove, per the maintainer's ruling of 2026-08-20 (route 2, provenance 「其他接受你的建议。」). Routes 1 (register a renderer) and 3 (demote off the node union) were rejected; only the mechanics are in this PR.Verified before writing: this is not #5861's situation
#5861 was stopped because its ruled key turned out to be declared and enforced in
@objectstack/spec, so no objectui edit could produce the required refusal. Checked here, on/home/user/objectstack@3637731:grep -rn "CRUDSchema" packages/spec/src— zero hits.grep -rn "crud" packages/spec/src/ui/— zero hits.'crud'literals that do exist in the spec belong to unrelated vocabularies:PublicAuthFeatureSurface = 'crud' | 'login' | 'status'(kernel/public-auth-features.ts, a REST auth-surface enum), the flow-node CRUD quartet inautomation/, and one JSON example key inapi/rest-server.zod.ts. None is a UI node type.All four declaration faces are objectui-owned, so the retirement is complete in this repo.
Re-measured "zero renderers" on this merge base, with controls
The card measured a literal
register('crud')grep onf2e11ae6f. That method is not sound on its own — the identical grep forregister('table')also returns zero, because registrations are namespaced and some are lazy. So the measurement here uses the doc gate's own registry derivation (deriveRegistryKeys), which readsregisterandregisterLazy, plus the loop, indirect and open-site forms:The lazy path was checked separately: 47
registerLazy(call sites acrosspackages/+apps/, none mentioningcrud;apps/console/src/register-plugins.tshas nocrudreference.What an authored
type: 'crud'does now — quotedDeleting the validator branch on its own would not have produced a refusal.
validateSchemahas no unknown-type check:validateBaseSchemaonly asks thattypebe a non-empty string, socrudwould have fallen through to a silentvalid: true— #5861's forbidden silence, one layer quieter than before. So the branch is replaced by a tombstone table that refuses the spelling by name. Measured through@object-ui/core's builtdist/(the layer a downstream consumer resolves throughexports):Counter-probes in the same run:
object-gridstill validates (valid: true, 0 errors), and acrudnode nested underchildrenis refused with its own path (schema.children[1].type) — so "crud is refused" is not satisfiable by validation being broken outright.What changed
@object-ui/types— theCRUDSchemainterface and its zod mirror; the four shapes that existed only to type its keys (CRUDOperation,CRUDFilter,CRUDToolbar,CRUDPagination), their zod mirrors and...SchemaTypealiases; both barrels; andCRUDSchemaas a member ofCRUDComponentSchema, which is what takes it off the node unionAnySchema(assumption 2 — not optional). The four sub-shapes are removed because they are orphaned by the retirement, measured, not assumed: afterCRUDSchemagoes they have zero consumers incrud.ts, and outside it only the barrel and the parity/builder tests that also go.ActionSchema/DetailSchema/CRUDDialogSchemaare unchanged and remain the union's members.@object-ui/core— thevalidateCRUDSchemabranch becomesRETIRED_NODE_TYPES+validateRetiredNodeType;CRUDBuilderand thecrud()factory are removed.Docs — the
### CRUDSchemasection ofapi/schema-reference.mdis replaced with a retirement note plus a mapping table onto shapes that render; five dangling[CRUDSchema](#crudschema)links are re-pointed; the import example andapi/index.mdare updated. The note deliberately carries no fenced block spelling the retired type — the doc gate judges everytypeliteral inside a fence, and re-teaching it there is the thing this landing removes.The
DOC_TYPE_EXEMPTIONSentry and the doc rewrite land together, as #5342 asked. Verified rather than asserted: re-adding thecrudentry with the rewrite in place turns the gate red with exactlyThe neighbouring
actionexemption's reason citedCRUDSchema'stoolbar.actions[]/rowActions[]/batchActions[]as its carriers; those keys went withCRUDSchema, so the reason is re-pointed at the sites that survive (ActionSchema.dialog.actions[]/chain[],DetailSchema.actions[],CRUDDialogSchema.actions[]) with re-derived line numbers.Which
defaultSortis whichDisambiguated mechanically, not by eye — every site tagged with its owning section:
CRUDSchema.defaultSortis a flat string plus a separatedefaultSortOrder;ObjectGridSchema.defaultSortis an object withfieldandorder— a different key on a different carrier. Only the first three lines are removed.Pins: flipped vs. retired
packages/cli/.../check-known-types.test.ts:84, from "warns aboutcrud, which four declaration faces describe..." to "warns aboutcrud, a RETIRED spelling that must never re-enter the key set". Not deleted. Its comment now states plainly what it can and cannot witness:KNOWN_SCHEMA_TYPESis derived from registrations, andcrudnever had one, so this assertion held before the retirement, holds after it, and would still hold on a revert. It is a regression pin againstcrudbeing registered back in, not a witness of the declarations being gone.scripts/__tests__/known-schema-types-derivation-5115.test.ts:82, whose comment assertedCRUDSchema"still has its interface, zod mirror, validator branch and builder" — now false.schema-validator.test.tstests that asserted a well-formedcrudnode was valid and an ill-formed one merely warned. They now assert the refusal, itscode, itspathand its message.describe('crud()')block and theoperationOfhelper inschema-builder.test.ts. They exercised a builder that no longer exists; there is nothing left to pin. Replaced by a pin on the builder's absence.crud.zod.ts#CRUD*entries in the zod-mirror parity test, plus theCRUDSchema: 'operations'known-drift entry (the same staleness path that surfaced objectui#5855).packages/types/src/__tests__/crud-retirement-5373.test.ts.Which assertions would still pass on a revert
Stated because three phantom-class defects this round had exactly this root.
Would still pass on a revert (and are labelled as such in-tree):
warns about crudpin, for the structural reason above;known-schema-types-derivation-5115.test.ts'srejects crudassertions — same reason, both read the registry, not the declarations.Would go red on a revert — these are the actual witnesses:
schema-validator.test.ts— the refusal, its code, path and message;crud-retirement-5373.test.ts— the zod union refusing acrudnode (restore the mirror as a union member andsafeParsesucceeds again), and the barrel not exporting the mirror or its four sub-shapes;schema-builder.test.ts—expect(builder).not.toHaveProperty('crud');check-doc-component-types.mjs— demonstrated above by re-adding the entry.Every negative carries a control drawn from the same object in the same run (
detailmust still parse,DetailSchemamust still be exported,formandgridmust still be functions,object-gridmust still validate), so none of them is satisfiable by the thing under test failing to load.Reverse verification
Predicted before running: removing the
crudentry fromRETIRED_NODE_TYPESwhile leaving the machinery should turn the two refusal tests red, leave the counter-probe green, and make an authoredcrudnode come back silently valid. Observed exactly that.The edit was committed first, so the
traprestore could not eat it. Mutation proven on disk by grepping the removed text (the refusal message → 0) and separately the injected marker (ABLATION-MARKER-5373→ 1), against a control present in both versions (RETIRED_NODE_TYPES→ 3).@object-ui/corewas rebuilt and the mutation proven to have reacheddist/(refusal text → 0, control → 3) before any result was read — an unbuilt ablation stays green and would have read as "the refusal never fired".expected true to be falseis the silence: with the table entry gone, an authoredcrudnode validates clean. The restore leg was run too, not just armed — source restored (git diff HEAD --statempty), rebuilt, anddist/re-checked (marker → 0, refusal text → 1), then 16/16 green again.Gates
Derived by enumerating each CI job's own step list, not from top-level script names. All run on
ec71e390d; the tree is byte-identical to439c54c87, which everything above was measured on (message-only amend,git diffempty).turbo run build --filter '@object-ui/types...' '@object-ui/core...' '@object-ui/cli...'.d.ts; every judgement after it unreadablepnpm --filter @object-ui/types type-check(tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json)examples/pnpm --filter @object-ui/core type-checkpnpm --filter @object-ui/cli type-checkpnpm type-check:scriptsscripts/files not compilingturbo run type-check --filter '...@object-ui/types'(78 tasks, 43 pkgs)CRUDSchemapnpm exec vitest runover every touched package (144 files, 2808 tests)pnpm lint(turbo run lint, 47/47 packages)node scripts/check-doc-component-types.mjsnode scripts/check-doc-snippet-types.mjs(157/157 blocks)node scripts/check-doc-links.mjs#crudschemaanchorpnpm check(the CLI over this repo, fromlint.yml)crudnode scripts/check-changeset-presence.mjsnode scripts/check-changeset-no-major.mjsmajorbump; policy isminornode scripts/check-control-bytes.mjs(5057 files)node scripts/check-lint-coverage.mjs/check-type-check-coverage.mjspnpm check:phantom-deps/check:self-import/check:esm-specifiers/check:spec-symbols/check:action-forward-parityExit codes were captured before any pipe (
cmd > log 2>&1; EXIT=$?), never from a| tail.half-state-patrol.ymlis a scheduled board patrol, not a per-PR gate, and it returned exit 3 ("no reading at all") here — deliberately excluded.The downstream sweep uses the prefix form, with the direction demonstrated rather than asserted:
...@object-ui/typesmatches 43 packages (consumers + itself); the suffix form@object-ui/types...matches 1 (types has no workspace dependencies). Prefix is the correct direction for a contract tightening.Version
minorfor both packages, per AGENTS.md 版本号策略 — nevermajor. The changeset namesCRUDSchemaand thecrudspelling verbatim and states the external caveat: in-repo zero is not npm zero, so a published consumer that imported the type, calledcrud()/CRUDBuilder, or authoredtype: 'crud'gets a compile error or a validation error respectively.Generated by Claude Code