What
The spec's defaultValue runtime token current_user (@objectstack/spec/dataDEFAULT_VALUE_TOKENS, #7127 family — legal on user fields and lookup with reference: 'sys_user') is resolved only by the engine at INSERT time (objectql/engine.ts — isCurrentUserDefaultToken → out[f.name] = execCtx.userId). ObjectForm resolves neither this token nor any dynamic default client-side: a new-record form renders the field empty, and the value appears only after save.
Why it matters (live prod repro, 2026-08-22)
Env os-6vp51e.objectos.ai, app app.v4b4 (报销流程): the owner asked the build agent 「报销单申请人默认不应该就是自己吗?」. The agent authored the spec-correct metadata —
"applicant": { "type": "lookup", "reference": "sys_user", "defaultValue": "current_user" }— and the engine WILL stamp the actor on save (verified: an untouched lookup is omitted from ObjectForm's insert payload — server error text "insert … did not supply 'project'" proves absence, not '' — so the omitted-or-null default path fires). But the user opened the new-record form, saw 申请人 empty, and reasonably concluded the change did not work. Two sessions of back-and-forth followed. The "default = current user" a user asks for IS form pre-fill; engine-on-save alone reads as broken.
Ask
When building the initial values for a create form, resolve defaultValue: 'current_user' on user / lookup→sys_user fields to the session user (id + display), the same way static schema defaults are seeded today (the objectui-form-defaults-and-falsy seam). The token spelling must come from @objectstack/spec (DEFAULT_VALUE_TOKEN_CURRENT_USER), not a local literal — that drift is exactly how #4560 happened engine-side. NOW() on date/datetime deserves the same treatment while in there. Engine-side resolution stays as the authority for non-form writers; the form seed is a UX mirror, and an untouched pre-filled value submits the same id the engine would have chosen, so no behavior fork.
Cross-refs: engine token application packages/objectql/src/engine.ts (#4560/#4597 comments); agent-side narration fix tracked in cloud#1584 (D2 addendum).
What
The spec's
defaultValueruntime tokencurrent_user(@objectstack/spec/dataDEFAULT_VALUE_TOKENS, #7127 family — legal onuserfields andlookupwithreference: 'sys_user') is resolved only by the engine at INSERT time (objectql/engine.ts—isCurrentUserDefaultToken→out[f.name] = execCtx.userId). ObjectForm resolves neither this token nor any dynamic default client-side: a new-record form renders the field empty, and the value appears only after save.Why it matters (live prod repro, 2026-08-22)
Env
os-6vp51e.objectos.ai, appapp.v4b4(报销流程): the owner asked the build agent 「报销单申请人默认不应该就是自己吗?」. The agent authored the spec-correct metadata —— and the engine WILL stamp the actor on save (verified: an untouched lookup is omitted from ObjectForm's insert payload — server error text "insert … did not supply 'project'" proves absence, not
''— so the omitted-or-null default path fires). But the user opened the new-record form, saw 申请人 empty, and reasonably concluded the change did not work. Two sessions of back-and-forth followed. The "default = current user" a user asks for IS form pre-fill; engine-on-save alone reads as broken.Ask
When building the initial values for a create form, resolve
defaultValue: 'current_user'onuser/lookup→sys_userfields to the session user (id + display), the same way static schema defaults are seeded today (theobjectui-form-defaults-and-falsyseam). The token spelling must come from@objectstack/spec(DEFAULT_VALUE_TOKEN_CURRENT_USER), not a local literal — that drift is exactly how #4560 happened engine-side.NOW()on date/datetime deserves the same treatment while in there. Engine-side resolution stays as the authority for non-form writers; the form seed is a UX mirror, and an untouched pre-filled value submits the same id the engine would have chosen, so no behavior fork.Cross-refs: engine token application
packages/objectql/src/engine.ts(#4560/#4597 comments); agent-side narration fix tracked in cloud#1584 (D2 addendum).