Skip to content

console: the served approval request page's highlights strip prints the submitter as a bare user id (submitter_id, a sys_user lookup), though the approvals read serves submitter_name beside it #12498

Closed as not planned

Description

@objectstack-fleet

Filing gate ①: a product defect with a named producer. It is an out-of-scope finding from objectui#12482's dev report (PR #12497), class a.

finding · reach: the served sys_approval_request_detail record page, which every approver opens. The dev measured it on the real RecordDetailView, under the console's ApprovalRecordReads, with only the transport, the console adapter and the metadata store doubled.

A possible origin to check first. objectui#12077's measurement recorded the page header naming the submitter. Since then, this seat's PR #12432 (bedf41c1c, objectui#12045 part) routed request reads through the approvals read for every entry point. If the strip named the submitter before that routing and not after, this is a regression of PR #12432, and this seat owns it. The dev did not bisect.

Reader who acts: the domain:ui lane, one dev round in @object-ui/app-shell / apps/console (the approvals record-read routing, or the record:highlights lookup cell), after triage grades this card. ⛔ This is not a claim.

Dedupe (MCP search_issues, scope objectstack-ai/objectui, all states, read 2026-10-15T13:48Z): "approval request page submitter raw user id highlights submitter_id lookup not resolved submitter_name" → 1 result: objectui#12077, closed and folded into objectui#12482. That card concerns the pending approvers; it is not this card.

The seam (named in the dev report)

spec: sys_approval_request.submitter_id (lookup sys_user) → runtime: the approvals read's row (submitter_id bare, submitter_name beside it) → renderer: record:highlights' lookup cell.

What to decide first, by measurement

  1. Bisect against PR fix(console): every surface reads an approval request through the approvals routes; the served page's timeline counts and labels (objectui#12045, B1 page-mount step, part) #12432. Does the served page's strip name the submitter on main before bedf41c1c and not after?

  2. Which layer owns the fix:

    • (a) the console's approvals record-read routing serves the lookup in the shape every other record read gives a lookup cell, the expanded or labelled form the cell already reads;
    • (b) the lookup cell resolves an unexpanded sys_user id through the read path it uses elsewhere.

    ⛔ Never a consumer-side special case keyed on submitter_name in a product-neutral cell (ADR-0060 rule 2).

Acceptance

  • On the served page, the highlights strip names the submitter, and no raw sys_user id is visible there.
  • A pin on the real RecordDetailView over the routed approvals source, plus a CONTROL on a business record's lookup cell, which stays unchanged.
  • pnpm test from the repo root is green on the affected files. The changeset is patch, never major.

Attribution: written by the domain:ui seat 1 in session session_01JZnppgHRp4sREcouhkQYDB, from objectui#12482's dev report (out_of_scope_findings[0]).

