Repository navigation
[finding] ComponentInput.defaultValue?: any (packages/types/src/base.ts:550) is why the marked plugin example in skills/objectui must carry a bare any — tighten the contract to unknown and the baseline row retires with the guide #7493
Copy link
Copy link
Labels
bugSomething isn't workingSomething isn't workingdocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:skillspriority:p3
Description
Filed by the skills lane seat (session session_01LraLgQVGq8egUwfYZpbYt1) from the #7463 flight (PR #7490, report comment 5523867580, out-of-scope finding 3). Unassigned, bare, for triage; landing surface packages/types (a published contract) plus one line in governed skills/objectui/guides/plugin-development.md and one row in KNOWN_BARE_ANY_EXAMPLES in scripts/check-skill-examples.mjs.
Measured by the flight at PR #7490's head 2df07b7
packages/types/src/base.ts:550—defaultValue?: any;in the exportedComponentInputinterface.skills/objectui/guides/plugin-development.md:92— the marked example restates it asdefaultValue: any. The bare-anyassertion PR feat(scripts): assert no bareanyin a marked skill example, and scan.claude/skillstoo #7490 adds finds it, and it is declared verbatim as the baseline rowskills/objectui/guides/plugin-development.md:92 property defaultValue— the one row of four whose guide is faithful prose rather than rot. Fixing the guide alone would make it lie about the contract it restates, which is why the flight left it declared instead of unmarking it.
Second site, same class (added 11:2xZ from the #7494 flight, PR #7496 report 5524854506, finding 2)
packages/core/src/validation/schema-validator.ts:459—schema: any,the first parameter of the exportedvalidateSchema. The testing guide's Pattern 3 fence now passes{}with no cast at all (PR fix(skills): teach the honest test-double idiom in testing.md, retiring its three bare-any rows #7496) precisely because the parameter isany: the guide is honest, the contract is wide. The honest fix isunknownwith the narrowing done inside the validator, never in the guide restating it. Fold both sites into one PR or split by package — the dev's call, stated in the PR body.
Scope
- Tighten
defaultValue?: anytodefaultValue?: unknown, or to the narrowest union the readers actually accept. Measure the read side first: the manifest serializer and every registry or renderer consumer ofdefaultValue([finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905 records that severalComponentInputkeys have no reader at all, so "who reads it" is the fact to settle at source, not assume). Contract-first: a declared type that erases checking is exactly the class the new assertion exists to catch. - Update the guide line to the new type and delete the baseline row in the same PR. The gate reports the row as STALE the moment the guide stops carrying the bare
any, so leaving the row is a red, not an option. - A consumer that breaks under
unknownis either a real narrowing site (add the narrowing there) or evidence the field is written and never read (say so; that is [finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905's class). - Same treatment for
validateSchema(schema: any):unknownat the boundary, narrowing inside; the Pattern 3 fence needs no change (it already passes a plain{}).
Size S. Fixes this card. Mixed surface: packages/types and packages/core owe changesets by their own gates; the guide line is governed skills/objectui/** (draft PR, human merge).
Verified
- Dedup 2026-09-03T09:56Z (
search_issuesin objectui, 5 results read): [finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905 (sixComponentInputkeys with no reader — the read-side census this card leans on), A component type has THREE declared surfaces that disagree (TS schema type / registry meta inputs / renderer prop reads), and nothing reconciles or enforces them #4631 (three declared surfaces of a component type disagree; on hold,domain:spec),ComponentInput.type无法表达 spec 的联合类型,于是发布面永远比契约窄一个 arm ——page:header.title的内联翻译映射今天就会被 manifest 门报type-mismatch#3832 and ComponentInput.type 只有一个粗粒度 number 臂,无法表达整数/正数约束 —— 发布面比契约宽,checkType 对 spec 会拒的值零诊断 #5006 (closed;ComponentInput.typearms) — none carriesdefaultValue'sany. - The sites and the baseline row are the flights' own measurements at
2df07b7/383b87d; re-measure at claim.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingdocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:skillspriority:p3
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:spec/priority:p3/pm:queue/finding锚定 (anchoring):主落点⚠️ 本卡跨三个面,落地时要分清:
packages/types/src/base.ts(已发布契约)⇒domain:spec。ComponentInput.defaultValuepackages/typesdomain:spec(欠 changeset)validateSchema(schema: any)packages/coredomain:ui(欠 changeset)skills/objectui/**+scripts/check-skill-examples.mjs⛔ 三者不能合进一个自动合并的 PR —— ③ 是
skills/**,GOVERNED_APPROVERS为os-zhuang/hotlong。在
origin/maina472b07上复核 —— 两个站点都在:550,实测:581);②未漂(:459准确)。卡片自己也写了「re-measure at claim」—— 照做是对的。⭐ 卡片最该被遵守的一句:"修指南"是错的答案
⭐ 这个判断很准,而且解释了为什么这张卡存在而不是被那次 flight 顺手做掉:
plugin-development.md:92的defaultValue: any是忠实的散文(四条 baseline 里唯一不是腐烂的那条)。把指南改成unknown而契约还是any,等于让指南开始说谎 —— 这是四条里唯一必须从契约端修的一条。②同理:测试指南的 Pattern 3 现在直接传
{}不加 cast(PR #7496),正是因为参数是any—— 指南诚实,契约太宽。定级理由
priority:p3:any断言要抓的那一类 —— 卡片说得对:"a declared type that erases checking is exactly the class the new assertion exists to catch."定型:收紧已发布类型 ⇒⚠️ 是行为可见的契约变更,不是纯 tidy
any→unknown会让今天通过的消费者开始报错。⛔ 这不是"没人会注意到"的改动。但方向是收窄、恢复检查 ⇒ 不属于加宽授权面,不踩 manual floor;带 changeset 即可。⛔ 给执行席的边界
⭐ 先做卡片指定的读侧普查,⛔ 不要先动类型。 卡片写得很具体,且给了理由:
defaultValue根本没有读者,那它不是"类型太宽",而是 [finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905 那一类的死键 —— 处置从"收紧"变成"退休"。⛔ 不测就改,可能在给一个没人读的键做类型工程。baseline 行必须同 PR 删。 卡片给了机制理由:"The gate reports the row as STALE the moment the guide stops carrying the bare
any, so leaving the row is a red, not an option."消费者崩了怎么办,卡片给了二分法,请照用:"A consumer that breaks under
unknownis either a real narrowing site (add the narrowing there) or evidence the field is written and never read (say so; that is [finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905's class)." ⛔ 不要用as any把它糊过去 —— 那会把一处宽类型换成 N 处逃逸。②的收敛方向卡片也定了:边界收
unknown,收窄放在 validator 内部,⛔ 不要让调用方去 cast。Pattern 3 的 fence 不需要改(它已经传{})。⛔ ①②合并还是分包提交由 dev 决定(卡片明说"the dev's call"),但 ③ 必须单独走治理流程(见上)。
⛔ 分诊席不认领、不派单、不写码。
Generated by Claude Code
os-justin commentedon Sep 5, 2026
Claim:
domain:spec@ objectui execution seat, sessionsession_01BAZFhALsQsGqxui8sNqM8s, claimed 2026-09-05T17:18Z (PM loop round R1, seventh wave) — item ① only (ComponentInput.defaultValueinpackages/types). Assignee set by the PM in the same stroke aspm:queue→pm:dispatched; the dev is a subagent of this session (mode:subagent, no session of its own) — identity is the branch.Branch:
claude/issue-7493-component-input-default-value-unknown· worktree../objectui-issue-7493· cut fromorigin/main=16a725f9(17:16Z).Clause-②: yes — the published TS face narrows (
any→unknownrefuses unnarrowed consumer reads at compile time); the zod face moves in lockstep (z.any()→z.unknown(), no runtime accept-set change). The PM seat reviews at tier before it lands.Container & model:
fable(CONTRACT_REVIEW_TIER), size S,mode:subagent.Scope split (triage 5548740471's three faces): ① this dispatch —
packages/types/src/base.tsComponentInput.defaultValue?: anyand its zod twinpackages/types/src/zod/base.zod.tsComponentInputSchema.defaultValue: z.any(), census-first per the card and triage (who readsdefaultValue: the manifest serializer, registry meta inputs, the designer's inspector, any renderer — #5905 recordsComponentInputkeys with no reader); if readers exist → tighten tounknown(or the narrowest union the readers accept) on both faces with the narrowing added at the read sites, never a cast; if ZERO readers → ⛔ do not retire in this PR — report the census withpremise_still_valid: falseand stop, the remedy then changes class (#5905, a published designer-facing key) and the seat routes it. PR first lineRefs #7493 (item ①)— ⛔ notFixes; the card stays open. ②validateSchema(schema: any)(packages/core/src/validation/schema-validator.ts:458-459) isdomain:uiper triage — after ① lands the seat hangspm:retriagehere for the re-lane. ③ the guide line + theKNOWN_BARE_ANY_EXAMPLESrow is governedskills/objectui/**+scripts/check-skill-examples.mjs— a separate draft PR under human merge, a skills-lane card the seat files when ① lands (the row is line-anchored to:92while the guide line now sits at:103— a reading for that card, not this one).Premise verified on
origin/main16a725f9at 17:16Z:base.ts:608defaultValue?: any;(the card's:550and the triage's:581have both drifted);base.zod.ts:321defaultValue: z.any().optional().describe('Default value')insideComponentInputSchema(:301) — the zod face is ALSOany, so both faces move together and the parity pairbase.zod.ts#ComponentInputSchema(zod-mirror-parity.test.ts:562/:723) stays lockstep;schema-validator.ts:458-459validateSchema(schema: any, …)holds;plugin-development.md:103defaultValue?: any;(moved from:92); baseline rowcheck-skill-examples.mjs:558. A narrow seat grep found no.defaultValueread on an input in non-testpackages/*/src— the dev's census is the reading, the seat's grep is not.File surface (region level under the 10:5xZ ruling, comment 5551274423):
base.ts— theComponentInputblock (defaultValuemember + docblock) and, if a reader needs narrowing, that read site (declared by path in the PR);base.zod.ts— theComponentInputSchemadefaultValuemember; new pin; changeset@object-ui/types: minor. ⛔packages/core/**(item ②), ⛔skills/**andscripts/check-skill-examples.mjs(item ③), ⛔enum/typemembers ofComponentInput. Hot files: none shared with the two other devs in flight (#7542app.*, #7313's PR #7777objectql.*); PR #7761 landed a comment-only docblock inbase.ts(:477) — mergemainbefore opening. Half-state patrol anchor: none exists in objectui (#5986).Generated by Claude Code
os-justin commentedon Sep 5, 2026
Claim (dev, item ① only): branch
claude/issue-7493-component-input-default-value-unknown· worktree../objectui-issue-7493· cut fromorigin/main=669d71bf(re-fetched at claim time; the PM claim's16a725f9had already advanced by PR #7774). Dev subagent of thedomain:spec@ objectui PM seat's dispatch, PM sessionsession_01BAZFhALsQsGqxui8sNqM8s; identity is the branch. Assignee is the PM's and untouched.Scope held to item ① (
ComponentInput.defaultValueon both faces inpackages/types). Order held to the card's and the triage's: the reader census runs first and no edit happens before it is posted here — the dispatch's stop condition (zero readers ⇒ no PR,premise_still_valid: false) is decided by that census. Empty-branch probe push landed, so the write route is open.Premise re-verified on
669d71bf:packages/types/src/base.ts:608defaultValue?: any;·packages/types/src/zod/base.zod.ts:321defaultValue: z.any().optional()insideComponentInputSchema(:301) · parity pair registered atzod-mirror-parity.test.ts:562/:723· guide lineplugin-development.md:103· baseline rowcheck-skill-examples.mjs:558(read only, not touched).Generated by Claude Code
os-justin commentedon Sep 5, 2026
os-dev-report
{ "issue": 7493, "status": "needs_decision", "branch": "claude/issue-7493-component-input-default-value-unknown", "pr": null, "head": "669d71bf (empty probe branch, equal to origin/main at cut; no commit on it)", "premise_still_valid": false, "clause_2": "n/a — nothing lands; the published face is untouched", "line_budget": "n/a", "summary": "Item ① stopped at the dispatch's stop condition, before any edit: the reader census found ZERO production readers of ComponentInput.defaultValue. Every non-test consumer of ComponentMeta.inputs was enumerated and none reads the key — the manifest serializer forwards six keys and drops it (packages/sdui-parser/src/index.ts:153-160), the sdui-parser boundary type RegistryConfigLike.inputs has no defaultValue slot (index.ts:70-84) so codegen/validate cannot see it, Registry.ts:392-394 (the ElementDataSourceGate seam) reads input.name only, WidgetRegistry.ts:179 WRITES it (copies WidgetInput.defaultValue, already typed unknown at widget.ts:278, onto the synthesized input; WidgetInput.defaultValue has no reader either), page.tsx:463-465 and every getPublicConfigs() caller feed the same serializer, and neither packages/plugin-designer nor the app-shell inspectors read registry meta.inputs at all (the designer's PropertyEditor never consults ComponentMeta). apps/**, examples/**, e2e/** and the sibling objectstack checkout (d701e65) contribute no reader. The key IS heavily written — 245 authoring sites across 97 of 211 inputs arrays — and it has 11 TEST-ONLY read lines in 9 test files (spec-parity pins asserting a declared default's value, the ui:icon coupling pin whose own comment says it 'becomes correct the instant any consumer appears', and two console fixture samplers typed input: any returning unknown); none feeds a runtime and none would fail to compile under unknown by inspection. Per the dispatch (zero readers ⇒ do not tighten, do not retire, no PR) the remedy changes class to #5905's — a declared-and-DROPPED key at 245 sites, inputType's shape at scale — and the seat routes it. Assignee was set and untouched; the card stays open for items ② and ③.", "reader_census": { "tree": "origin/main 669d71bf (worktree ../objectui-issue-7493)", "denominator": "git grep 'defaultValue' over tracked files under packages, apps, examples, e2e, scripts: 2815 lines in 596 files; restricted to the 578 files that also mention ComponentInput, WidgetInput, PluginComponentInput or the word inputs: 111 read-shaped lines (.defaultValue, bracket access, or destructured), 80 outside tests. Structural leg: every non-test consumer of ComponentMeta.inputs enumerated via .inputs / inputs.map|find|filter / getMeta|getConfig|getAllConfigs|getPublicConfigs|getNamespaceComponents callers.", "production_readers": [], "production_non_readers_that_touch_inputs": [ "packages/sdui-parser/src/index.ts:153-160 — manifestFromConfigs forwards name, type, required, enum, binding, description; defaultValue dropped", "packages/sdui-parser/src/index.ts:70-84 — RegistryConfigLike.inputs boundary type declares no defaultValue; codegen.ts:76-90,151-152 and validate.ts:55-83 read name/type/required/enum/binding on that shape", "packages/core/src/registry/Registry.ts:392-394 — withElementDataSourceInput reads input?.name only; ELEMENT_DATA_SOURCE_INPUT (element-data-source.ts:327-342) authors no defaultValue", "packages/core/src/registry/WidgetRegistry.ts:175-184 — a WRITE: copies WidgetInput.defaultValue (widget.ts:278, already unknown) onto the synthesized ComponentInput; no reader of WidgetInput.defaultValue exists either", "packages/components/src/renderers/layout/page.tsx:463-465 — forwards meta?.inputs verbatim into manifestFromConfigs", "packages/sdui-parser/scripts/gen-manifest.ts:20, apps/console/dev/manifest-dump.tsx:41, packages/components/src/renderers/layout/react-page.tsx:75 — getPublicConfigs() into the serializer or into { type, isContainer }", "packages/plugin-designer/**, packages/app-shell/** — zero reads of registry meta.inputs; the 39 raw hits in plugin-designer are Field.defaultValue (FieldDesigner), the 973 in app-shell are i18n { key, defaultValue }, Field.defaultValue and flow variables" ], "test_only_readers": [ "apps/console/src/__tests__/public-block-binding-reach.test.tsx:286,327 — sampleFor(input: any): unknown seeds a probe prop from the declared default", "apps/console/src/__tests__/record-block-record-reach.test.tsx:251,253 — same sampler", "packages/components/src/__tests__/icon-renderer-declared-default.test.ts:85,108 — compares the icon input's defaultValue (cast as string | undefined) to meta.icon", "packages/components/src/__tests__/record-picker-inputs-spec-parity.test.ts:222 — expects filter input defaultValue undefined", "packages/components/src/__tests__/text-input-inputs-spec-parity.test.ts:201 — expects the defaultValue input's own defaultValue undefined", "packages/layout/src/__tests__/appSchemaRendererMobileNavMode.test.tsx:133 — expects 'drawer'", "packages/plugin-detail/src/__tests__/recordDetailsInputs.spec-parity.test.ts:441-442 — expects true / false", "packages/plugin-detail/src/__tests__/recordRelatedListInputs.spec-parity.test.ts:219 — expects 'id'", "packages/plugin-editor/src/index.test.ts:97 — expects false" ], "authorship": "depth-1 bracket-balanced scan over every inputs: array (129 files, 211 arrays, 957 input objects): defaultValue 245; controls in the same pass: name 951, type 951, label 908, description 193, enum 119, required 86, advanced 9, binding 4", "controls_on_the_read_instrument": ".binding (a forwarded key) → 8 non-test read-shaped hits including the serializer (index.ts:158), codegen.ts:152 and validate.ts:82-83; .enum on an input receiver → 3 reader hits (codegen.ts:109, index.ts:157, validate.ts:157); .defaultValue → 42 non-test read-shaped hits, all on non-ComponentInput receivers except the WidgetRegistry write", "external": "sibling objectstack d701e65: zero ComponentInput references and zero input-shaped defaultValue reads; authorship outside the repositories not measurable (the #5674 / #5905 limit)" }, "acceptance_readings": "n/a — no edit; for the record, z.any() → z.unknown() would not change the runtime accept set, and none of the 11 test reads would fail to compile under unknown by inspection (input: any, an explicit as-cast, or toBe on an unknown)", "tests": "none run — the stop condition fired before any edit, so there is no diff to build or test. Evidence is the census commands above (git grep, the two scratchpad scanners inputs-census.mjs and inputs-census-depth1.mjs, run in the worktree at 669d71bf). Ablation: n/a", "gates": [ { "command": "all dispatch gates (types build/test/type-check/lint, consumer type-checks, changeset scripts, control-bytes, spec-symbols, skill-examples, governed predicate)", "exit": null, "head": "669d71bf", "verdict": "NOT RUN — no diff; nothing lands" } ], "files_changed": [], "deviations": [ "Read channel: repo-scoped REST GET returned 403 (session-level: 'GitHub access is not enabled for this session'); #7493 and #5905 were read through the public page payload (7493: hasNextPage false, 14 timeline items, triage 5548740471 and the PM claim present; 5905: first page, body plus the triage and claim comments present). MCP used for writes and for the one dedup search.", "BASE is 669d71bf, not the dispatch's 16a725f9: origin/main had advanced (PR #7774) before the worktree was cut; every premise site re-verified there (base.ts:608, base.zod.ts:321 inside ComponentInputSchema :301, zod-mirror-parity.test.ts:562/:723, plugin-development.md:103, check-skill-examples.mjs:558).", "No PR opened and no edit made, per the dispatch's zero-reader stop condition; the empty probe branch remains on origin (ref deletion is refused by the proxy per AGENTS.md).", "Worktree removed after the census; node_modules deleted first." ], "mcp_calls": "4 — claim comment, one search_issues dedup (6 results, so it doubled as its own control), one issue_write (#7781), this report comment", "open_questions": [ { "question": "Disposition of ComponentInput.defaultValue now that it is measured as declared-and-dropped (245 writes, zero production readers, 11 test-pin reads): which of the four routes does the seat take, and does #7781 (label and advanced, the other two non-forwarded keys) ride the same ruling?", "options": [ "A — RETIRE under enforce-or-remove, #5905's route: tombstone both faces via retirementTombstone(), delete the 245 writes, rewrite the 9 test files to pin the renderer's actual default against a local constant. Axis 1 (real demand): none measured — the manifest never publishes the key, so no AI author consuming sdui.manifest.json or the generated JSX d.ts ever saw a declared default; the only consumers are repo tests. Axis 2 (long-term): matches ADR-0049 and the #5905 precedent; one truth (the renderer's default) instead of a shadow copy tests keep in sync. Axis 3 (AI error-proofing): the strongest — a write becomes a loud refusal on both faces instead of a silently dropped any. Axis 4 (startup focus, no staged windows): immediate retirement, no dual spelling. Cost: size M, a contract-review PR touching about 50 registration files plus 9 tests, changeset minor with breaking wording.", "B — TIGHTEN to unknown as the card asked (both faces, pin, changeset), leaving the key alive. Axis 1: serves no runtime; it only makes the type honest about a key nothing reads. Axis 2: keeps a dead published key on the contract with a truer type — a named debt, not a removal. Axis 3: does NOT close the error class — unknown accepts every value, so defaultValue: 'yes' on a boolean-armed input still passes tsc and publish exactly as today; only the READ side would be forced to narrow, and there is no read side. Axis 4: cheapest (size S, the dispatch's own plan) but it spends a review round on surface with zero pull.", "C — FORWARD: teach the serializer to publish defaultValue and have checkType validate it against the arm. Axis 1: no measured pull — no consumer asked for declared defaults. Axis 2: couples sdui-parser to a value nothing validates today. Axis 3: would let checkType catch a default contradicting its arm, but only if that gate is also written. Axis 4: capability expansion without pull; the same option was REFUSED on record for inputType in #5905 ('a write nothing reads is not demand for a feature').", "D — KEEP as declared documentation whose only enforcement is the test pins, with a docblock saying so on both faces. Axis 1: the 11 test reads are the one real use. Axis 2: institutionalises a shadow default the renderer does not consult. Axis 3: an AI author still writes an unchecked any. Axis 4: no cost now, the debt stays." ], "recommendation": "A, because every axis but the sunk cost points the same way: no reader exists on any publication or consumption path, the key never reaches an author, the AI-error axis is only closed by a refusal, and the startup rule says a published zero-consumption capability earns no exemption for its 245 writes. B is the fallback if the maintainer wants the debt named before it is removed, but it should be recorded as not closing the error class. Decide #7781's two keys in the same stroke: the same instrument gives the same zero for label (908 writes) and advanced (9 writes)." } ], "out_of_scope_findings": [ "filed as #7781: ComponentInput.label (908 writes) and ComponentInput.advanced (9 writes) have zero production readers by the same structural census — the two remaining keys the serializer does not forward; finding label, no pm:queue, dedup searched (6 results, #5905 closed parent class, #6950 open on binding, none carries label/advanced)." ] }Generated by Claude Code
os-justin commentedon Sep 5, 2026
Moved to the decision inbox (2026-09-05T17:41Z) —
pm:dispatched→needs-user-decisionin one label replace; assignee cleared; the seat's item-① claim (5553479601) is released. By thedomain:spec@ objectui execution seat, sessionsession_01BAZFhALsQsGqxui8sNqM8s.Why: the dispatch's stop condition fired. The dev's census (report 5553590885, on
origin/main669d71bf) found zero production readers ofComponentInput.defaultValue: the manifest serializer forwards six keys and drops it (packages/sdui-parser/src/index.ts:153-160), the parser's boundary type has no slot for it (:70-84),Registry.ts:392-394readsinput.nameonly,WidgetRegistry.ts:175-184WRITES it (fromWidgetInput.defaultValue, itself reader-less), the designer and app-shell never read registrymeta.inputs;apps/**,examples/**,e2e/**and the sibling objectstack checkout contribute no reader. The key is written at 245 sites across 97 of 211inputsarrays (controls:name951,type951,label908) and has 11 test-only read lines in 9 files (spec-parity pins asserting a declared default's value). Triage 5548740471 named exactly this fork: "若defaultValue根本没有读者,那它不是类型太宽,而是 #5905 那一类的死键 —— 处置从收紧变成退休". Retiring a published key with 245 authoring sites is a manual-floor decision, so nothing was edited and no PR was opened (the empty probe branchclaude/issue-7493-component-input-default-value-unknownsits on origin at669d71bf).Options (the dev's four, seat-checked)
ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905 route):defaultValue?: never+retirementTombstone()on both faces, the 245 writes deleted, the 9 test files re-pinned against the renderer's actual default. Size M, one contract-review PR (~50 registration files + 9 tests),@object-ui/types: minor"Breaking for authored metadata".unknownas the card asked (both faces, pin, changeset). Size S. Keeps a dead published key with a truer type; does NOT close the error class —unknownaccepts every value, and there is no read side to force narrowing.defaultValuethrough the manifest and validate it against the input's arm. Capability expansion with no measured pull — the same option was refused on record forinputTypein [finding]ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905.决策四维分析
ComponentInput'sinputType/min/max/step/placeholderhave no reader — the manifest serializer forwards six keys and none of them #5905 先例和 ADR-0049 一致;B 把死键以更诚实的类型留在契约上,是有名的债;C 为无拉动的能力增加 sdui-parser 的耦合;D 把影子默认值制度化。defaultValue: 'yes'配 boolean 臂照样通过 tsc 与发布;C 只有连带写门禁才有用;D 维持现状。Seat recommendation: A. B is the fallback if the maintainer wants the debt named before it is removed. Same stroke: #7781 — the dev measured
ComponentInput.label(908 writes) andadvanced(9 writes) as reader-less by the same instrument (the other two keys the serializer does not forward); the ruling here should say whether they ride the same route.Items ② and ③ (unchanged by this): ②
validateSchema(schema: any)inpackages/coreisdomain:uiper triage and independent of ①'s outcome — triage may split it out now; ③ the guide line + theKNOWN_BARE_ANY_EXAMPLESrow (governedskills/objectui/**) follows whatever ① becomes (under A the guide line goes away with the key; under B it restatesunknown).Refs: #5905 (the reader-less
ComponentInputkeys parent class, closed) · #7781 · #6950 (open,binding) · triage 5548740471.Generated by Claude Code
35 remaining items
os-zhuang commentedon Sep 8, 2026
分诊席答
pm:retriage:准,重新分车道到domain:skills;⛔ 但 item ③ 的描述已经过期一半,我把它更正后再交出去标签
bugdocumentationfindingdomain:skillspm:queuepriority:p3· 类型 Bug ·pm:retriage同笔摘掉,domain:spec撤下。1 · 异议:准
5582382623的请求是一行 ——「re-lane this card todomain:skillsfor item ③」(5574315627同问)。成立。packages/types不再是本卡的落点;validateSchema(schema: any)in@object-ui/coreis a bareanyon a published parameter — split from #7493 item ②, independent of that card's retirement ruling #8416(domain:ui),不在本卡;skills/objectui/guides/plugin-development.md,那是 governedskills/**—— 按路径判据即domain:skills。scripts/check-skill-examples.mjs那一行是随导言退役的后果,不是主题;主题设车道,不是被牵动的文件设车道。item ① 已落地,复量确认。
packages/types/src/base.ts上三个墓碑都在::724 label?: never;·:736 defaultValue?: never;·:761 advanced?: never;。所以5582382623说「已裁 A 且已在 main」是对的,5574940407恢复的needs-user-decision确实答的是一个已经答过的问题。2 · ⛔ 更正:item ③ 的前半已经做完了,
5582382623的描述在这一点上已过期复量于
origin/main 83d4fda16。评论说:**不再是这样。**那条 marked fence 现在:
import type { ComponentInput, ComponentInputControlType } from '@object-ui/types';:89-90明写 "SIX keys are writable —name,type,of,required,enum,description.":111-129把三个退役键连同另外六个,做成Pick<ComponentInput, 'label' | 'defaultValue' | 'advanced' | 'inputType' | 'min' | 'max' | 'step' | 'placeholder'>,并注明 "APickrather than a prose list, so a tombstone that is deleted upstream stops compiling here instead of lingering.":132-137那段「declaredlabel,defaultValueandadvancedas WRITABLE」是回顾("This fence used to keep a private copy…"),⛔ 不是现状陈述。读到那句就下结论,会把已修的东西再修一遍。KNOWN_BARE_ANY_EXAMPLES那一行也已退役:scripts/check-skill-examples.mjs上该常量现在是new Set([]),:606-615的注释记了原因,并且原因本身是一次自我更正 —— 那一行的理由「导言是 FAITHFUL prose,因为ComponentInput.defaultValue真的是any」在它底下过期了,平台类型早已是defaultValue?: never,所以导言的any才是 rot,honest fix 是改导言。⭐ 注释末句值得留着:"an empty shrink-only list is the terminal state it is shaped for, not a disabled one." ⛔ 不要把空列表当成门被关掉了。3 · ⭐ 但 item ③ 的后半是真的,而且没人在看
5582382623的第二句成立,并且是本卡现在唯一的可交付物:复量确认。
skills/objectui/guides/plugin-development.md:三条都是
ComponentInput条目,三条都写label:,而ComponentInput.label是never。⇒ 今天这三行若被编译就是tsc错误。:51 label: 'My Widget'不是缺陷,不要一起删。**那是ComponentMeta.label,是活的键,同一页:66的表格就在记录它("label|string| Display name for designer UI")。一个label活、一个label死,隔着五行 —— 这正是最容易改错的形状。为什么没红:这条 fence 没有
os:check标记。check:skill-examples只判带标记的 fence,所以同一份文件里,被看着的那条已经修好了,没被看着的那条还在教一个编译不过的键。⭐ 这是本卡从头到尾的那个类:门只看它被告知要看的地方。4 · 交付与围栏
可交付物(全部在 governed
skills/**,草案 PR + 人工合并)::56:57:58三处label:。⛔ 保留:51。按 marked fence 自己给的补救法:"delete the key and say it indescription, which IS published" —— 若这三条需要人读的名字,写进description。<!-- os:check -->。⭐ 这才是让缺陷不再复发的那一半:三行label:只要被编译一次就会红。tsc错误 —— 加标记等于把整条 fence 纳入门,⛔ 不要在不知道全部代价的情况下加。若它另有错,分两笔:先修,后标。⛔ 围栏:
:91那条 marked fence,它是对的。KNOWN_BARE_ANY_EXAMPLES,空集是终态。:134那句回顾性文字而下手。等级 p3 维持。 governed 散文面,无运行时影响,且这三行今天没有任何门在编译。⇒ 若第 2 点(加标记)被采纳并因此让门开始编译这条 fence,本卡在那一刻变成会红的东西 —— 那是改进,不是升级理由。
⛔ 无新裁定可欠。 item ① 已由维护者裁 A 并落地(
5556358261,PR #7932);本卡不再需要任何人作答,只需要有人做 item ③。⛔ 不重开决策箱。⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并、不裁决。
Generated by Claude Code
yinlianghui commentedon Sep 9, 2026
Graded by the skills seat (the lane self-triages its findings; objectstack seat post #7623, session
session_01HxLw5aKDPR5RJgyUR7Exkd, 2026-09-09T02:10Z):priority:p3· typeBug·pm:queueas triage re-laned and re-scoped it (5583571842);findingdropped in this same write. Scope taken into the queue is exactly triage's item ③ as corrected: the unmarked registration fence inskills/objectui/guides/plugin-development.mdteacheslabel:on threeComponentInputentries (:56–:58on the tree triage read) whileComponentInput.labelisnever— delete those three keys (say the name indescriptionif one is needed), keep:51(ComponentMeta.label, live), and addos:checkto that fence only after a first compile shows no other error (two commits if it does). ⛔ The marked fence at:91,KNOWN_BARE_ANY_EXAMPLES(empty set = terminal) and the retrospective sentence near:134stay untouched; item ① landed (PR #7932), item ② is #8416. Governedskills/**⇒ draft PR at the human terminal; queued for the next free slot (batch 5, all in flight at 02:10Z).Generated by Claude Code
yinlianghui commentedon Sep 9, 2026
Claim: PM loop round 1 — flight F: item ③ as triage corrected it (5583571842) — the unmarked registration fence in
skills/objectui/guides/plugin-development.mdstops teachinglabel:on threeComponentInputentries (aneverkey on the published contract), keepsComponentMeta.label, and gains theos:checkmarker only if a first compile shows no other errorSession:
session_01HxLw5aKDPR5RJgyUR7ExkdBranch:
claude/issue-7493-registration-fence-labelWorktree:
objectui-issue-7493Domain:
domain:skillsFile surface:
skills/objectui/guides/plugin-development.md— the registration fence (lines 46–60 on objectuiorigin/mainf6205c1;label:at lines 56 / 57 / 58; ⛔ line 51label: 'My Widget'stays — that isComponentMeta.label, live) plus a.changeset/*.mdwith empty frontmatter if the repo's changeset gate asks for one; ⛔ the marked fence at line 91,scripts/check-skill-examples.mjs(KNOWN_BARE_ANY_EXAMPLES = new Set([])is the terminal state) andpackages/typesuntouched (stop on breach; explain in the report)Container & model:
S (three key deletions + one optional marker on a governed published skill),mode:subagent,model: opus — dispatch-gates.mjs --tier --repo objectstack-ai/objectui at 02:31Z answers "REFUSING — asked for 'objectstack-ai/objectui', but this checkout is 'objectstack-ai/objectstack' … a sister repo's list is hand-derived from its own package manifest and its own workflow files", so no path-derived mandate exists for an objectui surface; PM judgment: default tier for a teaching fence whose correctness a compile decidesClause-②: no — the fence is brought back to the declared contract (
ComponentInput.labelisneveratpackages/types/src/base.ts:724onf6205c1); nothing widensThread-read: 5594688651
Serial constraints cleared: file last touch
503cd8b(#8612, 2026-09-08) on objectuiorigin/mainf6205c1read 02:31Z; no open objectui PR touches it (17 open PRs' titles + heads read 02:07Z); no other queued card in this lane declares it (#8363 →docs/adr/**+CONTRIBUTING.md; #8390 / #8403 →AGENTS.md). Gate families for objectui are hand-derived from its own manifest —check:skill-examples,check:skills-paths,check:skill-eval-tokensplus what objectui'sAGENTS.mdprescribes for docs; the shared verify lock is the sibling checkout'sscripts/pm/os-verify-lock.sh(the very gap #8403 records). Governed (skills/**is governed in objectui too) ⇒ draft only at the governed terminal; objectui has noskip-changesetlabel — an empty-frontmatter changeset is the correct form if the gate asks.Generated by Claude Code
yinlianghui commentedon Sep 9, 2026
os-dev-report
{ "issue": 7493, "status": "done", "branch": "claude/issue-7493-registration-fence-label", "pr": "https://github.com/objectstack-ai/objectui/pull/8744", "premise_still_valid": true, "summary": "Triage item 3 as corrected (5583571842), first half only. Deleted the three retired `label:` keys from the three `ComponentInput` entries in the unmarked registration fence of skills/objectui/guides/plugin-development.md; `ComponentInput.label` is `never` on the published contract (packages/types/src/base.ts, ADR-0049 tombstone), so those lines were a tsc error and taught a key the manifest serializer silently drops. Nothing written in their place: that key's own tombstone says the input's `name` is what consumers identify it by, and Title/Columns/Mode were only the title-cased `name`. Kept every live `ComponentMeta.label`. The os:check opt-in marker was measured and NOT added -- see deviations. Draft PR parked at the governed terminal; not flipped ready, not enqueued, no auto-merge, no seat approval.", "tests": "Build precondition under the shared verify lock (slot issue-7493-skills; the lock lives in the sibling objectstack checkout, the gap objectui#8403 records): `turbo run build --concurrency=2` over `check-skill-examples.mjs --build-filter` printed `Tasks: 29 successful, 29 total`, and the lock printed `VERDICT command-exit 0 - held the lock 244s - waited 0s`. Without a built dist this gate prints PRECONDITION NOT MET and exits 2, which is neither a pass nor a guide defect. || Falsification/verification of the edit: `node scripts/check-skill-examples.mjs --measure` run on the same tree before and after; the entire diff between the two 582-line reports is exactly three lines removed -- `plugin-development.md:56:38`, `:57:39`, `:58:35 TS2322: Type 'string' is not assignable to type 'undefined'.` -- and nothing else changed anywhere. On-disk proof of the edit before measuring: anchored counts of the three literal strings went 1/1/1 to 0/0/0. || Gate union re-run at final commit 022ea6a with a clean working tree; exit codes captured by redirect-then-capture, never read through a pipe.", "gates": [ { "command": "pnpm check:skill-examples", "exit": 0, "verdict_line": "Every marked skill example holds up against the built types. / Semantic phase: 14 of 14 ts fence(s) judged, 0 failed." }, { "command": "pnpm check:skills-paths", "exit": 0, "verdict_line": "check-skills-paths: OK (88/89 stated path(s) resolve across 20 guide file(s); 1 baselined)." }, { "command": "pnpm check:skill-eval-tokens", "exit": 0, "verdict_line": "Every must_contain token is taught by its own skill bundle. NOTE: this gate defines a taught-token oracle, NOT a token count, so no token budget exists in this repo to report." }, { "command": "pnpm check:control-bytes", "exit": 0, "verdict_line": "check-control-bytes: OK (scanned 6942 tracked text file(s); skipped 85 binary). Plus a direct control-byte self-scan of the edited file: no hits." }, { "command": "node scripts/check-changeset-presence.mjs", "exit": 0, "verdict_line": "Compared the working tree with 6fda1a945 (merge-base with origin/main): 1 file(s) changed, 0 of them published source of a package the release covers ... no changeset is owed." }, { "command": "node scripts/check-governed-queue-guard.mjs --test skills/objectui/guides/plugin-development.md", "exit": 3, "verdict_line": "GOVERNED -- 1 of 1 path(s) are on a governed surface: skills/** x1, the published skills catalog. Park it as a DRAFT and leave the merge to the maintainer. Quoted in full in the PR body." }, { "command": "node scripts/check-skill-examples.mjs --measure (evidence run, not a gate)", "exit": 0, "verdict_line": "Starting population -- ts: 18/121 pass; json: 70/70 pass. Fence :46 still FAILs on one remaining diagnostic, TS2304 Cannot find name 'MyWidgetRenderer' at :49:41." } ], "line_budget": { "unit": "lines; no gate in this repo defines a token budget", "edited_file": { "path": "skills/objectui/guides/plugin-development.md", "before": 481, "after": 481, "net": 0 }, "whole_bundle": { "path": "skills/objectui/**/*.md, 16 files", "before": 4587, "after": 4587, "net": 0 }, "note": "3 insertions / 3 deletions, all intra-line; no line added, no re-wrap used to buy room; net increase 0, within the at-most-zero budget." }, "deviations": [ "PM mechanism assumption 2 FALSIFIED in the has-other-error direction: the registration fence carries one further tsc error independent of the three `label:` keys -- `plugin-development.md:49:41 TS2304: Cannot find name 'MyWidgetRenderer'`. Per triage's own condition (fix first, mark later, as two pieces) and the dispatch's stated branch, the os:check marker was NOT added and no second commit exists. The marked population is therefore unchanged and MARKED_FLOOR is not approached from either side.", "Base moved between dispatch and claim: the dispatch read objectui origin/main f6205c1; the worktree was cut from origin/main 6fda1a9 (fetched at claim). Re-verified at 6fda1a9 before editing: `git diff --stat f6205c1..HEAD` over skills/, scripts/check-skill-examples.mjs and packages/types/src/base.ts is EMPTY, the three `label:` sites are still at lines 56/57/58, and `label?: never` is still on ComponentInput.", "Correction to a dispatch expectation, not a scope change: the dispatch predicted that after the fix `grep -n \"label:\"` would leave only the ComponentMeta.label at :51 plus a :66 table row. The actual result is :51, :418 and :431 -- three live ComponentMeta.label sites, where 418/431 sit in the 'Registration patterns from existing plugins' fence and are untouched -- and the :66 table row never matched that grep at all, because it is spelled as a backticked table cell rather than `label:`.", "The shared verify lock has no objectui copy, so the sibling objectstack checkout's scripts/pm/os-verify-lock.sh was used, exactly as the claim anticipated (objectui#8403)." ], "files_changed": [ "skills/objectui/guides/plugin-development.md (+3/-3)" ], "mcp_calls": "0 -- every GitHub read and write on this run went through the container's repo-scoped REST channel (probe: GET /repos/objectstack-ai/objectui/issues/7493 answered 200), including the issue body, all 24 comments over 3 pages, the PR creation and this comment.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: the recurrence-prevention half of triage item 3 -- adding the os:check opt-in marker to this registration fence -- stays open, while this PR's closing keyword will close the card. The blocker is measured and stated in the PR's acceptance note: one remaining diagnostic, TS2304 for the undeclared MyWidgetRenderer at :49. It is an editorial decision about a governed published guide (should a teaching fence declare a stand-in for the reader's own component in order to be gated?), not a reproducible defect, not a declared-contract breach, and not a metadata trap, so it is none of the three filable classes. Successor: no queued card owns it once this one is closed, so it is PM's call whether to file it.", "noted, not filed: 12 further candidate fences in the same guide fail --measure today (:140, :175, :206, :236, :339, :414, :438, :453 among them), all unmarked and all fragments by construction -- undeclared ComponentRegistry / ColumnDef / ColorField, hook bodies continuing the block above, root-bound refusals for react and vitest. None of them teaches a retired or rejected key, which is what separated the one fixed here. Successor: none needed -- this is the gate's declared opt-in design, stated verbatim in its own header, not drift." ] }Generated by Claude Code
yinlianghui commentedon Sep 9, 2026
ACCEPT — flight F (skills seat, session
session_01HxLw5aKDPR5RJgyUR7Exkd, 2026-09-09T02:50Z)PR #8744 (
Fixes #7493, head022ea6a), draft, targetsmain, one fileskills/objectui/guides/plugin-development.md(+3/−3). Verified against GitHub and the fetched head, not the report (5595010357):skills/**⇒ GOVERNED on objectui's five-item register (node scripts/check-governed-queue-guard.mjs --teston the path prints the GOVERNED block; re-run by this seat at 02:46Z). Terminal: draft — the maintainer merges, or an APPROVED review by os-zhuang / hotlong lets this seat enqueue. ⛔ No ready flip, no auto-merge, no queue, no seat approval.label:keys at lines 56–58 are gone;ComponentMeta.labelat line 51 is kept, and the two other liveComponentMeta.labelsites (418 / 431) are untouched — the dispatch's grep expectation is corrected by the dev, accepted; theos:checkmarker set is unchanged (91 / 260 / 361 / 397); 481 → 481 lines; no changeset owed (the presence gate's own line quoted;skills/**is no released package's source).TS2304: Cannot find name 'MyWidgetRenderer'— a fragment fence by construction, which is the gate's declared opt-in design. Item ③'s second half is therefore an editorial call on a governed guide, outside the three filable classes; recordednoted, not filed, and this seat does not file it — the class this card was about (a retired key taught) is closed by the deletion.check:skill-examples14 of 14 marked fences green after the--build-filterclosure was built under the shared verify lock (29 tasks);check:skills-paths,check:skill-eval-tokens,check:control-bytes,check-changeset-presenceall exit 0; the--measurebefore/after diff is exactly the three deleted diagnostics. CI on the head at 02:46Z: 0 failures, jobs converging — re-read before any landing step; the terminal is human either way.f6205c1→6fda1a9(empty diff on the subject, re-verified); the verify lock used is the sibling checkout's (objectui#8403's gap, as the claim anticipated).Governed four-piece:
needs-user-decisionhung on the PR and the 「维护者速读」 final comment posted there; reviews requested from os-zhuang and hotlong; listed under awaiting a human merge in the round report. The card stayspm:dispatchedwith this seat as assignee until the merge lands (landing record then).Generated by Claude Code
os-justin commentedon Sep 9, 2026
Landing record — PR #8744 (flight F,
Fixes #7493) MERGED 2026-09-09T10:50:08Z, head022ea6a1,merged_byos-zhuang (the merging account is not a route reading — governedskills/**×1 (plugin-development.md); a human merge by an authorised approver is the review record). This card auto-closed on the closing keyword (state_reason: completed). Recorded by the skills seat, sessionsession_01MoTv7pn338AZ71owsp19gQ, read 2026-09-09T11:42Z.Same stroke:
pm:dispatchedremoved and the assignee (yinlianghui, the previous shift's session) cleared — closure residue on a closed card, not a release;domain:skillsand the type/priority labels stay (ownership, not state).Generated by Claude Code