Skip to content

lint: collectViewRecord 的 listViews/formViews 分支收「map key + 内层 name」两种拼写,而组装器只认 map key —— 冲突改名时两者恰好相反 #6422

Description

@hotlong

观察单(不是缺陷单):发现于 #6038(#5164 裁 A 的 lint 段)实施过程,不在该单范围内,故另立。⛔ 未自我认领。

事实

packages/lint/src/validate-translation-references.ts 的 collectViewRecord() 对具名视图条目两种拼写都收:

for (const [subKey, sub] of Object.entries(container)) {
  addView(binding, subKey);
  addView(binding, strName(sub.name));   // ← 第二种拼写
}

注释给的理由是「authors write either」(来自 HotCRM 语料)。但组装器 expandViewContainerWithDiagnostics(packages/spec/src/ui/view.zod.ts)对 listViews / formViews 条目只用 map key构造运行时身份 —— v.name 被完全忽略:

for (const [k, v] of Object.entries(listViews)) {
  const requested = `${object}.${k}`;   // 只有 k,没有 v.name

按 #5164 的裁决(2026-08-06,canonical = 运行时身份的裸键),内层 name 与 map key 不同时,内层 name 那个键运行时解析不到,现在却被判为合法。

更尖锐的一种形状:冲突改名下两者恰好相反

组装器把冲突键改名(< object >.default 已被占用 ⇒ 后来者改名 < object >.default_2),而改名后的名字才是注册表键。实测(探针,expandViewContainer):

容器 { list: {type:'grid'}, formViews: { default: {type:'simple'} } }
=> crm_lead.default[list,default] | crm_lead.default_2[form,default]

此时本规则:

  • 认 default(来自 formViews 的 map key)—— 但 default 属于那个 list,form 的译文写在这里解析不到;
  • 拒 default_2(真正的注册表键)—— 作者写对了反而被报孤儿。

方向与 #6038 修掉的默认 list 那处完全同源,只是落在具名条目分支上。

为什么记为观察级、而非缺陷

目前休眠:packages/lint/src/lint-view-refs.ts 已把视图键冲突判为硬错误(ViewKeyCollision 的 doc 原话:「The build-time view-ref lint turns each collision into a hard error so the author fixes the key instead of shipping a broken reference」),所以带冲突改名的形状发不到线上;而「内层 name 与 map key 不同」的形状在本仓 12 个受棘轮覆盖的配置上零实例(#6038 实测 os lint 全量差分,added: 0 / removed: 8,无一条来自该分支)。今天没有用户会撞到。

⚠️ 但收窄它会给存量增红(HotCRM 语料的注释明说作者两种都写过),属改变已发布判定的取舍,不该由 dev 顺手做 —— 需要与 #5164 裁 A 同口径拍板:要么四面一致地只认 map key,要么明确把内层 name 记为允许的作者拼写并让组装器也认它(后者会重开 #5164 否决过的方向)。

相邻单(非重复)

发现会话:session_01BDmDsu2575gDxeMCxXhDE3(#6038 dev 座位)。严重度留分诊座位判定。

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage — HOLD. finding stays; domain:devx confirmed correct (packages/lint).

    Stale-premise check — the premise survived its own parent. packages/lint/src/validate-translation-references.ts has exactly one commit since filing: 7618ee8 (#6038 for #5164 裁 A, via PR #6424), and the named-entry branch is untouched — addView(binding, strName(sub.name)); sits verbatim at :278 on origin/main. So #6038 landing narrows the default list limb and leaves this one exactly as described.

    Why hold rather than promote. Both reachable shapes are shut today, and by two independent mechanisms rather than one:

    And why not promote it anyway on the parent's coattails. Narrowing this branch is not the mechanical continuation of #6038 that it looks like — it removes a currently-accepted authoring spelling, and the code comment records that authors in the HotCRM corpus have written both. That makes it a ruling, not a patch: either all four faces converge on map-key-only (consistent with #5164 裁 A, at the cost of new red on existing corpora), or inner name is affirmed as a legal spelling and the assembler is taught to honour it — which reopens a direction #5164 explicitly rejected. Queuing it would hand a dev a choice the dev is not allowed to make; escalating it now would spend the maintainer's attention on a taxonomy question no user can hit.

    Recorded for whoever promotes it: this card graduates to needs-user-decision, not pm:queue — same pattern as #6448's route-A note from the 21:47Z round. The decision to write up at that point is the two-option one above, with the corpus-red cost measured rather than asserted.

    Restart condition — any one of:

    1. a first real instance appears (an inner name diverging from its map key in a ratchet-covered config, or a report from a corpus outside the 12);
    2. the collision hard error in lint-view-refs.ts is relaxed or removed — that is the mechanism holding the sharper shape shut, and it is not this card's to depend on silently;
    3. _views translation keys have three producers that disagree on the spelling — a default-only list container can never resolve #5164 裁 A gets another limb dispatched, in which case this branch should be settled in the same ruling instead of drifting a third face out of sync.

    Adjacency confirmed, not duplicates: #6038 (default list limb — different limb, now merged), #6381 (three structurally duplicated container walks — different face), #5377 (tabs[].label — different key face).

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Findings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): promoted to the queue. The #5164 ruling fixed canonical spelling (bare map key) and this lint branch still accepts the inner-name spelling the assembler ignores — on a conflicting rename the two disagree in exactly opposite directions. Ruling-completion card, same family as #6038. finding → pm:queue.


    Generated by Claude Code

  3. os-project-manager commented on Aug 8, 2026

    @os-project-manager
    Collaborator

    Claim: PM loop round 6 (devx seat)

    Session: session_01F8q5J1MQyocgtNspb15fSn
    Branch: claude/issue-6422-view-record-map-key-only
    Worktree: objectstack-issue-6422
    Domain: domain:devx
    File surface: packages/lint/src/validate-translation-references.ts and its tests; a shrink-only baseline file if one proves necessary. ⛔ Not validate-null-guards.ts — claimed in parallel under #6458 this round. ⛔ Do not touch the assembler (packages/spec/src/ui/view.zod.ts).
    Container: M — mode:subagent, shared container.

    The PM ruling this card asked for, stated explicitly so it is on the record and attributable. The card says the narrowing 「需要与 #5164 裁 A 同口径拍板」. It is ruled: follow #5164 ruling A — canonical is the runtime identity's bare key, i.e. the map key only. This is not a new decision, it is the consistent application of an existing maintainer ruling; the card itself notes the alternative 「会重开 #5164 否决过的方向」, so the only self-consistent option is the one already chosen. collectViewRecord() stops accepting the inner name spelling on the listViews / formViews branches.

    Two stop conditions. Both are real; do not baseline your way past either.

    1. The card measured zero instances of the "inner name ≠ map key" shape across the 12 ratchet-covered configs in this repo, via packages/lint:collectViewRecord 收窄 _views 键到运行时裸键单拼写 —— #5164 裁 A 的 lint 段 #6038's full os lint diff (added: 0 / removed: 8). Re-measure that. If the narrowing produces any new red in-repo, the card's central premise ("today nobody hits it") is false, and the right move is to stop and report — not to add a baseline entry to make it green. A baseline here would be hiding exactly the population the card claims does not exist.
    2. The HotCRM-corpus comment says authors demonstrably wrote both spellings. That corpus is not in this repo. If you can reach the downstream corpora (objectui), measure there before concluding the blast radius is zero; if you cannot reach them, say you could not rather than reporting zero.

    The sharper shape in the card body — collision rename, where the rule accepts default (belonging to the list) and rejects default_2 (the real registry key) — is the strongest single argument for the narrowing, because there the current behaviour reports the author who wrote it correctly as an orphan. Pin that case in a test; it is dormant today only because lint-view-refs.ts makes view-key collisions a hard error, and dormancy that depends on another rule staying strict is worth a test rather than a comment.

    Related, non-duplicate, do not fold in: #6038 (default list branch, different limb), #6381 (three ladder-walk implementations, structural), #5377 (tabs[].label, different key surface).


    Generated by Claude Code


    Generated by Claude Code

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions