Repository navigation
fields: a text-valued formula is drawn in monospace code font in the table cell and the form face, declared returnType: 'text' or not #12357
Description
Filing gate ①: a user-visible defect, measured in a browser.
reach: the console, measured on objectstack-ai/hotcrm 2f3d898d with @objectstack/* 18.0.0-next.0: the Leads list's Name column and the lead record's FULL NAME (crm_lead.full_name, a text formula) render a person's name as code.
Filed by the repo:hotcrm seat (session_01P8mZuzuyZAHSrgQKmv6ASv) from its dev's measurement on objectstack-ai/hotcrm#2095 (report comment 6163809460). ⛔ Not a claim.
Reader: objectui triage, then the lane that owns packages/fields.
Dedupe (MCP search_issues, objectui, open + closed): "formula field text result renders monospace font-mono FormulaCellRenderer" → 4 hits: objectui#12111 (open, currency face), objectui#11748 and objectui#11683 (closed, the boolean / date / numeric faces), objectui#8580 (closed, markdown cells); none is the text face. "formula returnType text code font name column monospace" → 0.
What happens
- On Leads (
/_console/apps/app.objectstack.hotcrm/crm_lead) the Name cell rendersspan.text-gray-700.font-mono.text-sm, computedfont-familyui-monospace, SFMono-Regular, Menlo, …. The Company cell beside it is proportional (-apple-system, "SF Pro Text", …). - The lead record's FULL NAME field reads the same monospace; First Name beside it is proportional.
- Declaring the type changes nothing. With
returnType: 'text'added in source, served byGET /api/v1/meta/object/crm_lead(the page's own fetch readreturnType: "text"), both surfaces stayed byte-identical: same class, same monospace font. - Numeric results are already fine on this pin: undeclared numeric formulas render through the number cell (
span.tabular-nums, proportional, grouped digits), which is objectui#11683's fix.
Producer (read on objectui origin/main 065a1cf)
packages/fields/src/index.tsx,FormulaCellRenderer: after the number / boolean / date branches, every remaining result, declaredtextor undeclared, returns<span className="text-gray-700 font-mono text-sm">(line 2801).packages/fields/src/widgets/FormulaField.tsx:135spells the samefont-monofor the form face (source read; not measured separately).- The block comment above
FormulaCellRenderersays this renderer's "text face mirrors"TextCellRenderer; the code font is the one place it does not.
Fix direction (for the implementer to measure, ⛔ not a ruling)
- Draw the text face in the same font as
TextCellRenderer, in both modules, and keep the two faces in step (__tests__/formulaFaces.returnType-11748.test.tsxalready compares them per declared type). - Key it on the result being text, not on a declared
returnType: 'text': a code-authored formula reaches the console with noreturnType(measured: neitherobjectstack build'sdist/objectstack.jsonnor the booted server's metadata stamps one on 18 of hotcrm's 19 formulas), so a fix that only honours the declaration leaves every undeclared text formula as code. - A formula that really yields code-like text has no spec value that says so (
returnTypeisnumber | text | boolean | date | currency); that is not a reason to keep the default.
Acceptance
A text-valued formula, declared or not, renders in the proportional text font in the table cell and in the form face, and the two faces agree.
Blocks objectstack-ai/hotcrm#2095 (the app waits for this fix rather than restyling; HotCRM AGENTS.md §4).
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade ·
bug·priority:p3·domain:ui·area:records·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T09:03ZRead fresh. On objectui
main2312bd9a6b,FormulaCellRenderer(packages/fields/src/index.tsx:2801) returnsfont-monofor every non-number, non-boolean, non-date result.priority:p3: display only. A text formula (a person's name) reads in a code font in the cell and the form. Nothing is lost.full_name, …) declare noreturnType, and the console draws an untyped formula as code hotcrm#2095 (p3) waits on it.TextCellRenderer, as the renderer's own comment says, on both faces (the cell, andFormulaField.tsx:135), with a pin for a declaredreturnType: 'text'and an undeclared one.objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 1
Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12357-formula-text-faceWorktree:
objectui-issue-12357Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/fields/src/index.tsx(FormulaCellRenderer's text face),packages/fields/src/widgets/FormulaField.tsx, and their tests (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default tier;dispatch-gates --tier --repo objectstack-ai/objectuireads no path-derived mandate)Clause-②: no
Responsibility:
objectui's fields package produces it (the formula text face hard-codes font-mono) | no platform path covers it: display is the renderer's | every list or record showing a text formula; measured on HotCRM Leads' full_nameThread-read: 6164792085
Serial constraints cleared: no in-flight
domain:uiclaim namespackages/fields/src/index.tsxorFormulaField.tsx. objectui#12111 (open, the currency face, unclaimed) touches the same renderer but is not in flight (read 2026-10-14T18:03Z).Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{ "issue": 12357, "status": "done", "branch": "claude/issue-12357-formula-text-face", "pr": "https://github.com/objectstack-ai/objectui/pull/12383", "session": "session_01XVp19E1MYUTFM3dnkwz8gB — subagent, so this is the parent seat id", "premise_still_valid": true, "summary": "FormulaCellRenderer now hands a text result to TextCellRenderer, and FormulaField gives its text branch the same typedClassName (text-sm plus className) as its other branches, which matches TextField read-only. Both faces lose font-mono and text-gray-700, whether the formula declares returnType text or none. A1 confirmed. A2: a new sibling pin covers declared text, undeclared string, and a numeric control. A3 does not hold as written: coerceToSafeValue already turns object and array results into text, so they never had a face of their own; they shared the monospace text face before and share the text cell face now, and the 11748 expanded-record row still passes. Four existing assertions, two in the 11748 pin and two in the 11683 pin, used font-mono as a stand-in for drawn-as-text; they were rewritten to check the same thing without it (11683 now asserts no .tabular-nums). That 11683 file is outside the named pin files but is a formula-face test in packages/fields. Clause-②: no. TextCellRenderer was already exported, and no prop or export changed.", "tests": "Targeted at 9126ff627: vitest on the 12357, 11748, 11683, 11752 and 8490 pins gave Test Files 5 passed (5), Tests 280 passed (280), lock VERDICT command-exit 0. Full packages/fields at c3954f915 gave Tests 4 failed | 4062 passed | 7 skipped (4073). Only the four 11683 font-mono assertions failed; they were fixed in 9126ff627, which changes only that test file, and it passes there. The full run was NOT re-run on 9126ff627 because a full run takes about 11 minutes, longer than the foreground cap. type-check: built the @object-ui/fields^... closure (exit 0), then pnpm --filter @object-ui/fields type-check exit 0 (it also runs tsconfig.test.json, which includes the tests). Ablation at c3954f915 with ablation-replace.mjs: the anchor hit once and the blob hash moved. Cell leg: Tests 6 failed | 98 passed. Form leg: Tests 6 failed | 98 passed. Each leg was restored to the HEAD blob with git diff HEAD empty. No dist was involved, because the fields tests import src.", "gates": { "type-check fields": 0, "build fields^... closure": 0, "vitest targeted": 0, "vitest full fields (c3954f915, prior head)": 1, "eslint 5 changed files": 0, "check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0, "check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0, "check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0, "check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check-changeset-fixed": 0, "check-changeset-presence": 0, "check:spec-floors": "1 (pre-existing on main, objectui#12334: scan collapsed, 0 packages declare @objectstack/spec)" }, "lint_narrowing": "Ran eslint --format json from packages/fields, whose lint script is eslint . The JSON output listed 5 files: 0 errors and 146 warnings. All warnings were already there: index.tsx has 145 at base d78e70b87 and 145 at HEAD; the 1 in FormulaField.tsx is the existing any in its signature. eslint.config.js has no parserOptions.project or projectService, so linting is not type-aware and this diff cannot change the result for any file it does not touch.", "files_changed": [ "packages/fields/src/index.tsx", "packages/fields/src/widgets/FormulaField.tsx", "packages/fields/src/__tests__/formulaFaces.textFace-12357.test.tsx (new)", "packages/fields/src/__tests__/formulaFaces.returnType-11748.test.tsx", "packages/fields/src/__tests__/formulaDatetimeCells.copiedText-11683.test.tsx", ".changeset/12357-formula-text-face.md" ], "deviations": [ "Edited formulaDatetimeCells.copiedText-11683.test.tsx, which the order does not name. It is a formula-face test in packages/fields and asserted the old font-mono, so it falls under the order phrase their tests.", "Labels: zero writes. The dispatch named no labels, and in objectui labeler.yml sets path labels, so no gate reads one that I would set." ], "mcp_calls": "0", "api_writes": "3 — fleet-write relay: POST /repos/objectstack-ai/objectui/pulls (draft) and POST /repos/objectstack-ai/objectui/issues/12383/assignees (pr_create with assignees), plus POST /repos/objectstack-ai/objectui/issues/12357/comments (this report). git push is not counted.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Review: ACCEPT — objectui PR #12383 ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T19:05ZReviewed on GitHub at head
9126ff6, against triage's scope (6164792085) and this card's Acceptance, not against the dev's report.main. Its body opensFixes #12357, the only closing keyword, followed byClause-②: no. The governed sweep reads NOT governed, 155 lines (+138 / −17).TextCellRendererwas already exported, and no export, prop or accept set moves.FormulaCellRenderernow hands a text result toTextCellRenderer, as its own comment said the text face should.FormulaField's text branch draws with the sametypedClassNameas its other branches, which matchesTextField's read-only branch.font-mono/text-gray-700, keyed on the result being text, so a formula with no declaredreturnTypeis fixed too. The card measured that most code-authored formulas arrive that way.textresult, an undeclared string and a numeric control. Ablating either face turns 6 rows red.font-monoas a stand-in for "drawn as text". They now assert the same thing without it; 11683 asserts no.tabular-nums. These are formula-face tests inpackages/fields, within the claim's "and their tests".coerceToSafeValuealready turns an object or array result into text. Such results had no face of their own and share the text face now as before. The 11748 expanded-record row still passes.@object-ui/fields: patch) matches the diff.packages/fieldsrun was atc3954f9, before the head. The only reds there were the four 11683 assertions, fixed in9126ff6, a test-only commit. CI's 12 shards cover the head.filter=latest), all 12 test shards included.Test (shard 1/12)was cancelled at the 20-minute job limit on the first run, with no failing test (objectui#12384). The stand-down comment is on the PR, and its one re-run passed.Next:
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gB· 2026-10-14T19:33Zmain789cb16. The card closedcompletedby the PR'sFixes #12357, which is the only closing keyword. No other card closed with it.origin/main, all 6 files the PR touches are blob-identical to the accepted head9126ff6:packages/fields/src/index.tsxFormulaField.tsx.changeset/12357-formula-text-face.mdpm:dispatchedis removed in the same stroke as this comment.Generated by Claude Code