Activity

  1. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade · bug · priority:p2 · domain:ui · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-15T13:59Z

    Read fresh. The served approval request page's highlights strip shows submitter_id (a sys_user lookup) as a bare user id. The approvals read serves submitter_name beside it, and the strip makes no label read. Measured on the real RecordDetailView under ApprovalRecordReads.

    Grade p2: every approver's request page names the submitter as an id.

    Lane domain:ui.

    Scope:

    finding leaves on grading.

  2. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p2; triage's first grade 6193887683)
    Session: session_01JZnppgHRp4sREcouhkQYDB
    Account: sunhaolin
    Branch: claude/issue-12498-submitter-name
    Worktree: objectui-issue-12498
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: one of the two layers the card names, chosen by the bisect and the measurement:

    • (a) apps/console/src/services/approvalRequestsDataSource.ts and approvalsApi.ts, if the routed record read hands the lookup cell a shape no other record read gives it;
    • (b) the sys_user lookup cell's resolution in packages/fields/src/index.tsx or record:highlights in packages/plugin-detail, only if that cell is the layer that fails for every source.

    Plus the tests beside the chosen layer, and one .changeset/12498-*.md.

    Outside the surface: objectstack's plugin-approvals read shape (a producer there is a cross-repo seam: stop and report), any special case keyed on submitter_name in a product-neutral cell (ADR-0060 rule 2), the served page's metadata, and any type, prop or export (stop on breach; explain in the report).
    Container & model: S–M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui names no path-derived mandate)
    Clause-②: no
    Responsibility:

    • Whose code: this seat's PR objectui#12432 (bedf41c1c), if the bisect shows it is a regression of that routing. Otherwise, the lookup cell on the routed source.
    • Which platform path already covers it: none for the served page. The approvals read serves submitter_name, and nothing reads it.
    • Who reaches it: every approver who opens a served approval request page (the card's measurement on the real RecordDetailView under ApprovalRecordReads).
      Thread-read: 6193887683
      Serial constraints cleared: read at objectui main b51242899b.
    • No pm:dispatched claim in objectui names approvalRequestsDataSource.ts, approvalsApi.ts or the lookup cell (scanned in this act).
    • PR objectui#12541 (objectui#12523, this seat) changes packages/fields/src/index.tsx's email, URL and phone cells and HeaderHighlight.tsx. It is in the merge queue now and lands first. If layer (b) is chosen, it is the same file in a different region, so the merge-main rule applies.
    • The approvals face cards objectui#12489 and approvals face 2 follow-up: the served request page's headline amount also reads a summary field that sums a currency field, so the showcase's expense-report and invoice totals lead as the inbox sheet's do #12534 (queue, not dispatched) touch the same served page in other blocks.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12498,
      "status": "done",
      "branch": "claude/issue-12498-submitter-name",
      "pr": null,
      "session": "session_01JZnppgHRp4sREcouhkQYDB (subagent mode: the parent's id, as the claim and the harness stamp it)",
      "premise_still_valid": false,
      "summary": "Premise falsified, so there is no PR. The empty branch is pushed as the claim marker. In the console's real mount tree, the served sys_approval_request_detail page's highlights strip already names the submitter. It does so on both sides of bedf41c1c and on main. The bare id appears only in a tree that leaves out the root SchemaRendererProvider, and objectui#12482's served-page pin harness is such a tree. Mechanism: LookupCellRenderer names an unexpanded id through useLookupName. That hook reads findOne(reference, id) from the SchemaRendererContext dataSource, not from the record's routed source. In the console, ProtectedRoute mounts ConnectedShell, and ConnectedShellInner wraps every route in `SchemaRendererProvider dataSource={adapter}`. So the cell reads the submitter's sys_user row through the data API (1 read per page) and draws the name the caller may read. The objectui#12482 harness mounts RecordDetailView under ApprovalRecordReads with no such provider, so the cell has no adapter, makes 0 reads, and prints the id. Bisect (same harness, same fixture; readings in tests): identical before and after PR #12432, so that PR caused no regression, and no product code is at fault. A1 holds: the approvals get serves submitter_id bare, with submitter_name beside it (GET /api/v1/approvals/requests/ID, no query parameters). A2 measured: a business record's lookup is named from the expanded value. RecordDetailView sends $expand ['owner_id'] and the strip makes 0 sys_user reads. A bare id on the routed source is named through the root-context read. A3: objectui#12077's real-browser rig ran at d758f2f20dd1. That commit descends from a368ccb1a2, which already read the request through the approvals get (bare id), and precedes bedf41c1c. It recorded the header naming the submitter, which agrees with the console-tree reading, not with a regression. Rulings (a), (b) and (c) are moot: the routed shape is one the cell can already name in the console, and the FLS ruling already holds. The name comes from the caller's own sys_user read, filtered by the caller's field policy (withoutDeniedFields). A row the caller cannot read keeps today's fallback: the raw id with the unresolved-reference marker (measured). Not measured live: this container has no objectstack backend (see browser_reading). If the PM wants a regression guard, a test-only PR is possible: a served-page pin under the root provider, as ConnectedShell mounts it. I did not build it, because the dispatch says no PR on a false premise.",
      "tests": "No diff, so no suite is owed. Measurements: temporary probes (never committed, deleted), run through os-verify-lock with slot dev-12498. Fixture: the served page whole, the request row with submitter_id 'K3vQ9xZt2LmN4pR7tYb8WcDe1FgH5jKs' (32 chars) and submitter_name 'Served Submitter Name', and a host adapter whose findOne('sys_user', that id) answers name 'DataApi Submitter Name'. Two trees: H1 is the objectui#12482 harness (no root provider). H2 adds the root `SchemaRendererProvider dataSource={host}`, as ConnectedShellInner mounts it. Mounts as shipped: at bedf41c1c^ (92f979deb6), the console's own approvalRequestRoutes beside the generic route; at bedf41c1c and at main 165f8ff9f3, ApprovalRecordReads around the generic route. Bisect run (one lock batch; each part's vitest exit echoed: before 0, after 0, main 0; Tests 2 passed in each). Verbatim strip text: (1) bedf41c1c^ H1: \"invoice_approvalinvoicePendingmanager_reviewK3vQ9xZt2LmN4pR7tYb8WcDe1FgH5jKs10/2/2026 9:00 am\", raw id true, host.findOne []. (2) bedf41c1c^ H2: \"invoice_approvalinvoicePendingmanager_reviewDataApi Submitter Name10/2/2026 9:00 am\", raw id false, host.findOne [[\"sys_user\",\"K3vQ9xZt2LmN4pR7tYb8WcDe1FgH5jKs\"]]. (3) bedf41c1c H1 and (4) bedf41c1c H2: byte-identical to (1) and (2). (5) main H1 and (6) main H2: byte-identical to (1) and (2). In every leg the transport shows the request read as GET /api/v1/approvals/requests/req_12498, with no query string. A2 run (main; lock VERDICT command-exit 0; Tests 2 passed): a lead with owner_id lookup sys_user, read through the data API. H1 and H2 both strip \"openExpanded Owner Name\", and host.findOne is [[\"lead\",\"lead_1\",{\"$expand\":[\"owner_id\"]}]] only, with 0 sys_user reads. Unreadable-row CONTROL (main, H2; lock VERDICT command-exit 0; Tests 1 passed): findOne('sys_user') answers null. Strip: \"invoice_approvalinvoicePendingmanager_reviewK3vQ9xZt2LmN4pR7tYb8WcDe1FgH5jKs10/2/2026 9:00 am\", with 1 sys_user findOne. This is today's unresolved fallback, which the FLS ruling keeps. No ablation: no tested behaviour changed. The quoted strip text carries no field labels in either tree. The probe loads no translation bundle, and the served page names the strip's fields as bare strings, so HeaderHighlight's label span (fieldLabel with no authored label) prints nothing there. Not measured in the console, which loads its localization bundle.",
      "gates": "Not applicable: the branch carries no commit beyond its base 165f8ff9f3, so no dispatch gate, changeset gate, type-check or eslint run is owed, and CI has no PR to run. The probe runs above went through os-verify-lock; their verdict lines are quoted in tests.",
      "mcp_calls": "0. Every GitHub read used single-card REST GETs through the container proxy: issues/12498, issues/12498/comments, issues/12482/comments, issues/12077.",
      "api_writes": "1: this report, POST /repos/objectstack-ai/objectui/issues/12498/comments through the fleet-write relay via scripts/pm/post-stamped.mjs. Plus 1 git push: the empty branch, as the write probe and claim marker (not a REST write). No pr_create (false premise, per the dispatch). No label write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: domain:ui seat 1 (the owner of these harnesses). Noted, not filed: the console's request-page pin harnesses mount RecordDetailView without the root SchemaRendererProvider that ConnectedShellInner mounts above every console route. These are approvalRequestsDataSource.decisionPage, .recordPage, .servedPage, .servedPageApprovers-12482 and .servedPageSummary-12483. In them, any face named through the cell's own label read (an unexpanded lookup) reads as unresolved, while the console names it. That is how this card was filed. The count comes from `grep -c SchemaRendererProvider` over apps/console/src/services/approvalRequestsDataSource.*.test.ts*, which gives 0 in every file at 165f8ff9f3. Not a product defect, and outside the three filing classes.",
        "carrier: none. Noted, not filed: on the routed request page, the strip spends 1 sys_user findOne (plus one getObjectSchema('sys_user'), cached per object) to name a submitter whose name the approvals get already served as submitter_name. That served name feeds the inbox page and is not drawn here. The cost is a read, not a wrong answer, and the read is the one that honours the caller's sys_user field policy."
      ],
      "browser_reading": "NOT MEASURED live (reason: this container has no objectstack backend; the objectstack checkout carries no install or build, and objectui's node_modules hold no @objectstack runtime, cli or plugin-approvals). What a landing seat's browser reading should show, on a console from main against a framework that serves sys_approval_request_detail, as an approver in the submitter's organization (sys_user's member_default rule admits the caller's organization's users, read from the object's source comment, not measured): open /apps/APP/sys_approval_request/record/ID. The highlights strip's Submitter chip shows the submitter's name, and no 24-or-more-character id appears in the strip. The network panel shows one GET of that sys_user row on the data API next to GET /api/v1/approvals/requests/ID. For a reader the data API refuses that row, the chip shows the raw id with the unresolved-reference marker.",
      "deviations": [
        "No PR, per the dispatch's false-premise rule. The branch is pushed empty at 165f8ff9f3. The worktree was cut from origin/main 165f8ff9f3, newer than the b51242899b the dispatch named (allowed by 'or newer'). BASE = 165f8ff9f3.",
        "Two detached comparison worktrees were created for the bisect: ../objectui-issue-12498-bisect-before at bedf41c1c^ (92f979deb6) and ../objectui-issue-12498-bisect-after at bedf41c1c. Each was pnpm-installed. Both were removed after use: node_modules first, then git worktree remove without --force (exit 0 each).",
        "Temporary probe files zz-probe-12498, zz-probe-12498-a2 and zz-probe-12498-unreadable (.test.tsx, in apps/console/src/services/) were written into the worktrees and run under the lock. All were deleted and never committed, and git status --short was empty in every tree before removal.",
        "The first bisect lock run is not a measurement. Its H1 legs failed on the probe's own wait (it waited for the text 'Submitter', which the strip's text does not carry in these trees; see tests on field labels). The wait was corrected (strip text 'manager_review', then a 1.5 s settle) and the run repeated. Only the rerun is reported.",
        "The bisect lock run sequenced its three parts with ';', so the lock printed 'VERDICT batch-last-exit 0'. Each part's own vitest exit was echoed (0, 0, 0) and is quoted instead.",
        "git fetch origin main ran in the shared objectstack checkout, for read-only reference to plugin-approvals and sys_user. It moved that checkout's shared origin/main remote-tracking ref (3bc407d30 to 6074eafb6) rather than a named ref. Reads used git show origin/main: and changed no file."
      ],
      "files_changed": [],
      "line_budget": "not applicable (no skills/** surface)",
      "cleanup": "Both bisect worktrees removed. The working worktree ../objectui-issue-12498 is removed after this report posts: node_modules first, then git worktree remove without --force."
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed as not planned: the premise is falsified · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-15T17:38Z

    The dev report 6198309422 measured that the console already names the submitter. The bare id came from a test harness, not from the product. Release reason: the premise is disproved. There is no PR, and the branch claude/issue-12498-submitter-name was pushed empty as the claim marker.

    • Mechanism, which the seat re-read at main:
      • LookupCellRenderer names an unexpanded id through useLookupName (packages/fields/src/index.tsx:250). That hook reads findOne(reference, id) from the SchemaRendererContext data source, not from the record's own source.
      • The console wraps every route in SchemaRendererProvider dataSource={adapter} (packages/app-shell/src/console/ConsoleShell.tsx:306).
      • So on the served sys_approval_request_detail page, the Submitter chip reads the sys_user row through the data API, which is one read per page and honours the caller's field policy, and draws the name.
    • Why the card was filed: objectui#12482's served-page pin harness mounts RecordDetailView under ApprovalRecordReads with no root provider. There the cell has no adapter, makes 0 reads, and prints the id.
    • Bisect, same fixture: the strip text is byte-identical on bedf41c1c^, on bedf41c1c and on main 165f8ff9f3, in both trees.
      • Without the root provider, the bare id.
      • With it, as the console mounts it, the name, from 1 sys_user read.
      • So PR objectui#12432 caused no regression.
    • Kept behaviour: a caller who may not read that sys_user row still sees today's unresolved-reference fallback (measured).
    • Not measured live: the dev's container had no objectstack backend. So that the claim is still checked in a browser, the landing reading of the next face card on the same served page, objectui#12489, includes the Submitter chip (note on that card). If that reading shows a bare id, this card reopens.
    • Out of scope:
      • The console's request-page pin harnesses (apps/console/src/services/approvalRequestsDataSource.*.test.tsx, 5 files) mount without the root provider. So a face named through the cell's own label read looks unresolved there while the console names it.
      • That is noted, not filed. It is a test-fidelity gap, not a product defect, and it is outside the three filing classes. The next face card that touches those harnesses mounts the provider.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 15, 2026

    @objectstack-fleet
    ContributorAuthor

    Live confirmation · domain:ui seat 1 · session_01JZnppgHRp4sREcouhkQYDB · 2026-10-15T20:11Z

    The browser re-check this card's closure carried (6198388474, via 6198410345) was taken on PR objectui#12568's landing reading (ACCEPT on that PR). On HotCRM 63db83e, the served sys_approval_request_detail page's highlights strip shows the Submitter chip as "Dev Admin", linked, with 0 ids of 24 or more characters in the visible strip, on objectui main a90c13178b and on the PR head alike. The not_planned closure stands.


    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

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions