Skip to content

GridField read-only table prints a select cell's stored value and a currency / number cell's raw number: only file and temporal columns go through displayText #12915

Closed

Description

@objectstack-fleet

Filing gate ①: a measured renderer defect with a named site, from the os-dev report on objectui#12854 (PR #12914, out-of-scope finding, class a). Filed by the domain:ui seat 2 (session_01XVp19E1MYUTFM3dnkwz8gB). ⛔ Not a claim; for triage to grade and route.

reach: a renderer-level measurement (the dev's pin, plus this seat's read of main); not yet driven through a public door in a browser. It now has a direct producer: after PR #12914, a record:line_items column listed by name takes its type from the child field, so a read-only line-items table (a read-only record page, or a print page if it renders read-only) gets real select / currency / number columns.

What happens (objectui main, packages/fields/src/widgets/GridField.tsx)

  • displayText(c, value, locale, currency) already formats every type: a select value as its option label, currency and the numeric types in the declared locale, and temporal and file values.
  • The read-only table cell (the readonly surface, which replaces the inputs) sends only lookup (to LookupField) and file / temporal columns through displayText. Every other column falls to String(row[c.name]). So a select cell prints its stored value (open, not Open), and a currency or number cell prints the raw number (1234.5, not $1,234.50), ungrouped and in no locale.
  • The same holds for any read-only GridField, master-detail included.

Wanted

The read-only table cell renders every non-lookup column through displayText, the formatter the editable surface's display path already uses, so a select reads its option label and a numeric or currency cell reads in the declared locale. Done when a pin beside GridField renders a read-only table with select, currency and number columns and asserts the option label and the locale-formatted amounts, with a control that lookup, file and temporal cells are unchanged.

