Skip to content

objectql: a stored field's expression is computed on insert before the autonumber is issued, so an expression that reads the record number stores null (or its has() fallback) until a later update by id #25073

Open

Description

@objectstack-fleet

Filing gate ① a product defect with reach measured. The defect was measured by the os-dev on objectstack-ai/hotcrm#2230, which executes #24981 ruling 6308445871 (maintainer 「其他同意」): "a composite title that must round-trip through import is a stored computed field". The run was on HotCRM main c8a7a704 with @objectstack/* 18.0.0 (framework 06cab4849), on the @objectstack/verify boot with the seed replay. Filed by the repo:hotcrm seat 2 (os-support-ai, session session_01KqkTQNLcxVc588eZpJmp1r). ⛔ Not a claim. Grade: triage's.

Reader (who acts): objectstack domain:engine triage. The fix lands here. objectstack-ai/hotcrm#2230 carries Blocked-by: this card and resumes on the @objectstack release that carries the fix.

The contract

FieldSchema.expression (packages/spec/src/data/field.zod.ts:1856 at 06cab4849): "On any other (stored) field: computed by the engine from the row the write stores and stored … on every insert and every update by id".

A row the insert stores carries its issued record number. So an expression that reads an autonumber column should store the value with the number in it.

The finding, as measured

  • Setup: HotCRM's nine record titles switched locally from Field.formula to a stored Field.text, with the same expression (the shape the ruling prescribes). The change was not committed.
  • On a seeded boot, 53 of 134 stored titles equal the pre-migration formula value:
    • the three objects whose title reads no autonumber are all correct (contact 9/9, lead 21/21, forecast 7/7);
    • the six whose title reads one are mostly wrong (product 0/13, knowledge_article 0/24, case 1/38, account 4/9, quote 4/6; campaign 7/7).
    • The rows that came out right were rewritten by id later in the seed, which recomputes.
  • Single inserts as the dev admin through REST (POST /api/v1/data/<object>):
    • crm_case answers 201 and stores display_title null beside case_number CASE-00039. The expression is record.case_number + " - " + record.subject.
    • crm_product stores "Probe 2230 product" without PRD-0014. Its has(record.product_code) ? … : record.name fallback took the empty branch.
    • Control: crm_lead (no autonumber in its title) stores "Pro Be - Probe 2230 Inc", correct.
  • Reach: every object whose stored-expression field reads an autonumber column, in any app, on every insert. The ruling directs HotCRM's nine titles to exactly this shape, and six of them read a record number.

Seat review (source at 06cab4849, unchanged on origin/main 688052e147)

packages/objectql/src/engine.ts, insert path:

  • computeStoredExpressions runs at :15807 (before the hooks) and again at :16410 ("after the hooks and the strips").
  • applyAutonumbers issues the record number afterwards, at :16466. Its own comment places it after validation on purpose ("no validation rule can depend on the value").
  • Nothing recomputes the stored-expression plan once the number is issued.
  • When the driver owns autonumber (driverOwnsAutonumber), the number arrives at the write itself, later still.

Direction (the reader's call):

  • Recompute the stored-expression plan for the fields whose expression reads an issued autonumber, after applyAutonumbers and before the row is written;
  • or issue the number before the second stored-expression pass.
  • Either way, the driver-owned path needs an answer too.
  • A pin: insert into an object whose stored expression reads its autonumber, and read the stored value back.

Dedupe

Method: every objectstack-ai/objectstack issue title (every state), listed through the repo-scoped issues?state=all endpoint and refreshed with since=2026-10-21. Matched case-insensitively on autonumber combined with expression / formula / stored / computed / title / order, and on stored expression / computeStoredExpressions / #24673 / #24981. The search API is refused for this session.

Results:


Generated by Claude Code

Activity

  1. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    priority:p1High: required for production / M2
    on Oct 21, 2026
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

    area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:enginepm:queuepriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions