Skip to content

lint: a field-typed rule cannot see registry-injected temporal columns (created_at / updated_at) — the object graph carries their names, not their types #16340

Description

@huangyiirene

Found while implementing #16106 (the field-typed arm of filter-preset-comparand; PR pending on branch claude/issue-16106-preset-comparand-field-typed). Read-only observation, report-first, unassigned, no label — triage decides.

What

@objectstack/lint's object graph (packages/lint/src/object-graph.ts, GraphObject.injected) records the registry-injected system columns by NAME only: injectedColumnsFor returns resolveInjectedSystemColumns(def).names (packages/spec/src/data/injected-system-columns.ts). A resolveFieldPath verdict on such a leaf is { kind: 'ok', injected: true } with no meta.type, and FieldPathVerdict's own contract says a second question about that leaf ("is it temporal?") is unanswerable there.

Consequence for the arm #16106 lands: on a dashboard widget bound to a dataset on crm_opportunity, close_date: 'last_30_days' (an author-declared date column) is refused at lint time with the window named, while created_at: 'last_30_days' on the same widget passes lint and the runtime publish gate — and created_at / updated_at are the most common temporal filter columns an author reaches for.

Measured

Worktree at origin/main 4a1a3b0c25, ObjectQL + @objectstack/driver-memory, an object declaring no created_at of its own (the registry injects it):

where engine
{ created_at: 'last_30_days' } REFUSED INVALID_FILTER / 400 — … compares a declared datetime field against "last_30_days" at where.created_at …
{ updated_at: { $in: ['last_30_days'] } } REFUSED INVALID_FILTER / 400 — … at where.updated_at.$in[0] …
{ created_at: { $gte: '{30_days_ago}' } } 200, 30 rows (positive control)

So the engine door refuses it with the registry's field map in hand; only the authoring-time layer cannot see the type. Failure direction: a MISSED CATCH — the authoring gap #16106 closes stays open for exactly these columns — never a false refusal.

Where a fix would go (not decided here)

resolveInjectedSystemColumns is the one derivation the registry's applySystemFields consumes. If its plan carried each injected column's declared type (the same datetime the registry injects), object-graph.ts could expose it on GraphObject.injected (or on meta for an injected leaf) without lint hand-copying "created_at is a datetime" — the second copy system-fields.ts's header forbids. Every field-typed rule, this one and any later one, would inherit it in one edit.

Dedupe

Searched "lint object graph registry-injected system columns created_at updated_at carry no field type": 5 hits (#16119, #15922, #16083, #16118, #8116). #8116 (closed) is the provenance-marker sibling — whether an injected anchor is unprovisioned — not its type. None names this.

Follow-up to #16106; not blocked by it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions