You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(lint,spec,objectql): resolve registry-injected system columns at author time (#5378) (#5904)
`buildFieldIndex` (validate-expressions.ts) and the `highlightFields`
existence check (validate-semantic-roles.ts) resolved field references
against the AUTHORED `fields` map only, so every registry-injected system
column was invisible: `has(record.owner_id)` was hard-rejected as an unknown
field and `highlightFields: ['owner_id']` warned that the column "is not a
field on this object". The platform's own linter denied the platform's own
contract, and apps escaped it by re-declaring system columns — hotcrm#548
declared `owner_id` on all 12 business objects for exactly this reason.
Add `resolveInjectedSystemColumns()` (@objectstack/spec/data): a pure
per-object derivation of WHICH system columns the platform provisions, and
make the registry's `applySystemFields()` consume it. Same split #3786
established for the audit family — the spec declares which columns exist,
the registry owns what each one looks like. `@objectstack/lint` (contract:
depends on spec, never on a runtime) reads the same derivation, so the
author-time verdict cannot disagree with the runtime that provisions the
column.
The union is CONDITIONAL per object, not a blanket allowance of every system
name: `ownership: 'org' | 'none'` gets no `owner_id`, so `record.owner_id`
there is still the error it should be; `tenancy.enabled: false` gets no
`organization_id`; `systemFields: { audit: false }` gets no audit family;
`systemFields: false` / `managedBy: 'better-auth'` get nothing but the
driver-provisioned `id`. Injected names also join the "did you mean?"
candidates.
The type-soundness and null-guard indexes deliberately stay declared-only
(reasons at each site): column types and nullability belong to the registry's
definitions, and the null-guard index feeds a build-breaking verdict.
Injection behaviour is unchanged — a new parity pin compares the derivation
against the live injection pass across the full condition matrix.
Fixes#5378
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments