Skip to content

lint: publish-time predicate validation should refuse a path-shaped RIGHT-hand side — outside the renderer's declared ==/!= subset, and unreachable by #7214's resolution check #7659

Description

@yinlianghui

Cross-repo relay from the objectui whole-repo seat (session session_017Qqyix2QcnpUC9XeYVDzx3), executing the D half of the ruling recorded on objectui#4049. Filed unassigned for the spec/lint lane's triage; this is a NEW card rather than a comment on the closed #7010, because that card's delivered scope (PR #7214 — paths that fail to RESOLVE against the target schema) is a different refusal from the one needed here, and a completed card is the wrong place to accrete scope.

The gap

objectui's metadata-admin predicate evaluator supports a declared subset: the RIGHT side of ==/!= is a LITERAL (parseLiteral), never a resolved path. data.a == data.b therefore compares data.a's value against the literal STRING "data.b" — always false, silently. objectui#4049 (PR objectui#4264, merged-pending) adds the consumer-side dev diagnostic naming this boundary; the objectstack maintainer's ruling on #6828-family shapes and the objectui seat's ruling on #4049 both put the CONTRACT half here: authored predicates that exceed the renderer's declared subset should be refused at publish time, contract-first, rather than tolerated into a silent wrong verdict.

What #7214 covers vs what this asks

  • feat(lint): publish-time resolution of metadata-form predicate paths (#7010) #7214 (landed): a path reference that does not RESOLVE against the target schema → refused. A well-formed data.a == data.b passes it — both paths resolve fine; the problem is that the right side's POSITION does not evaluate paths.
  • This card: the publish-time check additionally refuses (or warns, per this lane's severity conventions) a ==/!= right-hand side that is path-shaped — an unquoted identifier chain (data.b, or a bare text missing its quotes) — pointing the author at the sanctioned spellings: quote the literal, or restructure the comparison so the path is on the left. The refusal grammar the consumer diagnostic uses (identifier-chain: /^[A-Za-z_$][A-Za-z0-9_$]*(?:\.[A-Za-z_$][A-Za-z0-9_$]*)*$/) is the natural shared definition — one grammar, two enforcement points.

Why publish-time and not just the dev warning

The consumer diagnostic (objectui#4264) is dev-mode only and fires at RENDER time — after the metadata is stored. An AI author or CI pipeline publishing forms never sees it. The publish door is where "declared subset" becomes "enforced subset" (the ADR-0049 declared-equals-enforced shape this lint check exists for).

Refs: objectui#4049 (the ruling + consumer half), objectui PR #4264, #7010 / PR #7214 (the landed resolution check this extends), #6828 (the vocabulary-ruling family), objectui#4266 (adjacent third path in the same family — the in array-parse collapse — for the lane's awareness when shaping the check).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions