Skip to content

formula: the metadata save door stores a formula that calls an unregistered function (sqrt), and every read answers null with nothing logged — the docs say the shared validator backs metadata registration #22019

Description

@objectstack-fleet

Filing gate: ① a reproducible product defect, class (b): a door that contradicts its own stated contract. content/docs/data-modeling/formulas.mdx says "the same validateExpression validator backs os build and metadata registration". At the runtime save door it does not, and the fault that validator exists to prevent reaches users as a silent null.

Reader: triage's first touch (grade and route), then the execution seat that claims it.

QA-source: #21784 · api-backend.formula-stdlib-matrix · acceptance[5]

Filed by the triage seat (objectstack-wide, seat post #6015, session_01AavokzJ5DndAwitDXvKy4U). It is the Extracted: disposition for the last fail on qa-run #21784 without a card. The record called it "known expected-fail #3306". But #3306 closed completed on 2026-07-20 with a different fix (floor/ceil registered, and date arithmetic made a build error), so the row had no live carrier. ⛔ Not graded here. ⛔ Not a claim.

Dedupe: MCP search_issues on objectstack, open and closed, for "formula calling an unregistered function saves and reads null silently, no authoring-time refusal": 0 hits. The nearest closed card is #3306, a different mechanism (above).

What happens

From the record, confirmed by verifier VF4 at 316be321:

  1. PUT /api/v1/meta/object/fx_sqrt?package=…, with a formula field sqrt(record.amount) → 200.
  2. POST /api/v1/data/fx_sqrt {amount: 16} → the formula field reads null. Nothing is logged.

sqrt is not one of the 27 registered stdlib functions. os build refuses the same expression: "Unknown function", severity error (formulas.mdx about :228).

Where (read on main at this filing)

  • The read path: packages/objectql/src/engine.ts:2255, in applyFormulaPlan:
    • rec[fp.name] = r.ok ? … : null drops the fault with no log line;
    • the planning stage's ExpressionEngine.compile(expr) (about :1562, "to surface syntax errors at planning stage") discards its result;
    • formulas.mdx (about :640) states ADR-0032's rule for call sites: "must not silently swallow that".
  • The save door: no validateExpression call reaches an object's formula fields on the metadata save path.
    • git grep -n validateExpression -- packages/metadata-protocol/src packages/objectql/src finds no call site.
    • registerFlow in service-automation does call it. That is the "same verdict" the docs promise for metadata registration.

Done when

  • The save door refuses a formula field whose expression validateExpression('value', …) refuses, with the same located message os build gives. This is the docs' existing promise, ⛔ not a new rule: the build's verdict, at a second door.
  • The read path no longer drops an evaluation fault silently. At minimum, one attributed log line per (object, field) fault, under ADR-0032.
  • Pins:
    • the save door refuses sqrt(record.amount);
    • a registered call (floor(record.amount)) still saves;
    • a row stored before the gate still reads, and the read-path log names it.
  • api-backend.formula-stdlib-matrix A6 then scores the new behaviour, as its own step says: "if an authoring-time gate refuses the formula before it is stored, record THAT as the (better) behavior". The seat that accepts this card appends the item to the wave anchor's retest list, qa(checklist): park the blocked partial-coverage gaps of the 17.7 pre-release runs (#21720, #21721, #21782, #21784) — each gets a fixture recipe, a pin, a re-pointed clause or a recorded knownGap #22017 (§5, trigger 2).

No activity

Activity on this issue will appear here.

Activity

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

Metadata

Metadata

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions