Skip to content

[finding] NavigationItem.recordId's docblock says "Mutually exclusive with viewName" — the guard tolerates that exact pair, and the sentence is one field over from the one PR #16862 was filed to fix #16875

Description

@zhuangjianguo

⛔ 分级与路由(domain:* / priority:* / type)属分诊,本卡由执行席 domain:spec 不带分级立卡。⛔ Filed unassigned.

Surfaced by the at-tier contract review of PR #16862 (card #16714) as its finding N1, rated non-blocking by that reviewer and not ridden on that PR — the ruling for #16714 named only the filters docblock, and its item 3 explicitly preserves the tolerance this sentence misdescribes.

The defect

packages/spec/src/ui/app.zod.ts, the recordId field's docblock (locate by text, ⛔ not by line number):

Mutually exclusive with viewName (viewName is ignored if both are set).

The guard does not refuse that pair. Measured through NavigationItemSchema at bf41b3f60: recordId + viewName parses clean. It is the one combination objectNavTargetExclusivity deliberately tolerates, and the guard's own docblock says so in as many words — "The legacy recordId + viewName combination stays tolerated".

⇒ Two docblocks in one file describe the same rule and disagree: the guard's is right, recordId's is wrong. The parenthetical is the tell — "viewName is ignored if both are set" describes a precedence, not a refusal, so the sentence's own second clause contradicts its first.

⭐ Why this is worth a card and not a note

This is the same defect class as #16714, one field over, in the same file — prose that asserts a stricter contract than the code enforces. #16714 existed because a precedence sentence sat a few lines above a sentence declaring the combination unrepresentable; this is that shape again, inverted: a refusal sentence sitting above a rule that tolerates.

⚠️ And the harm direction is the one this file family keeps producing: an author (or an agent) who reads "mutually exclusive" will avoid a combination the platform accepts, or will file a bug when it parses. The failure is silent in both directions.

What bounds it — measured, so the card does not overstate itself

⇒ single-file, single-sentence, no consumer, no generated output. Fact layer only.

Shape of a fix (⛔ not a ruling — the tolerance itself is settled and stays)

Rewrite the sentence to describe what the code does. The reviewer's suggestion, recorded rather than mandated:

Tolerated, not refused: viewName is ignored when both are set.

Do not "unify" the asymmetry. Triage's ruling on #16714 item 3 keeps recordId + viewName tolerated, and PR #16862's ablation M2 exists precisely to make that tolerance go red if someone makes the fields pairwise exclusive. This card corrects the prose; the behaviour is deliberate and pinned.

⭐ Worth pinning the sentence too, if cheap: app-nav-target-exclusivity-export.test.ts already asserts recordId + viewName accepts, so a docblock assertion beside it would close the drift rather than just fix today's copy.

Dedup

Whole domain:spec lane enumerated to the last page at 2026-09-08T12:31Z — 141 returned against totalCount 141, so the enumeration is complete, not a sample — and no open card covers this sentence; #16714 is the only neighbour and it is the filters docblock.

⚠️ Limit of that check, stated rather than hidden: it is an enumeration of the domain:spec lane, so a bare/untriaged duplicate outside the lane would not appear in it. ⛔ Keyword search was deliberately not used as the control: search_issues returns total_count: 0 for camelCase identifiers in this repo (recorded on #16779), and every useful term here — recordId, viewName, objectNavTargetExclusivity — is camelCase, so a zero from that channel would be a tokenizer artefact and not a reading.

Refs: #16714 (the parent card) · PR #16862 (where N1 was found; the review is comment 5585289881).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions