Residual measured while implementing #8116 (PR pending on claude/issue-8116-provenance-predicate-to-spec).
The gap
#8116 sank the #7865 provenance derivation into @objectstack/spec/data and taught the per-object resolution sites in @objectstack/lint to warn when a reference resolves to an injected anchor with no storage behind it on an ADR-0015 external object. That covers the two rules that resolve fields per object today:
validate-expressions.ts (buildFieldIndex / the object-bound expression surfaces),validate-semantic-roles.ts (stageField / highlightFields).
The filter-position field checks are structurally different: they judge a field name against the object-independent blanket union SYSTEM_FIELDS (packages/lint/src/system-fields.ts), which by design answers "could this name be a system column anywhere" and therefore never flags a system name. Measured read sites:
packages/lint/src/validate-widget-bindings.ts:479 (dashboard filter effective field),packages/lint/src/validate-react-page-props.ts:476 (aggregate/filter field refs),packages/lint/src/validate-page-field-bindings.ts:343,packages/lint/src/validate-flow-template-paths.ts:100 (CRUD-node filter template paths).
So filter: [["owner_id", "=", "..."]] on a view/widget/page bound to a federated object lints clean while the runtime degrades exactly as #8116's warning describes (on SQLite: constant-false, HTTP 200, zero rows, no error).
Why it did not ride #8116's PR
Attaching the marker at these sites first requires converting each rule from the blanket union to the per-object derivation (injectedColumnsFor / unprovisionedInjectedColumnsFor) — #5378-shaped work with its own false-positive analysis per surface (each rule's tolerance for names it cannot resolve differs). The #8116 ruling scoped that card to the provenance predicate move only. The spec-side prerequisite now exists, so this is pure lint wiring.
Pointers
Generated by Claude Code
Residual measured while implementing #8116 (PR pending on
claude/issue-8116-provenance-predicate-to-spec).The gap
#8116 sank the #7865 provenance derivation into
@objectstack/spec/dataand taught the per-object resolution sites in@objectstack/lintto warn when a reference resolves to an injected anchor with no storage behind it on an ADR-0015externalobject. That covers the two rules that resolve fields per object today:validate-expressions.ts(buildFieldIndex/ the object-bound expression surfaces),validate-semantic-roles.ts(stageField/highlightFields).The filter-position field checks are structurally different: they judge a field name against the object-independent blanket union
SYSTEM_FIELDS(packages/lint/src/system-fields.ts), which by design answers "could this name be a system column anywhere" and therefore never flags a system name. Measured read sites:packages/lint/src/validate-widget-bindings.ts:479(dashboard filter effective field),packages/lint/src/validate-react-page-props.ts:476(aggregate/filter field refs),packages/lint/src/validate-page-field-bindings.ts:343,packages/lint/src/validate-flow-template-paths.ts:100(CRUD-nodefiltertemplate paths).So
filter: [["owner_id", "=", "..."]]on a view/widget/page bound to a federated object lints clean while the runtime degrades exactly as #8116's warning describes (on SQLite: constant-false, HTTP 200, zero rows, no error).Why it did not ride #8116's PR
Attaching the marker at these sites first requires converting each rule from the blanket union to the per-object derivation (
injectedColumnsFor/unprovisionedInjectedColumnsFor) — #5378-shaped work with its own false-positive analysis per surface (each rule's tolerance for names it cannot resolve differs). The #8116 ruling scoped that card to the provenance predicate move only. The spec-side prerequisite now exists, so this is pure lint wiring.Pointers
unprovisionedInjectedColumnsFor(packages/lint/src/system-fields.ts, finding: author-time expression validation resolves injected anchors on external objects but cannot warn they are unprovisioned — the #7865 provenance marker is unreachable from @objectstack/lint #8116) overunprovisionedInjectedColumns(@objectstack/spec/data).warnUnprovisionedAnchorsinpackages/lint/src/validate-expressions.ts.SYSTEM_FIELDSlists in packages/lint should derive from the spec's declarations #4330 (the blanket union's origin and its deliberate cost asymmetry), Author-time expression validator is blind to registry-injected system columns —record.owner_id/created_at/organization_idare rejected as unknown fields #5378, [Decision]applySystemFieldsinjects platform anchors intoexternalobjects the platform provisions no storage for — three consumers have now independently re-derived "that column is not really there" #7865, finding: author-time expression validation resolves injected anchors on external objects but cannot warn they are unprovisioned — the #7865 provenance marker is unreachable from @objectstack/lint #8116.Generated by Claude Code