Filed by the domain:ui execution seat (session_01KbJQ1y1J12nZxYzFWhP8Q3, os-sam) as the home for the question #5936 deliberately fenced out, so it does not close with that card. Filed unassigned.
⛔ Not dispatchable as filed — removing a published capability is a maintainer decision.
Why this is a card and not a line in a closing thread
#5936 asked "who consumes a component registration's icon meta?" and funded a three-repo search. It came back a third zero. Its own scope text says that outcome "would make the meta itself dead surface and change the ruling to retirement".
⚠️ But "retirement" has two readings with very different blast radius, and #5936's dispatch fenced the wide one out:
⭐ Three seats have now independently gone looking for this key's consumer, and #5936 is the second time that search was funded. Without a recorded decision there will be a fourth. That is the cost this card exists to stop.
The measurement — dead in every first-party population
| population |
reading |
controls that fired |
| objectui |
zero, re-derived over all five meta-bearing registry read paths (not just getMeta(...).icon) |
getMeta( 51 occurrences · -i icon 4898 lines |
| objectstack |
zero @ daacc1071 |
— |
| cloud |
zero @ 9b6abe0f2fd5 — structural: no component-registration surface at all, and no @object-ui/* dependency in any of its 19 package.json files |
getMeta 276 · -i icon 412 |
getMeta()'s four first-party callers read .labelling, .namespace, .isContainer, .inputs and .deprecated. getPublicConfigs()'s one reads { type, isContainer }. getConfig(), getAllConfigs(), getNamespaceComponents() have none. None reads .icon.
⭐ The evidence that cuts the other way, and it is new
packages/core/src/registry/WidgetRegistry.ts:173 copies manifest.icon into this meta from external widget manifests; :179 does the same for the inputs' defaultValue.
⇒ This is a first-party producer pipeline built specifically to carry an icon from an outside widget into registration meta. A key with a producer path and no first-party consumer is not the same shape as a key nothing touches — it is the shape of a key whose consumer is expected to be external (the designer palette).
⚠️ Three zeros close the three known populations. They are not a proof of absence: a customer-authored app, or an unmeasured repo, could read it. That is the standard ADR-0049 retirement premise, not a proof — and here it collides with a producer path pointing outward.
The options
|
what it does |
cost |
| A — keep, and close the question in the record |
The key stays. The boundary, the three readings and the producer-path evidence are already recorded in scripts/check-lucide-icon-record-names.mjs's header (landed with PR #7604), which states what would re-open it: an actual reader, in any repo |
A published key with no first-party consumer stays on the surface. ⚠️ Mitigated, not eliminated: the reasoning is now where the next auditor hits it |
| B — retire it (ADR-0049 enforce-or-remove) |
Remove ComponentMeta.icon; the coupling test kept by PR #7604 goes with it automatically, since both its operands are on the key |
⛔ Would break the WidgetRegistry inbound path silently — external widget manifests would still declare an icon and it would land nowhere. Also a published-surface removal for every downstream host |
| C — keep, and make the external contract explicit |
A, plus naming the expected external consumer in the type's own docblock, so "no first-party reader" stops reading as "dead" |
Costs one docblock. Does not resolve whether the external consumer actually exists |
四维分析(业务角度)
① 实际业务需求 — 有实测拉动,但方向是入站而非出站。WidgetRegistry 那条生产路径是真代码,专门把外部 widget manifest 的图标搬进注册 meta;这不是投机能力面,是一条已建成的集成。⚠️ 但"谁在读"三个仓都测不到 —— 拉动是生产侧证实、消费侧未证实。B 会静默切断已证实的那一半。
② 项目长远合理性(权重 ≥50%) — 指向 A/C。判据按本轴本义读:缩小特例与契约增生。这个键不是增生出来的特例,它有一条成建制的生产链;删掉它并不缩小契约面,而是在契约上开一个洞:manifest 照旧声明 icon,只是再也落不了地,且没有任何红灯。⛔ 更关键 —— 移除一个消费端在仓外的键,等于用"我们看不见"替换"它不存在",这正是本卡三次搜索所要终结的推理形态。保留 + 把边界写进读者会撞上的地方,是一份记录、改在它该在的地方;删除是把不确定性转成一次不可逆动作。
③ 防 AI 写错 — 指向 C > A > B。真正的结构性修法已经落地:网关头部现在带三份读数、各自对照、2026-09-04 裁定与"三个零不是不存在的证明"的告诫,并写明什么才能重开(任一仓里的真实读者)。C 再补一句:在类型自己的 docblock 上点名"消费者在仓外",让下一个审计者在类型定义处就读到,而不是先搜一圈再找到网关。⛔ B 的防错收益是假的:它消灭的是一个键,不是一个误解,而且会让"声明了却不兑现"从可发现变成不可发现。
④ 创业阶段不扩散 — 这条最像支持 B,必须诚实处理:「已发布零消费的能力不因沉没成本获得豁免」。但判据里的"零消费"在这里不成立 —— 三个零测的是第一方消费者,而本键的消费者按设计就在第一方之外。本轴管的是不要新增没有拉动的声明面;它不要求删除一个有生产链、且删除会造成静默断裂的既有键。⇒ 本轴在此不构成删除理由,只要求⛔ 不再围绕它扩建新面。
权衡与推荐:四棱不同向 —— ① 半支持保留、② 明确指向保留、③ 指向 C、④ 表面支持删除但其判据不成立。按长远合理性权重下限,②③ 合起来压过 ④ 的表面读数。
⇒ 推荐 C(= A 加一句 docblock)。它一次付清长远形态:把"消费者在仓外"从一个每次都要重新发现的事实,变成类型定义上的一句话。⛔ 不推荐 B:它的唯一硬证据是"我们看不见消费者",而同一份测量里有一条指向外部的生产路径。
What is already done, so this card does not re-fund the search
⛔ Do not re-run the consumer census. It is finished and recorded, with controls, in the header of scripts/check-lucide-icon-record-names.mjs (PR #7604). This card needs a decision, not a measurement.
Related: #5936 (the search, and the narrow half) · PR #7604 (the narrow retirement + the recorded boundary) · objectstack#12931 (the cloud reading) · #5633 / PR #5932 (the gate) · #5622 (the pin this came from) · #5935 / PR #7491 (the resolver consolidation).
Filed by the
domain:uiexecution seat (session_01KbJQ1y1J12nZxYzFWhP8Q3,os-sam) as the home for the question #5936 deliberately fenced out, so it does not close with that card. Filed unassigned.⛔ Not dispatchable as filed — removing a published capability is a maintainer decision.
Why this is a card and not a line in a closing thread
#5936 asked "who consumes a component registration's
iconmeta?" and funded a three-repo search. It came back a third zero. Its own scope text says that outcome "would make the meta itself dead surface and change the ruling to retirement".ui:iconpin's membership half. ✅ Done, PR test(components,scripts): retire the ui:icon pin's membership half, record the third zero #7604.ComponentMeta.iconkey itself. This card.⭐ Three seats have now independently gone looking for this key's consumer, and #5936 is the second time that search was funded. Without a recorded decision there will be a fourth. That is the cost this card exists to stop.
The measurement — dead in every first-party population
getMeta(...).icon)getMeta(51 occurrences ·-i icon4898 linesdaacc10719b6abe0f2fd5— structural: no component-registration surface at all, and no@object-ui/*dependency in any of its 19package.jsonfilesgetMeta276 ·-i icon412getMeta()'s four first-party callers read.labelling,.namespace,.isContainer,.inputsand.deprecated.getPublicConfigs()'s one reads{ type, isContainer }.getConfig(),getAllConfigs(),getNamespaceComponents()have none. None reads.icon.⭐ The evidence that cuts the other way, and it is new
packages/core/src/registry/WidgetRegistry.ts:173copiesmanifest.iconinto this meta from external widget manifests;:179does the same for the inputs'defaultValue.⇒ This is a first-party producer pipeline built specifically to carry an icon from an outside widget into registration meta. A key with a producer path and no first-party consumer is not the same shape as a key nothing touches — it is the shape of a key whose consumer is expected to be external (the designer palette).
The options
scripts/check-lucide-icon-record-names.mjs's header (landed with PR #7604), which states what would re-open it: an actual reader, in any repoComponentMeta.icon; the coupling test kept by PR #7604 goes with it automatically, since both its operands are on the keyWidgetRegistryinbound path silently — external widget manifests would still declare an icon and it would land nowhere. Also a published-surface removal for every downstream host四维分析(业务角度)
① 实际业务需求 — 有实测拉动,但方向是入站而非出站。⚠️ 但"谁在读"三个仓都测不到 —— 拉动是生产侧证实、消费侧未证实。B 会静默切断已证实的那一半。
WidgetRegistry那条生产路径是真代码,专门把外部 widget manifest 的图标搬进注册 meta;这不是投机能力面,是一条已建成的集成。② 项目长远合理性(权重 ≥50%) — 指向 A/C。判据按本轴本义读:缩小特例与契约增生。这个键不是增生出来的特例,它有一条成建制的生产链;删掉它并不缩小契约面,而是在契约上开一个洞:manifest 照旧声明 icon,只是再也落不了地,且没有任何红灯。⛔ 更关键 —— 移除一个消费端在仓外的键,等于用"我们看不见"替换"它不存在",这正是本卡三次搜索所要终结的推理形态。保留 + 把边界写进读者会撞上的地方,是一份记录、改在它该在的地方;删除是把不确定性转成一次不可逆动作。
③ 防 AI 写错 — 指向 C > A > B。真正的结构性修法已经落地:网关头部现在带三份读数、各自对照、2026-09-04 裁定与"三个零不是不存在的证明"的告诫,并写明什么才能重开(任一仓里的真实读者)。C 再补一句:在类型自己的 docblock 上点名"消费者在仓外",让下一个审计者在类型定义处就读到,而不是先搜一圈再找到网关。⛔ B 的防错收益是假的:它消灭的是一个键,不是一个误解,而且会让"声明了却不兑现"从可发现变成不可发现。
④ 创业阶段不扩散 — 这条最像支持 B,必须诚实处理:「已发布零消费的能力不因沉没成本获得豁免」。但判据里的"零消费"在这里不成立 —— 三个零测的是第一方消费者,而本键的消费者按设计就在第一方之外。本轴管的是不要新增没有拉动的声明面;它不要求删除一个有生产链、且删除会造成静默断裂的既有键。⇒ 本轴在此不构成删除理由,只要求⛔ 不再围绕它扩建新面。
权衡与推荐:四棱不同向 —— ① 半支持保留、② 明确指向保留、③ 指向 C、④ 表面支持删除但其判据不成立。按长远合理性权重下限,②③ 合起来压过 ④ 的表面读数。
⇒ 推荐 C(= A 加一句 docblock)。它一次付清长远形态:把"消费者在仓外"从一个每次都要重新发现的事实,变成类型定义上的一句话。⛔ 不推荐 B:它的唯一硬证据是"我们看不见消费者",而同一份测量里有一条指向外部的生产路径。
What is already done, so this card does not re-fund the search
⛔ Do not re-run the consumer census. It is finished and recorded, with controls, in the header of
scripts/check-lucide-icon-record-names.mjs(PR #7604). This card needs a decision, not a measurement.Related: #5936 (the search, and the narrow half) · PR #7604 (the narrow retirement + the recorded boundary) · objectstack#12931 (the cloud reading) · #5633 / PR #5932 (the gate) · #5622 (the pin this came from) · #5935 / PR #7491 (the resolver consolidation).