Repository navigation
feat(types)!: retire ChatbotSchema.body on both published faces (objectui#8572) - #9639
Conversation
Ruling A on objectui#8572 (decision batch #137, item 4): the chat API's body params are authored as `requestBody`, and `body` means the content slot on every component. The record-shaped arm on the zod mirror becomes an ADR-0049 retirement tombstone and the TypeScript face gains the matching `?: never`, so `tsc` and the parse face say the same thing. The two load-bearing pins in node-recursion-point-8344.test.ts are INVERTED, not deleted: the root case asserts the refusal (path, code and the named replacement) and `ArmsNotAssignableToSchemaNode` reads `never` — with an empty-set guard, because the bare projection resolves to `unknown` on an empty exclusion set. zod-mirror-parity.test.ts drops the key from `KnownDrift` and the whole `WiderThanDeclared` entry, header figures re-derived by that file's own pins. Two pending changesets whose paragraphs this falsifies are amended in place, prose only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCpmqvacV4BypY48QdoxcE
|
changeset-claim-re-read
|
✅ 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
|
objectui#8572's retirement of `ChatbotSchema.body` reaches three assertions that encode the hold-out it ends, by entailment rather than by choice: two in `content-channel-family-d-9256.test.ts` and one in `strict-authoring-face-8345.test.ts`. The two family-D controls are RE-POINTED at a twin face, where the hold-out this card recorded still stands, rather than inverted — so this PR's verdict is not restated inside objectui#9256's file. The strict-face case is INVERTED, because dropping its root legs would leave a case that no longer reads the root at all; its comment records that the input no longer discriminates the clause. `zod/base.zod.ts`'s comment block is corrected, prose only: the clause is now redundant, and the block says why it nevertheless stays — the wrapper is load-bearing independently of what it checks, so removing it is surgery on objectui#8344's recursion point, not a deletion. The `requestBody` docs row carries the new mechanism (AGENTS.md #2). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCpmqvacV4BypY48QdoxcE
✅ 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
|
Contract reviewServed-tier: ① Derived judgmentsDiff judged three-dot against the real merge base
② Semver levelA published-face narrowing on both faces of ③ Boundary flagsDeclared by the PR body, each answered:
Found, not declared by the PR:
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位记录 —— 达档复核 PASS 已逐字采纳;⛔ 但本轮不清标,理由在下面记录:上一条评论 档位:本席独立量的,来自转录 ⛔ 不是自述同题发火对照(同一次扫描,最近 7 份转录):
⛔ 为什么 PASS 了还不剥双载体
⇒ 要落地就得先合 ⇒ 双载体原样留置(卡 + PR 各一个 已派:合并轮,⛔ 不是补丁轮原 dev 续派,同卡同分支同 worktree。范围写死:合 冲突本身是一处台账数字: 复核件点名的 4 条非阻断残留 ⇒ 另行立卡渲染路径未对齐(不同包、不同卡)· — PM Generated by Claude Code |
|
补上一条欠的行:复核件点名的 4 条非阻断残留已立 objectui#9659(
— PM Generated by Claude Code |
One conflicted path: packages/types/src/__tests__/zod-mirror-parity.test.ts,
in the `KnownDrift` header bullet. Both sides moved that bullet in opposite
directions — objectui#9647 added the `TreeViewSchema` entry (one entry, one
key), this branch retired `complex.zod.ts#ChatbotSchema::body` (one key, no
entry).
Resolution keeps BOTH history sentences and re-anchors the chain in
chronological order:
46 entries / 83 keys today
— 46 / 84 until objectui#8572 retired the `body` record arm
— 45 / 83 until objectui#7804's `TreeViewSchema` slice
— 41 / 72 until objectui#7804's `objectql.ts` slice
The two head figures are DERIVED, not typed. Probing the bullet with 99 / 97
made this file's own ratchets state them:
the ledger entry counts the header states are derived, not prose (objectui#7733)
Expected knownDrift: 46 Received 99
the header key totals and cross-ledger figures are derived, not prose (objectui#8222)
Expected knownDriftKeys: 83 Received 97
The ratchet restatement (`46 of the registered pairs carry TYPE drift TODAY`)
came in from main unchanged and is pinned to the same ledger by #7733.
No behavioural line moved: every one of this branch's 48 changed lines outside
the conflicted bullet is byte-identical before and after the merge. The merge
forced no other edit — no lockfile, no generated file, no other test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCpmqvacV4BypY48QdoxcE
✅ 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
|
合并轮已落 —— 新 head
|
| 读数 | 值 | 取法 |
|---|---|---|
| 新 head 的两个父 | 24b009d088…(被复核过的那个,parent 1)+ e896c3899…(main 的一个 tip) |
git rev-list --parents -n1 |
| 两父的 merge-base | a5b660f21005235b603b0f7f08476ae231b8a129 |
git merge-base —— 与旧贡献 diff 的基准一致 |
| 文件集 | 11 个,前后完全相同 | 两侧 --name-only 排序后 diff 无输出 |
| ⭐ 冲突文件之外,分支自身的贡献逐字节相同 | 573 行 diff,两侧完全一致 | diff(a5b660f2..24b009d088) 与 diff(e896c3899..93c41f812) 各自剥掉 index 行、排除 zod-mirror-parity.test.ts 后逐字节比 |
⇒ 「合并没有顺手带进任何别的改动」不是 dev 的自述,是本席这一支仪器的读数。
冲突解法:台账链的算术逐节闭合,两侧历史句子都还在
唯一的冲突 hunk 是 KnownDrift 表头那行。解出来的链条:
今天 46 条 / 83 键
← 46 / 84 直到 objectui#8572 退役 ChatbotSchema 的 body 记录臂(键 -1,条目不变)
← 45 / 83 直到 objectui#7804 的 TreeViewSchema 切片(新条目 +1,键 +1)
← 41 / 72 直到 objectui#7804 的 objectql.ts 切片(条目 +4,键 +11)
每一节的差都对得上。main 侧(objectui#9647)的那句 45 / 83 的历史原字保留,只是从「表头开头」重锚到一条 It was 链上;本分支的句子同样在。⇒ ⛔ 没有一侧的意思被悄悄丢掉。
⭐ 数字是推出来的,不是写的:dev 先把表头故意填成 99 / 97,让文件自己的棘轮报数 —— objectui#7733 的块回 expected 99 to deeply equal 46,objectui#8222 的块回 expected 97 to deeply equal 83。两支仪器各自点名了 46 和 83,然后才落笔。
⚠️ 门② 本来根本不可判 —— 而且原因是本席自己
--pair 9639 第一次读到的是 exit 4 / C2 无读数,⛔ 不是绿也不是红,是读不出来:本席昨天写的认领行,在声明的同一行里又把拼法引了一遍(为了说明「裁决自己写死了这一行」),于是那一行出现两次键名,判据按 markdown 结构读 ⇒ 它成了对协议的引用,不是声明。
按脚本给出的第四种动作(⛔ 不改认领、⛔ 不加第二条 Claim:)贴了一条专用更正评论(5710468879),复读 exit 0,两载体一致。
check-clause2-carriers.mjs 里出现三处),⛔ 不是本卡的认领号 —— 照抄它会指向一条不存在的评论,而脚本会带理由忽略整条更正。本席核过源码才落的号。⭐ 工具给的示例数字,和工具给的读数,是两种东西。
C6-RECORD 行缺席 = 机读确认「这个 head 上没有复核记录」
⇒ 5710188415 判的是 24b009d088,已被取代,⛔ 不继承。双载体继续原样挂着。
二审已起,同样是隔离的达档复核子代理,简报里写死了「老记录判的是已被取代的 head,⛔ 不许继承,要在新 head 上自己重推」,并把冲突解法点成本轮最该对抗性看的地方。
— PM domain:spec @ objectui · session session_01VCpmqvacV4BypY48QdoxcE · 2026-09-17T07:10Z
Generated by Claude Code
Contract reviewServed-tier: ① Derived judgmentsJudged three-dot. 1. Conflict resolution — 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. Corpus impact — zero, re-taken. Structural walk of 518 JSON files under examples/content/packages/apps/docs: 3 chatbot-family nodes, all plain ② Semver levelThe change is BREAKING for a consumer that authored a record ③ Boundary flagsDeclared by the PR body, each answered:
Not declared as boundaries by the PR body, found here — all NON-BLOCKING, to be filed as separate cards:
Implemented-by: VERDICT: PASS Generated by Claude Code |
清标 provenance —— 条款②双载体已剥(二审,新 head,PASS)记录: 这张卡走的路
⭐ 一审那次「PASS 了却不清标」是本班学到的一条:清标即落地,落不了地就不能清标。 档位:本席独立量的,来自转录 ⛔ 不是自述同题发火对照,同一小时内并排跑的两个子代理:合并轮的 dev 读 落地前检三条
受管面: 复核件点名的 4 条非阻断残留⇒ 已补进 objectui#9659(评论 — PM Generated by Claude Code |
…g SelectOptionSchema (objectstack-ai#7759 group F) (objectstack-ai#10307) Closes objectstack-ai#10296 Part of objectstack-ai#7759 Clause-②: yes ## What this does `views.zod.ts#DetailViewFieldSchema.options` now reads the spec's AUTHORING `SelectOptionSchema` (`@objectstack/spec/data`) by reference, wrapped in `stripImportedDefaults` like every other crossing. That follows ruling F1 on objectui#7759 (5617221514, adopted in 5617465269): a structural mirror points at the spec's authoring schema, ⛔ never at the declaration's runtime read model (`SelectOptionMetadata`). The TypeScript declaration is unchanged. Before: an inline option shape. It admitted a number or boolean `value`, which the declaration refuses, and silently stripped every other key. After: the spec's strict schema. `value` must be a machine identifier. `icon` and `disabled` are refused by name (`unrecognized_keys`). `description`, `default` and `visibleWhen` are accepted as the spec declares them. ## Re-derived population (origin/main `8b1f06619`, `WIDER_ARMS`, CONCRETE rows only) Sibling branches were fetched into private refs, and each row was checked for whether it disappears there. | row | group | owner | this PR | | --- | --- | --- | --- | | `DashboardComponentSchema::header` / `::globalFilters` | D | objectstack-ai#2231, twin region PR objectui#10273 | excluded | | `DashboardComponentSchema::dateRange` | F | inside the excluded `DashboardComponentSchema` region (PR objectui#10273) | STOP, reported | | `FilterBuilderSchema::fields`, `FilterFieldSchema::operators`, `ContainerSchema::maxWidth`, `HeaderBarSchema::variant` | C/D | objectui#10286 (all four gone on its branch) | excluded | | `FormSchema::mode` | D | objectui#10286 region | excluded | | `FormSchema::layout` | C | renderer feature | excluded | | `CalendarSchema::defaultValue` / `::value` | D | objectui#10293 (gone on its branch) | excluded | | `SliderSchema::defaultValue` / `::value`, `TooltipSchema::content` | B | PR objectui#10292 (gone on its branch) | excluded | | `DataTableSchema::columns` / `::renderCellEditor`, `TableColumnSchema::cell`, `FieldConditionSchema::custom`, `FieldConstraintsSchema::validate`, `FormFieldSchema::condition` / `::validation`, `FormSchema::fields` | E (+F, D) | PR objectui#10294 (all gone on its branch) | excluded | | `HeaderBarSchema::logo` | F | inside the excluded `HeaderBar` region; still present on the objectui#10286 branch | STOP, reported | | `DetailViewFieldSchema::options` | F | this card | **settled per F1** | `ChatbotSchema.body` is already settled on `main`. objectui#8572 (PR objectstack-ai#9639) retired it on both faces as a `?: never` tombstone, and the row left the ledger. Nothing is left to do for it here. ## The ledger reading: an expected divergence, not a zero After the mirror points at the authoring schema, the two faces differ on exactly one member: `visibleWhen`. The spec's input envelope requires `dialect`. The read model's wire (objectui#2212) makes `dialect` optional and `source` required. Measured with `tsc`, this is the only incompatibility. `label`, `value` and the whole-object check agree otherwise. - ⛔ I did not override `visibleWhen` locally to reach a zero-row ledger. That would narrow and widen a spec-declared shape inside objectui, which the ordering note 5617614225 forbids. - The row stays in `WiderThanDeclared` and `WIDER_ARMS`, re-annotated as EXPECTED DIVERGENCE (read model). The old reason, the inline shape, is gone. - `KnownDrift` gains `DetailViewFieldSchema: 'options'`. The same cause is measured one level up, so it also gains `DetailViewSectionSchema: 'fields'` (new entry), and `DetailViewSchema` gains `fields` and `sections`. The header figures were re-derived to 48 entries / 89 keys. The restated figure under "KNOWN_DRIFT is a ratchet" was updated too. - `SPEC_DERIVED_PAIRS` gains `views.zod.ts#DetailViewFieldSchema`, because the census test derived it from the source. ## Evidence (HEAD `a8446a2ae`) - `pnpm --filter @object-ui/types type-check` (all three tsconfigs): exit 0. `pnpm exec vitest run packages/types/` gave `Test Files 215 passed (215)` and `Tests 4929 passed (4929)`. These ran under the verify lock, on bytes identical to the commit. - New pin `packages/types/src/__tests__/detail-view-field-options-10296.test.ts`: 6 tests. It asserts `code` and `path` for each refusal, next to an accepting control, plus verdict parity with the spec schema. - Reverse verification (committed first, trap-guarded): I restored the mirror file from the base commit. The inline marker count was 1 and the spec-reference count was 0. Results: the pin gave `5 failed | 1 passed (6)` (the accepting control stays green), and `tsc -p tsconfig.test.json` failed with exit 2 on `LedgerMismatch` naming `views.zod.ts#DetailViewFieldSchema`. After `git checkout HEAD -- FILE`: `git diff HEAD` was 0 bytes and the blob hash matched HEAD. - Downstream: built the closure of `@object-ui/plugin-detail` (turbo, 11 tasks). `pnpm --filter @object-ui/plugin-detail type-check` exit 0. Its two tests that import the zod `DetailViewSchema` / `DetailViewSectionSchema` passed: `2 passed`, `21 passed`. - eslint `--no-inline-config` on the 3 changed source files: `--format json` gave 3 files, 0 errors, and 2 warnings on lines this diff does not touch. Type-aware linting is not configured, so the diff cannot move any verdict on an untouched file. - `check-changeset-presence`, `check:spec-symbols`, `check:new-line-citations` (0 new), `check:control-bytes`, `check-changeset-no-major`, `check:changeset-claims`, `check:pending-changeset-literals`, `check:installed-pin-claims`: all exit 0. - `check:spec-floors`: NOT MEASURED. It needs a whole-workspace build (`no-artifact`), so it is left to CI. ## Acceptance notes - `DashboardComponentSchema::dateRange`: STOP, because it sits in PR objectui#10273's excluded region. For whoever takes it: `@objectstack/spec` 17.4.0 exports `DATE_RANGE_DEFAULT_RANGES` / `DateRangeDefaultRange` from `@objectstack/spec/ui`, so rule 1 likely applies (the mirror takes the spec's vocabulary). That is not measured here. - `HeaderBarSchema::logo`: STOP, because it sits in objectui#10286's `HeaderBar` region. Proposal F routed it to ADR-0049 enforce-or-remove together with `variant`. - A reviewer can reopen the choice between recording `visibleWhen` as an expected divergence (this PR) and overriding it with objectui's wire, which would give a zero-row ledger but a local reshaping of a spec-declared key. The session is `https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S` (PM seat `domain:spec#1`, dispatched dev). --- _Generated by [Claude Code](https://claude.ai/code/session_01877XiBYSaRCk2CU7cMSg3S)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #8572
Executes maintainer ruling A on objectui#8572 (decision batch #137, item 4, 2026-09-15, verbatim 「同意」 — comment 5689209004):
ChatbotSchema.bodybecomes an ADR-0049 retirement tombstone on both published faces, pointing the author atrequestBody. B (keep and document) and C (narrow to the children slot) were refused by that ruling and are not built here.What landed, file by file
packages/types/src/complex.tsbody?: nevermember onChatbotSchema, beside thechildrentombstone objectui#9256 / ADR-0049 already put therepackages/types/src/zod/complex.zod.tsbody: z.record(z.string(), z.unknown()).optional()→retirementTombstone(…); theChatbotSharedMirrorShapenote that said the ruling was "a separate question and is not decided here" now records that it was decidedpackages/types/src/__tests__/node-recursion-point-8344.test.tspackages/types/src/__tests__/zod-mirror-parity.test.tsKnownDriftrow losesbodyand records the ruling; theWiderThanDeclaredentry goes (its whole content left);WIDER_ARMSrow goes; header figures re-derived by this file's own pins.changeset/8572-chatbot-body-retired.mdminoron@object-ui/types, BREAKING banner, ADR-0087 D2 disposition line.changeset/8344-…·.changeset/9256-…packages/types/src/__tests__/content-channel-family-d-9256.test.tspackages/types/src/__tests__/strict-authoring-face-8345.test.tspackages/types/src/zod/base.zod.tscontent/docs/plugins/plugin-chatbot.mdxrequestBodyrow's mechanism half (AGENTS.md #2, docs-driven)⭐ The ruling's last sentence, answered with measurements
Delivery surface: parse-time on the zod mirror, compile-time on the TypeScript face — and nowhere else.
YES — a consumer path skips the root parse, and it is the one authors hit most. The runtime render path never parses through these mirrors at all.
SchemaRenderer(@object-ui/react) validates in dev builds only, through@object-ui/core's hand-writtenvalidateSchema, which walks base keys and recurses into content and knows no per-component key. Traced to the end:objectui validate/objectui check(@object-ui/cli)safeValidateSchema=AnyComponentSchema.safeParseon the document rootChatbotSchemaliteraltscSchemaRendererrender path (dev build)@object-ui/core'svalidateSchema— hand-written, no mirrorSchemaRendererrender path (production build)__DEV__gates the whole passSchemaValidatorbodyonly), never imports the zod faceplugin-map/plugin-view/plugin-list/plugin-detailimports of@object-ui/types/zodObjectMapConfigSchema.shapekey lists, not parsesThe readings, with their controls
1. The refusal, on the BUILT artifacts (
@object-ui/cliand its dependency closure built from this branch — thedistbytes a consumer installs, notsrc):2. The render path, rendered (
@testing-library/react, dev build,console.warnspied):childrenfor a key the author spelledbody, and it prescribes adding atypeto the params. It says the same thing before and after this change. (The probe rendered through the fallback component —plugin-chatbotis not registered in it — which does not affect the validation reading, since validation runs before component resolution. Only the warnings are cited.)3. The same document through the render-path validator directly (
@object-ui/core'svalidateSchema):⇒ the retirement is delivered where documents are authored and checked, and ⛔ not where they are rendered. Making the render path agree is a change to
@object-ui/coreon a different card and is not made here.Re-taken reachability (the card's own table, re-measured on this branch — ⛔ not cited from the card)
AnyComponentSchema.safeParse, this branch's source:bodyat the ROOTinvalid_typeat pathbody, message namesrequestBodycard.body[]div.children[]requestBodyinsteadsuperRefineon the installed arm, so what this card actually retires is the ROOT.Corpus impact: zero documents
Every tracked file carrying a
chatbotnode is inexamples/schema-catalog/src/schemas/plugin-chatbot/(3 files). Each was parsed and its node key sets read structurally (⛔ not grepped — a tombstone leaves a comment behind andgrep -ccounts it):Pin inventory — what moved, and in which direction
node-recursion-point-8344.test.ts, two pins INVERTED (⛔ neither deleted):is still ACCEPTED at the ROOT — the published mirror is untouched→is REFUSED at the ROOT too — objectui#8572 retired the published record arm. The inverted leg asserts the issue'scodeand that the message namesrequestBody— the named remedy, ⛔ not the sentence carrying it.ArmsNotAssignableToSchemaNode ≡ 'chatbot'→≡ never.extends { type: infer K }conditional — resolves tounknown— notnever— when the exclusion set is empty, becauseneversatisfies the probe shape andKis inferred from nothing. Written that way the inverted pin could only ever be red. It now answers the empty case first with a tuple-wrappedextends [never]guard and keeps the projection for its diagnostic value: it still NAMES the arm when there is one.Unchanged and still green (the legs that make this a measurement rather than an echo):
is REFUSED one slot down,NON-VACUITY: the same node without body is accepted at both depths,names body in the refusal, and the wholethe fill is LIVEsuite.zod-mirror-parity.test.ts:KnownDrift['complex.zod.ts#ChatbotSchema']'body' | 'onError' | 'onSend' → 'onError' | 'onSend' (the entry survives; the ruling is recorded in its docblock — this is the row the ruling says "becomes 「ruled」");WiderThanDeclared['complex.zod.ts#ChatbotSchema']and itsWIDER_ARMSrow are gone, per that ledger's own clause 4 ("a key DISAPPEARED — the faces agree again; correct or delete the entry"), with the departure recorded in place as a standalone note in the ledger's own convention. Header figures were corrected to the derived ones with the cumulative history sentence each bullet keeps.Ablation — both halves proven load-bearing, from the committed state
body: retirementTombstone(in the file, which belongs toCalendarViewSchema, not toChatbotSchema— so it reddened pins about a different pair and said nothing about this change. The re-run below anchors on this card's own guidance string, which occurs exactly once in the file, and carries scoped structural counters (the declaration block only, comments stripped) plus untouched-neighbour controls.24b009d08)body?: never1childrenarm still 1 and the four other schemas'bodytombstones still 4 (CONTROLS); on-disk hash ≠ HEAD blobArmsNotAssignableToSchemaNode ≡ neverfails, and the parity WIDER ratchet namescomplex.zod.ts#ChatbotSchemaand its keybodybody?: never(zod tombstone kept)children?: neverstill 1 and four other interfaces'body?: neverstill 4 (CONTROLS); on-disk hash ≠ HEAD blob?: neveris erased before a test runs) and theKnownDriftratchet fails namingcomplex.zod.ts#ChatbotSchema— the mirror refuses what the declaration admits⭐ One reading is worth naming because it is evidence about the surface extension itself: under leg A the two RE-POINTED controls in objectui#9256's file stay green. They are aimed at a twin, so they are insensitive to this card's arm — which is what re-pointing rather than inverting buys, and it is the difference between borrowing another card's file and writing this card's verdict into it.
Both legs restored from⚠️ Honest asymmetry worth reading: leg A does not redden
HEAD(⛔ never a baregit checkout --), each verified bygit diff HEADbeing empty and the file hash returning to its HEAD blob.KnownDriftand leg B does not redden the WIDER ledger — each ledger sees one direction, which is why the entry left one and the whole row left the other.Local verification
pnpm exec vitest run packages/types/pnpm --filter @object-ui/types run type-checktsc --noEmit+ the examples project + the tests project)pnpm --filter @object-ui/types run buildnode scripts/check-changeset-presence.mjspnpm changeset:checkmajorpnpm check:changeset-claimspnpm check:new-line-citationsnode scripts/check-control-bytes.mjspnpm check:doc-snippetspnpm check:doc-types·check:prompt-keys·check:component-surface-paritypnpm check:doc-types·check:doc-fences·check:doc-example-idspnpm lintand the rest of thecheck:*roster)--ranreconciliation against a derived gate listdispatch-gates.mjslives in objectstack and refuses cross-repo; this list was hand-derived from this repo's owncheck:*scripts and.github/workflows/, and ⛔check-expected-skips.mjswas not pointed at this repo (it carries objectstack's roster and would answer about the wrong board)24b009d08), after the surface extension, not at the first commit. One reading is explicitly a re-run and says so; one gate invocation in between exited 1 for a reason that is not a red —pnpm run check:changeset-presenceis not a script name in this repo (the script is run directly), which is "I could not run", and it was re-run correctly to exit 0.exit 99= never acquired, place kept) behind a live holder — a sibling worktree's fullpackages/vitest run, held for 22+ minutes and still running at the second timeout. The narrowed runs are two named test files plus onetscproject, and every reading cited here is a verdict (exit code, FAIL line, error identity), not a wall-clock figure, so contention cannot move it.Surface extension — granted, reasoned, and bounded
The ruling names four files. Four more are in this diff. Each is here because the ruling reaches it, not because it was convenient; the alternative for each is stated so the choice is reviewable, and the ground is the one an at-tier reviewer already ruled on this round (objectui#8801 / PR #9621): "the ruling authorised narrowing this arm's accept set, and a pin that asserts the old accept set is reached by that ruling as a matter of necessity, not of choice."
1.
content-channel-family-d-9256.test.ts— two hold-out controls, RE-POINTED (⛔ not inverted). Both were aimed atChatbotSchema.bodyprecisely because objectui#9256 held that key out pending a ruling: the runtimeLIVE CONTROLkept the chatbot rows "a reading aboutchildren", and the type-levelCONTROLpinned the two-meanings collision. This ruling ends that hold-out — for one of the three chatbot faces. Measured: the two TWIN faces still acceptbodyas the content channel (chatbot-enhancedandchatbot-floatingparsebody: CONTENT;chatbot-enhancedrefuses a recordbodyand refuseschildren, which objectui#9256 narrowed). ⇒ both controls are re-pointed at a twin, where the hold-out this card recorded is still true, and neither line says anything aboutChatbotSchema.body. The alternative was to invert them — to assert the refusal — and that is exactly the residual the #9621 reviewer named: restating a retirement inside another card's file. Dropping them was the third option and was refused: the file's header leans on that control by name.2.⚠️ the comment records the honest consequence: this input no longer discriminates the clause, because the arm refuses it with or without the wrapper. That clause's disposition is not this ruling's and is not touched.
strict-authoring-face-8345.test.ts— one case, root half INVERTED. Here re-pointing is not available and dropping does not suffice. The case asserts that the derived strict twin keeps the clause the tolerant face carries; its two root legs asserted acceptance. Dropping them would leave a case that no longer reads the root at all — it would stop noticing if the two faces ever disagreed there. So the root legs are inverted, and3.
packages/types/src/zod/base.zod.ts— prose only, three sentences. That block does not only describe behaviour: it instructs readers not to narrowChatbotSchemabecause objectui#8572 has not ruled. Shipping a live instruction, in a published package's source, citing this card and saying the opposite of what it decided, is the silent-misinformation shape this board exists to stop. The block now records what the clause was for (past tense), that it is REDUNDANT after this ruling, and — the sentence that matters for the next reader — why it nevertheless stays: the wrapper is load-bearing independently of what it checks (node-recursion-point-8344.test.ts'sthe fill is LIVEleg reads that slot 0 holds the WRAPPED union, and the read-back assertion throws when the recursion point did not take), so removing the clause is surgery on objectui#8344's recursion point, not a deletion. ⛔ ThesuperRefineclause, its installation and the pin that reads it are untouched —git diffon this file is comment lines only.4.
content/docs/plugins/plugin-chatbot.mdx— prose only, one table row. TherequestBodyrow told authors that writingbody"sets the base schema's children container and never reaches the API". The remedy was right and the mechanism is now wrong. AGENTS.md #2 makes this a required companion edit, not optional scope.The host cards' own claims survive — checked suite by suite
Both files run whole and green (758 cases across the two):
content-channel-family-d-9256.test.tsfamily D refuses the content channels its renderers never read·a nested family-D node is refused too·the TypeScript face refuses both channels at the AUTHORING site·CONTROLS: the node itself, and the held-out channel, are untouchedstrict-authoring-face-8345.test.ts(a) a known-good document parses under the strict face·(b) one invented top-level key is refused, and the key is named·(c) the tolerant face is behaviourally unchanged·a nested node is judged by its own component schema·checks survive the clone·the barrel is the sole entry into the module cycle·the node face (child slot) twin·the population is closed·the strict authoring face — positive controls·the type-level pins are reachable·what strict could not close is enumerated, not claimed⇒ objectui#9256's narrowing rows, its nested refusal, its authoring-site
@ts-expect-errorblock and its other live controls (buttonfamily C, thetabsandlistITEM channels,div) all still assert what they existed to assert; objectui#8345's strict-face suites likewise, including the closed-population pin its own header calls the one whose absence let a real defect ship.The
changeset-claim-re-readanswerThe gate named 20 pending changesets on the first commit and 29 once the surface extension widened the diff (
base.zod.tsand the docs page bring their own). Read paragraph by paragraph: 29 still true, 0 falsified. The near calls, stated so the reading is checkable:6687-chatbot-surface-authorable.mdquotes "ChatbotSchema… declared 34 keys" — a count this diff moves, but the paragraph frames it explicitly as "measured on both declaration faces before the fix", so it is a historical reading and cannot rot. Closest call of the twenty.8338-retire-toast-action.mdquotes ledger deltas (KnownDrift42/64 → 41/63,WiderThanDeclared23/36/47 → 22/35/45). Those are that card's own move at its own head, not live totals; this change moves the live totals and leaves those sentences true. ⛔ My changeset deliberately quotes no ledger digit for the same reason.8478-zod-pins-complex.mdsays the published.describe()strings incomplex.zod.tscarry no source-line citations. Still true: the describe string this PR replaces carried none and the one it adds carries none — 0 of 167.describe()strings in that file contain a line address, andcheck:new-line-citationsreports 0 new.7703-chatbot-dark-keys-retired.mdstates the?: never+retirementTombstone()lockstep convention; this change follows it rather than falsifying it.zod-mirror-parity.test.tsor the two schema files for ledgers, keys and pairs this diff does not touch (EXCLUSIONS,RuntimeOnlyDeclared,UnmirroredDeclared,KanbanColumn,FilterBuilderCondition,ChatMessage,CalendarView, …).base.zod.ts, and every one of them is about a part of that file this change does not touch:ComponentInput's tombstones (5905×2,7493), thedisabledtwin symmetry (7087), theExpressionWireSchemahoist (7530), thez.lazyspelling census (7918— this diff changes comment text only, not a singlez.lazyinitializer), the node-slotz.number()arm (9162) andComponentMetaSchema(5893). The four naming the docs page (6169,6687,7295,7703) are the chatbot ones already read above.⭐ The gate's list and the falsified set were DISJOINT here, which is the gate's own stated blind spot. It judges name resolution, and the two paragraphs this diff actually falsifies name no file at all:
.changeset/8344-node-recursion-point-redirect.md§2 — "accepted at the root before and after" and "the publishedChatbotSchemais untouched". Both halves sit in ONE paragraph. Route taken: corrected in place, prose only, frontmatter untouched — an AMENDED note naming this card, which keeps that card's own measurements (the nested verdict, the installed check, "narrows at 109, widens at none") intact because those are readings of a fixed head..changeset/9256-content-channel-family-d.md— this key recorded as "a naming collision awaiting a ruling". Route taken: corrected in place, prose only — the hold-out has ended for one of the three chatbot faces, and the reason that card gave for holding it out stays true..changeset/7655-chatbot-registration-authoring-faces.md— "the twins … do not copyChatbotSchema'sbodynaming collision". Route taken: left as written and named in my own changeset, because its claim about the TWINS is still exactly true; only the collision it refers to is the thing retired here.Deviations from the ruling's literal wording, declared
KnownDriftrow as the one that "becomes 「ruled」". Mechanically, a ruled key leaves that ledger (the faces agree, so the row would be stale and its own ratchet would fail on "a listed key that has been fixed"). The row therefore keeps the entry, drops the key, and records the ruling in its docblock — that is the reading of 「ruled」 taken here.WiderThanDeclaredentry and itsWIDER_ARMSrow go, per that ledger's own clause 4, and the header figures move with them. Both are the file's own pins refusing a stale ledger, not scope taken on.ArmsNotAssignableToSchemaNodepin is inverted toneverwith an added empty-set guard — measured, not preferred: without it the inverted pin can only ever be red.维护者速读
聊天机器人节点上的
body从今天起会被当场拒绝,并在拒绝文案里告诉作者该写requestBody(渲染器一直读的就是它)。本仓三份聊天机器人文档一份都没写过body,所以没有任何现存文档受影响。objectui validate/objectui check会拒,TypeScript 会拒;而运行时渲染路径根本不走这套镜像(它走@object-ui/core手写的校验器,且只在开发构建里跑),所以在渲染路径上写错的人得到的仍然是一条指错键名的旧警告,生产构建里则什么都没有。要让渲染路径也说同一句话,是另一个包、另一张卡。⛔ 另有四处被本裁决推翻、但在本 PR 文件面之外的位置(两条 hold-out 对照、一处
base.zod.ts注释、一处文档行),已在上面逐条点名,等 PM 决定是否扩面。Generated by Claude Code
Generated by Claude Code