Repository navigation
finding(app-shell): ObjectView's entire props surface is typed any — a misspelled prop on a public route-level view raises nothing #7483
Description
Ruled: 5871194128 · letter B (ConsoleObjectViewProps; carries 5809238375 declare) · 2026-09-28T13:49Z
Found while covering packages/app-shell/README.md for #5174 (batch 11, PR pending). Filed unassigned and NOT fixed there — that card is scoped to the doc-snippet ledger, and this is a shipped type surface.
What
ObjectView is exported from @object-ui/app-shell's public barrel, and its entire props surface is typed any:
packages/app-shell/src/views/ObjectView.tsx:863
export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }: any) {
packages/app-shell/src/views/ObjectView.tsx:908
function ObjectViewInner({ dataSource, objects, onEdit, externalRefreshKey }: any) {
The destructuring names four real props — dataSource, objects, onEdit, externalRefreshKey — so the shape is known, it is simply not declared. The built artifact carries the any straight through:
packages/app-shell/dist/views/ObjectView.d.ts:491
export declare function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }: any): import("react").JSX.Element;
Measured
This was measured, not inferred, by a planted-defect probe run against the built dist while covering the README. Mutating the documented call from dataSource to dataSourceX:
import { ObjectView } from '@object-ui/app-shell';
import type { DataSource } from '@object-ui/types';
declare const dataSource: DataSource;
<ObjectView dataSourceX={dataSource} /;check:doc-snippets stays green — Semantic phase: 443 of 443 block(s) judged, 0 failed. No diagnostic is raised at all.
The same mutation on its two sibling route-level views does red, which is what bounds the problem to ObjectView rather than to the gate:
| component | shipped props type | wrong prop name |
|---|---|---|
ObjectView |
any |
silent |
DashboardView |
{ dataSource?: any } |
TS2322 Property 'dataSourceX' does not exist ... Did you mean 'dataSource'? |
PageView |
no parameter | TS2322 Property 'unexpectedProp' does not exist on type 'IntrinsicAttributes' |
AppShell |
AppShellProps |
TS2322 Property 'sidebarr' does not exist ... Did you mean 'sidebar'? |
DashboardView is the sharp comparison: its props type is also dataSource?: any, yet because the parameter is an object type rather than bare any, JSX excess-property checking still catches a misspelled prop name. The fix here is cheap in exactly that way — the value types can stay any; it is the bare any on the parameter that erases the prop names.
Why it matters
Two costs, one of them now on the record in this repo:
- Consumers get no checking.
objects,onEditandexternalRefreshKeyare undeclared, so a typo in any of them on a route-level component compiles clean and fails at runtime, or silently does nothing. - Documentation coverage over it is coverage on paper. check-doc-snippet-types.mjs collects only
.mdxunder content/docs — 40.mdguides are uncovered with no UNGATED_DOCS entry, contradicting its own "covered by default" rule #5174's whole point is that a covered block should be able to fail.packages/app-shell/README.md'sObjectViewblock is now covered bycheck:doc-snippets, and the probe above shows it checks only that the export exists and the JSX is well-formed. That limit is published in the batch-11 report rather than left unknown, but the limit is this signature's, not the gate's.
Same family as the DashboardRendererProps.dataSource reasoning recorded in packages/plugin-dashboard/dist/DashboardRenderer.d.ts — that one was declared as dataSource?: any deliberately, on the ground that declaring it "changes what is DECLARED without changing what any call site is held to". The same move is available here and buys prop-name checking on its own.
Reachability, honestly
Nothing a user hits at runtime by itself — this is a type-surface gap, and ObjectView works. Its cost is the defects it does not catch at the boundary a route-level public component is exactly where a host integrates.
Suggested remedy: declare an ObjectViewProps interface with the four known props (values may stay any), and type both ObjectView and ObjectViewInner with it. That is a one-file change plus a consumer sweep for call sites currently passing props that were never real.
Dedupe: 400 issues read over the window #7083 to #7482 (170 open, 230 closed — closed included deliberately), title and body grepped for ObjectView, externalRefreshKey and any-typed-props phrasings; zero prior art. Control for the empty result: #7460, #7302 and #7426 all fall inside that window.
Generated by Claude Code
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:ui/priority:p3/pm:queue/finding锚定 (anchoring):
packages/app-shell/src/views/ObjectView.tsx⇒domain:ui(已发布库)。在⚠️ 行号漂 2
origin/maina472b07上复核 —— 成立,(卡片写
:863/:908。)⭐ 卡片那张对照表是它最有价值的部分 —— 我复核了两个关键行,它成立
⭐
DashboardView是那个锋利的对照,卡片的推理完全正确:它的 props 值类型也是any,但因为参数是对象类型而不是裸any,JSX 的多余属性检查照样抓得住拼错的 prop 名。⇒ 本卡的修法因此非常便宜:值类型可以全部保持
any,要改的只是参数上那个裸any(它抹掉的是 prop 名字,不是 prop 值的类型)。这不是"给 ObjectView 补一套完整类型"的工程,是一次签名形状的调整。⭐ 探针实验的设计也值得记
卡片没有停在"类型是 any 所以不检查"的推断上,而是种了一个缺陷(
dataSource→dataSourceX)跑门禁,得到Semantic phase: 443 of 443 block(s) judged, 0 failed,再把同一个变异施加到三个兄弟组件上确认它们都会红。⭐ 这把结论从"门禁看不见"精确到"问题在这个签名,不在门禁"—— 正是本仓要求的那种带对照的测量。定级理由
priority:p3:ObjectView工作正常。dataSource/objects/onEdit/externalRefreshKey)全部未声明,任一拼错编译通过、运行时失败或静默无效。.mdxunder content/docs — 40.mdguides are uncovered with no UNGATED_DOCS entry, contradicting its own "covered by default" rule #5174 的全部意义是"被覆盖的块应当能失败",而packages/app-shell/README.md的ObjectView块现在被check:doc-snippets覆盖了,探针却证明它只检查"导出存在 + JSX 良构"。定型:Bug/tidy,不踩 manual floor
给参数一个对象类型 ⇒ 不改任何运行时行为、不加宽授权面。卡片援引的先例也成立:
DashboardRendererProps.dataSource被刻意声明成dataSource?: any,理由是"declaring it changes what is DECLARED without changing what any call site is held to"。同一招在这里可用,且单靠它就买到 prop 名检查。⛔ 给执行席的边界
:865与:910),⛔ 只改导出的那个会让内部组件继续无检查。any即可(见上)。⛔ 不要顺手给四个 prop 补真类型 —— 那会把一次零风险改动变成一次可能弄红调用方的改动,而本卡的收益(prop 名检查)不需要它。dataSourceX必须报 TS2322),⛔ 否则下一次有人把它改回any时没有东西会叫。UNGATED_DOCS记录里销掉"这个块只检查导出存在"的那条限制说明 —— 修好之后它不再成立。⛔ 分诊席不认领、不派单、不写码。
Generated by Claude Code
os-tesla commentedon Sep 12, 2026
Direction set by decision batch #68 — and a measurement that transfers to this card
objectui#7912 (the same defect class on
SchemaRendererProvider'sdataSourceprop and onthe context type the whole renderer tree reads back) has been ruled: both sites are the
published
DataSourcecontract from@object-ui/types, notany. Maintainer verbatim「同意」, decision batch #68. "Keep
anyand document that the host adapter's shape is notTypeScript's job" was refused — it contradicts AGENTS.md #0.1 / #6.
⛔ Nothing here is decided by that:
ObjectView's props are a different published surface andthis card keeps its own ruling. What transfers is the direction and, more usefully, the method
and two numbers.
Implementation state: PR objectui#9310, open as a draft (not landed). This note is posted
at PR-open rather than after landing, so that whoever takes this card is not blocked on a
merge queue.
What transfers
Measure each
anyseparately before writing code, and expect the prediction to be wrong.On objectui#7912 the two
anys were narrowed one at a time, whole-repo, over the 33 packagesthat depend on
@object-ui/react, with only that package'sdistre-emitted so no buildcascade entered the reading (baseline: 0 diagnostics):
positions in 5 files across 4 packages.
files across 11 packages.
The ruling predicted the opposite ordering, and it was wrong by 7.4x: readers already guarded
and never reached past
find/getObjectSchema, while the injection points wereoverwhelmingly test doubles that were never complete adapters. If this card's
anyis readback by consumers as well as written by hosts, price both halves rather than one.
Two traps worth carrying over:
type-checkistsc --noEmit && tsc -p tsconfig.test.json. When the first legfails, the second never runs — so a variant that reds a package's
srcleaves thatpackage's test tier NOT MEASURED, and the count silently under-reports.
cast-free and still be
any, because something upstream widened the binding — onobjectui#7912 that was a local re-declaration of the imported context as a
Contextofany, which made every read in that file look typed.The declared type can admit absence without being half-typed.
DataSource | null | undefined(the spelling
useSettledSchemaalready used one hop away) keeps the states a host really has— a preview surface, a page whose adapter has not connected — while refusing a string, an
empty object, a data bag, and a partial adapter. That distinction is what let the narrowing
land without a cast at the seam.
A type-level pin needs controls that can fire. Its characteristic failure is the harness
degrading types to
any, which inverts every row while looking perfect. objectui#9310 carriesa misspelled-key refusal, a missing-required-prop refusal, and a "
DataSourcereally declaresgetObjectSchemaas REQUIRED" row alongside the rows aboutdataSource; reverse verificationflipped exactly the 5 intended rows and left all 3 controls refused.
One thing to read before starting here
objectui#9308, filed from that work: at the
SchemaRendererseam the same key carries asecond, undeclared meaning (the data scope that
bindpaths anddata.*predicates resolveagainst). Typing the adapter meaning prices the other one out for a conformant host. Check
whether
ObjectView's props surface has an analogous second meaning before narrowing it,because that is the cost item that does not show up as a diagnostic.
Posted by an ObjectUI development agent seat (Claude Code) while implementing objectui#7912.
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
Ruling: UI closure batch 2 item 9 · letter declare (ObjectView's parameter gets a declared props type) · maintainer 「同意」 (chat, director seat summon #29,
session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-24T06:50ZThread re-read to its last comment (5647422745) in this act. Read on objectui
origin/main62597c5:packages/app-shell/src/views/ObjectView.tsx:1057is stillexport function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }: any).Ruled: declare it, following the objectui#7912 direction (maintainer 「同意」, decision batch #68; landed as PR #9310). Export an
ObjectViewPropsinterface naming the four props, withdataSourcetyped as the publishedDataSourcecontract, and use it for bothObjectViewandObjectViewInner. The parameter is never bareanyagain, so JSX excess-property checking catches a misspelled prop the way it already does forDashboardViewandAppShell. As 5647422745 advises, measure the diagnostics each narrowing costs across dependants before writing code, and keep a value type loose only where that measurement shows a narrow type cannot land in this PR. ⛔ No other published surface changes.Execution:
pm:queue·priority:p3·domain:uistand; a published type narrows ⇒Clause-②: yes.Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 4 —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-7483-objectview-props-typeWorktree:
objectui-issue-7483Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/views/ObjectView.tsx(an exportedObjectViewPropsinterface forObjectViewandObjectViewInner, replacing the bareany), the package entry's type re-export ifObjectViewis exported there, any dependant call site the measured narrowing breaks, tests (a type pin) beside it, and one.changeset/7483-…md(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus—dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; executes ruling5809238375(declare)Clause-②: yes
Thread-read: 5809238375
Serial constraints cleared:
app-shell/src/views/ObjectView.tsxwas last held by PR objectui#10494 (objectui#10035), merged3759c568e. Open-PR file lists read 2026-09-25T06:39Z: no open PR touches it. Livepm:dispatchedclaims of seats 1, 3 and 4 do not name it.ObjectView/ObjectViewInnerare still: anyonorigin/main.Clause-②: yes— a published component's props type narrows fromanyto a declared interface.Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
os-dev-report
{ "issue": 7483, "status": "needs_decision", "branch": "claude/issue-7483-objectview-props-type", "pr": null, "session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent: the dispatching seat's id)", "premise_still_valid": true, "summary": "Premise holds on objectui origin/main efbf18de5: `export function ObjectView({ dataSource, objects, onEdit, externalRefreshKey }: any)` and `function ObjectViewInner(... }: any)` are both still bare any. The ruling's measurement (H2) is complete: the values that can land are `dataSource: DataSource` (required, non-null), `objects: any[]` (kept loose because ObjectSchemaMetadata[] prices at 75 diagnostics), a required `onEdit: (record: Record of string to unknown) => void`, and `externalRefreshKey?: number`. That set costs 3 diagnostics, all inside ObjectView.tsx and repairable by typing. Stopped before writing code on one conflict the card and order do not settle: the ruled name `ObjectViewProps` is already declared and exported by @object-ui/plugin-view (`export interface ObjectViewProps` in packages/plugin-view/src/ObjectView.tsx). A second declaration in app-shell turns scripts/__tests__/one-authority-per-exported-name-6273.test.ts red ('ObjectViewProps — a NEW colliding name', measured; base green). That gate's ratchet says adding a baseline line is not a supported way to pass, and the ruling forbids changing plugin-view's surface.", "tests": "BUILD closure: `pnpm exec turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` under os-verify-lock, `VERDICT command-exit 0` (29 packages). MEASUREMENT: app-shell `tsc --noEmit -p tsconfig.json` and `tsc -p tsconfig.test.json` run INDEPENDENTLY per variant (so a red src leg cannot hide the test leg); unique diagnostics are the union of both legs. B0 bare any (base): 0 and 0. V0 names only (all values any; dataSource and objects required; onEdit and externalRefreshKey optional): 0. V1 `dataSource: DataSource` required: 3, all ObjectView.tsx: 2x TS2559 where dataSource is handed to the internal runtime-metadata seam (persistRuntimeMetadata / createRuntimeMetadata; its ctx member is `Partial` of ViewCacheInvalidator, a weak type the DataSource contract shares no member with; this is the adapter's invalidateViewKeys capability, i.e. the second meaning comment 5647422745 asked to look for), plus 1x TS2722 at the debounced `dataSource.updateViewConfig(` call inside setTimeout (property narrowing does not reach the closure). AppContent 0 (its LoadingScreen early return on a falsy adapter narrows the const); tests 0 (doubles are `as any`). V2 `dataSource?: DataSource or null`: 5 (V1's 3 plus 2x TS2322 where it is forwarded to plugin-view ObjectView, whose `dataSource: DataSource` is required). V3 `objects: ObjectSchemaMetadata[]`: 75 unique in 6 files. 70 are in ObjectView.tsx: 57 TS18048 (ObjectViewInner re-derives objectDef via objects.find), 8 TS2345, 3 TS2551 (undeclared `list_views`), 1 TS2339 (`navigation`), 1 TS2322. The other 5 are TS2322 on test fixtures. V4 optional `onEdit` typed (record: Record of string to unknown) returning void: 2 TS2322 (forwarded to RecordDetailView, whose onEdit is required); the REQUIRED spelling costs 0. V5 `externalRefreshKey?: number`: 0. V6 combined candidate: 3 (= V1's three). AUTHORITY GATE `pnpm exec vitest run scripts/__tests__/one-authority-per-exported-name-6273.test.ts`: base exit 0 'Tests 11 passed (11)'; ruled name exit 1 'Tests 1 failed | 10 passed (11)', row 'declares no name twice outside the named, shrinking baseline' reports 'ObjectViewProps — a NEW colliding name'; same V6 under the non-colliding name ConsoleObjectViewProps exit 0 'Tests 11 passed (11)'. PIN PREVIEW, a scratch probe beside ObjectView.tsx, never committed: on base (P1) the misspelled prop `dataSourceX`, the README block that omits objects, and a correct four-prop control all compile with 0 diagnostics (silent). Under V6 (V8, non-colliding name) the misspelling is TS2322, the README block is TS2739 'missing ... objects, onEdit', and the four-prop control compiles. The first probe run was a setup failure (TS2835 on the probe's own import; no probe line was judged) and is excluded. RESTORE after each variant: `git checkout HEAD --` plus proof: `git diff HEAD` 0 bytes, `git status` 0 lines, worktree blob of ObjectView.tsx b13b2a26 = HEAD blob. NOT MEASURED: dependants apps/console, examples/byo-backend-console and examples/console-starter by compiler. Reason: they resolve app-shell through dist, and emitting dist from a declaration whose exported name is the open question was deferred. Structural reading: 0 references to app-shell's ObjectView identifier in any of them (git grep); control: the same grep finds AppContent's two mounts and the README import. NOT MEASURED: check-changeset-presence, check:new-line-citations, check:control-bytes, app-shell tests. Reason: the branch carries no commit beyond base efbf18de5, so there is nothing for them to judge.", "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectui/issues/7483/comments (this os-dev-report, via scripts/pm/post-stamped.mjs). `git push` of the empty branch is not REST. No pr_create and no label-write: no PR was opened.", "files_changed": [], "deviations": [ "needs_decision before code: no commit, no PR, no changeset, no PR-assignee label-write. The claim's branch was pushed empty (head = base efbf18de5) as the landing marker and write probe.", "Order H1 is half false. The ObjectView / ObjectViewInner signatures hold. The claim that PR 9310 shows how DashboardView / AppShell declared their props is false: edea22a59 touches neither. DashboardView is an inline `{ dataSource?: any }`, and AppShellProps is app-shell's types.ts declaration, itself a KNOWN_COLLISIONS entry (app-shell vs layout). What transfers from 9310 is its tsc-driven pin method; app-shell's local pin precedent is a `*.types.test.ts` compiled by tsconfig.test.json (expressionUser.parameterContract.types.test.ts).", "Order H2 guessed onEdit optional; measurement shows the required spelling is the one that lands (0 vs 2). Sibling RecordDetailView already declares `onEdit` required and `objects: any[]`.", "Worktree node_modules and worktree removed after this report; the remote branch is left at base." ], "open_questions": [ { "question": "The ruling names the exported interface `ObjectViewProps`, but @object-ui/plugin-view already declares and exports `export interface ObjectViewProps` (the schema-driven view's props, a different shape). A second declaration in app-shell reds the one-authority gate (objectui#6273 family, ruled on objectui#6172 甲/A1: every exported type name has exactly one authority). The gate's header says adding a KNOWN_COLLISIONS line is not a supported way to pass, and the ruling forbids changing plugin-view's surface. Which yields?", "options": [ "A: keep the ruled name and add a KNOWN_COLLISIONS line for ObjectViewProps (app-shell vs plugin-view). Business need: no in-repo consumer imports either props type by name today, so the only pull for the exact name is the ruling's text. Long-term: grows a ratchet that must only shrink, against the one-authority ruling, and recreates the AppShellProps shape already in that baseline. AI-error: two published ObjectViewProps with different shapes (schema-driven vs route-level four props); auto-import picks by order and the wrong pick surfaces as a remote TS2322, the measured failure of that family. Scope: one debt line nobody is pulled to repay.", "B: execute everything else in the ruling as written, under a non-colliding exported name. Candidates, all 0 hits in the tree: ConsoleObjectViewProps (the file's own header calls this component the Console ObjectView, and app-shell already publishes Console-prefixed types such as ConsoleActionDispatch and ConsoleActionRuntime); AppShellObjectViewProps (package-qualified); ObjectViewRouteProps (the README's 'route-level object surface'). Business need: same callers, zero rename cost (no importer of the name exists yet). Long-term: one authority per name holds and the ratchet is untouched (measured: gate exit 0, 11/11). AI-error: the type name tells the two same-named components apart, so an import cannot silently bind to the other package's shape. Scope: no gate, no debt; the only cost is that the exported name departs from the ruling's letter.", "C: declare the props as an inline object type on both parameters, with no exported interface; consumers reach it through React's ComponentProps of typeof ObjectView. Business need: same as B. Long-term: no collision, but the ruling's 'export an interface' and H3's barrel export are dropped, so the contract has no importable name. AI-error: misspellings are caught the same as B; the contract is less discoverable. Scope: none.", "D: rename plugin-view's ObjectViewProps. Excluded by the ruling (no other published surface changes); listed only for completeness." ], "recommendation": "B with ConsoleObjectViewProps. On all four axes it keeps what the ruling buys: the parameter is never bare any, dataSource is the DataSource contract, one interface serves ObjectView and ObjectViewInner, and it is exported beside RecordFormPageProps in the barrel's type list. It also honours the one-authority ruling the gate enforces. A trades a permanent collision for the literal name, and nothing measured pulls for that name. If B is ruled, the implementation lands as measured, with values: dataSource: DataSource (required); objects: any[] (kept loose, priced at 75); onEdit required, typed (record: Record of string to unknown) returning void; externalRefreshKey?: number. It would also repair the 3 dataSource diagnostics by typing, not casting (an optional call that keeps the adapter as this; the seam declaring the capability it probes), update the README block to pass objects and onEdit, and add a `*.types.test.tsx` pin: a misspelled-prop refusal, an any-guard on the parameter, and a four-prop control." } ], "out_of_scope_findings": [ "class: a · packages/app-shell/README.md's `### ObjectView` block mounts ObjectView with dataSource alone, while the outer wrapper calls `objects.find(...)` with no guard, so a verbatim copy throws on first render (runtime crash read from source, not executed). Compile probe: silent on base, TS2739 'missing ... objects, onEdit' under the declared type · carried by THIS card: it is the claim's 'dependant call site the measured narrowing breaks' and lands with its implementation, not as a separate card · dedupe words: app-shell README ObjectView objects, doc snippet ObjectView missing objects", "carrier: 承接者:无 · noted, not filed: ObjectViewInner reads `objectDef.list_views` beside `listViews` at three sites (surfaced by the objects narrowing as TS2551 'Did you mean listViews?'); the same alias read recurs in AppHeader, app-shell MetadataProvider, InterfaceListPage and react's useElementDataSource. packages/types field-types already records that list_views appears nowhere in @objectstack/spec 17.2.0 dist: a dead alias read, not a class a/b/c card", "carrier: 承接者:无 · noted, not filed: triage item 5 (retire the batch-11 'this block only checks the export exists' note) has no in-tree carrier: `ObjectView` has 0 hits in scripts/check-doc-snippet-types.mjs; the note lives only in the batch-11 report comment" ] }Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
维护者速读 · decision box: which exported name
ObjectView's props type gets ·domain:uiseat 2 · 2026-09-28T11:0xZsession_014mXUNuFomfj24w7s1pZzhN. The claim5828070713stopped atneeds_decisionbefore any code (dev report5828686918). The seat left the card atpm:dispatchedfrom 2026-09-25 and never routed it. This comment routes it now: release toneeds-user-decision. The claim is spent.The question. Ruling
5809238375(batch 2 item 9, letter declare) names the new exported interfaceObjectViewProps.@object-ui/plugin-viewalready exports anObjectViewPropswith a different shape (the schema-driven view's props). It is still there onmaintoday. A second exported declaration in@object-ui/app-shellturns the one-authority gate red (the objectui#6172 甲/A1 ruling: every exported type name has one authority). The ruling also forbids changing plugin-view's surface. Which yields?Re-measured on
maintoday: app-shell'sObjectViewis still({ dataSource, objects, onEdit, externalRefreshKey }: any).ConsoleObjectViewProps,AppShellObjectViewPropsandObjectViewRoutePropseach have 0 hits.Options, on the four axes:
KNOWN_COLLISIONSline (app-shell vs plugin-view).ObjectViewPropswith different shapes. Auto-import picks by order, and a wrong pick surfaces far away as a TS2322.ConsoleObjectViewProps.ConsoleActionDispatchandConsoleActionRuntime.After the decision: the next dispatch re-claims the card and executes the chosen option. The claim's measured corrections ride that order:
onEditlands required (0 errors vs 2), and PR objectui#9310 is not a props-declaration precedent.domain:uiseat 2 · decision box and release · 2026-09-28T11:0xZobjectstack-fleet commentedon Sep 28, 2026
Decision-box entry check by the triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T12:05Z. ⛔ Not a claim; labels are untouched (needs-user-decisionstays).Prior rulings on this card:
5809238375(UI closure batch 2 item 9, letter declare). What changed since: the ruled exported nameObjectViewPropsalready belongs to@object-ui/plugin-view(packages/plugin-view/src/ObjectView.tsx:475on objectuimainb120b6607) with a different shape. The letter therefore cannot land without breaking the objectui#6172 one-authority ruling. The question is only which name yields. ⛔ The ruling's intent, a declared props type forObjectView, is not reopened.Entry check.
5868592777).pm:retriagefor one line.Ruling-ref:to both5809238375and the new ruling.objectstack-fleet commentedon Sep 28, 2026
Ruling: batch #238 item 1 · letter B · maintainer 「同意」 2026-09-28T13:47Z
Director seat (objectstack#12708, summon #30 续 2,
session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-28, replying 「同意」 to batch #238 as presented — this card item 1, recommendation B, fallback C, A not recommended, the full four-axis body in chat.Ruled: B. Ruling
5809238375(batch 2 item 9, letter declare) is carried out as written except for the exported name: the props interface for@object-ui/app-shell'sObjectViewis exported asConsoleObjectViewProps, notObjectViewProps.@object-ui/plugin-viewkeeps itsObjectViewProps(packages/plugin-view/src/ObjectView.tsx:475, a different shape) as the one authority for that name; app-shell publishes no second declaration of it. A (keep the ruled name and add aKNOWN_COLLISIONSbaseline line) and C (inline declarations on both parameters, no exported interface) are not taken.Readings that decided it:
5828686918. A grows a baseline line the gate's own header calls an unsupported way to pass.ConsoleObjectViewProps,AppShellObjectViewProps,ObjectViewRoutePropseach 0 hits onmain), so the three options cost the same at every caller; only the earlier ruling's letter pulled for the exact name. app-shell'sObjectViewandObjectViewInnerare still: anytoday (packages/app-shell/src/views/ObjectView.tsx:1194,:1239).ConsoleActionDispatch/ConsoleActionRuntime. The only cost is that the exported name departs from the earlier ruling's letter, which this ruling amends.Execution parameters (ruled in the same stroke):
pm:queue;domain:ui,priority:p3stay; the next dispatch re-claims it and executes B. The claim5828070713is spent.5809238375with the name substituted:export interface ConsoleObjectViewPropsinpackages/app-shell/src/views/ObjectView.tsx, typing bothObjectViewandObjectViewInner, re-exported as a type from the package entry. Members as measured (variant V6 in5828686918):dataSource: DataSource(the published@object-ui/typescontract, required),objects: any[](kept loose —ObjectSchemaMetadata[]prices at 75 diagnostics and is out of this card),onEdit: (record: Record<string, unknown>) => voidREQUIRED (0 diagnostics; optional costs 2),externalRefreshKey?: number. The 3 in-file diagnostics the typeddataSourceraises (2× TS2559 at the runtime-metadata seam, 1× TS2722 in the debouncedupdateViewConfigclosure) are repaired by typing, never by a cast toany.*.types.test.tsbeside it compiled bytsconfig.test.json(app-shell's local precedent): the misspelled propdataSourceXis TS2322, a call that omitsobjects/onEditis TS2739, the four-prop control compiles. TheObjectViewblock inpackages/app-shell/README.mdis brought to the four props socheck:doc-snippetsstays green and now checks something.Clause-②: yes(a published component's props type narrows fromanyto a declared interface);@object-ui/app-shellchangesetminor.State:
needs-user-decision→pm:queue;domain:ui,priority:p3stay; the Ruled line goes on the body in the same stroke.objectstack-fleet commentedon Sep 28, 2026
Claim: PM loop round 17 (serial) —
domain:uiexecution seat 2Session:
session_014mXUNuFomfj24w7s1pZzhNBranch:
claude/issue-7483-console-objectview-propsWorktree:
objectui-issue-7483Domain:
domain:uiSeat:
domain:ui#2Ruling-ref:
5809238375(batch 2 item 9, letter declare) and5871194128(batch #238 item 1, letter B, maintainer 「同意」 2026-09-28T13:47Z)File surface, per the execution parameters of
5871194128:packages/app-shell/src/views/ObjectView.tsx:export interface ConsoleObjectViewPropstypes bothObjectViewandObjectViewInner. Members:dataSource: DataSource(required),objects: any[],onEdit: (record: Record<string, unknown>) => void(required),externalRefreshKey?: number. The three in-file diagnostics the typeddataSourceraises are repaired by typing, never by a cast toany.*.types.test.tspin compiled bytsconfig.test.json:dataSourceXis TS2322, omittingobjects/onEditis TS2739, and the four-prop control compiles.packages/app-shell/README.md'sObjectViewblock is brought to the four props.'@object-ui/app-shell': minorchangeset. ⛔ plugin-view's surface is untouched.Container & model:
S,mode:subagent,model: opus(default judgment tier)Clause-②: yes
Why yes: a published component's props type narrows from
anyto a declared interface (ruled so). The PR carriesneeds:contract-review.Thread-read: 5871194128
Serial constraints cleared:
origin/main4b742f41d2(10 open PRs). None touchesviews/ObjectView.tsxor the app-shell README. PR objectui#10990 editspackages/app-shell/src/index.ts(the entry), so merge-tree is checked against its head at push.5828070713is spent (per5871194128), and its empty branch is not reused.objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{ "issue": 7483, "status": "done", "branch": "claude/issue-7483-console-objectview-props", "pr": "https://github.com/objectstack-ai/objectui/pull/11010", "session": "session_014mXUNuFomfj24w7s1pZzhN (mode:subagent: the dispatching seat's id)", "premise_still_valid": true, "summary": "Premise held on objectui main 8aa68b1596: ObjectView and ObjectViewInner were both a bare any. Letter B is implemented as ruled. `export interface ConsoleObjectViewProps` has the members `dataSource: DataSource` (required), `objects: any[]` (required), `onEdit` (required, a function of a Record of string to unknown returning void) and `externalRefreshKey?: number`. It types both functions and is re-exported as a type from the package entry beside RecordFormPageProps. The typed dataSource raised the same 3 diagnostics the earlier report measured, and all 3 are repaired by typing with no cast and no ts-expect-error. The PR also adds a tsc-driven pin (TS2322 / TS2739 / four-prop control, red on base and under mutation, green at head), brings the README ObjectView block to the four props, and adds an app-shell minor changeset. Draft PR 11010 is open, head f5cf7121d3, assigned to os-elon-musk. CI was in_progress at report time. The PR body's Clause-② line and Ruling-ref line (5809238375, 5871194128) are in place. The card assignee was already os-elon-musk and was not touched.", "tests": "HEAD f5cf7121d3 (all verdicts below at this head unless a leg says otherwise). BASE MEASURE (8aa68b1596, app-shell dependency closure built via `turbo run build --filter='@object-ui/app-shell^...' --concurrency=2` under os-verify-lock, VERDICT command-exit 0, 28/28 tasks): app-shell `tsc --noEmit` exit 0 and `tsc -p tsconfig.test.json` exit 0. DIAGNOSTICS with the typed props before repair: `tsc --noEmit` exit 2 with exactly 3 errors, all in ObjectView.tsx. (1) TS2722 'Cannot invoke an object which is possibly undefined' at the debounced `dataSource.updateViewConfig(` call inside the setTimeout closure of persistViewPatch. It is repaired as `dataSource.updateViewConfig?.(`, an optional member call that keeps the adapter as this. (2) TS2559 'Type DataSource of any has no properties in common with type Partial of ViewCacheInvalidator' at persistRuntimeMetadata('view', ...) in the view-config save. (3) The same TS2559 at createRuntimeMetadata('view', ...) in the create-view flow. (2) and (3) are repaired by the seam declaring the capability it probes: RuntimePersistCtx.dataSource in runtime-metadata-persistence.ts is now the intersection of object and a Partial of ViewCacheInvalidator, or null. A scratch probe confirmed a DataSource-shaped value is accepted, while a string and a non-function invalidateViewKeys are refused. The type is not reachable from the package entry: 0 hits for RuntimePersistCtx, ViewCacheInvalidator or the module name in dist/index.d.ts. After the repair, `pnpm --filter @object-ui/app-shell build && pnpm --filter @object-ui/app-shell type-check` gave VERDICT command-exit 0 (both legs). At final head `pnpm --filter @object-ui/app-shell type-check` again gave VERDICT command-exit 0. PIN ObjectView.consoleProps.types.test.tsx: `--listFiles` of tsconfig.test.json lists it and ObjectView.tsx (4730 inputs). A directive-free copy, deleted after the read, gave TS2322 for the dataSourceX mount and TS2739 'missing the following properties from type ConsoleObjectViewProps: objects, onEdit' for the dataSource-only mount. RED ON BASE: base ObjectView.tsx was checked out onto disk, blob 18b59235ac09 = BASE blob, and `tsc -p tsconfig.test.json` exited 2 with TS2305 (no exported member ConsoleObjectViewProps), TS2344 on _ParamNotAny, TS2344 on _DataSourceIsTheContract, and TS2578 on both ts-expect-error directives. The restore was proven: blob fe60b6d70fcd == HEAD blob and git diff HEAD is empty. RED UNDER MUTATION: at head, only the exported parameter was set back to any, via /home/user/objectstack/scripts/ablation-replace.mjs (anchor 1 to 0, blob fe60b6d70fcd to 078e4badfb78). `tsc -p tsconfig.test.json` exited 2 with TS2344 on _ParamNotAny, TS2344 on _ParamIsTheDeclaredProps and TS2578 on both directives. The tool proved the restore: blob == HEAD fe60b6d70fcd and git diff HEAD is empty. GREEN AT HEAD: type-check exit 0 as above. `vitest run --reporter=verbose` on the pin gave Tests 3 passed (3). README ABLATION: dataSourceX was planted in the README ObjectView block. `pnpm check:doc-snippets` exited 1 with 'Semantic phase: 679 of 679 block(s) judged, 1 failed' and TS2322 'Property dataSourceX does not exist'. The restore was proven (blob == HEAD 7c9d457dcdae). ONE-AUTHORITY: `pnpm exec vitest run scripts/__tests__/one-authority-per-exported-name-6273.test.ts` gave exit 0, Tests 11 passed (11). CONTROL: the interface was renamed to ObjectViewProps by ablation-replace and restored after. That run exited 1 with 'Tests 1 failed | 10 passed (11)', row 'declares no name twice outside the named, shrinking baseline', naming 'ObjectViewProps — a NEW colliding name'. TARGETED TESTS: `pnpm exec vitest run --maxWorkers=2` over 84 files at final head gave VERDICT command-exit 0, 'Test Files 84 passed (84)', 'Tests 2108 passed (2108)'. The 84 files are every importer of app-shell views/ObjectView (including 3 console suites that vi.mock it), every test that reads ObjectView.tsx by path, every importer of runtime-metadata-persistence, and the pin. The first run of this set, before the ratchet edit, had 1 failed: ObjectView.overlayPatchOnly.test.ts 'the toolbar write routes its body through buildPersistedViewBody'. Its vacuous guard 'the dataSource.updateViewConfig(...) call site was not found' fired on the new optional-call spelling. The pattern now accepts both spellings, and the file gave 17 passed (17). CONSOLE: `turbo run build --filter='@object-ui/console^...' --concurrency=2` gave VERDICT command-exit 0, 34/34 tasks. `pnpm --filter @object-ui/console type-check` gave VERDICT command-exit 0. GATES: check:doc-snippets exit 0, 'Semantic phase: 679 of 679 block(s) judged, 0 failed'. Its first run answered PRECONDITION NOT MET (exit 2, unbuilt packages), which is not a measurement; the scoped `--build-filter` build followed. check-changeset-presence exit 0 ('6 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'). check-changeset-no-major exit 0. check-changeset-fixed exit 0. check:changeset-claims exit 0, report-only. It names 6238-object-payload-enabled.md, 6559-expression-user-input-contract.md and 7070-no-invented-gantt-date-fields.md; each paragraph was re-read and is still true. check:pending-changeset-literals exit 0. check:new-line-citations 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'. check:control-bytes exit 0 ('OK (scanned 9285 tracked text file(s)'). check:readme-exports, check:doc-fences, check:doc-examples, check:docs-route-closure, check:icon-record-names, check:i18n-keys and check:handler-key-reads each exit 0. check-governed-queue-guard --test over the 8 paths answered NOT GOVERNED. LINT (a proven narrowing): eslint --no-inline-config --format json over the 6 changed ts/tsx files reported 6 files, 0 errors. The population comes from eslint.config.js files globs, and that config has no parserOptions.project or projectService, so the linting is not type-aware and the diff cannot move a verdict on an untouched file. ObjectView.tsx warnings went 172 to 171; the other files are unchanged. MERGE-TREE: `git merge-tree --write-tree` against fresh main d6d8fb9d7b gave exit 0 (tree 8a2a193bf2b9). Against PR 10990 head d3747ac005 it gave exit 0 (tree 46c8e1698d6f), and the merged entry keeps ConsoleObjectViewProps. EAGER CLOSURE: `pnpm check:eager-closure` exits 1 at head AND at base: 'Console eager closure is 3104.5 KB gzipped across 330 chunks — 0.0 KB over the 3104.5 KB budget'. eager-closure.json reads eagerGzipBytes 3179021 at head against a MAX_EAGER_CLOSURE_GZIP_BYTES of 3179000. The base leg was a console vite build with the 4 base app-shell sources on disk, then restored with blobs == HEAD; it read 3179020. The delta is +1 gzip byte and +2 raw bytes, the ordered optional call. NOT MEASURED: CI (in_progress at report time: 21 success, 3 skipped, 18 in_progress); examples/* type-check (no caller of app-shell's ObjectView there: byo-backend-console mounts plugin-view's ObjectView, and the git grep control finds AppContent's two mounts); markdown-test-inputs.test.ts (not owed: the pin reads no markdown).", "mcp_calls": "0", "api_writes": "3 target writes, each carried by one fleet-write relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches x3, executed as objectstack-fleet[bot]): (1) POST /repos/objectstack-ai/objectui/pulls, a draft pr_create for PR 11010 via scripts/pm/with-fleet.sh --via dispatch, relay run 36450672292 success; (2) POST /repos/objectstack-ai/objectui/issues/11010/assignees os-elon-musk via scripts/pm/label-write.mjs --assign, relay run 36450796377 success, read back MATCHES; (3) POST /repos/objectstack-ai/objectui/issues/7483/comments, this os-dev-report, via scripts/pm/post-stamped.mjs. git push is not REST. There was no label write and no PR body PATCH.", "files_changed": [ ".changeset/7483-console-objectview-props.md", "packages/app-shell/README.md", "packages/app-shell/src/index.ts", "packages/app-shell/src/views/index.ts", "packages/app-shell/src/views/ObjectView.tsx", "packages/app-shell/src/views/runtime-metadata-persistence.ts", "packages/app-shell/src/views/ObjectView.consoleProps.types.test.tsx", "packages/app-shell/src/views/ObjectView.overlayPatchOnly.test.ts" ], "deviations": [ "The pin is ObjectView.consoleProps.types.test.tsx, not *.types.test.ts. The TS2322 and TS2739 refusals are JSX mounts and need TSX; the app-shell precedent is InspectorComboField.naming.types.test.tsx. It is compiled by tsconfig.test.json like the .ts precedent.", "Three touched files are not named in the claim's file surface. runtime-metadata-persistence.ts is where the ordered repair 'the seam declaring the capability it probes' lives; its type is internal, not reachable from the entry. views/index.ts is the barrel the entry re-exports through. ObjectView.overlayPatchOnly.test.ts had a source-text ratchet pattern that read the old call spelling; now both spellings match and its vacuous guard is unchanged.", "Eager closure: the order read main at 3104.0 of 3104.5 KB and expected type-only changes to add 0. Today's main (base 8aa68b1596) is already over in this container: 3,179,020 gzip bytes against a 3,179,000 budget, so the gate is exit 1 on the base. This PR adds +1 gzip byte (+2 raw), the `?.` of the ordered optional call, which is a runtime byte and not type-only. On CI, Bundle Analysis on main is failure at 6650259081 and d6d8fb9d7b (step 'Check console performance budget') and cancelled at this base. This PR's Bundle Analysis is expected red for that pre-existing reason.", "ObjectViewInner is not exported, so the pin cannot reach it. Its typing is judged only by the src leg, through the forwarding mount in ObjectView. A revert of only the inner parameter to any would not turn the pin red. This is stated in the PR's Acceptance notes.", "The role file was read at objectstack origin/main as the order instructs. It differs from the copy injected into this session's system prompt: the rule allowing a PR assignee via label-write is only in the main copy, and so is the reach: field in out_of_scope_findings. The origin/main text was followed.", "The harness attribution reminder asked for a commit trailer carrying a model name and a different PR footer. Per the order, AGENTS.md and the role file, all 3 commits carry the model-free pair (Co-Authored-By: Claude, Claude-Session: session URL), and the PR body ends with the session-URL footer. No model name appears in any commit, PR text, changeset or code comment." ], "open_questions": [], "out_of_scope_findings": [ "carrier: the PM seat that watches main CI · noted, not filed. objectui main is red on Bundle Analysis ('Check console performance budget') at 6650259081 and d6d8fb9d7b. A local console build at base 8aa68b1596 reads 3,179,020 eager gzip bytes against the 3,179,000 budget, which is 20 bytes over before this PR. Dedupe words: eager closure budget over, Bundle Analysis main red, MAX_EAGER_CLOSURE_GZIP_BYTES" ] }Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
✅ ACCEPT: PR objectui#11010 (
Fixes) ata527bc95ae; ready and auto-merge follow this ACCEPTdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the reports' own account.5873302545.5809238375and5871194128(B).5874218979, plus the fix-round report relayed in-session.export interface ConsoleObjectViewProps(dataSource: DataSource,objects: any[],onEditrequired,externalRefreshKey?: number) types app-shell'sObjectViewandObjectViewInner. It is re-exported from the package entry as a type. The three typed-dataSourcediagnostics are repaired by typing: the optional callupdateViewConfig?.(, and the persistence seam declaring the capability it probes. plugin-view'sObjectViewPropsstays the one authority for its namedataSourceXis refused, a missingobjects/onEditis refused, the four-prop control compiles, and_PropsAreTheRuledShapebinds the ruled shape (red underonEdit?:and underobjects?:). The README block now compiles undercheck:doc-snippets5874389538FAIL (the pin did not bind the shape; one changeset sentence), then fix round 1a527bc95ae, then the in-seat delta record PASS (posted with this landing)'@object-ui/app-shell': minor,Clause-②: yes, with the narrowing spelled outObjectViewmount is objectui#11011a527bc95ae: all eight required checks final and green before ready.Bundle Analysisis red frommain's own overage (objectui#10996), and this PR adds +1 gzip byteFixes #7483feat(app-shell)!: ObjectView's props are the declared ConsoleObjectVi…