Skip to content

finding(app-shell): data.* lints CLEAN at scope:'record' and resolves against the host's ambient data, never the record — visibleWhen/readonlyWhen/requiredWhen silently constant-false today #8166

Description

@os-justin

Filed unlabelled by the objectui PM seat (session session_01YBWFb5YgMU5dw8p2VKj16S) for triage to grade. Found during contract review of #8164; ⛔ not folded into that PR — this predates it and has a different fix surface.

Sibling to #8155, and the opposite failure from the same list: #8155 is a root that is bound but refused; this is a root that is accepted but dead.

What

@objectstack/formula's SCOPE_ROOTS contains data (measured dump in #8155). So at scope: 'record' the authoring lint accepts data.status == 'x'. But objectui#5741 (Phase 2 of the #5330 canon) retired data.* on record surfaces — it does not name the record. The tree already knows this: packages/core/src/evaluator/rowPredicateCanon.ts:36-38 records data.status as "⚠️ silently accepted" by the authoring oracle.

The result is a green lint on an expression that is constant-false at runtime — the exact silent-death shape #7727 was filed to abolish, on surfaces #7727 does not touch.

This is live on main today, independent of #8164

Authoring side — already at record scope before #8164:

site what it authors
inspectors/ObjectFieldInspector.tsx:874 visibleWhen
inspectors/ObjectFieldInspector.tsx:888 readonlyWhen
inspectors/ObjectFieldInspector.tsx:902 requiredWhen
inspectors/ObjectFieldInspector.tsx:760 formula expression (role:'value')
views/metadata-admin/clientValidation.ts:792, :806 the draft-level validator

Runtime side — the chain that makes data resolve to the host's bag rather than the record:

providers/ExpressionProvider.tsx:123 → buildExpressionScope (:82-90) binds ambient `data`
  → PredicateScopeProvider → usePredicateScope()
  → packages/components/src/renderers/form/form.tsx:1213, 1426, 1491
  → evalFieldPredicate(..., scope)
  → packages/core/src/evaluator/fieldRules.ts:174-178   ← lands as `extra`

So visibleWhen: "data.status == 'x'" lints clean, resolves against the host's ambient data, and is constant false for every record. No error, no warning, no signal to the author — the field simply never appears.

Why it is worth its own card

The data case is nastier than #8155's app case in exactly the way that matters: app fails loudly (a blocking lint error the author cannot miss), data fails silently. #7727's whole thesis is that the silent direction is the one that costs an author real time.

It is also not fixed by dropping data from any advertised-roots list. De-advertising stops autocomplete recommending it; the lint still accepts it, so every already-authored data.* predicate stays green and stays dead. The accept set is the engine's.

Fix shape (for triage, not ruled)

Same producer/consumer split as #8155, and the two should probably be decided together:

⛔ Not the answer: filtering the diagnostic in celAuthoring.ts. There is no diagnostic to filter — the problem is the absence of one.

Related

Dedup

Searched open and closed. #8155 covers the app mirror. Nearest closed hits are different surfaces and different mechanisms: #4807 (record:alert bare scope), #5687 (SchemaRenderer resolving data.* against the data-source adapter), #5454, #5776. No open card names data against the record-scope accept set on the field-rule surfaces.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions