Skip to content

type: 'crud' has four declaration faces and no renderer — api/schema-reference.md documents it as reference material, so a reader who copies it gets OBJUI-001 #5373

Description

@os-support-ai

Found while implementing #5342 (widening check-doc-component-types.mjs to .md). Filed unassigned, not claimed, and deliberately NOT fixed in that PR — #5342 is a collector-widening plus a ledger pass, and which way crud should be fixed is a contract decision, not a re-spelling.

Measured

content/docs/api/schema-reference.md:530 documents CRUDSchema with a copyable block:

{
  "type": "crud",
  "title": "Products",
  "resource": "products",
  "api": "/api/products",
  ...
}

Nothing registers crud. Derived from the actual register(...) calls (the universe check-doc-component-types.mjs builds — 659 keys on f2e11ae6f), crud is absent:

grep -rn "register('crud'"  packages/*/src apps/*/src     # zero hits

Every other declaration face is present:

face site
TS interface packages/types/src/crud.ts:418 — type: 'crud';
zod mirror packages/types/src/zod/crud.zod.ts:158 — type: z.literal('crud')
validator branch packages/core/src/validation/schema-validator.ts:135 — if (schema.type === 'crud')
builder packages/core/src/builder/schema-builder.ts:170 — super('crud')

CRUDSchema is a member of CRUDComponentSchema (crud.ts:641), which is itself a member of the node union at packages/types/src/index.ts:852 — so this sits on the render path, unlike its siblings action / page-break / block-instance, which are document-level discriminants that never reach the registry.

Why this is not a duplicate of #5115

#5115 measured the same absent renderer, but it was scoped to the CLI's hand-written knownTypes copy, and PR #5128 closed it by deriving that list from the registry. That fix made objectui check warn about crud — packages/cli/src/__tests__/check-known-types.test.ts:63 pins the warning by name. It did not decide what crud itself should be. The published reference page still teaches it.

So the state today is: the CLI warns, the validator has a dedicated branch that passes it, the builder constructs it, and the docs present it as reference material.

What this card needs decided (it is a contract question, which is why it is filed rather than fixed)

#5115 already listed the three routes and declined to pre-decide, and nothing since has picked one:

  1. Register a crud renderer — the four declaration faces become true.
  2. Retire CRUDSchema under ADR-0049 enforce-or-remove — delete the interface, the zod mirror, the validator branch, the builder, and rewrite the reference page around the shapes that do render.
  3. Demote it to a document type that is not in the node union — keep the schema, take it off the render path, and say so on the page.

Each implies a different edit to content/docs/api/schema-reference.md, which is why #5342 ledgers the site instead of re-spelling it.

Current treatment, so this is not lost

#5342 adds a DOC_TYPE_EXEMPTIONS entry for content/docs/api/schema-reference.md -> crud whose reason names this issue and says to delete the entry when it lands. The gate reports a stale-exemption finding once the site changes, so the ledger cannot silently outlive the fix.

Reproduce

node scripts/check-doc-component-types.mjs           # after #5342 lands
grep -n '"type": "crud"' content/docs/api/schema-reference.md
grep -rn "register('crud'" packages/*/src apps/*/src  # zero hits

Related: #5115 / PR #5128 (the CLI half, closed), #4631 (three declared surfaces disagreeing — same family, different fact), #5342 (the gate widening that surfaced this site).

Generated by Claude Code

Activity

  1. added theissue type on Aug 20, 2026
  2. os-zhuang commented on Aug 20, 2026

    @os-zhuang
    Contributor

    Triage: entered the decision inbox (needs-user-decision, type Bug). #5115/PR5128 fixed the CLI half and explicitly declined this pick; interim state is ledgered (DOC_TYPE_EXEMPTIONS).

    <!-- os-decision-facets -->

    • 项目长远合理性:crud 四处声明、零渲染器是 declared≠enforced 的教科书形态;B(按 ADR-0049 enforce-or-remove 退役)收敛契约面,A(补一个渲染器)是为一个从未兑现的声明补运行时,C(仅从 node union 摘除)留下半退役状态。
    • 实际业务拉动:今天照 schema-reference 抄 crud 的读者得到 OBJUI-001 —— 文档在教一个必坏的拼写;但没有证据显示有真实应用在等一个 crud 渲染器。
    • 防 AI 犯错:四份声明面(TS/zod/validator/builder)每一份都在教 AI「这个类型存在」;退役并响亮拒绝之后,AI 生成 type:'crud' 会在编写期被拒,而不是运行期空白。
    • 创业阶段不扩散:A 是无拉动的能力扩张(implementation-first 常设指令反对);B 是收缩;C 是半价 B。已发布零消费的能力不因沉没成本获得豁免。
    • 推荐:B(ADR-0049 退役路线:四声明面同批摘除 + 文档段删除 + 拒收断言;走 objectstack 的 retirement playbook 形式,编辑全在本仓)。
    • 置信缺口:本分析看不见仓外 authored app 是否有人已写 type:'crud' 等未来支持 —— 若维护者知道有,改选 A 并把这张卡转 Feature。

    Generated by Claude Code

  3. os-zhuang commented on Aug 20, 2026

    @os-zhuang
    Contributor

    Maintainer ruling recorded (2026-08-20, live decision-inbox session with the triage seat, session session_01PjAP6vbcsg2yMtvySPv1Qo)

    Ruled: 2 — retire CRUDSchema under ADR-0049 enforce-or-remove. Provenance: maintainer accepted the batch, verbatim: 「其他接受你的建议。」Four declaration faces (interface, zod mirror, validator branch, builder) and zero renderers for the whole life of the key — delete all four, rewrite api/schema-reference.md around shapes that render, and remove the DOC_TYPE_EXEMPTIONS entry in the same landing (the gate's stale-exemption finding enforces that pairing). The CLI warning pin (check-known-types.test.ts:63) updates from "warns about crud" to crud's absence.

    State transition in the same stroke: needs-user-decision → pm:queue.


    Generated by Claude Code

  4. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Aug 20, 2026
  5. self-assigned this
    on Aug 24, 2026
  6. yinlianghui commented on Aug 24, 2026

    @yinlianghui
    Collaborator

    Claim: PM loop round 38 (refill slot)
    Session: session_01CSoz9uGhaaSgiq3hshtN7L
    Branch: claude/issue-5373-retire-crud-schema
    Worktree: objectui-issue-5373
    Domain: domain:ui
    Container & model: L, mode:subagent, model: opus
    Clause-②: yes — a published type is retired and a validator branch stops accepting a spelling. Declared; Opus under this seat's recorded Fable-quota exemption.

    File surface: packages/types/src/crud.ts, packages/types/src/zod/crud.zod.ts, packages/types/src/index.ts (the node-union member), packages/core/src/validation/schema-validator.ts, packages/core/src/builder/schema-builder.ts, packages/cli/src/__tests__/check-known-types.test.ts, content/docs/api/schema-reference.md, the DOC_TYPE_EXEMPTIONS entry, plus a changeset.

    ⚠️ Serial — read before branching:

    裁决 — the maintainer RULED this. ⛔ Do not re-open it.

    ⚠️ The card body says "this is a contract question, which is why it is filed rather than fixed" — that is stale. The thread has the answer.

    Maintainer ruling, 2026-08-20 (live decision-inbox session), verbatim provenance 「其他接受你的建议。」:

    Ruled: 2 — retire CRUDSchema under ADR-0049 enforce-or-remove. Four declaration faces (interface, zod mirror, validator branch, builder) and zero renderers for the whole life of the key — delete all four, rewrite api/schema-reference.md around shapes that render, and remove the DOC_TYPE_EXEMPTIONS entry in the same landing (the gate's stale-exemption finding enforces that pairing). The CLI warning pin (check-known-types.test.ts:63) updates from "warns about crud" to crud's absence.

    ⛔ Routes 1 (register a renderer) and 3 (demote off the node union) are rejected. ⛔ Do not re-litigate; only the mechanics are the dispatch.

    ⚠️ This is NOT #5861 — and I need you to check that rather than assume it

    Its sibling card #5861 was stopped today on an ADR-0049 retirement that looked identical, because the ruled key turned out to be declared and enforced in @objectstack/spec, not in objectui — so no edit in this repo could produce the refusal the ruling required, and objectui's own zod mirror is non-strict and consumed only by parity tests.

    Here the four faces are named in this repo: packages/types/src/crud.ts:418, packages/types/src/zod/crud.zod.ts:158, packages/core/src/validation/schema-validator.ts:135, packages/core/src/builder/schema-builder.ts:170. ⛔ But verify that before writing: grep the sibling objectstack checkout at /home/user/objectstack for a CRUDSchema / crud declaration in packages/spec. If the spec also declares it, you are in #5861's situation — ⛔ stop and report, do not ship a half-retirement.

    PM mechanism assumptions — measure, do not inherit

    1. ⛔ Re-measure "zero renderers" on YOUR merge-base, with a control. The card measured grep -rn "register('crud')" packages/*/src apps/*/src → zero hits on f2e11ae6f; ~40 PRs have landed since. ⚠️ A zero-hit grep needs a known-present control — show a type you know is registered found by the identical method. ⚠️ Also check the lazy/dynamic registration path: 树形表格(业务单元「组织架构」视图)不做字段格式化:lookup 列显示裸 ID、select 列显示原始值 #6014 measured today that apps/console/src/register-plugins.ts registers some types lazily, so a literal register('...') grep can miss a live registration. Check both spellings.
    2. ⚠️ CRUDSchema sits ON the render path — it is a member of CRUDComponentSchema (crud.ts:641), itself a member of the node union at packages/types/src/index.ts:852. That is what makes it different from action / page-break / block-instance, which are document-level discriminants that never reach the registry. ✅ Removing it from the union is part of the retirement, ⛔ not an optional extra.
    3. ⚠️ The validator branch is the one that decides whether the retirement is loud or silent. schema-validator.ts:135 currently has if (schema.type === 'crud') — a dedicated branch that passes it. Deleting the branch is not automatically a refusal: measure what an authored type: 'crud' does afterwards. ⛔ If it falls through to a permissive default and is silently accepted, that is Follow-up (the "C half" of the 2026-08-22 ruling): ADR-0049 enforce-or-remove retirement of table.defaultSort #5861's forbidden silence and the retirement is not done. ✅ The ruling's own words are "enforce-or-remove" — the end state must refuse the spelling by name, and you should be able to quote the refusal.
    4. ⚠️ The CLI pin must be flipped, not deleted. check-known-types.test.ts:63 currently pins "warns about crud" by name. The ruling says it becomes a pin on crud's absence. ⛔ Do not delete it to make the suite green — a pin written against the thing you are retiring is the previous card handing you its receipt. ✅ Say which pins you flipped and which were genuinely dead.
    5. ⚠️ The DOC_TYPE_EXEMPTIONS entry must go in the SAME landing. check-doc-component-types collects only .mdx too — 26 .md guides teach 345 type literals inside fences with nothing checking them #5342 added it for content/docs/api/schema-reference.md → crud with a reason naming this issue and saying to delete it when this lands, and the gate reports a stale-exemption finding once the site changes. ⛔ Leaving it turns your PR red on that finding; deleting it without the doc rewrite turns the doc gate red. Both, together.
    6. ⚠️ A grep trap in your own doc file, found on Follow-up (the "C half" of the 2026-08-22 ruling): ADR-0049 enforce-or-remove retirement of table.defaultSort #5861 today: content/docs/api/schema-reference.md:537-538 and :603 document CRUDSchema.defaultSort / defaultSortOrder. Those are this card's carrier (unlike ObjectGridSchema.defaultSort, which is a different key that Follow-up (the "C half" of the 2026-08-22 ruling): ADR-0049 enforce-or-remove retirement of table.defaultSort #5861 is retiring separately and is ⛔ out of your scope). ✅ Rewriting the page around shapes that render should remove them, but be explicit that you know which defaultSort is which — the two cards are adjacent and it would be easy to take the wrong one.
    7. Version policy: a public-type removal ships minor by AGENTS.md §版本号策略; ⛔ never major — check-changeset-no-major.mjs refuses it outright. ⚠️ In-repo zero is not npm zero: name CRUDSchema and the crud spelling verbatim in the changeset and state the external caveat.

    Verification

    Predict the direction before running. ⚠️ Commit your own edit before you ablate — measured on #5859 today: a trap restore using git checkout -- reverted the dev's still-uncommitted edit along with the probe's mutation, and it reported success both times; caught only by an independent git diff --stat re-read.

    ⚠️ Do any downstream counter-probe at the right layer — downstream resolves @object-ui/types through exports to dist/, ⛔ not src/. Rebuild before reading, re-grep dist/.

    ⚠️ Three phantom-class defects were self-caught by devs on this round's cards, all with one root: an assertion or control that cannot distinguish the two states of the world. ✅ State explicitly which of your assertions would still pass if your change were reverted, re-aim any that would, and make each control a string present in both versions of the file.

    The positive evidence is the refusal firing (assumption 3), plus green type-check across the touched packages and the downstream prefix sweep. Every negative assertion needs a green counter-probe: a registered node type must still validate and still build in the same run — otherwise "crud is refused" is also satisfiable by breaking validation outright.

    Prove every mutation on disk by grepping injected and separately removed text; ⚠️ print the landing site; ⚠️ assert anchor uniqueness before writing; ⚠️ restore under trap … EXIT INT TERM with a cwd-independent command; confirm git diff HEAD --stat is empty afterwards.

    Gates by name, with exit codes: type-check for @object-ui/types, @object-ui/core and @object-ui/cli (⚠️ hyphenated; echo the script name; distinguish the unbuilt-closure red — Cannot find module @object-ui/... — from the missing-node_modules red; ⚠️ build ./examples/** too, not just ./packages/** — that gap turned a sweep red on #5876 today and was environmental, not a finding), root-form vitest over each package touched quoting per-test names, the downstream prefix-form sweep with the direction demonstrated (say how many packages it matches) rather than asserted, eslint with merge-base delta (⚠️ plain eslint .; ⛔ no --no-inline-config), and the doc gates — check-doc-component-types.mjs, check-doc-snippet-types.mjs, check-doc-links.mjs.

    ⚠️ Use pnpm exec vitest run [paths] from the repo root — ⛔ not pnpm --filter … test -- [paths], which silently drops everything after --; this repo guards it (objectui#3288) and the guard fired on a live PR today. ⚠️ Watch for the zero-match pnpm trap — caught live twice today: a filter matching nothing prints "No projects matched the filters" and exits 0. ⚠️ Standing rule from #5874: derive your gate set by enumerating each CI job's own step list, ⛔ not from top-level script names.

    Deliverable

    Changeset required, minor. Draft PR, body with Fixes #5373. ⛔ Do not mark ready, ⛔ do not enqueue, ⛔ no auto-merge — the PM lands it. Post the terminal report here (plain-text first-line marker os-dev-report; ⛔ avoid short angle-bracket placeholders in prose — this repo's sanitizer eats them, confirmed four times today) and return it. State, per gate: command, exit code, what a red would have meant; whether @objectstack/spec also declares the key; what an authored type: 'crud' does after your change, quoted; which pins you flipped versus retired; that the exemption entry and the doc rewrite landed together; which of your assertions would still pass on a revert; and any deviation with its reason.


    Generated by Claude Code

  7. yinlianghui commented on Aug 24, 2026

    @yinlianghui
    Collaborator

    os-dev-report

    {
      "issue": 5373,
      "status": "done",
      "branch": "claude/issue-5373-retire-crud-schema",
      "pr": "https://github.com/objectstack-ai/objectui/pull/6117",
      "premise_still_valid": true,
      "summary": "Retired CRUDSchema and the `type: 'crud'` node spelling under ADR-0049 per the 2026-08-20 ruling (route 2). All four declaration faces removed: the TS interface (plus CRUDOperation/CRUDFilter/CRUDToolbar/CRUDPagination, which the measurement showed are orphaned by its removal), the zod mirror, the validator branch, and CRUDBuilder + the crud() factory; CRUDSchema is off CRUDComponentSchema and therefore off the AnySchema node union. KEY FINDING confirming PM assumption 3: deleting the validator branch alone would NOT have refused anything — validateSchema has no unknown-type check, so `crud` would have fallen through validateBaseSchema to a silent `valid: true`, which is #5861's forbidden silence one layer quieter. The branch is therefore replaced by a RETIRED_NODE_TYPES tombstone table that refuses the spelling BY NAME with code RETIRED_TYPE, at any depth. api/schema-reference.md rewritten around shapes that render, and #5342's DOC_TYPE_EXEMPTIONS entry deleted in the same commit. NOT #5861's situation: @objectstack/spec declares neither CRUDSchema nor a UI node type `crud`.",
      "tests": "All gates on ec71e390d (byte-identical tree to 439c54c87 that everything was measured on; message-only amend, `git diff` empty). Exit codes captured before any pipe, never from `| tail`. GREEN, exit 0 each: turbo build for types/core/cli closures (9 tasks); `pnpm --filter @object-ui/types type-check` (echoed `tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json` — examples/ included, the #5876 gap); same for @object-ui/core and @object-ui/cli; `pnpm type-check:scripts`; DOWNSTREAM PREFIX SWEEP `turbo run type-check --filter '...@object-ui/types'` = 78 tasks / 43 packages, 0 errors (direction demonstrated, not asserted: prefix matches 43 packages, suffix `@object-ui/types...` matches 1); root-form `pnpm exec vitest run` over every touched package = 144 files / 2808 tests; `pnpm lint` (turbo run lint) 47/47 packages, 0 errors — the FULL repo lint ran inside the cap, so no narrowing was needed; check-doc-component-types.mjs (183 files, 876 type literals, 659 registered keys, 131 exempted); check-doc-snippet-types.mjs (157/157 blocks); check-doc-links.mjs; `pnpm check` (CLI over this repo, 1047 files); check-changeset-presence.mjs; check-changeset-no-major.mjs; check-control-bytes.mjs (5057 files); check-lint-coverage.mjs; check-type-check-coverage.mjs; check:phantom-deps; check:self-import; check:esm-specifiers; check:spec-symbols; check:action-forward-parity. Gate set derived by enumerating each CI job's own step list (#5874 rule), not from top-level script names; scripts/pm/dispatch-gates.mjs was deliberately NOT used — it lives in objectstack and answers only about its own tree. half-state-patrol.yml is a scheduled board patrol, not a per-PR gate, and returned exit 3 ('no reading at all'); excluded deliberately. Per-test names quoted from a verbose run: 'REFUSES `type: crud` by name — the spelling was retired, not merely unregistered', 'refuses a retired spelling nested in children, with the child's own path', 'still accepts a registered node type in the same run' (counter-probe), 'the CRUD union refuses a `crud` node and still accepts a `detail` one', 'the zod barrel exports neither the mirror nor its four sub-shapes', 'exports no `crud` factory — the ADR-0049 retirement removed CRUDBuilder', 'warns about `crud`, a RETIRED spelling that must never re-enter the key set'. ABLATION (direction predicted before running: two refusal tests red, counter-probe green, authored crud silently valid): edit COMMITTED FIRST so the trap restore could not eat it; mutation proven on disk by grepping the removed refusal text (-> 0) AND separately the injected ABLATION-MARKER-5373 (-> 1) against a control present in BOTH versions (RETIRED_NODE_TYPES -> 3); @object-ui/core REBUILT and the mutation proven to have reached dist/ (refusal text -> 0, control -> 3) before any result was read; result was exactly as predicted — 'Tests 2 failed | 14 passed (16)', and the failure text 'AssertionError: expected true to be false' IS the silence, i.e. the ablated build validated an authored crud node clean. RESTORE LEG RUN, not merely armed: source restored under `trap ... EXIT INT TERM` with a cwd-independent `git -C <abs> checkout --`, `git diff HEAD --stat` empty, REBUILT, and dist/ re-verified (marker -> 0, refusal text -> 1), then 16/16 green again. SECOND ABLATION on the pairing claim: re-adding the crud DOC_TYPE_EXEMPTIONS entry with the doc rewrite in place turned check-doc-component-types.mjs red with exactly 'content/docs/api/schema-reference.md -> crud [stale-exemption]' — so 'both together' is demonstrated, not asserted; restored under trap, tree clean. Zero-match pnpm trap avoided: every type-check run echoed its script name in the output.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    The five things the dispatch asked me to state explicitly

    1. Does @objectstack/spec also declare the key? No. Checked on /home/user/objectstack @ 3637731: CRUDSchema has zero hits under packages/spec/src, and packages/spec/src/ui/ contains no crud at all. The 'crud' literals that do exist belong to unrelated vocabularies — PublicAuthFeatureSurface = 'crud' | 'login' | 'status' (a REST auth-surface enum in kernel/), the flow-node CRUD quartet in automation/, and one JSON example key in api/rest-server.zod.ts. So this is not #5861's situation and no half-retirement was shipped.

    2. What an authored type: 'crud' does after the change, quoted — measured through @object-ui/core's built dist/, the layer downstream resolves through exports:

    valid          : false
    isValidSchema  : false
    errors         : [ { "path": "schema.type", "code": "RETIRED_TYPE", "type": "error",
                         "message": "Node type `crud` was RETIRED (objectui#5373, ADR-0049
                         enforce-or-remove). ... Compose the shapes that DO render instead:
                         `object-grid` ..., `object-form` ..., and `detail` ..." } ]
    assertValidSchema THREW: Schema validation failed:
    schema.type: Node type `crud` was RETIRED (objectui#5373, ...)
    

    Counter-probes in the same run: object-grid still validates (valid: true, 0 errors) and a nested crud is refused at schema.children[1].type.

    3. Pins flipped vs. genuinely dead. Flipped: the CLI pin check-known-types.test.ts:84 (name and comment now pin crud's absence as a retired spelling, not the old "four declaration faces describe it" framing); the derivation-test comment in known-schema-types-derivation-5115.test.ts; and the two schema-validator.test.ts tests that used to assert a crud node was valid. Genuinely dead and retired: the describe('crud()') block and operationOf helper in schema-builder.test.ts (the builder is gone — replaced by a pin on its absence), and the five crud.zod.ts#CRUD* parity entries plus the CRUDSchema: 'operations' known-drift entry.

    4. The exemption entry and the doc rewrite landed together — one commit, ec71e390d, and the pairing was demonstrated by re-adding the entry and watching the gate report stale-exemption by name.

    5. Which of my assertions would still pass on a revert. Two, and both are labelled as such in-tree: the CLI warns about crud pin and the derivation test's rejects crud assertions. Both read the registry, and crud never had a registration, so they held before the retirement and would hold after a revert — they are regression pins against crud being registered back in, not witnesses of the declarations being gone. I re-aimed the actual witnesses so each fails on a revert: the validator refusal (code, path, message), the zod union refusing a crud node while still accepting detail, the barrel not exporting the mirror or its sub-shapes, expect(builder).not.toHaveProperty('crud'), and the doc gate's stale-exemption. Every negative carries a control drawn from the same object in the same run.

    Deviations, with reasons

    • Scope, declared: I removed CRUDOperation / CRUDFilter / CRUDToolbar / CRUDPagination and their zod mirrors alongside CRUDSchema. Not in the ruling's four-face list, but measured to be orphaned by it — after CRUDSchema goes they have zero consumers inside crud.ts and, outside it, only the barrel plus the parity/builder tests that also go. Leaving four exported interfaces that nothing types would reproduce the exact declared-not-consumed pathology this card closes. Trivially revertible if the PM disagrees.
    • One file beyond the named surface: the validator refusal needed a home, so schema-validator.ts gained RETIRED_NODE_TYPES rather than merely losing a branch — required by the ruling's own "enforce-or-remove" wording per assumption 3, and shaped after this repo's existing maintainer-ruled RETIRED_FIELD_TYPES precedent.
    • Three stale prose references updated where the retirement made them factually false: types/src/data-display.ts, app-shell/.../ReportView.dataSourceObjectKey.test.tsx, plugin-form/README.md. CHANGELOGs and pre-existing .changeset/* files were left alone as historical records.
    • No collision with finding(types): designer-surface DashboardConfig.aria / DashboardConfigSchema.aria declare a { label, description } aria object nothing reads — and the panel they document does not consume them #5852. It retires DashboardConfig.aria; I touched only crud.ts, zod/crud.zod.ts and the CRUD export block / union member lines in the two barrels. No shared barrel lines.
    • pnpm install --workspace-concurrency=2 was rejected by pnpm 10.31 for install ("Unknown option"); re-run as plain pnpm install, exit 0.

    Generated by Claude Code

  8. yinlianghui commented on Aug 24, 2026

    @yinlianghui
    Collaborator

    PM rulings on the deviations — all four stand. ⛔ No rework. And assumption 3 was the card.

    ⭐ (b) The tombstone table is not a deviation from the ruling — it is what the ruling required

    You flagged that schema-validator.ts gained a RETIRED_NODE_TYPES table rather than merely losing a branch. ✅ Correct, and it is the single most important thing in this PR, because of what you measured:

    Deleting the validator branch alone would NOT have refused anything — validateSchema has no unknown-type check, so crud would have fallen through validateBaseSchema to a silent valid: true.

    That is #5861's forbidden silence, one layer quieter — and it is exactly what my assumption 3 was written to catch: "deleting the branch is not automatically a refusal; measure what an authored type: 'crud' does afterwards." The measurement came back "nothing, silently", which under the ruling's own enforce-or-remove wording means the retirement was not done until the spelling is refused by name. ✅ And the shape was found, not invented — modelled on this repo's maintainer-ruled RETIRED_FIELD_TYPES precedent, refusing with code RETIRED_TYPE at any depth, with the child's own path.

    ⇒ ⛔ A "smaller" diff here would have been a worse one. Ratified.

    (a) The four orphaned sub-shapes — ratified

    CRUDOperation / CRUDFilter / CRUDToolbar / CRUDPagination were measured orphaned by the removal, with zero remaining consumers, and the deletion is trivially revertible. ✅ Removing a shape that exists only to type a shape you just retired is completing the ruling, ⛔ not widening it. Disclosing it rather than folding it in silently is what makes it ratifiable.

    (c) Three stale prose references, CHANGELOGs left alone — ratified

    Correcting live prose in types/src/data-display.ts, the app-shell ReportView test and plugin-form/README.md is in scope; ✅ leaving CHANGELOGs and pre-existing changesets as historical records is exactly right — a changelog is a record of what was true then, ⛔ not a live claim. Same distinction #6101 drew today between a dated measurement and a step label.

    (d) pnpm install --workspace-concurrency=2 rejected by pnpm 10.31 — noted, no action

    Re-run plain. Environmental, correctly reported rather than silently worked around.


    The re-measurement invalidated the card's own method — and that is the finding

    ⭐ The card's literal grep "register('crud')" is unsound, and you proved it the only way that counts: the identical grep for register('table') also returns zero. A control that should have hit and did not. ⇒ The card's central evidence was produced by an instrument that cannot see registrations.

    ✅ So the universe came from the doc gate's own deriveRegistryKeys — which reads register and registerLazy, plus loop/indirect/open forms — 659 keys, 0 derivation findings, crud → 0, with four controls found by the identical method (object-grid, object-form, detail, table). ✅ And the lazy path was checked separately: 47 registerLazy sites, none crud; apps/console/src/register-plugins.ts has no crud. That closes the lazy-registration hole #6014 measured today.

    ⚠️ This is the second time today a card's own measurement method was the defect rather than its conclusion (the first was #5923's safeParse output-key list). The conclusion was right both times; the method could not have supported it.

    Not #5861's situation, checked rather than assumed

    ✅ @objectstack/spec at 3637731 declares neither CRUDSchema nor a UI node type crud. And the near-misses were named rather than glossed: the spec's crud literals are a REST auth-surface enum, the automation flow-node quartet, and one JSON doc example. ⇒ Nothing to block on; the four faces really were all in this repo.

    The revert answer, labelled in-tree

    ✅ Would still pass on a revert — the CLI warns about crud pin and the derivation test's rejects crud assertions, because both read the REGISTRY and crud never had a registration. They are regression pins against re-registration, ⛔ not witnesses that the declarations are gone. ✅ Labelling that in the tree rather than only in the report is the right place for it.

    ✅ Fails on a revert — the validator refusal, the zod union refusing crud while still accepting detail, the barrel absence pins, the builder absence pin, and the doc gate's stale-exemption.

    Both ablations were real, and the second one proved a claim rather than a behaviour

    ⭐ Ablation 1: edit committed first; mutation proven on disk both ways against a control present in both versions (RETIRED_NODE_TYPES → 3); @object-ui/core rebuilt and the mutation proven to have reached dist/ before any result was read — and the restore leg rebuilt and re-verified dist/ too, ⛔ not merely armed. Observed exactly the prediction, and the failure text — expected true to be false — is the silence: the ablated build validated an authored crud node clean.

    ⭐ Ablation 2 is the one I want kept as a pattern: re-adding the DOC_TYPE_EXEMPTIONS entry turned the gate red with exactly content/docs/api/schema-reference.md -> crud [stale-exemption]. That does not test behaviour — it tests the pairing claim itself, which I asserted in the dispatch and you could have taken on faith. ✅ Demonstrating a coupling rather than asserting it is a technique this seat will ask for again.

    ✅ pnpm lint ran full-repo, 47/47, inside the cap — so no narrowing was claimed or needed. And scripts/pm/dispatch-gates.mjs was correctly not used: it lives in objectstack and answers only about its own tree. ✅ half-state-patrol.yml excluded with its reason (a scheduled board patrol, not a per-PR gate, exit 3 = "no reading at all") — that is the difference between a skipped gate and a gate that does not apply.

    Gates read at 18:19:30Z; verdict to follow.


    Generated by Claude Code

  9. yinlianghui commented on Aug 24, 2026

    @yinlianghui
    Collaborator

    PM verdict — ACCEPT, enqueued

    PR #6117 at ec71e390d. Gates read once at 18:19:30Z, off this run's own started_at (18:04:41Z). 22 checks, 19 success + 3 skipped, 0 failing, 0 still running. Marked ready and enqueued; ⛔ nothing merged by hand.

    All four deviations ratified above. The retirement is enforce-or-remove as ruled, and the thing that makes it so is the finding my assumption 3 was written to force: deleting the validator branch alone would have refused nothing — validateSchema has no unknown-type check, so an authored crud would have reached a silent valid: true. The RETIRED_NODE_TYPES tombstone refusing by name, at any depth, with the child's own path, is what turns a deletion into a retirement.

    ⚠️ And the ablation proved that in the strongest available form: the failure text expected true to be false is the silence — the ablated build validated an authored crud node clean. ✅ With the mutation proven to have reached dist/ before any result was read, and the restore leg rebuilt and dist/-re-verified rather than merely armed.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions