Surfaced by the dev implementing #7659 (PR #7691), disclosed in that PR's body rather than papered over, and pinned in runtime-gate.test.ts so the interaction is recorded in the suite rather than only in prose. Filed separately because reconciling two rules' messages is not a rider on the PR that introduced one of them.
Filed unassigned, observation class. ⛔ Grading is the triage seat's single channel.
The fact
For one token — a bare unquoted word on the right of ==, e.g. status == active — two publish-time rules both fire, and they prescribe different fixes:
| rule |
severity |
reads the token as |
prescribes |
visibility-bare-identifier |
error |
a dropped binding root |
data.active |
predicate-rhs-path-shaped (#7659, PR #7691) |
warning |
a literal missing its quotes |
'active' |
Both statements are true about the token. They are not true about the same intent, and nothing in either message tells the author which intent the linter thinks they had — because neither rule can know.
Why this is worth a card rather than a shrug
The two fixes are not merely different, they are semantically opposite: one turns the token into a path lookup, the other into a string literal. An author following the error (which is louder, and blocks) when they meant a literal gets a predicate that compares against data.active — a path that probably does not resolve, so #7214's predicate-path-unresolved then fires and the author is walked around a triangle.
⚠️ Note also that the bare-word spelling works today by accident — that is exactly why #7659 landed it as warning rather than error, per objectui#4049's ruling ("it would flip data.type == text, the unquoted-string spelling that works today by accident, into a fail-open true"). So the author is being told, at error severity, to change something that currently works, in a direction that may break it.
What is NOT being claimed
Shapes a fix could take (none obviously right — hence a finding)
- Suppress one when the other fires. Cheapest. Requires deciding which reading wins for a bare word on an RHS, which is the actual open question.
- Merge the two messages for this one position — a single finding naming both spellings and letting the author choose. Keeps both diagnoses, costs a special case in two rules.
- Accept it and make the messages cross-reference each other, so an author seeing both is told they are two readings of one ambiguity rather than two independent errors.
- Accept as-is. Defensible: both fire, the author reads both, and the pin stops it drifting. Weakest, because the
error is the one that blocks and it is the one asserting the less likely intent for an RHS position.
Pointers
Surfaced by the dev implementing #7659 (PR #7691), disclosed in that PR's body rather than papered over, and pinned in
runtime-gate.test.tsso the interaction is recorded in the suite rather than only in prose. Filed separately because reconciling two rules' messages is not a rider on the PR that introduced one of them.Filed unassigned, observation class. ⛔ Grading is the triage seat's single channel.
The fact
For one token — a bare unquoted word on the right of
==, e.g.status == active— two publish-time rules both fire, and they prescribe different fixes:visibility-bare-identifiererrordata.activepredicate-rhs-path-shaped(#7659, PR #7691)warning'active'Both statements are true about the token. They are not true about the same intent, and nothing in either message tells the author which intent the linter thinks they had — because neither rule can know.
Why this is worth a card rather than a shrug
The two fixes are not merely different, they are semantically opposite: one turns the token into a path lookup, the other into a string literal. An author following the
error(which is louder, and blocks) when they meant a literal gets a predicate that compares againstdata.active— a path that probably does not resolve, so #7214'spredicate-path-unresolvedthen fires and the author is walked around a triangle.warningrather thanerror, per objectui#4049's ruling ("it would flipdata.type == text, the unquoted-string spelling that works today by accident, into a fail-opentrue"). So the author is being told, aterrorseverity, to change something that currently works, in a direction that may break it.What is NOT being claimed
errorwhere "there is no reading of the metadata under which it was going to work",warningwhere the predicate is merely advisory-wrong) and the bare-word case is genuinely the second.Shapes a fix could take (none obviously right — hence a finding)
erroris the one that blocks and it is the one asserting the less likely intent for an RHS position.Pointers
packages/lint/src/validate-predicate-path-refs.ts— both rules after PR feat(lint): refuse a path-shaped==/!=right-hand side at publish time (#7659) #7691packages/lint/src/runtime-gate.test.ts— where the pair is pinned==/!=right-hand side at publish time (#7659) #7691 (introduced the second rule, disclosed this), Publish-time validation of predicate path references — a spec-delivered predicate naming a nonexistent path should fail at authoring, not evaluate to a guess at render (#6936 companion) #7010 / PR feat(lint): publish-time resolution of metadata-form predicate paths (#7010) #7214 (predicate-path-unresolved, the third corner of the triangle), objectui#4049 (the ruling that the bare-word spelling works today), view/page 可见性谓词的 CEL **语法**在构建期无人校验 ——country === "USA"这类写法零诊断、运行时静默 fail-open #6253 (visibility-predicate-syntax)