Skip to content

validate / lint / build accept a lookup or master_detail whose reference names an object that exists nowhere — the dangling target is found only at runtime #16611

Description

@hotlong

Symptom

objectstack validate, objectstack lint and objectstack build all exit 0, with no diagnostic of any severity, for a Field.lookup (and Field.masterDetail) whose reference names an object that is declared nowhere — neither in the stack nor in the platform-provided object registry. The metadata ships, and the target is discovered only at runtime: the record picker for that field asks the REST layer for an object that is not registered (404 / OBJECT_NOT_FOUND), $expand on the field fails, and the object's own form renders a lookup control that can never resolve.

Measured on @objectstack/spec / @objectstack/cli / @objectstack/lint 17.3.0, in the objectstack-ai/hotclm app (9 objects, requires: ['ui']).

Minimal repro

In any ObjectSchema.create({...}) add:

zzz_probe: Field.lookup('zzz_object_that_does_not_exist', { label: 'Control probe' }),

Then:

pnpm validate   # ✓ Validation passed — Data: 9 Objects 144 Fields, no finding
pnpm lint       # ✓ All checks passed (one unrelated rollup/missing-summary suggestion)
pnpm build      # ✓ Build complete

Same result for a plausible cross-package spelling (Field.lookup('crm_contract', …) in an app that does not ship HotCRM) — which is the case that made this visible: a card asked "declare the cross-package lookup only if validate accepts it", and validate cannot answer that question at all.

Why nothing catches it

  • packages/spec FieldSchema requires reference to be present and non-empty on lookup / master_detail ([spec] FieldSchema accepts a lookup/master_detail with no reference target, though its own TSDoc calls the key required #13632 closed that hole), but says nothing about the target existing.
  • packages/lint/src/validate-object-references.ts (the object-reference-unknown rule, ADR-0072) deliberately covers "the reference sites no other rule owns": action params, dashboard globalFilters[].optionsFrom.object, dataset object, navigation requiresObject / requiresService / objectName. Field-level reference is not on the list.
  • defineStack's validateCrossReferences hard-fails on hooks, view data, seeds, mappings, permission grants, nav objectName and action targets — not on field references.
  • #4441 covers a related but different gap (a lookup VALUE — a row id — that does not exist, refused on the write path since then); the object-level target is a different hole.

So the one metadata reference every record form depends on is the one no gate reads.

Expected capability

A finding on the field's reference target, with the same severity ladder validate-object-references.ts already implements for its other surfaces:

  1. resolves in the stack's own objects → OK;
  2. resolves in PLATFORM_PROVIDED_OBJECT_NAMES (e.g. sys_user, which Field.user() targets) → OK;
  3. unresolved, not platform-prefixed → error at validate / build;
  4. unresolved, platform-prefixed but unknown → the existing advisory.

Cross-package references (an app that expects a sibling package to provide the target, e.g. HotCLM's clm_contract.crm_contract → HotCRM's crm_contract) need a declared escape rather than a silent pass — e.g. an authored crossPackage: true / externalObject marker on the field, or resolution against requires / composition — so the reviewer sees the choice in the diff instead of the gate being blind to every spelling.

Where it was found

hotclm issue #2 (card 02, contract domain): the card's condition "declare crm_contract only if objectstack validate accepts a cross-package reference" turned out to be vacuous — validate accepts every reference, including a control probe to a nonexistent object. The field was left out of that PR (objectstack-ai/hotclm#5) rather than shipped as a dangling reference. Per hotclm AGENTS.md ("Platform gaps: report, never patch") this issue is the report; the docs/PLATFORM_GAPS_FROM_TEMPLATES.md append is left to whoever picks this up here.

Activity

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

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions