Observed by the domain:services seat while working #14453 (showcase permission gaps). Not touched there — different package, different defect class. Filed unassigned, no severity claimed.
What the rule tells the author
packages/lint/src/validate-nav-access.ts emits this hint with every finding:
Add "OBJECT" to a permission set's objects with allowRead: true (or viewAllRecords), gate the entry with requiredPermissions/visible if it is meant for admins only, or drop it.
Three remedies. The module doc-block says the same thing again in prose.
What the rule actually reads
collectNavExposures walks exactly four keys per nav item — type, objectName, id, children — and validateNavAccess then filters only on isPlatformProvidedObjectName, membership in stack.objects, and the read column of buildAccessMatrix. Neither requiredPermissions nor visible is read anywhere in the file.
So a nav entry gated exactly as prescribed keeps warning, forever.
Measured
Against the shipped rule (packages/lint/dist/index.js, tree at 53cbad9f7), on a synthetic stack with one ungranted object in nav, with both controls:
CONTROL ungated+ungranted (MUST be 1): 1 finding(s) -> nav-object-ungranted
CONTROL granted (MUST be 0): 0 finding(s)
PROBE requiredPermissions : 1 finding(s) -> nav-object-ungranted
PROBE visible:false : 1 finding(s) -> nav-object-ungranted
The negative control (granted ⇒ silent) and the positive control (ungranted ⇒ fires) both behave, so the two probe readings are about the gating keys and nothing else.
Why it is worth a card
The prescribed action is not merely ineffective at silencing the diagnostic — it is the one remedy an author reaches for when the entry is deliberately admin-only, which is exactly the case the hint invents it for. Following it costs an edit, changes what the app serves, and leaves the warning standing, with nothing saying why. The author's next move is to distrust the rule.
It also narrows the rule's real menu to two: grant, or drop the entry. On #14453 that was load-bearing — with gating unavailable, every one of the seven flagged objects had to be granted or removed from navigation, and there was no third disposition to weigh.
requiredPermissions on a navigation ITEM is a real, server-enforced gate (app.zod.ts: the item is stripped server-side for a caller lacking the capability), so the hint is not wrong about the platform — only about this rule. Note also that visible is separately reported as inert at runtime in #15135, which would make it a poor second half of the prescription even if the lint did honour it.
Shape of the work
Two readings, and they are not equivalent:
- Honour the keys — skip an exposure whose item carries
requiredPermissions (a capability gate this stack can see) and/or a statically-false visible. Note requiredPermissions gates on capabilities, not object grants, so "gated ⇒ genuinely reachable only by holders" needs deciding rather than assuming.
- Correct the hint — drop the gating clause and say plainly that grant-or-drop are the two remedies that clear it.
Either is small; picking between them is a judgement about what the rule is asserting, which is why this is filed rather than patched.
Refs: #14453 (where it was measured) · #15135 (visible inert at runtime) · packages/lint/src/validate-nav-access.ts.
Observed by the
domain:servicesseat while working #14453 (showcase permission gaps). Not touched there — different package, different defect class. Filed unassigned, no severity claimed.What the rule tells the author
packages/lint/src/validate-nav-access.tsemits this hint with every finding:Three remedies. The module doc-block says the same thing again in prose.
What the rule actually reads
collectNavExposureswalks exactly four keys per nav item —type,objectName,id,children— andvalidateNavAccessthen filters only onisPlatformProvidedObjectName, membership instack.objects, and the read column ofbuildAccessMatrix. NeitherrequiredPermissionsnorvisibleis read anywhere in the file.So a nav entry gated exactly as prescribed keeps warning, forever.
Measured
Against the shipped rule (
packages/lint/dist/index.js, tree at53cbad9f7), on a synthetic stack with one ungranted object in nav, with both controls:The negative control (granted ⇒ silent) and the positive control (ungranted ⇒ fires) both behave, so the two probe readings are about the gating keys and nothing else.
Why it is worth a card
The prescribed action is not merely ineffective at silencing the diagnostic — it is the one remedy an author reaches for when the entry is deliberately admin-only, which is exactly the case the hint invents it for. Following it costs an edit, changes what the app serves, and leaves the warning standing, with nothing saying why. The author's next move is to distrust the rule.
It also narrows the rule's real menu to two: grant, or drop the entry. On #14453 that was load-bearing — with gating unavailable, every one of the seven flagged objects had to be granted or removed from navigation, and there was no third disposition to weigh.
requiredPermissionson a navigation ITEM is a real, server-enforced gate (app.zod.ts: the item is stripped server-side for a caller lacking the capability), so the hint is not wrong about the platform — only about this rule. Note also thatvisibleis separately reported as inert at runtime in #15135, which would make it a poor second half of the prescription even if the lint did honour it.Shape of the work
Two readings, and they are not equivalent:
requiredPermissions(a capability gate this stack can see) and/or a statically-falsevisible. NoterequiredPermissionsgates on capabilities, not object grants, so "gated ⇒ genuinely reachable only by holders" needs deciding rather than assuming.Either is small; picking between them is a judgement about what the rule is asserting, which is why this is filed rather than patched.
Refs: #14453 (where it was measured) · #15135 (
visibleinert at runtime) ·packages/lint/src/validate-nav-access.ts.