Repository navigation
finding(types): zod-mirror-parity pairs navigation.zod's two Breadcrumb mirrors with the data-display declaration, so their green says nothing about the mirror it names #6720
Description
Activity
- addeddomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Aug 29, 2026 huangyiirene commented
on Aug 29, 2026 CollaboratorMore actions分诊:入决策箱 + 四棱块
定级:
needs-user-decision·domain:devx·priority:p2· typeBug。domain:devx依据同族先例:#6705 落在同一个文件(zod-mirror-parity.test.ts,不同机制),上轮已按 #6152 / #6155 这对同族卡定为domain:devx并留痕。同文件同车道,⛔ 不因本卡母卡 #6349 涉及packages/types就改判 —— 本卡自己的落点是那个 parity 文件。进决策箱的理由:路线 1 可能要往治理棘轮台账写新债(
KnownDrift/UnmirroredDeclared/RuntimeOnlyDeclared),卡面自己写明那是裁决不是编辑。<!-- os-decision-facets -->
一句话问题:parity 门禁把
navigation.zod的两个 Breadcrumb 镜像,配对到了data-display的声明上。镜像重述的是navigation的声明,比对的却是另一个同名声明 ⇒ 两对都读作完全干净,而那份「干净」说的是一个没有任何消费者解析的声明。选项 × 真实客户可感成本
做什么 代价 1 立即重指 到 ../navigation机械上只是两个 import specifier ⚠️ 比对随即多出maxItems·icon·onClick·siblings四个键,暴露出来的东西可能要写进棘轮台账 —— 即往治理面新增债务。而 #6349 落地时又会把这些债删掉 ⇒ 可能是白写2 等 #6349 去重 零动作。一个权威之后,配对不可能指错 ⚠️ 期间门禁对maxItems与icon保持沉默 —— 而这两个恰恰是最近才被赋予行为的键(#6646 / #5931+PR #6644)四棱
① 长远合理性:2 是结构性正解 —— 病根是一个名字有两个权威(#6349 的全部内容),配对指错只是症状。1 是给症状贴布。
② 业务拉动:零直接客户可感面。代价形式是「门禁在它最该说话的地方沉默」,而不是用户撞到什么。
③ 防 AI 犯错 —— 分水岭。⭐ 这是本席位这两天反复看到的同一形状:被计数、读作绿、实则什么也没验证。而本卡的版本尤其毒 —— 任何人读这份 parity 文件都会以为BreadcrumbSchema被检查了,TypeScript 也不会报任何东西,因为两个声明同名、不同文件。⇒ 沉默的绿 + 编译器共谋。
④ 不扩散:2 是零动作;1 是小编辑但可能新增治理面债务,而债务比编辑贵。推荐:⛔ 本席不裁。但把取舍点说清 —— 1 与 2 的差别不在工作量,在「要不要为一个 #6349 迟早会删掉的中间态,往治理棘轮台账写债」。若 #6349 短期内会动,2 明显更省;若 #6349 遥遥无期,门禁对刚获得行为的两个键持续沉默就是真实代价。
⇒ 这实质上是一个排期问题,而排期信息只有你有。
⭐ 置信缺口
没有人测过路线 1 到底会暴露出什么。 卡面说比对会多出四个键,但没有实际跑过重指后的 parity —— 所以「可能需要新台账条目」是推断,不是实测。四个键里可能一条债都不用写(若镜像本就覆盖它们),也可能四条全要。
⇒ 这个数字直接决定 1 的真实成本,而它便宜到可以先量:改两个 import 跑一次 parity,看输出,不提交。⛔ 建议裁前先做这一步 —— 若结果是零新条目,1 就不再是「写债」,两条路线的取舍完全改变。
低摩擦裁决格式:回「先跑一次重指看输出」(推荐)/「1 立即重指」/「2 等 #6349」。
裁后执行段:先跑 ⇒ 留决策箱,输出回帖后再裁。裁 1 ⇒ 转
pm:queue(domain:devx);⚠️ 若确需新台账条目,那部分单独上报,⛔ 不在同一 PR 里默默写进棘轮。裁 2 ⇒ 转pm:blocked,正文补Blocked-by: #6349(本卡目前没有机读边,仅有散文,解锁扫描看不见它)。
Generated by Claude Code
Premise check on
main: the mis-pairing is already gone — closing as completed, no dispatchdomain:devx@ objectui execution seat, PM sessionsession_01BGMDbrVa8JjZcCQ7DWYH1b, R40. This card was next after #6705 on the same file; the pre-dispatch stale-premise check found the card's route 2 already delivered.Read from
origin/main=67dadd6(control: the same file hitsDataTableSchema5 times, so the probe surface is live):packages/types/src/data-display.ts:1759—export type { BreadcrumbItem, BreadcrumbSchema } from './navigation.js';and:20importsBreadcrumbSchemafrom./navigation.jsfor theDataDisplaySchemaunion (:1850). The docblock at:1741-1744records that this module "declared its ownBreadcrumbItem/BreadcrumbSchemauntil" the de-duplication, naming exactly the keys this card measured missing (icon/onClick/siblings/maxItems).- Introduced by commit
b84dc18— fix(types): one authority for ActionSchema and the Breadcrumb pair (fix(types): one authority forActionSchemaand the Breadcrumb pair #6936), the 46 exported type names carry a second authority — 42 of them are named by no family card #6349 batch-1 landing. zod-mirror-parity.test.ts:140still importsTs_BreadcrumbItem/Ts_BreadcrumbSchemafrom'../data-display'— but that specifier now resolves to the navigation declarations through the re-export, so the pairing compares the mirror against the declaration it restates. The parity file itself was not edited by fix(types): one authority forActionSchemaand the Breadcrumb pair #6936 andmainis green, so no ledger debt was needed for the wider comparison.
⇒ Both options on the triage four-prism block are moot: the "one authority" route the block recommended as structurally correct has landed, and there is no remaining decision. Closing as completed (fixed by PR #6936);
pm:queueremoved with the close,domain:devx/priority:p2kept.⚠️ Note for the record: this card's labels readpm:queuewhile its triage comment (2026-08-29) graded itneeds-user-decision, and no ruling comment is retrievable on the thread (API and web payload both return one comment against a count of two). Had the premise still held, this seat would have treated it as unruled and returned it to the box rather than dispatch it.Optional follow-up, not filed: re-pointing the two
Ts_Breadcrumb*import specifiers at'../navigation'would make the pairing's authority explicit at the import site instead of via re-export. Cosmetic today; a one-line rider for whoever next edits that file (#6705's dev has been told it is out of scope for their card).
Generated by Claude Code
Observed while wiring objectui#6646 / #6645 (branch
claude/issue-6646-breadcrumb-family-declared-keys). Filed unassigned, not fixed there — see "Why it was not fixed in that PR" below.Sub-issue of #6349: this is the
BreadcrumbSchema/BreadcrumbItemrow of that card's table, measured at the one place the duplication is already doing damage.Measured
packages/types/src/__tests__/zod-mirror-parity.test.tsstates its own pairing rule in its header:Two of its pairings do not follow it:
The mirror half comes from
navigation.zod.ts; the declaration half comes fromdata-display.ts. They are not the same contract, becauseBreadcrumbSchemaandBreadcrumbItemare each declared twice in this package (#6349's table):packages/types/src/navigation.tspackages/types/src/data-display.tsBreadcrumbSchematype·items·separator·maxItemstype·items·separatorBreadcrumbItemlabel·href·icon·onClick·siblingslabel·hrefindex.ts./navigation.jsDataDisplaySchemaunion (data-display.ts:1623)zod/navigation.zod.ts:40/:97— the only zod breadcrumb in the package;data-display.zod.tshas noneSo the mirror restates the navigation declaration (it is the one that carries
maxItems, and itsBreadcrumbItemSchemacarriesicon), while the file compares it against the data-display one.Why the mis-pairing is currently silent, and why that is the bad half
The comparison runs over the union of the mirror's keys and the declaration's, and reports two classes: a key the mirror REFUSES (
KnownDrift) and a key the mirror has never heard of (UnmirroredDeclared). A key the MIRROR has and the DECLARATION does not is neither.maxItems,icon,onClickandsiblingsare exactly that shape against the narrow declaration, so:KnownDrift,UnmirroredDeclaredorRuntimeOnlyDeclared;This is #6349's hazard realised inside a gate, in the wording that card's own triage used: anyone who thinks the mirror is checked against
BreadcrumbSchemais reading a check against the one nobody uses, and TypeScript reports nothing because the two declarations are different files with the same name.Which declaration each consumer actually resolves (verified on
98188c284)renderers/data-display/breadcrumb.tsx(import type ... from '@object-ui/types')navigation.ts:205packages/types/src/registry.ts:87,176('breadcrumb': BreadcrumbSchema)navigation.ts(importedfrom './navigation.js')packages/types/src/index.ts:272public exportnavigation.tszod/navigation.zod.ts:97navigation.tsdata-display.ts:1623DataDisplaySchemauniondata-display.ts:1578— publicly reachable throughDataDisplaySchema/ComponentSchema, so narrowing either union ontype: 'breadcrumb'yields a member with nomaxItemsand items with noicon__tests__/zod-mirror-parity.test.tsdata-display.tsWhy it is worth a card now rather than before
objectui#6646 makes
ui:breadcrumbreadmaxItems, and objectui#5931 / PR #6644 made it readBreadcrumbItem.icon. Both keys live only on the navigation declaration, so the two published keys most recently given behaviour are precisely the ones this pairing cannot see. The parity file exists to catch a mirror drifting narrow against a declaration that widened; on this pair it would not.Not decided here
Two routes, and the second is not this card's to take:
../navigation. Mechanically two import specifiers. But the comparison then runs against a declaration with three more keys (icon,onClick,siblings) plusmaxItems, and whatever that reveals may need newKnownDrift/UnmirroredDeclared/RuntimeOnlyDeclaredentries — writing new debt into governed ratchet ledgers, which is a ruling, not an edit. (onClickis the callback-shaped class objectui#6152 split into its own ledger.)KNOWN_COLLISIONSline in the same PR.⛔ Nothing was stripped and no ledger was touched. Note also the standing fence from #6646's triage: the un-exported-from-index
BreadcrumbSchemaindata-display.tsmust not simply be deleted —data-display.ts:1623's union references it, so any route 2 work re-points that union rather than removing the reference.Adjacent, not this
zod-mirror-parity's SPEC_DERIVED_PAIRS scans raw text betweenexport constboundaries, so a Spec-token mentioned in PROSE is attributed to the neighbouring export #6705 — a differentzod-mirror-paritymechanism (SPEC_DERIVED_PAIRSscanning raw text betweenexport constboundaries). Same file, unrelated defect.FormField,MarkdownSchema,KanbanSchema— and one doc assertsFormFieldis declared once #6172 / finding(types):KanbanCard/KanbanColumnare declared four times in this tree and the published copies disagree (cardsvsitems,badgesvslabels) #6155 / finding(plugin-timeline): thetimelinerenderer reads seven keysTimelineSchemadoes not declare, and declares three it never reads #6170 — the family batches for other rows of 46 exported type names carry a second authority — 42 of them are named by no family card #6349's table; none of them namesBreadcrumbSchema(read on 2026-08-29).