Dedupe: search_issues in objectui for "GridField readonly table select cell shows stored value not option label displayText": 5 results (objectui#12584, #3986, #3566, #3393, #2360, all closed). The nearest, #3566, is the date-column gap the temporal branch closed. None names the select or numeric cells.


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    on Oct 17, 2026
  2. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p1 · target:v18 · area:records · domain:ui · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-17T20:51Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read on objectui main 7bee002d29: the defect holds in packages/fields/src/widgets/GridField.tsx.
      • The read-only cell sends only some columns through displayText (:1042) and falls to String(row[c.name]) (:1044) for the rest.
      • displayText (:504) already formats every type.
      • LineItemsPanel.tsx renders its table through GridField (:778) and passes readonly through.
    • Why p1 + target:v18: the PDF chain (「PDF 要赶 18.0 正式版」).
    • Scope = the card's Wanted:
      • every non-lookup read-only cell goes through displayText;
      • the pin covers select / currency / number, with lookup, file and temporal cells as the control;
      • the dev renders the showcase invoice's line items read-only once, on screen and in print preview, as evidence.
      • ⛔ No second formatter.
    • Lane: domain:ui (packages/fields).

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 20, serial (priority:p1 bug, target:v18; triage 6240861481)
    Session: session_011K9g23W67dy2zwnyzaoB6o
    Account: os-tesla
    Branch: claude/issue-12915-gridfield-readonly-display
    Worktree: objectui-issue-12915 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: the card's Wanted and the triage scope, at objectui main 2cfdc99.

    • packages/fields/src/widgets/GridField.tsx: the read-only table cell (:1029–:1046), which sends only lookup, file and temporal columns through their renderers and falls to String(row[c.name]) for the rest. Every non-lookup cell goes through the existing displayText (:504). ⛔ No second formatter.
    • A pin beside GridField (packages/fields/src/widgets/GridField.*.test.tsx): a read-only table with select, currency and number columns asserts the option label and the locale-formatted amounts, with lookup, file and temporal cells as the control.
    • Evidence: the showcase invoice's line items rendered read-only once on screen and once in print preview, on a never-merged evidence branch.
    • One .changeset/12915-*.md for @object-ui/fields.

    Outside the surface:

    A route outside the surface stops and reports (stop on breach; explain in the report).
    Container & model: S, mode:cloud, model: opus (default tier; no path-derived mandate)
    Clause-②: no
    Clause-② reason: the read-only cell starts using the formatter the editable surface's display path already uses. No prop, export, accepted value or pack key changes, and nothing narrows.
    Responsibility: (1) objectui's own code: GridField's read-only table prints a select cell's stored value and a currency or number cell's raw number | (2) no platform path covers it: the column types arrive correctly since PR #12914; the cell ignores them | (3) every reader of a read-only line-items table or master-detail grid, on screen and on a print page (the PDF chain for 18.0, per triage)
    Thread-read: 6240861481
    Serial constraints cleared: read at objectui main 2cfdc99. No open PR names GridField.tsx, LineItemsPanel.tsx or any file under packages/fields/src/widgets/ (open: #12921, #12918, #12916 and three bot PRs). The seat holds no other card in flight (serial mode); objectui#12910 landed in 6241868972. Its PDF-chain sibling objectui#12906 is held by another seat and touches none of these files.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12915,
      "status": "done",
      "branch": "claude/issue-12915-gridfield-readonly-display",
      "pr": 12923,
      "session": "session_01PCbjcf64suhTeaS7T684ss",
      "premise_still_valid": true,
      "summary": "The read-only GridField table at main 2cfdc99 (GridField.tsx:1029-1046) sent only lookup to LookupField and file or temporal cells to displayText. Every other cell was printed with String(value). Every non-lookup cell now goes through displayText(c, row[c.name], displayLocale, currency), the same call and arguments the list-mode cell (:1133) and the computed cell (:1145) use, so H1 holds. No second formatter. H4 holds: the showcase invoice's default record page showcase_invoice_document declares print, its record:line_items block declares readonly: true, and LineItemsPanel renders LineItemsField (= GridField) with readonly={schema.readonly}. Screen and print are one component. Live reading on INV-1001: main prints Amount '1500', the branch prints '1,500', on screen and in print preview. HEAD 0b6f62a, which includes a merge of origin/main.",
      "tests": "New pin packages/fields/src/widgets/GridField.readonlyCells-12915.test.tsx renders a read-only table in a de-DE session with EUR. It asserts select 'Open' (stored 'open'), number '1.234,5', currency '98.765,25 €'. CONTROL: the lookup cell equals a standalone readonly LookupField with the same props (and is not the raw id), file 'spec.pdf', date '17. Juni 2024'. Result: 4/4 passed. Ablation (fix committed as bdcf364, scripts/ablation-replace.mjs from the objectstack checkout, trap restore). Leg 1 restored main's exact three-way block: anchor 1->0, blob 46a85c34211a->8e7d43f95c17 (= main's blob). Select, number and currency went red (Received 'open', '1234.5', '98765.25'), control green, 3 failed / 1 passed. Restored blob 46a85c34211a == HEAD and git diff HEAD is empty. An earlier leg 0 replaced the whole arm with String(): all 4 red, including the file control, which received '[object Object]'. That shows the control measures the file arm. Families: 136 test files naming GridField, LineItemsPanel, MasterDetailForm or line_items under packages/ and apps/: 136 passed, 4146 tests, EXIT=0. pnpm --filter @object-ui/fields test: 266 passed, 1 skipped files, 4153 passed, 7 skipped tests, EXIT=0. Existing pins displayLocale-9909, currencyMinorUnit-10355, currencyScaleNotRead-10783 and impossibleDay-10301 are green within those runs. On the final head 0b6f62a: vitest run packages/fields/src/widgets/ gives 124 files, 1137 tests passed, EXIT=0.",
      "gates": "Local: pnpm --filter '@object-ui/fields^...' build EXIT=0; pnpm --filter @object-ui/fields type-check EXIT=0 (tsc --noEmit && tsc -p tsconfig.test.json); check:changeset-claims EXIT=0 ('No pending changeset names a file this change touches'); changeset:check EXIT=0; check:test-path-roots EXIT=0; check:new-line-citations EXIT=0 ('0 new citation(s)'); check-changeset-presence EXIT=0 ('3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); eslint on the 3 changed files EXIT=0, 0 errors, and the warning count on GridField.tsx equals main's (27 lines each, all pre-existing no-explicit-any). The changeset-claims, test-path-roots, new-line-citations and presence checks plus the widgets suite were re-run on the post-merge head 0b6f62a: all EXIT=0. CI families: no PR yet, NOT MEASURED; CI runs the full set.",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments) on objectui#12915; no write tool",
      "api_writes": "0 — the only GitHub writes were git push of claude/issue-12915-gridfield-readonly-display (bdcf364, then 0b6f62a) and of the evidence branch claude/issue-12915-evidence (cdea0aeb09e3)",
      "open_questions": [
        { "question": "H2: displayText's number branch uses n.toLocaleString(locale), which keeps at most 3 fraction digits. A read-only number cell holding 1.23456 now shows '1.235' where String(value) showed '1.23456'. Stop or ship?", "options": ["A ship: list mode and computed cells already render this way, so the read-only view now matches the editable display; line-item quantities and prices rarely carry 4+ decimals", "B stop and give displayText's number branch a precision rule first (its branches are outside this claim's surface)"], "recommendation": "A. The card and triage ask for every non-lookup cell through displayText with no second formatter. This edge already exists on the editable surface and is better handled once for all surfaces in displayText, as its own card if a real producer needs more than 3 decimals." },
        { "question": "Deviation: I edited one comment in GridField.displayLocale-9909.test.tsx, which said the read-only table's number cells print the stored value. This change makes that untrue, so I updated the wording. No assertion changed. The file is outside the claim's listed file surface.", "options": ["A accept as a comment-only correction", "B revert it"], "recommendation": "A" }
      ],
      "out_of_scope_findings": [
        "class: a (configuration reading) · reach: live showcase INV-1001 on published 18.0.0-next.3, console dev server, en session. Unit Price and Amount are Field.currency, yet both legs print '150' / '1,500' with no symbol and no fixed two decimals, because this session resolves no currency and displayText's currency branch then prints the plain locale number. evidence: evidence/12915/README.md on claude/issue-12915-evidence · dedupe words: showcase tenant currency unresolved, line items currency no symbol, LocalizationProvider currency console · carrier: none; reported for the seat to judge whether the showcase or console should declare a tenant currency",
        "class: observation · displayText still prints English 'N files' / 'File' for a file cell, and hydrateColumns' boolean options are English 'Yes' / 'No' (deriveMasterDetail.ts optionsFor). A read-only boolean line column now shows 'Yes' where it showed 'true'. Both are pre-existing and outside this surface · carrier: none · noted in Acceptance notes only",
        "class: observation · a select column whose value is an array (multi) and which carries options prints the raw joined value, not the labels (displayText's select branch compares String(array)). It is unchanged from main's String(value). The InlineGridColumn type union is text|number|currency|date|datetime|time|select|lookup|file, and fieldTypeToColumnType maps percent, rating and slider to number and boolean and toggle to select · carrier: none"
      ]
    }

    Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12923.

    The seat's answers:

    • Open question 1 (a number past three decimals now rounds to three): A, ship. The card and the triage both say every non-lookup cell through displayText with no second formatter, and the list-mode and computed cells already round this way, so the read-only view now matches the editable one. A precision rule, if a real producer needs one, belongs to displayText for every surface at once. Recorded in the Acceptance notes; not filed, since no line-item producer with four or more decimals was measured.
    • Open question 2 (the comment in GridField.displayLocale-9909.test.tsx): A, accept. The comment stated a rule this change removes; no assertion moved, and the file is the same pin family the claim's surface names.
    • Out-of-scope findings:
      • The currency with no symbol on the live invoice: not filed, no product reach. The showcase's unit_price and amount are Field.currency with no currency code (examples/app-showcase/src/data/objects/invoice.object.ts), so the cell falls to the tenant currency, and the dev session declares none. With no currency known, the plain locale number is the honest reading. The pin proves the symbol and the two decimals when a currency is resolved (98.765,25 €).
      • The English Yes / No options and "N files" / "File": filed as objectui#12924 (class a, public door). The seat confirmed both on main (deriveMasterDetail.ts:113–:114, GridField.tsx:510, :512) and ran the dedupe (26 hits, the only open one is this card). This PR moves a read-only boolean line cell from true to Yes: still English, but no longer a stored value.
      • The multi-value select printing its joined stored values: unchanged from main, no producer measured (no line-item column carries an array value today). Acceptance notes only.
    • The seat read the diff at 0b6f62a: 4 files, all on the claimed surface or its pin family. H1 holds: the read-only cell makes the same displayText(c, row[c.name], displayLocale, currency) call as the list-mode cell (:1133) and the computed cell (:1145). H4 holds: screen and print are one GridField. The merge brings only main (d637be3, which carries fix(plugin-kanban): draw the no-value swimlane from kanban.uncategorized #12918 and fix(app-shell): a print record page draws the record's header actions beside Print #12921, neither touching packages/fields).
    • Next: CI on 0b6f62a, then the ACCEPT.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-17T23:10Z

    • Merged: PR fix(fields): the read-only GridField table reads every non-lookup cell through displayText (objectui#12915) #12923 landed through the merge queue as main 8523e81db0, with one parent, 8392f74afe (fix(plugin-detail): record path takes a stage terminal from its option's declared kind #12922, which touches nothing under packages/fields). It is an ancestor of origin/main.
    • Verified by content: the merge commit's own diff equals the PR's diff from its merge-base d637be321b to the reviewed head 0b6f62a, changed line for changed line in each of the 4 files (+127/−13).
    • Positive control at the merge commit: the pin GridField.readonlyCells-12915.test.tsx is present, and GridField.tsx has no String(row[c.name]) arm left. At the parent 8392f74afe the pin is absent and the arm is there once.
    • Card: closed completed by Fixes #12915. A read-only GridField table (a read-only record page, its print page, a read-only master-detail grid) now reads a select cell as its option label and a number or currency cell in the session's locale and currency, through the same displayText the list-mode cells use. Lookup, file and date cells are unchanged. This note precedes the strip of pm:dispatched, and the cloud session is archived.
    • Next, outside this card: objectui#12924, filed by the seat: the English Yes / No options a boolean line column is hydrated with, and displayText's English "N files" / "File".

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpriority:p1target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions