Repository navigation
[Decision] Should @object-ui/types ship a generated JSON Schema? — the contract an AI author can read before writing #5392
Description
Filed by the repo:objectui execution seat (session session_01RV6yuVCxymHYE16PL9vQkE) as the follow-up the 2026-08-20 ruling on #5127 surfaced. Filed unassigned. ⛔ Not a grading, ⛔ not a recommendation between the options — this is a Feature/contract question and sits on the manual floor.
Where this came from
#5127 proposed minting a public $schema URL. The maintainer ruled C — do not mint it (ruling comment 5353861854), and the reasoning turned on a question that this card is the real answer to:
「为什么不用本地 node_modules」 · 「以后已经没有人用 vscode 了呀,代码都是 ai 写」
Under AI-first authoring, an agent does not want a URL an editor resolves. It wants two things:
- A contract it can read before writing — and in a repo,
node_modulesis right there. - A good error after writing —
objectui check, which already validates against the installed packages and is therefore version-correct by construction.
Item 2 exists. Item 1 does not, and that is this card.
Measured, on origin/main
@object-ui/types files |
['dist', 'README.md', 'CHANGELOG.md', 'LICENSE'] |
its exports |
11 entries, all TS/zod module entry points — no JSON Schema |
packages/vscode-extension/schemas/objectui-schema.json |
exists, 2723 bytes |
| what binds it | contributes.jsonValidation, by filename glob (*.objectui.json, *.oui.json) — not by $schema, no network |
in-repo files declaring an ObjectUI $schema |
0 |
BaseSchema's full key surface, that document cannot be describing the contract. Anyone weighing this card should read it before assuming a real artifact already exists — the "we already have one, just serve it" framing does not survive opening the file.
The question
Should @object-ui/types generate and ship a JSON Schema describing the ObjectUI node vocabulary, as a published artifact of the package?
It would be generated from the same source the package already owns (the zod mirrors under ./zod), so it inherits version correctness: the schema shipped in @object-ui/types@17.5.0 describes exactly what that version accepts. No skew, no serving obligation, no permanent identifier in users' files.
What it would buy, and what it would cost
Buys:
- The contract an agent reads before writing, at the version actually installed.
- It dissolves the
$schemaURL question thatobjectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127 hit. If a URL is ever wanted, the unpkg-pinned form this repo already uses for@changesets/config(https://unpkg.com/@changesets/config@4.0.0/schema.json) becomes available for free, version-pinned, with zero hosting. - It gives
packages/vscode-extensiona real document to bind instead of the 2.7 KB stub. - It may give
objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127's coverage debt a second route: today 258 real schema files (60.8%) leave the judgement surface because single-node leaves like{type: button, label: Send Email}carry no structural key by construction.
Costs — and these are why it is a decision, not a task:
- A generated artifact is a maintained artifact. It needs a generator, a gate that fails when it drifts from the zod source, and a place in the build. This repo has strong opinions about generated files (⛔ hand-editing them) and about gates whose green means "did not look".
- It publishes a second description of the contract. The zod mirrors are already one; a JSON Schema is a second. This repo has an open card family about exactly that shape ([finding]
ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972,ComponentInputin three structural copies; finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605, the zod mirror drifting from the TS declarations). Two descriptions that can disagree is the failure mode, and the mitigation — generate, never hand-write, and gate the drift — has to be part of whatever ships. - Package size, if the schema is large and shipped to every consumer.
Not in scope here
⛔ This card does not re-open #5127's ruling. No public URL is minted by answering it either way.
Related
objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127 / PR5334 — the ruling that surfaced this; drops the$schemaarm, keeps the structural arm and skip count- [finding]
ComponentInput有三份结构副本(types 两份 + core 一份)外加一个窄孪生WidgetInput,而 #4580 的裁定说的是「re-export 而不是 restate」—— 副本之间今天已经有一处分歧 #4972, finding(types): the zod BaseSchema mirror still declares visible/disabled as boolean and ariaLabel as string, after the TS declarations widened #4605 — the "two descriptions of one contract can disagree" family this would be joining .changeset/config.json— the in-repo precedent for an unpkg version-pinned$schema
Restart-when: #5155 is CLOSED — BaseSchema's open index signature was the decisive measurement against shipping (all 105 node roots project open; PR #6203); if #5155 closes BaseSchema, re-evaluate fork A per those measurements. Ruled 2026-08-25: B — do not ship now (recorded in the comments).
Activity
os-zhuang commentedon Aug 20, 2026
<!-- os-decision-facets -->
Triage(决策箱勤务:入箱卡补标准四棱卡面块;定级 Feature,人工地板 —— 扩大公开面/新增发布物,座位不代裁)。四维分析:
① 项目长远合理性:契约应当有机器可读投影,这符合 contract-first;但 JSON Schema 是同一契约的第二份描述,本仓已有该形态的漂移事故家族(#4972 三份结构拷贝、#4605 zod 镜像漂移)。若 ship,「生成、⛔ 永不手写、drift 门禁红」必须是交付的一部分而非后补 —— 这是选项 A 的固定价格,不是可谈项。
② 实际业务拉动:主航道是 AI 写 app —— agent 写 metadata 前需要读得到的闭合契约,今天的替代品要么读 zod 源码(贵、间接),要么写完靠
objectui check事后报错;vscode 侧现存的 2.7KB stub 覆盖不了 ~200 组件词表,等于没有。客户可感知差异:agent 首轮写对 vs 写错-报错-重写的迭代税。行业类比:@changesets/config的 unpkg 版本 pin$schema是本仓已在用的成熟范式,A 落地后该形态免费可得(不重开 #5127 的 URL 裁决)。③ 防 AI 犯错:写前读到闭合枚举优于自由结构+事后拒绝 —— 方向正确;但两个反面:漂移的 schema 会让 AI「对着假契约写」,比没有更糟(⇒ drift gate 承重);且生成物只能忠实于源 ——
BaseSchema的[key: string]: any(#5155)会原样投影成开放 schema,A 买不到.strict()没买的拒绝,两卡的先后关系值得在裁决时一并看。④ 创业阶段不扩散:新常设生成器+门禁+构建位 = 永久维护义务;但服务的是主航道而非投机面。可最小化形态:仅 build 时生成、不承诺 URL、不进运行时。
选项:A ship 生成的 JSON Schema(含 drift 门禁,发布进
@object-ui/types)/ B 不 ship —— 维持 zod 源 +objectui check两件套 / C 只为packages/vscode-extension生成完整 schema,不进包发布面(中间态,维护义务较小,但 agent 面收益归零)。一行强制置信缺口(本分析看不见什么):zod→JSON Schema 转换在本仓 zod 形态上的保真度未测(
lazySchema/refine/effects 常不可转或转成{},若大面积失真则 A 的收益名不副实);生成物体积未测;#5127 那 60.8% 无结构键的文件是否真会因此获得判定面,是推断不是测量。若维护者倾向 A,建议按「带前提的裁决」形态:先派一张测量卡(转换保真度 + 体积),前提不成立报 fork。Generated by Claude Code
huangyiirene commentedon Aug 22, 2026
Maintainer ruling recorded (2026-08-22, decision-inbox digest with the skills seat,
session_01ApyDuQY2fkunMCqXiqvBhR)The full decision inbox (46 cards) was presented with per-card four-axis recommendations; the maintainer accepted the batch, verbatim: 「接受所有」.
Ruled: A measurement card first. This card's first step is the measurement flagged as the mandatory confidence gap: the fidelity of zod→JSON Schema conversion on this repo's actual zod shapes (
lazySchema/refine/effects, which often convert poorly or to{}), the size of the generated artifact, and whether #5127's 60.8% structure-key-less files would actually gain a judgement surface. The fork between A (ship a generated JSON Schema with a drift gate in@object-ui/types), B (do not ship; keep zod source +objectui check), and C (vscode-extension-only schema) is deliberately NOT decided now — it is decided by the measured result. If the measurement falsifies the premise, report the fork rather than proceeding.State:
needs-user-decisionremoved →pm:queue(ready for dispatch).Generated by Claude Code
claude commentedon Aug 24, 2026
Triage (daily round, session
session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24):domain:uiadded (types package measurement; pm:queue already present). The 2026-08-22 ruling stands: measurement card first — the dispatch is the fidelity measurement, not the generator.Generated by Claude Code
yinlianghui commentedon Aug 24, 2026
Claim: PM loop round 38 (refill slot)
Session:
session_01CSoz9uGhaaSgiq3hshtN7LBranch:
claude/issue-5392-json-schema-fidelity-measurementWorktree:
objectui-issue-5392Domain:
domain:uiContainer & model:
M,mode:subagent,model: opusClause-②: no — ⛔ this ships no generator, no gate, no published artifact. It is a measurement.
File surface: a throwaway measurement script (⛔ not a committed generator) plus the report.⚠️ If you conclude the deliverable is a committed script, stop and report — that is the generator, and it is not ruled yet.
packages/typesis read-only for you. It is contended: #5234 (objectql.ts) and #5232 are in flight, and #6117 (retiringCRUDSchemafromcrud.ts+ the node union) is enqueued and will change the shape inventory you are measuring. ⛔ Branch from a base containing #6117 once it lands, and say which base you measured on — a fidelity census taken before that retirement will disagree with the tree by exactly one node type.裁决 — maintainer RULED this, and ⛔ it ruled a MEASUREMENT, not the feature
[Decision], and the decision was made — to measure first. Maintainer, 2026-08-22 (46-card decision-inbox digest, verbatim 「接受所有」), reaffirmed by triage 2026-08-24:⛔ Do not build the generator. ⛔ Do not add a drift gate. ⛔ Do not publish anything from
@object-ui/types. ⛔ Do not pick A, B or C — the measurement picks it, and you report the fork.The three questions, and what a good answer looks like
lazySchema,.refine()and effects convert to{}or not at all. ✅ Report a census with counts: how many shapes convert faithfully, how many degrade, how many fail — and name the degraded ones, because "80% fidelity" is useless if the missing 20% is every container type an author actually writes. ⛔ A percentage without the list is not an answer.objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127's 60.8% structure-key-less files actually gain one?⇒⚠️ A generated JSON Schema inherits the permissiveness of its source. If most authorable shapes descend from a passthrough base, the generated artifact will accept nearly anything, and shipping it would hand AI authors a contract that looks closed and is not — measurably worse than no schema, which is the card's own axis ③ argument. ✅ Measure this directly and report it as a first-class result, ⛔ not a footnote. It is entirely possible that the honest answer to this card is "A is not worth having until #5155 moves", and that is a result, not a failure.
PM mechanism assumptions — measure, do not inherit
.passthrough()finding from [finding]maxToolRoundtripsis an authorable, documented chatbot key that reaches nothing — useObjectChat destructures it and never reads it #5605 is directly relevant:BaseSchemais.passthrough(), which is why an authored unknown key survivessafeParsetoday. ✅ Check what that projects to in JSON Schema —additionalProperties: trueor its absence — and whether any authorable shape closes it.objectui check把每个 JSON 文件的根type都当成组件键判定,于是在任何 Node 工程里都对 package.json 的"type": "module"报未知类型 #5127's URL ruling is NOT reopened by this card. ⛔ Do not propose, mint or assume a$schemaURL.Verification
.refine()", show a construct you know is there, found by the identical method. ⛔ A zero from an untested instrument is the failure mode this lane hit twice today (type: 'crud'has four declaration faces and no renderer —api/schema-reference.mddocuments it as reference material, so a reader who copies it gets OBJUI-001 #5373'sregister('crud')grep, which also returned zero forregister('table'); and docs(guide): layout guide's PageHeaderProps list names a retired key and omits three live ones; its registration-inputs claim is two entries behind #5923'ssafeParseoutput-key list).⛔ Do not ablate anything — there is no behaviour to ablate, and a ceremonial ablation on a measurement card is noise.⚠️ If you write a temporary script, keep it out of the commit and restore the tree under
trap … EXIT INT TERM; confirmgit diff HEAD --statis empty.Gates:⚠️ mostly not applicable — say so explicitly per gate rather than running a farm over a diff that may be report-only. If the PR contains only a report, ⚠️ #6073 widened the first beyond
node scripts/check-changeset-presence.mjsandcheck-control-bytes.mjsare the live ones (/src/today). ⛔ Do not claim a green from a gate that had nothing to judge.Deliverable
Part of #5392— ⛔ not a closing keyword: the fork is still open and this card decides it, not you. ⛔ Do not mark ready, ⛔ do not enqueue, ⛔ no auto-merge.os-dev-report; ⛔ avoid short angle-bracket placeholders in prose) and return it. State: the converter and version; how you chose the population; the fidelity census with the degraded shapes named; the byte size; the #5127 judgement-surface answer; what the[key: string]: anyprojection does to the artifact's closedness; which of A / B / C the measurement points to and why; and what your measurement cannot see.Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
os-dev-report
{ "issue": 5392, "status": "done", "branch": "claude/issue-5392-json-schema-fidelity-measurement", "pr": "https://github.com/objectstack-ai/objectui/pull/6203", "premise_still_valid": true, "summary": "Measured, not built: no generator, no drift gate, no published artifact, packages/types untouched. Converter is zod 4.4.3's built-in z.toJSONSchema (already a dependency; the repo's transitive zod-to-json-schema@3.25.2 is pinned to zod 3 and cannot convert these shapes). Population is AnyComponentSchema — the union validateSchema/safeValidateSchema parse — 14 members expanding to 105 leaf node schemas, chosen over the barrel's 194 exported zod symbols because most of those are sub-shapes nobody writes at a node position. Census: 0/105 convert under default options (all 105 throw on the same cause, z.undefined() reachable from every node via SchemaNodeSchema); 105/105 convert lenient; 0/105 faithful; 105/105 degraded. Size measured, not estimated: 651,908 bytes pretty, 369,028 minified, 55,529 gzipped — +21.5% / +12.2% of the 3,029,129-byte published dist, the largest single file in the package. The trap the card named is CONFIRMED as the decisive result: BaseSchema is .passthrough(), .strict() is called zero times in the mirrors, and all 105 node roots project additionalProperties to an accept-anything schema (ButtonSchema's resolves through a $ref to {}); the artifact accepts thisKeyIsNotDeclaredAnywhere and accepts classNmae, a misspelling of className — it reads closed and is not. Over the repo's 475 root-type JSON files the artifact agrees with safeValidateSchema on 461 (97.1%), is weaker on 14, and is stricter on ZERO — a strict relaxation that adds no rejection anywhere. Two findings the earlier pre-#6117 run did not have: all 5 refinement sites are now isolated with passing controls rather than 2 of 5, and @objectstack/spec — already a dependency — ALREADY ships generated JSON Schema (json-schema/ in its files array, 23.4 MB, 156 UI documents), of which 118 of 124 object-rooted documents close at the root because its sources are strictObject. Same class of pipeline, opposite closedness: the permissiveness is inherited from the source, not caused by the converter. The spec artifact does not cover this contract — it has no Button/Flex/Card/Table/Form document, so this card is not a duplicate of it.", "tests": "Measured on branch commit 12dcdc110 (merge of origin/main @ 50d0d6cc5, which CONTAINS #6117 / 105f3c55c retiring CRUDSchema); report commit b149c2b14, and the gates below were run on that head. Base delta: the pre-#6117 run had 106 leaves; this one has 105, and the union stayed at 14 members — an earlier projection that #6117 would drop the union to 13 was wrong about the mechanism (CRUDComponentSchema, the CRUD family union, remains; the CRUDSchema leaf inside it is what went), corrected in the report. BUILD FIRST: `pnpm --filter @object-ui/types build` exit 0 — a stale dist/*.d.ts lies in both directions. CONSTRUCT CENSUS in packages/types/src/zod, `grep -oF` with stderr visible: z.function( 60, .superRefine( 3, .refine( 2, z.lazy( 13, z.any( 71, z.unknown( 10, z.undefined( 1, .passthrough( 14 hits / 5 real calls, .strict( 3 hits / 0 real calls. CONTROLS from the identical instrument: z.string( 689 and z.object( 117 (positive) beside z.bigint( 0, z.symbol( 0, .transform( 0, z.custom( 0 (negative) — every zero sits beside a non-zero. An earlier attempt at this census returned 0 for EVERY parenthesised pattern because of an unescaped '(' in grep -oE; it was caught by the control and is recorded in the report rather than quietly fixed. PREDICATE ISOLATION, 5 of 5 sites, each with a control that accepts on both legs before the probe is read — base.zod.ts:272 (input control type arms must be distinct), app.zod.ts:99 (label required on navigation items), form.zod.ts:596 (UNRESOLVABLE_FIELD_WIDGET_NAMESPACE), objectql.zod.ts:258 (tab requires a name, probed via ListViewSchema), complex.zod.ts:481 (the delegated spec date-defaultValue vocabulary) — every one reads `CONTROL zod=accept jsonschema=accept / PROBE zod=REJECT jsonschema=accept`, i.e. PREDICATE SILENTLY DROPPED. CLOSEDNESS CONTROL in the same run: z.strictObject projects additionalProperties=false while .passthrough() projects {} and plain z.object() projects undefined, so 'open' is not an artefact of the converter call. CORPUS, rule copied verbatim from packages/cli/src/commands/check.ts: 620 .json files scanned, 475 with a root string type, 166 JUDGED / 309 SKIPPED (65.1%), of which 45 are package.json — 264 non-package.json, adjacent to the card's 258 on a tree five days older. CENSUS-COMPLETENESS CONTROL: 69 files fail JSON.parse and check.ts reads them with jsonc-parser; re-reading exactly those 69 with jsonc-parser@3.3.1 finds 0 with a root string type, so the 475 is complete against check.ts's own reader. AGREEMENT validated with ajv 8.20.0 (dist/2020.js, strict:false): AGREE 461/475 (97.1%), WEAKER 14, STRICTER 0. RECOGNISER CONTROLS: {type:'button',label:'Send'} accepted by both, {type:'module',name:'x'} rejected by both, and injecting className into a skipped file flips it to JUDGED and removing it flips it back — the instrument demonstrably emits both verdicts. GATES, exit codes captured before any pipe, quoting each gate's own printed line: scripts/check-changeset-presence.mjs exit 0, its line `No source of a released package changed in this range, so no changeset is owed.`; scripts/check-control-bytes.mjs exit 0, its line `check-control-bytes: OK (scanned 5122 tracked text file(s); skipped 85 binary).`. Every other gate family is NOT APPLICABLE and no green is claimed from them — the diff is one file under docs/audits/, 555 additions, zero source files, so lint/typecheck/test/ratchet farms had nothing to judge. NO ABLATION: no behaviour exists to ablate on a report-only diff, and a ceremonial one would be noise. The measurement scripts live entirely outside the repository (session scratchpad) and were never written into the tree, so no restore trap was needed; `git diff HEAD --stat` is empty and `git status --porcelain` is empty.", "open_questions": [ { "question": "Which fork does #5392 take — A (ship a generated JSON Schema from @object-ui/types with a drift gate), B (do not ship; keep zod source + objectui check), or C (vscode-extension-only)? The measurement points, the maintainer decides.", "options": [ "A — ship it. Measured against: it is a strict relaxation (0/475 stricter, 14/475 weaker), so it adds no rejection anywhere; it costs +12-22% of the published package plus a permanent generator, drift gate and build slot; it publishes a second description of the contract into the #4972/#4605 family and this one is GUARANTEED to disagree with the first, measured at 14 files; and it hands AI authors a document that reads closed and is open on all 105 node types. The blocker is the source, not the converter — if #5155 closed BaseSchema, the artifact would project additionalProperties:false and only the 5 dropped predicates would remain, which over 105 node types is a defensible loss.", "B — do not ship. safeValidateSchema already delivers everything the artifact would, strictly better: 97.1% agreement, never worse, better on the 14 the artifact wrongly accepts. Zero bytes, version-correct by construction, cannot drift from itself.", "C — vscode-extension-only. NOT damaged by these numbers, and it is easy to misread them as killing it: C's value is completion, not rejection, and openness, dropped predicates and {} handlers all leave key-name/enum-arm/description suggestions intact. The 2,723-byte stub covers essentially none of a ~200-type vocabulary; a 369 KB generated document would. No publish obligation, so a stale artifact misleads an editor rather than a contract." ], "recommendation": "B now, with A parked behind #5155 rather than refused forever, and C available on its own merits. Real business need: the main lane is AI authoring, and the artifact does not serve it — an agent handed this document would be told classNmae is fine. Long-term soundness: a second description of one contract, measurably disagreeing with the first on day one, is the exact #4972/#4605 failure shape, and contract-first says fix the source (close BaseSchema) rather than publish a lossy projection of a permissive one. Making AI-written metadata hard to get wrong: this is the axis that decides it — a document that reads closed and is not is worse than no document, and the measurement confirms rather than predicts that. Startup scope discipline: a permanent generator, drift gate and build slot bought no rejection at all, while the same recall benefit (~209 of the 309 skipped files) is available today with zero new artifact by using safeValidateSchema as the recogniser, which also unblocks #6075 from this card entirely. Note the countervailing evidence, reported because it cuts the other way: @objectstack/spec already ships a 23.4 MB generated JSON Schema, so the maintenance shape is one this platform has accepted once already — the argument against A is the openness, not the pipeline." }, { "question": "#6075 is currently blocked on this card. Does the measurement release it?", "options": [ "Yes — repay the recall debt with safeValidateSchema as the recogniser, independent of whatever the A/B/C fork decides.", "No — keep it waiting for a shipped artifact." ], "recommendation": "Yes, and it needs no artifact from this card: over the 309 skipped files safeValidateSchema admits 209 and refuses all 45 package.json, which is strictly better than the artifact's 223-accepted / 14-false-accept. One caveat that belongs to #6075's own design, not this card: a validity-based recogniser conflates 'foreign file' with 'broken ObjectUI schema', so files that fail validation today would be filed as not-ObjectUI rather than reported as invalid." } ], "out_of_scope_findings": [ "filed as #6124: 28 zod-mirror keys are declared z.function(), which no JSON document can satisfy; 14 in-repo corpus files author them, are invalid today, and sit outside objectui check's judgement surface. Filed unassigned earlier under this same claim and confirmed still open; it is the entire cause of the 14 weaker files above. Not re-filed and not touched.", "not filed, reported here as an input to the fork rather than a defect: @objectstack/spec ships json-schema/ (23.4 MB, 156 UI documents) in its published files array. It is both the precedent for A's maintenance shape and the closedness contrast that shows the permissiveness comes from BaseSchema, not the converter. It contains no ObjectUI node-vocabulary document, so it does not already answer this card." ] }What the measurement cannot see (the full list is in the report): it measures the zod
mirrors, not the contract — the TypeScript declarations are a second description already
known to disagree (#5927, #5853, #6058, and the ledgers landed by #6149 / #6152), and a
generated artifact would inherit the mirror's view including every one of those
disagreements. In-repo corpus only (475 files, heavily weighted to
examples/schema-catalog); what consumers author against the published package isinvisible. One validator, and it silently ignores one keyword — ajv reported
unknown format "uri" ignored, so.url()projects to aformatajv does not enforcewithout
ajv-formatsand the artifact is even weaker in practice than its own text, byan amount this run did not quantify. Completion quality for option C is structural
reasoning, not measurement — nobody drove an editor against the artifact. Runtime is out
of frame: validation agreement is not rendering agreement. And only the
io: 'input'sidewas converted.
Process note. An earlier attempt on this card pushed a report commit and then died
before opening a PR or reporting. Its branch was found intact at
b70cd2b6band wasnot force-pushed over: this run merged
origin/maininto it and added the re-measuredreport on top, so the history is preserved and the new base (with #6117) is the one
reported. The earlier run's numbers are superseded.
Generated by Claude Code
yinlianghui commentedon Aug 25, 2026
PM routing — the measurement is in, and ⛔ the fork is the maintainer's. Not mine.
PR #6203 (report-only,
docs/audits/, 555 additions, zero source files). Gates read at 01:31Z: 21 of 22 complete,Doc Snippet Type Checkstill running — ⛔ not enqueued, re-armed. (Reading 21-of-22 as green is the early-read error this seat made three times yesterday.)The measurement answered the card, and it answered it against A
The ruling was "measure first, the result decides". It decides:
z.undefined()reachable from every node viaSchemaNodeSchema); all 105 convert only in lenient mode⭐ "Stricter on zero" is the whole result. A generated artifact that adds no rejection anywhere and removes rejection in 14 places is a strict relaxation of what
safeValidateSchemaalready does.The trap the card named is confirmed, and it is decisive
BaseSchemais.passthrough();.strict()is called zero times in the mirrors; all 105 node roots projectadditionalPropertiesto an accept-anything schema (ButtonSchema's resolves through a$refto{}).classNmae— a misspelling ofclassName. It reads closed and is not. For a document whose entire purpose is to let an AI author check itself before writing, that is worse than no document.And all 5 refinement sites are silently dropped, each isolated with a control that accepts on both legs first:
CONTROL zod=accept jsonschema=accept / PROBE zod=REJECT jsonschema=accept.⭐ The countervailing evidence, reported because it cuts the other way
@objectstack/spec— already a dependency — already ships generated JSON Schema (json-schema/in itsfiles, 23.4 MB, 156 UI documents), and 118 of its 124 object-rooted documents close at the root, because its sources arestrictObject.⇒ Same pipeline, opposite closedness. The permissiveness is inherited from the source, not caused by the converter — which both removes "the converter is bad" as an argument and establishes that this platform has already accepted A's maintenance shape once. ✅ Reporting evidence that weakens your own recommendation is what makes the recommendation usable. And it was checked for duplication: the spec artifact has no Button/Flex/Card/Table/Form document, so it does not already answer this card.
⛔ Two things I am NOT deciding
[key: string]: anyleaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155 rather than refused forever, C available on its own merits.{}handlers all leave key-name/enum-arm/description suggestions intact against a 2,723-byte stub covering ~none of a ~200-type vocabulary.[key: string]: anyleaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155" is the right shape — ifBaseSchemaclosed, the artifact would projectadditionalProperties: falseand only the 5 dropped predicates would remain, which over 105 node types is arguably defensible. That is a sequencing judgement about a different card.✅ What I AM deciding: #6075 is unblocked
#6075 was blocked on this card. The blocker's stated purpose is discharged — and the answer needs no artifact from here: over the 309 skipped files⚠️ One caveat belonging to #6075's own design, not this card: a validity-based recogniser conflates "foreign file" with "broken ObjectUI schema", so files failing validation today would be filed as not-ObjectUI rather than reported as invalid. I will route that with the unblock.
safeValidateSchemaadmits 209 and refuses all 45package.json, strictly better than the artifact's 223-accepted / 14-false-accept. ⇒ Repaying the recall debt withsafeValidateSchemaas the recogniser is independent of the fork.The self-caught instrument bug is the seventh this lane has recorded
(ingrep -oE. ✅ Caught by the control (z.string(689 andz.object(117 sitting besidez.bigint(0 andz.symbol(0 — every zero beside a non-zero), and recorded rather than quietly fixed. That is exactly the rule that caught #5373'sregister('crud')grep, which also returned zero forregister('table').✅ And a prior projection of its own was corrected: #6117 dropped the leaf count 106 → 105, but the union stayed at 14 members — the earlier claim that it would drop to 13 was wrong about the mechanism (
CRUDComponentSchema, the family union, remains; theCRUDSchemaleaf inside it is what went).Base is honest: measured on a merge containing #6117 (
50d0d6cc5/105f3c55c), with the pre-#6117 delta stated rather than silently superseded.Generated by Claude Code
os-litant commentedon Aug 25, 2026
Dead-claim reclaim + routed to the decision box — ⛔ this was never dispatchable work
domain:ui@ objectui execution seat, PM sessionsession_01Mn4BZ5AVDM81pvfij1WwM9(os-litant), on a maintainer forced-handover fromsession_01CSoz9uGhaaSgiq3hshtN7L(accountyinlianghui, retired).Two things were wrong at once
main.pm:dispatchedwas never the right state. This card's own body says so, in as many words:Shipping a generated JSON Schema as a published artifact of
@object-ui/typeswidens the public surface and creates a second description of the contract alongside the zod mirrors. That is aFeatureby the mechanical boundary test, ⛔ not a code-tidy and ⛔ not a bug fix — so it is not this seat's to adjudicate, and it should never have been in a dispatch state.This stroke:
pm:dispatched→needs-user-decision, assignee cleared.⛔ Nothing was lost
The dev never pushed. There is no work to recover and ⛔ nothing to re-run — the card returns to the decision box in the state it was filed in, with its own measurements intact (
files: ['dist','README.md','CHANGELOG.md','LICENSE'], 11 export entries with no JSON Schema, and the 2723-byte vscode stub the card correctly warns is far too small to describe a ~200-type vocabulary).Note on the measurement, because it nearly produced a false reading
The container's clone is shallow. On a shallow checkout
git merge-basecan return multiple bases or none, andgit diff A...Bcan die withfatal: no merge base— which, with stderr swallowed, reads as "no changes". That is a failed command masquerading as a clean measurement. The readings above were taken aftergit fetch --deepen=500(main: 105 → 711 commits) and re-derived.Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
关闭
not_planned—— 维护者同意:问题已有答案(08-25 裁定 B,现在不发布),测量报告已入库;唯一的重开条件是 #5155分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ,objectstack 座位贴 #6015),2026-09-24T14:02Z。objectui 清理第九批(#8587 的挂起卡一次性清点):本席读了卡面和能读到的评论(共 8 条,本席能读到其中 7 条,另外 1 条本席的读取权限看不到),并在本地 main(62597c5)上重新核对,把建议报给维护者。维护者答:「第⑨批 同意」。本卡说的是什么
@object-ui/types要不要生成并附带一份 JSON Schema,让 AI 写元数据之前先读契约。08-22 的裁定是先测量;测量(PR #6203)结果是:safeValidateSchema严格的地方为 0 处,宽松的有 14 处。原因是BaseSchema接受任意多余的键,生成出来的 schema 连classNmae这种拼错都会接受。08-25 裁定 B:现在不发布;方案 A 等 #5155 之后再评估。
本席实测(本地 main
62597c5)docs/audits/2026-08-zod-to-json-schema-fidelity.md。packages/cli/src/__tests__/check-validity-recogniser.test.ts引用了 B 裁定,objectui checkskips 263 real corpus files it should judge — the recall debt #5329 could not repay #6075 已经不再被本卡阻塞。base.zod.ts:486仍然是.passthrough(),base.ts:592仍有[key: string]: any。⇒ 重开条件(finding(types): BaseSchema's[key: string]: anyleaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155 关闭)没有发生。为什么关
卡片问的问题已经有了答案,数据保存在审计报告里,继续挂起没有额外价值。
什么时候重开
#5155 关闭、
BaseSchema不再接受未知键时,按审计报告里的数据重新评估方案 A。⛔ 不重开 #5127 的公开 URL 裁定。标签:摘
pm:on-hold;以not_planned关闭。Generated by Claude Code