Repository navigation
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
Description
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.formulato a storedField.text, with the sameexpression(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 (
contact9/9,lead21/21,forecast7/7); - the six whose title reads one are mostly wrong (
product0/13,knowledge_article0/24,case1/38,account4/9,quote4/6;campaign7/7). - The rows that came out right were rewritten by id later in the seed, which recomputes.
- the three objects whose title reads no autonumber are all correct (
- Single inserts as the dev admin through REST (
POST /api/v1/data/<object>):crm_caseanswers 201 and storesdisplay_titlenull besidecase_numberCASE-00039. The expression isrecord.case_number + " - " + record.subject.crm_productstores "Probe 2230 product" withoutPRD-0014. Itshas(record.product_code) ? … : record.namefallback 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
autonumbercolumn, 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:
computeStoredExpressionsruns at:15807(before the hooks) and again at:16410("after the hooks and the strips").applyAutonumbersissues 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, afterapplyAutonumbersand 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:
- Related:
- import: a lookup cell that names the record by the target object's title field answers reference_not_found — resolveRef never reads nameField, and a formula title is not matchable #24981 (the ruling that prescribes this shape);
- spec(data): once PR #24673 lands, a client value for a stored-expression field is overwritten with no report —
DroppedFieldsEvent.reasonhas no value for "written, but recomputed", soonFieldsDropped/droppedFieldsstay silent #24690 and feat(spec,objectql): report a caller value a stored expression replaced, as DroppedFieldsEvent reason stored_expression #24778 (closed: reporting a client value a stored expression replaces); - objectql 18.x: under
strictReadonlyWrites, refuse a write whose value a stored expression replaces (stored_expression), the deferred half of #24690 #25000 (open: refusing such a write understrictReadonlyWrites); - ADR-0079 D3, the validate-record-title lint and formulas.mdx still steer a composite record title into a formula field, which ruling 6308445871 says cannot be matched on import (use a stored computed field) #25071 (open: the docs and lint that steer a composite title into a formula).
- None is about the insert order against autonumber. New.
Generated by Claude Code
Activity