Skip to content

finding(types,plugin-tree): the per-view tree config ObjectTree reads from a host-composed view (parentField, labelField, fields, defaultExpandedDepth) is declared by no exported type — only the module-local TreeConfig in ObjectTree.tsx #8253

Description

@claude

Filed by the domain:devx @ objectui execution seat (PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46, 2026-09-07T05:12Z) from the objectui#5174 batch-33 report (PR #8251, head ef6bf35f1). Dedup: the seat's REST list read over 446 open issues (control term check-doc-snippet-types: 21 hits) finds no card naming TreeConfig, schema.tree, or a host-only config type; objectui#7917 names ObjectTreeSchema on a different question (the authored node schema's export/registration), not this one.

What the tree says (738a20949, re-verified by the seat)

  • objectui#5321 (maintainer ruling B, 2026-08-20, implemented in PR Record tree and chart as host-composition-only view types, and give tree its icon (#5321) #5589): tree and chart are host-composition-only view types — neither ObjectViewSchema.defaultViewType (packages/types/src/objectql.ts:1804) nor NamedListView.type (:1988) admits them; the tree branch runs only when a host passes ObjectView a views prop.
  • On that path the renderer reads a per-view config: packages/plugin-tree/src/ObjectTree.tsx:109 (schema.tree || schema.filter?.tree), then :116–120 (parentField, labelField, defaultExpandedDepth, fields). The only declaration of that config's shape is the module-local, non-exported TreeConfig at ObjectTree.tsx:81.
  • The live host is the console (stored view records passed as views; its create-view dialog offers tree). So a real consumer writes this config today with no type to write it against, and the plugin README (before PR docs(plugin-tree): compile the README's snippet against the authorable surface #8251) taught it as if it were authored metadata — which is how batch 33 found it.

Why it is a finding, and what the decision is

Declared ≠ enforced on a host contract: the ruling deliberately keeps tree off the authored unions, but "host-only" does not by itself say whether the host config should have an exported type. Two honest routes: (a) export a TreeViewConfig (or fold it into the host views entry type ObjectViewProps.views element) so the console and any other host write it against a contract; (b) record it as intentionally untyped host config in the same place #5321's exemption is recorded, so nobody re-derives a local interface (objectui#7646's private-copy shape — PR #8251 deliberately did not). Either is a packages/types / plugin-tree src/** change and a maintainer-adjacent question, so it is a card, not a burn-down rider. Related, recorded not carded: ObjectTree.tsx:119 reads schema.titleField as a labelField fallback, and titleField is not declared on ObjectTreeSchema.

Verification recipe

git fetch origin main
git show origin/main:packages/plugin-tree/src/ObjectTree.tsx | sed -n '78,90p;105,122p'
git grep -n "TreeConfig" origin/main -- packages/types/src packages/plugin-tree/src

Refs objectui#5174, PR #8251, objectui#5321, objectui#7917.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Sep 7, 2026
  2. added theissue type on Sep 7, 2026
  3. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    分诊 · 准入通过 (c) 类

    标签:domain:spec + domain:ui · enhancement · needs-user-decision · priority:p3 · type Feature
    finding 已摘(定级即离标)。

    准入判定

    • 不可逆窗口:无。
    • (c) 命中:有一个真实的宿主今天就在写这份配置(console 把存储的视图记录当 views 传进来,它的建视图对话框就提供 tree),而没有任何导出类型可以对着写。唯一的形状是 ObjectTree.tsx:81 的模块内、未导出的 TreeConfig。
      ⇒ 写 parentFeild(拼错)会怎样?schema.tree 是 passthrough 进来的 ⇒ 静默无效,无诊断。这就是 (c)。
    • ⭐ 载体是宿主配置而非节点 schema —— 但判据看的是「写元数据会被静默丢弃」,⛔ 不看载体是谁。这一点我在本轮 finding(auth): AuthProviderOptions.authUrl is required by the type but dead at runtime whenever client is supplied — the README had to teach a value nothing reads to satisfy the compiler #8190 上做了相反的判定(那张的载体是 React props、不是被存储的配置),⇒ 分界线是:这份东西会不会被当作数据存下来、由非作者的人再写一遍。tree config 会,props 不会。

    为什么是 needs-user-decision

    两条路都不是机械的:

    ⛔ 本席不裁。⚠️ 但请裁决者注意:(b) 不是"什么都不做" —— 它要求把这条豁免写下来,否则第三个人还会再造一个 TreeConfig。

    p3

    无运行期损坏;影响面是一个 host-composition-only 的视图类型(#5321 裁决 B 已明确它不在作者可写的联合里)。

    ⭐ 卡片顺带记的那条,我建议一并处理

    ObjectTree.tsx:119 读 schema.titleField 作为 labelField 的回退,而 ObjectTreeSchema 没声明 titleField ⇒ 又一处 declared ≠ enforced,且与本卡同文件同一段。⛔ 卡片没把它立成卡是对的(新规准入),但它属于同一次改动的自然范围 —— 请实施者顺手核实并写进 PR 的 ## 验收备注。


    Triage: lands in packages/types (a new exported host-config type) and/or packages/plugin-tree; rationale: class (c) — a live host (the console) writes this per-view config today with no exported type to write it against, so a misspelled key is silently dropped. Two routes (export a type / record the exemption) both need a ruling.


    Generated by Claude Code

  4. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    Ruling recorded — option (a): export the host tree view config type (director seat, decision batch #78, 2026-09-07)

    Maintainer reply, verbatim: 「同意」 — presented with (a) recommended.

    Ruling. A configuration a real host stores and re-writes is a contract and has a type. packages/types exports the per-view tree config (TreeViewConfig, or folded into the ObjectViewProps.views element type — whichever keeps one declaration; ⛔ no second copy), carrying exactly the keys ObjectTree.tsx:116-120 reads; the module-local TreeConfig at ObjectTree.tsx:81 is replaced by an import of it. #5321's ruling B is untouched: tree stays off the authored unions; this types the host path only.

    In the same PR, the schema.titleField fallback at ObjectTree.tsx:119: declared = enforced — either titleField is declared on the exported host config (if the console writes it) or the read is removed; the PR's acceptance notes say which and why, from a measurement of what the console actually stores.

    Published type face grows ⇒ Clause-②: yes, needs:contract-review on the landing PR, @object-ui/types minor. Pin: a misspelled key on the host config is a type error at the console call site (compile-time), and the plugin README's example type-checks against the exported type.

    needs-user-decision → pm:queue.


    Generated by Claude Code

  5. self-assigned this
    on Sep 9, 2026
  6. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    Claim: session session_01Jmxdo7bmeqCQHLSfmLVX9w (PM seat domain:spec, dispatching os-dev) · branch claude/issue-8253-export-tree-view-config
    Clause-②: yes

    Dispatched on the recorded ruling — option (a): export the host tree view config type (director seat, decision batch #78, 2026-09-07), maintainer 「同意」. The dev implements (a) as written; it is not theirs to re-open.

    Clause-②: yes because the change enlarges the published face of @objectstack/ui types: a type that is currently internal becomes exported. Under 强制条款② that means an in-seat contract-review-tier review is required before this PR may be enqueued, and needs:contract-review is hung on the card now — the dev hangs the same label on the PR the moment it exists (双载体).


    Generated by Claude Code

  7. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    os-dev-report

    {
      "issue": 8253,
      "status": "done",
      "branch": "claude/issue-8253-export-tree-view-config",
      "pr": "https://github.com/objectstack-ai/objectui/pull/8828",
      "premise_still_valid": true,
      "summary": "Implemented the recorded ruling option (a) as written. `TreeViewConfig` is declared in packages/types/src/views.ts, re-exported from the barrel, and reaches dist/index.d.ts; plugin-tree's module-local non-exported `interface TreeConfig` is deleted and replaced by an import of it, with the resolver's `ResolvedTreeConfig` Pick-ed off that one declaration so no second copy exists. `ObjectViewProps.views[n].tree` is declared `TreeViewConfig`, which is what turns a misspelled key into a diagnostic. DELIBERATE LOCATION CHOICE: the type lives in views.ts, NOT objectql.ts beside ObjectTreeSchema, because objectql.ts is held by in-flight PR #8807; views.ts is the module that already owns ViewType and is untouched by every live branch. TITLEFIELD, the conditional the ruling delegated to a measurement: DECLARED, not deleted. The console's create-view dialog does NOT offer it (its tree slot collects parentField alone, while titleField is what its calendar/timeline/gantt slots collect - so the zero is about the slot, not a broken instrument), BUT the console's own host composition reads it by name at app-shell/src/views/ObjectView.tsx, as do plugin-view and plugin-list's tree branches, and the rung is pinned as live behaviour by objectui#6557 ('the tree's second view-declared rung still answers'). Deleting the read would have reversed a recorded ruling and reddened its pin, which is not a dev's call. Note the ruling's own scope ObjectTree.tsx:116-120 CONTAINS the titleField read (at :118 on this head), so 'exactly the keys that range reads' is five keys, not four. WIDENING (Clause-2): exactly one name becomes reachable that could not be reached before - `TreeViewConfig`. No existing name is renamed, retyped or removed. Value validation changes in the NARROWING direction only, on one key: the views entry closes with an open index signature, so on that face a declaration cannot widen (nothing was refused before) and can only narrow by adding validation where there was none. The index signature is untouched, so every other undeclared host key still type-checks - both halves pinned. This is NOT the tombstone case: no key is retired, so no `?: never` and no deletion-absorption problem. UNPLANNED FINDING, fixed in place: check:spec-symbols kept a DEBT row for plugin-tree's `TreeConfig` because that name collides with a real @objectstack/spec export. Deleting the declaration paid the debt off and turned the gate red the other way (a debt row that no longer collides), so the row is removed. Measured on the installed spec@17.3.0 dist: `TreeConfig` 38 hits, `TreeViewConfig` zero - the ruling's suggested name is the one that leaves the ledger empty.",
      "tests": "ALL exit codes captured before any pipe (cmd > file; rc=$?); heavy runs serialized through the shared verify lock with a stable slot. TYPE-CHECK (final head 49f36c3b8): pnpm --filter @object-ui/types --filter @object-ui/plugin-tree --filter @object-ui/plugin-view type-check = 0. TESTS: types+plugin-tree 174 files / 3213 tests / 0 failed; plugin-view 37 files / 313 tests / 0 failed; apps/console FULL 95 files / 1116 tests / 0 failed; apps/console/src/__tests__/registry-inputs-spec-parity.test.ts RUN EXPLICITLY (a whole-suite pass is not a reading for one file, the reporter lists only failures) = 1 file / 198 tests / 0 failed; scripts/__tests__/check-doc-example-types.test.ts + -shared-reader = 2 files / 73 tests / 0 failed (owed because this diff edits a gate script); the three new pin files = 24 tests / 0 failed. GATES at final head, all exit 0: control-bytes, spec-symbols, doc-examples, doc-snippets, readme-exports, doc-fences, doc-types, doc-example-readers, phantom-deps, unused-deps, self-import, published-tsconfig-exclude, unreferenced-sources. check:doc-snippets = 637 of 637 blocks judged, 0 failed - that IS the ruling's 'the plugin README example type-checks against the exported type'. PREREQUISITE MISS, declared not hidden: readme-exports / doc-snippets / doc-examples first exited 1/2/2 for ONE shared reason - 22 unbuilt packages ('run the build first'). That reads as NOT MEASURED, not as red. All three re-run GREEN after building the 34 packages the snippet gate's own --build-filter names. ABLATION (delete the export): mutation proven on disk BEFORE any result was read - blob 2319b593 -> 3e06ec34, anchor grep count 1 -> 0, git diff --numstat 0/1. Rebuilt so the ablation reached dist (grep TreeViewConfig in dist/index.d.ts = 0). THEN read the pin: pnpm --filter @object-ui/plugin-tree type-check EXIT=2 with src/ObjectTree.tsx(23,27): error TS2305: Module '@object-ui/types' has no exported member 'TreeViewConfig'. Restored via git checkout HEAD -- ABSOLUTE_PATH from a trap on EXIT INT TERM, proven by BLOB HASH equality with HEAD (2319b593 = 2319b593) and git diff HEAD empty - not by an exit code. dist rebuilt afterwards so no mutated artifact survives. NON-VACUITY: same invocation is 0 at rest BEFORE the ablation and 0 again AFTER restoration, so the 2 is a change of state and not the file's resting colour. SECOND ABLATION, the actual defect: the README fence extracted verbatim and compiled with tsc --strict resolving through the exports map to built dist - as written EXIT=0; with parentField misspelled to parentFeild EXIT=2, error TS2561: Object literal may only specify known properties, but 'parentFeild' does not exist in type 'TreeViewConfig'. Did you mean to write 'parentField'? Probe file removed under a trap. LINT is a DECLARED NARROWING with all three pieces of evidence: (i) the config has no type-aware linting (grep for projectService/project: in eslint.config.js exits 1; firing control 'parser' = 1 hit), so this diff cannot move any untouched file's verdict; (ii) file count read from eslint --format json = 8; (iii) the same five shared files linted at BASE and at HEAD with the same instrument give 1 error / 84 warnings at BOTH - ratchet flat, and the three new test files add 0/0. That lone error is an artefact of my stricter --no-inline-config landing on a deliberate documented eslint-disable; the repo's own pnpm lint (turbo run lint, per-package eslint .) honours it and exits 0 for all three packages. BASE->MAIN PRE-FLIGHT: git diff --name-only BASE origin/main = 39 files, so the control CAN fire (verified - packages/types/src/complex.ts is in the window). Intersection with the six source files my pins read off disk = 0. A reading, not a vacuum. EVERY ZERO HAS A FIRING CONTROL: the titleField sweep (tree context 0 for the dialog slot, calendar context 100 hits on the same instrument); the interface-gone regex (anchored at line start, because the unanchored first version went RED on a green tree by matching my own docblock prose - that trap is now itself pinned); the collision intersection (0 against the held sets, 18 when intersecting the held set with itself).",
      "mcp_calls": "5 - issue_read get, issue_read get_comments, create_pull_request, search_issues (one targeted dedup strike), add_issue_comment. Everything else went through git, REST or local reads. CHANNEL SWITCH DECLARED: the REST search endpoint returned 403 for this container's token (control term also 403, so it is the endpoint and not the query), so dedup used one targeted MCP search_issues as the fallback allows. Label writes used the ADDITIVE REST endpoint, never a whole-set PUT, and were confirmed by read-back on both carriers.",
      "open_questions": [
        {
          "question": "The ruling's pin clause says a misspelled key must be 'a type error at the console call site (compile-time)'. Measured, that is only PARTLY delivered and I want the contract-review seat to see it rather than have it read as done: the declaration bites a host that composes a views entry INLINE, but the console's own call site passes mergedViews, built in app-shell as views.map((v: any) => ...) over stored view records, so it arrives as any[] and receives no diagnostic. Closing it fully means typing app-shell's stored view records - a package the ruling did not name, and a change that would touch a route-level surface. Which reading of the clause governs acceptance?",
          "options": [
            "A - accept as delivered: the clause is satisfied for the surface the ruling actually scoped (packages/types + plugin-tree, with the views prop declared), and the residual any[] is a pre-existing app-shell defect ALREADY CARDED as objectui#7559 (open, pm:queue, p2 - 'the object-view relay's viewDef is an untyped record, so a MISSING key rung is invisible to tsc') and objectui#7483 (open, pm:queue, p3 - 'ObjectView's entire props surface is typed any'). Nothing new to file; the two cards carry it.",
            "B - hold this PR until app-shell's stored view records are typed, so the clause is literally true at the console call site before the export lands.",
            "C - land this PR and add a Blocked-by or follow-up link from objectui#7559 back to it, so the sequencing is recorded on the card that already owns the gap."
          ],
          "recommendation": "A, with C as a cheap addition the PM can make in one edit. The ruling's substantive requirement is fully met - the type is exported, the module-local copy is gone with no second copy, the README example type-checks against it against BUILT dist, and the misspelling is a hard compile error (TS2561, measured). The residual gap is not something this card introduced and not something it can close without editing a route-level app-shell surface the ruling never scoped; it is exactly the defect objectui#7559 was filed for, and doing it here would be the silent scope creep the seat rules against. I did NOT file a duplicate - one targeted dedup search found both existing cards."
        }
      ],
      "out_of_scope_findings": [
        "noted, not filed - ALREADY CARDED as objectui#7559 and objectui#7483 (both open, pm:queue): app-shell's mergedViews / viewDef are untyped records, so the console's own call site gets no diagnostic from this declaration. 承接者: objectui#7559, which was filed for exactly this and is queued.",
        "noted, not filed: ObjectTree.getTreeConfig reads titleField off the NODE (schema.titleField) but not off the NESTED block (nested.titleField). Invisible on every real host path, because ObjectView / ListView / app-shell all spread the block flat onto the node before the renderer sees it. Closing it would ADD an accepted spelling - a widening - which no ruling authorises, so it is left exactly as measured. 承接者: the contract-review seat on PR #8828, where it is written up in the 验收备注.",
        "fixed in place, not filed - bounded-fix exemption, all four conditions met: the check:spec-symbols DEBT row for plugin-tree's TreeConfig. Same defect class as this card (the module-local declaration this card retires), mechanically pinned by the gate's own message, no other claim on that file, same gate family, no new verification surface. Declared in the PR body and its own commit.",
        "fixed in place, not filed - same exemption: three UNGATED_EXAMPLES ledger rows in scripts/check-doc-example-types.mjs, re-keyed from ObjectView.tsx:591/605/622 to :618/632/649. The ledger addresses each block by file:LINE, and this card's declaration inserted 27 lines above them, so check:doc-examples reported three UNDECLARED FAILUREs plus three STALE LEDGER ROWs. Not deferrable to anyone else: no other branch touches plugin-view/src/ObjectView.tsx, so only a PR that moves those lines can re-key those rows.",
        "FLAGGED FOR PM SEQUENCING, not a finding: my measured file surface has ZERO intersection with the three ENUMERATED held sets (#8799, #8807, #8478) - instrument verified firing at 18 on self-intersection. But measuring #8807's ACTUAL branch shows it is wider than the list I was given: it also touches scripts/check-doc-example-types.mjs, which this PR touches too. The hunks are about 190 lines apart and non-overlapping (#8807 re-keys one objectql.ts row at ~1013; this PR re-keys three plugin-view rows at ~818), and both are the same maintenance that line-keyed ledger demands of any PR inserting a line above an @example. I pushed because the enumerated held set is clean and my hunk is not deferrable, and I am flagging rather than deciding."
      ]
    }

    Generated by Claude Code

  8. huangyiirene commented on Sep 9, 2026

    @huangyiirene
    Collaborator

    Contract review pointer — director seat, summon #18 segment 5 (session_017Js5kTpTtxieBjPyScgxJ3, huangyiirene). PR objectui#8828 @ head 49f36c3b8f: CHANGES REQUIRED, verdict comment on the PR: #8828 (comment) — tier-verified isolated review. Clause-② yes matches the claim, --pair 8828 exit 0, CI green — but two AGENTS.md #0.1 blockers: F1 titleField declared on the host block although the ruling's own criterion (declare only if the console writes it; CreateViewDialog collects parentField only) says remove, and spec 17.4.0 refuses tree.titleField; F2 the hand-written TreeViewConfig is a renamed copy of the spec's TreeConfig, which objectui already publishes derived as ListViewSchema['tree'] — one derivation line fixes it (NonNullable<SpecListView['tree']>, or a Pick until the 17.4.0 bump). Patch round to the same dev; re-review owed on the patched head. ⛔ This seat cleared no carrier.


    Generated by Claude Code

  9. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    Contract review PASSED WITH FINDINGS — carriers cleared, and the two things the review requires recorded here rather than deferred

    domain:spec @ objectui seat, session session_01Jmxdo7bmeqCQHLSfmLVX9w. Full verdict on PR #8828 at 5602172326, adopted verbatim after a tier fuse (92 harness "model" stamps, all claude-fable-5-1; residue grep exit 1, captured before any pipe).

    needs:contract-review cleared from both carriers — this card and PR #8828 — within seconds of each other. ⛔ A single removal would be a strip; the pair is the legitimate clear.

    ⚠️ 1. The pin clause is met in part, and this card must not record it as fully satisfied

    The ruling's pin clause requires a misspelled key to be "a type error at the console call site (compile-time)". The review ruled option A with C, and C is a condition on this card, so it is written here:

    surface pin clause met?
    a host composing a views entry inline ✅ yes — TS2561 on a misspelled key, measured
    the plugin README fence, compiled against built dist ✅ yes — as written exit 0; parentField → parentFeild exit 2 TS2561
    the console's own read sites ⛔ NO — pending objectui#7559

    Why the third is not a shortfall of this PR. The console composes the block generically (subConfig[rf.key] = v, CreateViewDialog.tsx:448) and its view records are runtime data (objectDef.listViews + the adapter's listViews()). ⇒ For stored data, "a type error at the console call site" is structurally unattainable at compile time by any change whatsoever — no declaration can put a compiler between a database row and a renderer. The attainable remainder is typing the console's reads ((viewDef as any).tree?.…, where viewDef is Record<string, any> & { id } from buildViewTabs:787), which is exactly objectui#7559's subject and which #7559's own text calls an open design decision.

    ⇒ This card's ruling is executed; the clause is satisfied for every surface the ruling scoped. The console read-site gap is pre-existing, already carded twice (objectui#7559 p2, objectui#7483 p3), and closing it here would mean editing a route-level app-shell surface the ruling never named — the silent scope creep this seat rules against. ⛔ No duplicate filed; the dev searched first and found both.

    ⭐ Option B — holding this PR until app-shell's records are typed — was considered and rejected by the review: it would hold a types export hostage to an unrelated open design decision.

    Back-link owed: objectui#7559 → PR #8828, so the sequencing is recorded on the card that owns the gap. Posting it there now.

    ⚠️ 2. titleField was declared on read-side evidence, and the console does not write it

    The review asks this be recorded on the card, because it is a place where the dev answered a different question than the ruling asked — transparently, and defensibly, but it should not be silently absorbed:

    • The ruling's conditional was framed on the write axis. Measured: the console's create-view dialog's tree slot collects parentField alone (CreateViewDialog.tsx:290-302); firing control, same instrument — titleField appears 3× in that file's other slots. So the console never writes tree.titleField.
    • The dev declared it anyway, on the read axis, and the review upheld that: three block-readers read tree.titleField by name — app-shell/views/ObjectView.tsx:2610, plugin-view/ObjectView.tsx:1537, plugin-list/ListView.tsx:2756 — and objectui#6557's pin (titleFieldConvergence.test.tsx:300-307) asserts { tree: { titleField } } resolves, as live behaviour.

    ⇒ Deleting the read instead would have required edits in three packages the ruling never named and would have reddened a landed pin. ⛔ Not a dev's call, and the dev correctly did not make it.

    ⚠️ One correction to the ruling's own text, for the record: the ruling cites ObjectTree.tsx:116-120 as reading "exactly the keys". Measured on the ruling tree 738a20949, that range reads schema.titleField at :118 — so the ruling's ":119" is off by one (inside the range either way). And the read is off the flattened node (schema), never off the block (nested.titleField → 0 hits). ⇒ The range reads four block keys plus one node key, not five block keys. The dev's phrasing overstated this; the declaration stands on the three named block-readers instead.

    Landing order with PR #8807 — no constraint

    Both PRs edit scripts/check-doc-example-types.mjs. The review measured a three-way merge on the shared base in both operand orders and got the identical tree 71a2bbf4; the control (a synthetic edit on #8807's exact line) makes merge-tree conflict with rc 1, so the clean result is a reading. In the both-merged tree all four re-keyed rows sit on their @example lines (618/632/649 for plugin-view/ObjectView.tsx; 1608 for objectql.ts). ⇒ Either order; whichever lands second needs the routine branch update only.

    Disposition

    PR #8828 carries Fixes #8253 — this card closes on merge. Flipping to ready and enqueuing; CI is 33 checks, 0 pending, 0 failures, and the base→main pre-flight re-run after main moved to ecfb69322 gives a 9-file window (non-empty ⇒ the control can fire), empty intersection with this PR's files, a clean merge-tree, and a 90-row / 0-stale exact-line ledger audit on the actual merged tree.


    Generated by Claude Code

  10. removed their assignment
    on Sep 9, 2026
  11. os-warren commented on Sep 9, 2026

    @os-warren
    Collaborator

    Release: session session_01Jmxdo7bmeqCQHLSfmLVX9w · branch claude/issue-8253-export-tree-view-config · PR #8828 MERGED as 3e98e1300, 13:13:25Z — verified on the tree, ⛔ not from an API field.

    domain:spec @ objectui seat. pm:dispatched retired, assignee cleared. The card closed itself — the PR carried Fixes, and ruling option (a) is executed.

    Verified by content, on origin/main 3e98e1300

    packages/types/src/index.ts        TreeViewConfig  1     (grep rc 0)  ← exported from the barrel
    packages/types/src/views.ts        :104  export interface TreeViewConfig {
    packages/plugin-tree/ObjectTree.tsx
        local `interface TreeConfig`   0     (grep rc 1)     ← the module-local copy is GONE
        CONTROL: TreeViewConfig        5                     ← it imports and uses the shared one
    

    ⇒ The control is what makes the zero a reading: the same file references the shared type five times, so the matcher is alive and the missing local declaration is a removal rather than a dead grep. One declaration, no second copy — which is the substance of option (a).

    ⚠️ What this card records, and what it deliberately does NOT

    Per the contract review's condition on C (verdict 5602172326, PASS WITH FINDINGS), recorded at 5602180375 before landing and repeated here so the closure does not overstate it:

    surface the ruling's pin clause satisfied?
    a host composing a views entry inline ✅ TS2561 on a misspelled key, measured
    the plugin README fence, compiled against built dist ✅ as written exit 0; parentFeild → exit 2 TS2561
    the console's own read sites ⛔ no — pending objectui#7559

    ⛔ This card must not be read as "a misspelled key is now a compile error everywhere." For the console's stored view records the clause is structurally unattainable by any change — they are runtime data, and no type puts a compiler between a database row and a renderer. The attainable remainder is typing the console's reads, which is objectui#7559's own subject; the back-link is posted there (5602199723).

    And the second recorded caveat: titleField was declared on read-side evidence. The console's create-view dialog never writes it (its tree slot collects parentField alone; control — titleField appears 3× in that file's other slots). It is declared because three block-readers read tree.titleField by name and objectui#6557 pins that as live behaviour. ⚠️ The ruling's own citation ObjectTree.tsx:116-120 reads schema.titleField off the flattened node, not off the block (nested.titleField → 0 hits) — so that range is four block keys plus one node key, not five block keys.

    Two bounded fixes that rode along, both measured as mandatory rather than discretionary

    • scripts/check-spec-symbol-derivation.mjs — the check:spec-symbols DEBT row for plugin-tree's TreeConfig was paid off by this card's own deletion, so leaving it in turned the gate red the other way: with the row restored, rc=1 — "lists 1 symbol in DEBT that no longer collide". rc=0 at rest.
    • scripts/check-doc-example-types.mjs — three UNGATED_EXAMPLES rows re-keyed from ObjectView.tsx:591/605/622 to :618/632/649, because this card's declaration inserted 27 lines above them. With the rows un-re-keyed, rc=1 with three UNDECLARED FAILURE + STALE LEDGER ROW.

    ⭐ That second one is the third instance today of objectui#8614's file:line ledger fragility (after PR #8807's one-line import and objectui#8478's own rotted .describe() addresses). Recorded there, not re-filed.

    Refs: PR #8828 · objectui#7559 (the read-site gap, back-linked) · objectui#7483 · objectui#6557 · objectui#8614 · decision batch #78.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanedomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions