立卡自 #7293 的执行席交办(该席自己的 dedup 搜索失败,判定「那个 0 不是读数」后交给 PM,没有盲填 —— 处理正确)。PM 席已独立复核下述每一条读数 ,并完成了 dedup。
一、缺陷
DashboardRenderer.tWidgetSubCaption 有两条肢 :
packages/plugin-dashboard/src/DashboardRenderer.tsx:412-421
const authored = (widget.options as Record<string, unknown> | undefined)?.description;
const fallback = resolveLabel(authored); // 肢 1:把作者写的值(含 inline per-locale map)塌成当前语言
if (!dashName || !widget.id) return fallback;
return widgetSubCaption(dashName, widget.id, fallback); // 肢 2:让 i18n bundle 里的条目盖过作者值
#7293 / PR #8887 接上了肢 1 (以及随之而来的 server-overlay 通道 —— translateDashboard 在 bundle 有非空 subCaption 时会把翻译写进 options.description,所以一个由平台服务 的 dashboard 现在能拿到译文)。
肢 2 仍然到不了 dataset-bound tile。 它需要 dashName,而:
packages/plugin-dashboard/src/DatasetWidget.tsx:408
export function DatasetWidget({ widget, dataSource }: { widget: any; dataSource: unknown })
packages/plugin-dashboard/src/DashboardRenderer.tsx:935 <DatasetWidget widget={effectiveWidget} dataSource={dataSource} />
packages/plugin-dashboard/src/DashboardGridLayout.tsx:584 <DatasetWidget widget={widget} dataSource={dataSource} />
两个 dispatch site 都只传 widget 和 dataSource。 没有 dashboard 名,也没有把 tWidgetSubCaption 的结果传进去(tWidgetSubCaption 的返回值只挂在 getComponentSchema() 的两条 inline arm 上 —— 这正是 #7293 的根因,一层未变)。
⇒ 一个从 app bundle 加载 、而非由平台服务的 dashboard,其副标题若只 写在客户端 i18n bundle 的 {ns}.dashboards.{dash}.widgets.{id}.subCaption 上、作者没写 options.description,那么在 dataset-bound tile 上什么也不渲染 。
⚠️ 而这种写法不是滥用 :tWidgetSubCaption 自己的 docblock 写着 —— 「A translation with no authored counterpart is legitimate and matches the server」。这是被明文承认的合法形态。
这是 ADR-0049 「declared-but-unenforced」家族,与 #7293 同型,位置低一层。
二、命名探针(未跑,留给执行席)
在一个 I18nProvider 里渲染一个 dataset-bound metric tile,provider 的 bundle 携带 {ns}.dashboards.{dash}.widgets.{id}.subCaption,而 widget 不 声明 options.description。
预期今天:什么都不渲染 。修好后:渲染 bundle 里那句。
⚠️ 控制必须会动 :一个同时 写了 options.description 的 tile,在两个世界里都必须渲染出bundle 的值盖过作者值 (这是肢 2 的既定语义:「a bundle entry always wins over an inline map and the two channels can never disagree」)。如果你的控制在主体坏掉时也红,它不是控制。
三、⚠️ 形状上的两条岔路,⛔ 分诊/执行席请勿默认走第一条
修法不止一种,而且代价差得很远 :
把 dashName 传下去 —— 改 DatasetWidget 签名。⚠️ 它有两个 dispatch site,只改一个会「修好一个面、另一个面静默照旧」,A dataset-bound KPI tile can render no sub-caption at all: DatasetWidget drops every measure after values[0] and never reads options.description #7293 的执行席正是因为这一点才选择在组件内读键而非加 prop(objectui#4614 是这条教训的原始卡)。
把已解析的值传下去 —— 同样改签名,但把 tWidgetSubCaption 的调用留在 renderer 侧。
在 DatasetWidget 内部读 i18n —— 不改签名,但要在组件里拿到 dashboard 名,而它今天根本不知道自己在哪个 dashboard 上 。
⛔ 本卡不裁定走哪条 。三条都改了授权面或组件契约,值得分诊席按机械边界测一次型(Bug / Feature)。
四、定级理由(p3,可被分诊席推翻)
不上 p2 —— 与 #7293 的差别是实的:
不降 p4 —— 它是被 docblock 明文承认为合法 的形态,静默无输出,作者无从察觉。
五、dedup(已完成,非盲填)
search_issues 语义检索,owner/repo 限定 objectui,19 个结果全部过目:#7293 (本卡的父,肢 1)、#4032 (resolveLabel 从不调 t() —— 本卡的祖先,已关)、#4614 (DashboardGridLayout 无 dataset 路径 —— 「两个 dispatch site」这条教训的出处,已关)、#4620 、#7353 、#7534 、#7151 、#5742 、#5280 等。无一是本卡 。
⚠️ 执行席交办时该通道对它返回 API rate limit already exceeded(未在循环里重试,正确);其 fallback(repo 限定 issue 列表 + 本地 grep)自控制失败 (扫了 200 行 domain:ui,连 #7293 自己都不在里面 ⇒ 那个 0 不是读数)。它因此拒绝盲填并交办 —— 这个判断是对的 。本席重跑时限流已恢复,读数成立。
立卡自 #7293 的执行席交办(该席自己的 dedup 搜索失败,判定「那个 0 不是读数」后交给 PM,没有盲填 —— 处理正确)。PM 席已独立复核下述每一条读数,并完成了 dedup。
一、缺陷
DashboardRenderer.tWidgetSubCaption有两条肢:#7293 / PR #8887 接上了肢 1(以及随之而来的 server-overlay 通道 ——
translateDashboard在 bundle 有非空subCaption时会把翻译写进options.description,所以一个由平台服务的 dashboard 现在能拿到译文)。肢 2 仍然到不了 dataset-bound tile。 它需要
dashName,而:两个 dispatch site 都只传
widget和dataSource。 没有 dashboard 名,也没有把tWidgetSubCaption的结果传进去(tWidgetSubCaption的返回值只挂在getComponentSchema()的两条 inline arm 上 —— 这正是 #7293 的根因,一层未变)。⇒ 一个从 app bundle 加载、而非由平台服务的 dashboard,其副标题若只写在客户端 i18n bundle 的
{ns}.dashboards.{dash}.widgets.{id}.subCaption上、作者没写options.description,那么在 dataset-bound tile 上什么也不渲染。tWidgetSubCaption自己的 docblock 写着 —— 「A translation with no authored counterpart is legitimate and matches the server」。这是被明文承认的合法形态。这是 ADR-0049 「declared-but-unenforced」家族,与 #7293 同型,位置低一层。
二、命名探针(未跑,留给执行席)
预期今天:什么都不渲染。修好后:渲染 bundle 里那句。
options.description的 tile,在两个世界里都必须渲染出bundle 的值盖过作者值(这是肢 2 的既定语义:「a bundle entry always wins over an inline map and the two channels can never disagree」)。如果你的控制在主体坏掉时也红,它不是控制。三、⚠️ 形状上的两条岔路,⛔ 分诊/执行席请勿默认走第一条
修法不止一种,而且代价差得很远:
dashName传下去 —— 改DatasetWidget签名。tWidgetSubCaption的调用留在 renderer 侧。DatasetWidget内部读 i18n —— 不改签名,但要在组件里拿到 dashboard 名,而它今天根本不知道自己在哪个 dashboard 上。⛔ 本卡不裁定走哪条。三条都改了授权面或组件契约,值得分诊席按机械边界测一次型(Bug / Feature)。
四、定级理由(p3,可被分诊席推翻)
不上 p2 —— 与 #7293 的差别是实的:
options.description,今天就渲染。不降 p4 —— 它是被 docblock 明文承认为合法的形态,静默无输出,作者无从察觉。
五、dedup(已完成,非盲填)
search_issues语义检索,owner/repo限定 objectui,19 个结果全部过目:#7293(本卡的父,肢 1)、#4032(resolveLabel从不调t()—— 本卡的祖先,已关)、#4614(DashboardGridLayout无 dataset 路径 —— 「两个 dispatch site」这条教训的出处,已关)、#4620、#7353、#7534、#7151、#5742、#5280 等。无一是本卡。API rate limit already exceeded(未在循环里重试,正确);其 fallback(repo 限定 issue 列表 + 本地 grep)自控制失败(扫了 200 行domain:ui,连 #7293 自己都不在里面 ⇒ 那个 0 不是读数)。它因此拒绝盲填并交办 —— 这个判断是对的。本席重跑时限流已恢复,读数成立。