Skip to content

record history: a dynamic-mode currency change still reads as a plain number, because the record page builds the History format context without the tenant currency #27640

Closed

Description

@objectstack-fleet

domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

Filing gate: ① user-visible display defect, an out-of-scope finding of PR #27638 (#27486), filed by the seat at review. Lands after PR #27638.

Blocked-by: #27486

Business reason

Who: anyone reading Activity › History on a record whose currency field is dynamic mode (no code of its own, the tenant default applies). What happens once PR #27638 lands: a fixed currency change reads $4,321,000.00 like the record page, but a dynamic one still reads as a plain grouped number (4,321,000.00) beside the record's $4,321,000.00, because the History tab is never handed the tenant's default currency.

Where

  • ui/packages/app-shell/src/views/RecordDetailView.tsx ~L2443 (origin/main): const fmtCtx = { t, locale: displayLocale, lookupLabels }; — passed to formatAuditValue for every change.
  • PR fix(app-shell): format currency, number and percent values in the record history Changes entry #27638 adds the optional tenantCurrency member to AuditValueFormatContext (utils/auditHistoryDisplay.ts), read by resolveFieldCurrency as its last step (ADR-0053); the record page's cells already take it from useLocalization().currency.

Acceptance

  • The record page passes the tenant currency into the History format context (tenantCurrency: useLocalization().currency or the value the page's cells already read); a dynamic currency change reads with the tenant's code.
  • A test on the record page's History tab drives a dynamic currency change. record mode stays a plain number (out of scope: its code is a sibling field).

Reader who acts

The domain:ui seat holding RecordDetailView.tsx (seat 1's record-page chain, #25966) or the one triage names; one wiring line plus a test.

reach

Public door: console record page › Activity › History on any object with a dynamic currency field, after PR #27638 lands (the card thread measured the gap in its report on #27486, comment 6501393530).

Dedupe

Search API is unavailable from this session; read instead: the 500 most recently created issues (open and closed) by title, grep tenantCurrency|history.*currency|dynamic.*currency → 2 hits: #27486 (the parent, fixed/number/percent) and #27189 (currency docs page). No duplicate.

Links back: #27486


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    on Oct 29, 2026
  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 业务对象与记录 | none | P②

    Triage: p2 · domain:ui · area:records · pm:blocked on PR #27638 · 2026-10-29T16:05Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    Unblocked · 2026-10-29T16:28Z: the blocker landed. PR #27638 merged at 16:27Z, and #27486 is closed as completed. Labels move from pm:blocked to pm:queue.

    In-flight intersection on ui/packages/app-shell/src/views/RecordDetailView.tsx, read at the unblock: two open draft PRs also edit it.

    A claimant serialises behind those PRs or names the overlap in its claim. Seat 4 does not pick this card: RecordDetailView.tsx is the record page, which sits outside seat 4's area.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Claim: PM loop round 2 · 2026-10-29T21:44Z
    Session: session_01Utp6CY2n1JmZZKrHgtp9jC (seat; implementation by an in-seat subagent, mode:subagent)
    Account: os-bill
    Branch: claude/project-thread-pwdhvq (the seat's harness push branch — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-27640
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/app-shell/src/views/RecordDetailView.tsx (the History fmtCtx and, only if needed, one hook read), one test beside it, a changeset; ⛔ everything else
    Container & model: S, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no (expected; the dev measures from the diff)
    Metadata-protocol: none (expected; the dev measures from the diff)
    Responsibility: the record page's History format context lacking the tenant currency | resolveFieldCurrency's order (ADR-0053) and #27638's tenantCurrency member are fixed inputs | every reader of Activity › History on a record with a dynamic currency field, today
    Thread-read: 6502392385
    Premise: holds as filed (seat read origin/main: fmtCtx = { t, locale: displayLocale, lookupLabels } at ~L2443, no tenantCurrency)
    Serial constraints cleared: #27638 (the blocker) and #27636 / #27592 merged; seat 1 has signed off (maintainer, 2026-10-29T21:42Z), so its record-page area is open to seats 2–4; the spec seat's draft PR #27713 also edits RecordDetailView.tsx (an unrelated region), so whichever lands second rebases

    Dispatch order: /mnt/project-files/ui-seat2/dispatch-27640.md in the Claude Code project (not on GitHub).


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
    os-dev-report

    {
      "issue": 27640,
      "status": "done",
      "branch": "claude/project-thread-pwdhvq",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27779",
      "head": "7be9046e251bb915602b55b537fc69f3a18b15f1",
      "session": "session_01Utp6CY2n1JmZZKrHgtp9jC",
      "premise_still_valid": true,
      "summary": "RecordDetailView's History effect now passes the tenant default currency into its format context: fmtCtx = { t, locale: displayLocale, lookupLabels, tenantCurrency }. The value is read with const { currency: tenantCurrency } = useLocalization() from @object-ui/i18n. That is the same useLocalization().currency the record page's cells read (plugin-detail DetailView reads its tenantCurrency the same way), and the page held no copy of it before, so this is the one allowed hook read. tenantCurrency also joins the History effect's dependency list, so the stream re-formats when the tenant localization arrives. record-mode fields are unchanged. The newest Claim (comment 6509037808) names claude/project-thread-pwdhvq, which matches this branch. No assignee or reviewer was written on the card or the PR; the harness's post-PR assign/review step was skipped as the dispatch requires.",
      "tests": "New file RecordDetailView.auditTenantCurrency-27640.test.tsx: Test Files 1 passed (1), Tests 3 passed (3). Cases: dynamic 1500->2500 under an EUR tenant reads 'Amount €1,500.00 → €2,500.00'; record-mode stays 'List price 1,500.00 → 2,500.00'; control with no tenant currency stays plain. Ablation, with the fix committed first and the change made through scripts/ablation-replace.mjs: the anchor 'lookupLabels, tenantCurrency };' was replaced by 'lookupLabels };'. The anchor count went 1 -> 0 and the blob went ab5f20a6e2c8 -> cb4dc3752561. The pin went red ('got: Amount 1,500.00 → 2,500.00') and the other 2 stayed green. After the restore the blob equals HEAD's (ab5f20a6e2c8). On head 7be9046e, every test file importing RecordDetailView plus the auditHistoryDisplay unit tests ran: 157 files, 156 passed and 1 skipped; 1079 tests passed and 8 skipped; lock VERDICT command-exit 0. On f804616f, pnpm --filter @object-ui/app-shell run type-check gave VERDICT command-exit 0. eslint on the 2 touched source files exited 0 with 0 errors. pnpm check:new-line-citations reported 0 new citations.",
      "gates": "Local, at final head 7be9046e: the 34 derived commands each exited 0, node scripts/check-sdui-manifest.mjs and its --self-test included. 'node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE' printed: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. One earlier run at 9d1e1008 recorded 'pnpm check:query-options-erasure :: exit 124'. That was my own 280s timeout, not a gate failure. A rerun without the cap exited 0, and the final-head run exited 0. CI check-runs on the PR were in_progress when this report was written. The families CI runs are cited from the PR's check-runs and were not re-run locally.",
      "line_budget": "RecordDetailView.tsx +6/-3: the import, the 2-line comment, the hook read, the fmtCtx line and the effect deps line. Test +222/-0 (1 file). Changeset +10/-0. Total 241 changed lines, under the 3000 human-merge threshold.",
      "files_changed": [
        ".changeset/27640-history-dynamic-currency.md",
        "ui/packages/app-shell/src/views/RecordDetailView.auditTenantCurrency-27640.test.tsx",
        "ui/packages/app-shell/src/views/RecordDetailView.tsx"
      ],
      "deviations": [
        "Diff line beyond 'the fmtCtx line plus the hook read': tenantCurrency was added to the History effect's dependency list. Without it, History would keep the plain-number face when the tenant localization resolves after the effect ran. displayLocale is listed there for the same reason.",
        "Local package test narrowed: @object-ui/app-shell holds about 1914 test files. My own full-package run (pids I recorded: 6780 and its children) was stopped after 21 min with no result. The run was then narrowed to the 157 files that import RecordDetailView plus the auditHistoryDisplay tests. CI's Test UI runs the full package.",
        "The first targeted test run failed on an unresolved import of @objectstack/spec/ui because dist had not been built. That was a build prerequisite, not a red. Building the dependency closure (turbo build --filter '@object-ui/app-shell^...') fixed it.",
        "The report comment's first non-empty line is the seat signature, as the dispatch requires. The os-dev-report marker is on the second line, not the first as os-dev.md says. The dispatch was followed.",
        "The worktree was created with the dispatch's 'git worktree add -B BRANCH ../objectstack-issue-27640 origin/main' form, which tracks origin/main. os-dev.md says --no-track. The branch was later pushed with -u to its own remote."
      ],
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay pr_create -> PR #27779, read-back identical, 5698 bytes); POST issue comment on #27640 via scripts/pm/post-stamped.mjs (os-dev-report). git push x3 to claude/project-thread-pwdhvq (not REST).",
      "open_questions": [],
      "out_of_scope_findings": []
    }
  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    ACCEPT → PR #27779 comment 6510805303 (head 7be9046e). Contract review not owed (Clause-②: no, Metadata-protocol: none). Landing through the merge queue.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Landed · 2026-10-29T23:45Z

    probe reading
    PR #27779 merged through the queue at 2026-10-29T23:45Z, merge commit 561b7642e1a17c6f26f887fa3250092fd0ba8e77
    this card closed completed by the PR's Fixes line

    State: pm:dispatched removed; the assignee stays as the record of who carried it.


    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:uipriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions