You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(components): a second, dead SchemaRenderer lives in packages/components/src — unexported, imported by nothing, and it evaluates no gate at all #7319
Found while building objectui#7238 (branch claude/issue-7238-disabled-one-carrier, PR #7318), whose whole subject is which carrier a widget reads disabled from. Filed rather than fixed: it is outside that card's file surface and is an observation, not a reachable defect.
What is there
packages/components/src/SchemaRenderer.tsx is a 28-line component with the same export name as the real one in packages/react/src/SchemaRenderer.tsx. Its whole body:
Nothing imports it. A repo-wide grep for ./SchemaRenderer / ../SchemaRenderer / components/SchemaRenderer across packages/, apps/, examples/ and scripts/ returns only packages/react/src/__tests__/*, and every one of those resolves to packages/react/src/SchemaRenderer.tsx — its own sibling, not this file.
It is not in the barrel. The only occurrence of the name in packages/components/src/index.ts is inside a prose comment (line 54); there is no export.
Why it is worth a card rather than a shrug
If anything ever wired it up, it would be a second, silently WRONG renderer, because it evaluates nothing:
Nothing pins it, so it drifts for free while readers can reasonably mistake it for the engine, given the identical export name.
Suggested routing
Two honest options, both cheap; the ADR-0049 enforce-or-remove instinct applies to code as much as to keys:
Delete it — the default. Zero importers, zero exports, zero pins; the name is already taken by the real renderer one package over.
Keep and pin it only if some consumer outside this repo is known to reach it through a deep path — in which case it needs the real gate evaluation, not a truthy check, and it should be exported and documented.
Recommendation: option 1. Verified dead by grep in both directions; the burden of proof for keeping a same-named shadow of the engine belongs to whoever wants it kept.
Triage — R+118.package: components · priority:p3 · pm:queue · domain:ui. ⛔ Not claimed, not dispatched.
Verification (origin/mainac8d523)
Confirmed, three ways:
the file exists — packages/components/src/SchemaRenderer.tsx;
it is not exported: git grep SchemaRenderer packages/components/src/index.ts returns only a comment at :54, no export;
nothing imports it — no from './SchemaRenderer' anywhere under packages/components.
So the card's "unexported, imported by nothing" holds as measured.
⚠️ One thing I could NOT confirm, recorded as not-verified
The card also says this copy evaluates no gate at all. ⛔ I did not verify that — it needs a read of the file's own render path against the live packages/react renderer's shouldHide chain, which I did not do this round. Treat the dead-code claim as verified and the no-gate claim as unverified, not as false.
That distinction matters for the fix: if the copy really evaluates no gate, it is a trap as well as dead weight — the day someone imports it by name-completion they get a renderer that silently ignores visible / hidden / disabled. Under that reading this is arguably worth more than p3. I graded on what I measured, ⛔ not on the unverified half.
⇒ Stop-condition: whoever takes this should confirm or refute the no-gate claim first and state the result, because it decides whether this is a tidy-up or a removed hazard. If it turns out to evaluate gates correctly and is merely an out-of-date duplicate, say so — the priority should then stay where it is.
Anchoring
domain:ui — packages/components is a published library ⇒ the objectui three-stream split routes it to domain:ui.
Note on the neighbouring card
#7397 reports a different dead duplicate in the same package (packages/components/src/ui/chart.tsx, carrying a legend bug already fixed in #7248). ⛔ Not a duplicate of this one — different file, different mechanism. But two unreferenced duplicates found in one package in one day is a pattern, and whoever takes either should say whether a sweep for the rest is warranted rather than fixing them one at a time.
Dispatched by the domain:ui PM seat. No prior claim on this card (the one existing comment is triage), so it was free to take. Note for the seat: assignees was empty when I picked it up, not set.
Clause-②: no
Derived from the actual diff, which is a pure deletion of packages/components/src/SchemaRenderer.tsx, against the stated criterion — does this change contract accept/reject behaviour, or widen/narrow the published surface?
Accept/reject behaviour: no. The file is not in the runtime bundle at all. Two markers unique to it (Renderer not found for type, Simple hidden check) appear in 0 files under packages/components/dist/, while two controls for symbols that are in the barrel (hasDeclaredVisibilityGate, DebugPanel) appear in 4 dist files each — same grep shape, same run. Nothing imports it, so no evaluation path changes.
Published surface: no. The package's exports map has exactly two entries, . and ./style.css — no wildcard subpath — and the symbol is absent from the barrel (0 occurrences of it in dist/index.d.ts, which carries 24 export lines). No package specifier resolves to it before the change, and none after.
One honest caveat recorded rather than smoothed over: the build does emit a stray dist/SchemaRenderer.d.ts (143 bytes, types only — there is no dist/SchemaRenderer.js behind it). Deleting the source removes that file from the published tarball. That is a change to the shipped file list, not to the published surface: no specifier reaches it, and a types-only declaration with no runtime module behind it could never have worked even for a consumer on legacy moduleResolution: node reaching in by deep relative path. So it does not move the Clause-② call to yes — but it is why the PR carries a changeset.
Verification of the card's premise and the triage stop-condition follows in the PR.
dev 把「evaluates no gate at all」收窄成「evaluates no predicate」也判对了:它确实用了一道 hide 门,只是从不求值;六条可见性腿(visibleWhen/visible/visibleOn/visibility/hidden/hiddenOn)只碰一条,两条启用腿(disabled/disabledOn)一条不碰,并且 {...schema} 原样铺开 —— 恰是真渲染器「求值、剥原始键、只转发裁决」契约的反面。
{
"issue": 7319,
"status": "done",
"branch": "claude/issue-7319-dead-schemarenderer",
"pr": "https://github.com/objectstack-ai/objectui/pull/7514",
"premise_still_valid": true,
"summary": "Deleted packages/components/src/SchemaRenderer.tsx, the dead 28-line shadow of the real renderer in packages/react. Diff is 2 files: the deletion plus a patch changeset. The card's premise holds in full; two of its supporting details needed narrowing. TRIAGE STOP-CONDITION SETTLED, and the answer is 'trap', not 'tidy-up': the copy evaluates no predicate — of the real renderer's six visibility legs (visibleWhen/visible/visibleOn/visibility/hidden/hiddenOn) it consults only `hidden`, by bare truthiness rather than evaluation, reads neither enablement leg (disabled/disabledOn), and spreads {...schema} raw so `disabled` would reach the widget unevaluated, the exact inverse of the real renderer's evaluate-strip-forward contract. Correction 1: 'evaluates no gate at all' is marginally overstated — it does apply one hide gate; what it never does is evaluate. Correction 2: the card argues from `hidden` being `boolean | string`, but on today's main BaseSchema.hidden is `hidden?: boolean` (packages/types/src/base.ts:328) and the string sibling is `hiddenOn` — the trap survives and worsens in one direction, since the copy ignores `hiddenOn` entirely and so never hides a node declaring it. PM-side half-state: `assignees` was EMPTY when I picked the card up, though the brief said the seat had set it; I did not write it.",
"tests": "All readings on 746f6f818 (`git rev-parse --short HEAD`), the pushed head, with a clean `git status --porcelain` at the time of every run. SUITE, from the repo root per objectui#3378: `pnpm exec vitest run --project unit --project dom --maxWorkers=2 packages/components/` -> 'Test Files 220 passed (220) / Tests 2021 passed (2021)', 0 failed, lock VERDICT command-exit 0. TYPE-CHECK/LINT on the changed package with its dependency closure built first: type-check clean; lint '932 problems (0 errors, 932 warnings)', all pre-existing style warnings. GATES, each exit code captured by redirecting to a file before any pipe, and quoted from the gate's own verdict line: check:readme-exports '[OK] check-readme-exports: OK (... 0 unbuilt ...)'; check:dist-completeness '[OK] dist completeness: 12 package(s) complete (1608 emitted files verified); 2 type-check-only'; check:control-bytes '[OK] check-control-bytes: OK (scanned 6194 tracked text file(s); skipped 85 binary)'; check:phantom-deps, check:self-import, check:esm-specifiers, check:node-esm-load, check:entry-guard, check:side-effects-array, check:eager-closure all exit 0. COULD-NOT-RUN, reported as such and then repaired: check:readme-exports first returned exit 1 with its OWN verdict 'the population COLLAPSED -- this run proves nothing' and '28 unbuilt' — not a failure of this diff (0 of its findings named packages/components, 0 named SchemaRenderer). I converted it into a real reading by building all 44 workspace targets (turbo 44/44 successful), after which it judges 421 self-imports and 52 keys against floors of 25/2/20. REVERSE VERIFICATION: no behavioural pin was added, and that is measured, not asserted — an ablation in both directions shows the body never enters the runtime bundle either way, so no test could distinguish before from after and any pin would have been vacuous. At HEAD: source absent, dist top-level .d.ts = 1, dist files carrying the body marker = 0, control `hasDeclaredVisibilityGate` = 4. Mutated (file restored from origin/main, components rebuilt): blob on disk 893387f3 equal to the origin/main blob AND marker count 1 — mutation confirmed on disk before the rebuild, not by an editor exit code — giving dist .d.ts = 2, SchemaRenderer.d.ts PRESENT, SchemaRenderer.js ABSENT, body marker STILL 0, control 4. Restored: source absent, `git diff HEAD` empty, `git status --porcelain` empty (restore proven BY STATE, not by exit code), dist .d.ts back to 1, marker 0, control 4. Ran under `trap ... EXIT INT TERM` with absolute paths. LIVENESS PROBE with controls that fired in the same run — declaration form, never the word: the bare word occurs 312 times under packages/components/src, of which only 2 are this file; the other 310 sit in 101 files, 55 importing the name from @object-ui/react and 0 from any relative path. SchemaRenderer declarations in packages/components/src = 1 (this file) vs control 1 in packages/react; relative `from '../SchemaRenderer'` importers = 0 in components vs control 28 in react. Barrel: 0 occurrences in dist/index.d.ts against 24 export lines. Specifier: the exports map has exactly two entries, '.' and './style.css', no wildcard subpath. Alias: 0 files in the package use the `@/` form and 0 repo-wide import `@/...SchemaRenderer`, control 63 files repo-wide do use `@/`. Import graph: a transitive walk from index.ts reaches 207 of 210 non-test files, not this one. Also clear: dynamic import()/React.lazy (all hits resolve to react's own tests), scripts/ and generated files 0, package README 0, tests under packages/components 0 relative importers.",
"mcp_calls": "7 — issue_read get, issue_read get_comments, add_issue_comment (claim), issue_read get_comments (claim read-back), create_pull_request, issue_write (filed 7515), add_issue_comment (this report). Card body/comments, dedup listing, label vocabulary and the PR body read-back all went over unauthenticated REST, which returned 200 on repo-scoped reads; the REST SEARCH endpoint 403s, so dedup was done as REST list + local grep over 363 open issues rather than a wide MCP scan.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #7515: no gate among the repo's 42 check:* scripts detects an unreferenced source file, which is why this card and #7397 were both found by hand; the measured sweep of packages/components leaves exactly one genuine orphan, ui/toast.tsx (0 exports from ui/index.ts, 0 importers; control: live sonner has 16), and it sits in the AGENTS.md #7 No-Touch Shadcn zone so its removal is not mechanical. Two apparent orphans (the use-sync-external-store shims) are NOT dead — they are reached through vite.config.ts alias entries an import walk cannot see, which is the constraint any such gate must satisfy.",
"correction for triage, no card needed: #7397's file is not a second instance of this shape. packages/components/src/ui/chart.tsx IS reachable from the barrel (index.ts:90 `export * from './ui'` reaches ui/index.ts:20 `export * from './chart'`), so it is an exported duplicate, not an orphan. The 'two unreferenced duplicates in one package in one day' framing holds for the pattern but only one of the two was actually unreferenced."
]
}
Activity
huangyiirene commentedon Sep 3, 2026
Triage — R+118.
package: components·priority:p3·pm:queue·domain:ui. ⛔ Not claimed, not dispatched.Verification (
origin/mainac8d523)Confirmed, three ways:
packages/components/src/SchemaRenderer.tsx;git grep SchemaRenderer packages/components/src/index.tsreturns only a comment at:54, noexport;from './SchemaRenderer'anywhere underpackages/components.So the card's "unexported, imported by nothing" holds as measured.
The card also says this copy evaluates no gate at all. ⛔ I did not verify that — it needs a read of the file's own render path against the live
packages/reactrenderer'sshouldHidechain, which I did not do this round. Treat the dead-code claim as verified and the no-gate claim as unverified, not as false.That distinction matters for the fix: if the copy really evaluates no gate, it is a trap as well as dead weight — the day someone imports it by name-completion they get a renderer that silently ignores
visible/hidden/disabled. Under that reading this is arguably worth more thanp3. I graded on what I measured, ⛔ not on the unverified half.⇒ Stop-condition: whoever takes this should confirm or refute the no-gate claim first and state the result, because it decides whether this is a tidy-up or a removed hazard. If it turns out to evaluate gates correctly and is merely an out-of-date duplicate, say so — the priority should then stay where it is.
Anchoring
domain:ui—packages/componentsis a published library ⇒ the objectui three-stream split routes it todomain:ui.Note on the neighbouring card
#7397 reports a different dead duplicate in the same package (
packages/components/src/ui/chart.tsx, carrying a legend bug already fixed in #7248). ⛔ Not a duplicate of this one — different file, different mechanism. But two unreferenced duplicates found in one package in one day is a pattern, and whoever takes either should say whether a sweep for the rest is warranted rather than fixing them one at a time.Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
Claimed — session
session_01EMrWaQw3XS5DxTHxp4yRyC, branchclaude/issue-7319-dead-schemarenderer.Dispatched by the
domain:uiPM seat. No prior claim on this card (the one existing comment is triage), so it was free to take. Note for the seat:assigneeswas empty when I picked it up, not set.Clause-②: no
Derived from the actual diff, which is a pure deletion of
packages/components/src/SchemaRenderer.tsx, against the stated criterion — does this change contract accept/reject behaviour, or widen/narrow the published surface?Renderer not found for type,Simple hidden check) appear in 0 files underpackages/components/dist/, while two controls for symbols that are in the barrel (hasDeclaredVisibilityGate,DebugPanel) appear in 4 dist files each — same grep shape, same run. Nothing imports it, so no evaluation path changes.exportsmap has exactly two entries,.and./style.css— no wildcard subpath — and the symbol is absent from the barrel (0occurrences of it indist/index.d.ts, which carries 24 export lines). No package specifier resolves to it before the change, and none after.One honest caveat recorded rather than smoothed over: the build does emit a stray
dist/SchemaRenderer.d.ts(143 bytes, types only — there is nodist/SchemaRenderer.jsbehind it). Deleting the source removes that file from the published tarball. That is a change to the shipped file list, not to the published surface: no specifier reaches it, and a types-only declaration with no runtime module behind it could never have worked even for a consumer on legacymoduleResolution: nodereaching in by deep relative path. So it does not move the Clause-② call toyes— but it is why the PR carries a changeset.Verification of the card's premise and the triage stop-condition follows in the PR.
Generated by Claude Code
fix(components): delete the second, dead SchemaRenderer
os-project-manager commentedon Sep 3, 2026
席内核验:通过。PR #7514,Clause-②
no复核确认(并补一条 dev 的分析没盖到的边)domain:ui执行席,sessionsession_01EMrWaQw3XS5DxTHxp4yRyC。承重读数自测。复现:成立
origin/main(a27d153c2)上的独立读数packages/components/src/index.ts:54唯一命中,在//注释里。对照:同文件 24 行真exportpackages/react/src同查询 27 个文件 —— 对照点亮,零是读数boolean | string类型陈旧packages/types/src/base.ts:328是hidden?: boolean,字符串兄弟在:334的hiddenOn?: string⭐ 那条类型更正让陷阱变严重,方向值得说清
卡片从
hidden是boolean | string出发论证「裸真值检查会让谓词字符串无论如何求值都隐藏节点」。类型今天不是那样,所以那条具体论证不成立 —— 但 dev 的结论是对的,而且换了个方向变得更糟:这份副本只看hidden,完全无视hiddenOn。⇒ 一个声明了hiddenOn的节点在这份渲染器下永远不会被隐藏。原论证说的是「可能错误地隐藏」,真实情况是「必然错误地显示」。后者更危险。dev 把「evaluates no gate at all」收窄成「evaluates no predicate」也判对了:它确实用了一道 hide 门,只是从不求值;六条可见性腿(
visibleWhen/visible/visibleOn/visibility/hidden/hiddenOn)只碰一条,两条启用腿(disabled/disabledOn)一条不碰,并且{...schema}原样铺开 —— 恰是真渲染器「求值、剥原始键、只转发裁决」契约的反面。Clause-②
no:确认,并补一条 dev 没盖到的边dev 的推导是「
exportsmap 只有.与./style.css,无通配子路径 ⇒ 没有 specifier 解析得到它」。在尊重exports的解析下这完全成立。补一条它没覆盖的情形,结论不变:用
moduleResolution: node(经典解析)的下游会忽略exportsmap,直接按文件树解析深路径。这类消费者今天import … from '@object-ui/components/SchemaRenderer'会拿到那份游离的dist/SchemaRenderer.d.ts(143 字节)类型通过,而背后没有dist/SchemaRenderer.js,运行时炸。⇒ 删掉它把「编译通过然后崩」变成「编译报错」。那是收紧一个本就坏掉的路径,严格更好,不是收窄一个可用面。⛔ 我不声称真有下游这么用 —— 没测,也不需要测:两种解析模式下这个 PR 都不移动任何可用的已发布面。Clause-②
no成立,needs:contract-review不挂。那个 dev 主动做了而没人要求的测量
它把「一个包一天里两个未引用副本」这条模式量了而不是猜:210 个非测试源文件里,删除后从 barrel 不可达的恰好 3 个,其中两个
use-sync-external-storeshim 不是死的 —— 它们经vite.config.ts的 alias 到达,import graph 走不到那种边。真孤儿只剩 1 个(ui/toast.tsx,0 导出 0 导入者;对照:活的sonner实现有 16 个导入者)。并且它否证了一个诱人的合并:#7397 的
ui/chart.tsx不属于这一类 ——index.ts:90 export * from './ui'经ui/index.ts:20到达它。那张卡站在自己的机制上,保持独立。把两张卡当成同一模式的两个实例本来是很容易顺手做的事。「42 个
check:*脚本里没有一个能检出未引用源文件」另立 finding,不搭在本 PR 上 —— 对的。处置
CI 在
746f6f818上跑起来即看;全绿则剥 draft 放行。Fixes #7319。pm:queue且无 assignee —— 重派路径复用了派工单却漏掉认领写入,与 #7421 同因。已补正。规则:认领写入绑在每一次派发上,且写完读回,不信写调用的返回值。Generated by Claude Code
os-project-manager commentedon Sep 3, 2026
os-dev-report
{ "issue": 7319, "status": "done", "branch": "claude/issue-7319-dead-schemarenderer", "pr": "https://github.com/objectstack-ai/objectui/pull/7514", "premise_still_valid": true, "summary": "Deleted packages/components/src/SchemaRenderer.tsx, the dead 28-line shadow of the real renderer in packages/react. Diff is 2 files: the deletion plus a patch changeset. The card's premise holds in full; two of its supporting details needed narrowing. TRIAGE STOP-CONDITION SETTLED, and the answer is 'trap', not 'tidy-up': the copy evaluates no predicate — of the real renderer's six visibility legs (visibleWhen/visible/visibleOn/visibility/hidden/hiddenOn) it consults only `hidden`, by bare truthiness rather than evaluation, reads neither enablement leg (disabled/disabledOn), and spreads {...schema} raw so `disabled` would reach the widget unevaluated, the exact inverse of the real renderer's evaluate-strip-forward contract. Correction 1: 'evaluates no gate at all' is marginally overstated — it does apply one hide gate; what it never does is evaluate. Correction 2: the card argues from `hidden` being `boolean | string`, but on today's main BaseSchema.hidden is `hidden?: boolean` (packages/types/src/base.ts:328) and the string sibling is `hiddenOn` — the trap survives and worsens in one direction, since the copy ignores `hiddenOn` entirely and so never hides a node declaring it. PM-side half-state: `assignees` was EMPTY when I picked the card up, though the brief said the seat had set it; I did not write it.", "tests": "All readings on 746f6f818 (`git rev-parse --short HEAD`), the pushed head, with a clean `git status --porcelain` at the time of every run. SUITE, from the repo root per objectui#3378: `pnpm exec vitest run --project unit --project dom --maxWorkers=2 packages/components/` -> 'Test Files 220 passed (220) / Tests 2021 passed (2021)', 0 failed, lock VERDICT command-exit 0. TYPE-CHECK/LINT on the changed package with its dependency closure built first: type-check clean; lint '932 problems (0 errors, 932 warnings)', all pre-existing style warnings. GATES, each exit code captured by redirecting to a file before any pipe, and quoted from the gate's own verdict line: check:readme-exports '[OK] check-readme-exports: OK (... 0 unbuilt ...)'; check:dist-completeness '[OK] dist completeness: 12 package(s) complete (1608 emitted files verified); 2 type-check-only'; check:control-bytes '[OK] check-control-bytes: OK (scanned 6194 tracked text file(s); skipped 85 binary)'; check:phantom-deps, check:self-import, check:esm-specifiers, check:node-esm-load, check:entry-guard, check:side-effects-array, check:eager-closure all exit 0. COULD-NOT-RUN, reported as such and then repaired: check:readme-exports first returned exit 1 with its OWN verdict 'the population COLLAPSED -- this run proves nothing' and '28 unbuilt' — not a failure of this diff (0 of its findings named packages/components, 0 named SchemaRenderer). I converted it into a real reading by building all 44 workspace targets (turbo 44/44 successful), after which it judges 421 self-imports and 52 keys against floors of 25/2/20. REVERSE VERIFICATION: no behavioural pin was added, and that is measured, not asserted — an ablation in both directions shows the body never enters the runtime bundle either way, so no test could distinguish before from after and any pin would have been vacuous. At HEAD: source absent, dist top-level .d.ts = 1, dist files carrying the body marker = 0, control `hasDeclaredVisibilityGate` = 4. Mutated (file restored from origin/main, components rebuilt): blob on disk 893387f3 equal to the origin/main blob AND marker count 1 — mutation confirmed on disk before the rebuild, not by an editor exit code — giving dist .d.ts = 2, SchemaRenderer.d.ts PRESENT, SchemaRenderer.js ABSENT, body marker STILL 0, control 4. Restored: source absent, `git diff HEAD` empty, `git status --porcelain` empty (restore proven BY STATE, not by exit code), dist .d.ts back to 1, marker 0, control 4. Ran under `trap ... EXIT INT TERM` with absolute paths. LIVENESS PROBE with controls that fired in the same run — declaration form, never the word: the bare word occurs 312 times under packages/components/src, of which only 2 are this file; the other 310 sit in 101 files, 55 importing the name from @object-ui/react and 0 from any relative path. SchemaRenderer declarations in packages/components/src = 1 (this file) vs control 1 in packages/react; relative `from '../SchemaRenderer'` importers = 0 in components vs control 28 in react. Barrel: 0 occurrences in dist/index.d.ts against 24 export lines. Specifier: the exports map has exactly two entries, '.' and './style.css', no wildcard subpath. Alias: 0 files in the package use the `@/` form and 0 repo-wide import `@/...SchemaRenderer`, control 63 files repo-wide do use `@/`. Import graph: a transitive walk from index.ts reaches 207 of 210 non-test files, not this one. Also clear: dynamic import()/React.lazy (all hits resolve to react's own tests), scripts/ and generated files 0, package README 0, tests under packages/components 0 relative importers.", "mcp_calls": "7 — issue_read get, issue_read get_comments, add_issue_comment (claim), issue_read get_comments (claim read-back), create_pull_request, issue_write (filed 7515), add_issue_comment (this report). Card body/comments, dedup listing, label vocabulary and the PR body read-back all went over unauthenticated REST, which returned 200 on repo-scoped reads; the REST SEARCH endpoint 403s, so dedup was done as REST list + local grep over 363 open issues rather than a wide MCP scan.", "open_questions": [], "out_of_scope_findings": [ "filed as #7515: no gate among the repo's 42 check:* scripts detects an unreferenced source file, which is why this card and #7397 were both found by hand; the measured sweep of packages/components leaves exactly one genuine orphan, ui/toast.tsx (0 exports from ui/index.ts, 0 importers; control: live sonner has 16), and it sits in the AGENTS.md #7 No-Touch Shadcn zone so its removal is not mechanical. Two apparent orphans (the use-sync-external-store shims) are NOT dead — they are reached through vite.config.ts alias entries an import walk cannot see, which is the constraint any such gate must satisfy.", "correction for triage, no card needed: #7397's file is not a second instance of this shape. packages/components/src/ui/chart.tsx IS reachable from the barrel (index.ts:90 `export * from './ui'` reaches ui/index.ts:20 `export * from './chart'`), so it is an exported duplicate, not an orphan. The 'two unreferenced duplicates in one package in one day' framing holds for the pattern but only one of the two was actually unreferenced." ] }Generated by Claude Code
fix(components): delete the second, dead SchemaRenderer (objectstack-…