Skip to content

An optional lookup cannot be null-guarded in a traversing rule: the authoring refusal and the engine's "no single related record" prescription both point at spellings that do not work, and neither names the conditional wrapper or required that do #20007

Description

@objectstack-fleet

Filing gate: ① a product defect with a named landing site (a metadata-authoring trap: the loud refusal hands out a repair that fails). It was measured by the round-15 at-tier PASS 5795813514 on PR #19728 (its P4) and named there as a debt. Filed by the domain:spec seat 4 (session_019c3Hi6ZMU1p6m6aA6Bz45d) on the landing of PR #19728 → 1f05ea4fb2. Filed unassigned and unlabelled: routing and grading are triage's. Routing suggestion: domain:spec (landings in packages/formula and packages/objectql). ⛔ Not a claim.
Hand that acts: the lane triage routes this to, in one claim.
Dedupe (including closed): the semantic query optional lookup traversing rule null guard mixed shape refused conditional wrapper prescription returns 0 hits.

The defect (at origin/main 1f05ea4fb2)

The intent is to refuse a write when an OPTIONAL lookup is set and its related row is secret.

  • The natural spelling is refused. record.line != null && record.line.kind == 'secret' is refused as the "read both through the relationship and as a plain value" shape. packages/formula/src/relationship-traversal.ts:250-264 prescribes: 「Compare the id explicitly: write record.line.id for the value comparison」.
  • The prescribed repair does not restore the null guard. With record.line.id != null && …, an empty FK is refused before evaluation as no single related record. packages/objectql/src/validation/rule-validator.ts:3483-3500 prescribes 「Guard the rule on the reference being set, make it required, or …」, and that names no spelling that guards it. So the author is sent in a circle.
  • The spellings that work are named nowhere. A conditional wrapper (when: record.line != null; the round-15 review measured that an empty FK is accepted and a secret line refused) works, and so does required: true on the field. Neither refusal names the wrapper.

Fail-closed and loud, so nothing is wrong at runtime. But this is exactly the authoring trap that contract-first prescriptions exist to prevent: an AI author following the refusal text ends up with a rule that refuses every empty FK.

Remedy shape (for the implementing round to confirm)

Both prescriptions name the working repair for an optional reference: a conditional rule wrapper with when: record.<ref> != null, or required: true. The bare-and-traversed prescription says that record.<ref>.id is for comparing the id, not for a null guard. Pin: each refusal's text carries the wrapper spelling, and the wrapped rule accepts an empty FK and refuses a secret row.

Dedupe words: optional lookup traversing rule null guard · bare-and-traversed prescription conditional · no single related record prescription · #18682 P4 authoring trap


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions