You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
The routed approval request page shows pending_approvers as raw user ids under More details, while its header resolves the submitter's name #12077
Filing gate ①: a measured UI defect with a named landing site. Filed by the repo:cloud#1 seat (session session_01WVbr5J6u8BHh8EyFtcWciH) from cloud#2755's dev report (6092351997) and the seat review 6092375821. Reader: triage, which routes it; the landing is in objectui.
What was measured
Rig: framework at 56bf27affb, with the objectui console built from main at d758f2f20dd1 and overlaid byte for byte. Chromium (Playwright) opened the routed request page /_console/apps/APP/sys_approval_request/record/ID for the showcase's quorum request.
Under "More details",PENDING APPROVERS renders raw user ids: one id three times, qFpo…, qFpo…, qFpo….
The same page's header resolves the submitter to a name.
A screenshot was taken on the rig. It is not attached, because the rig is gone.
Landing site
The page arrived in a368ccb1a, the B1 build round of objectui#12045 (approvals epic objectui#2763).
pending_approvers is drawn by the generic details rendering of sys_approval_request (RecordDetailView / DetailSection), which prints the stored value.
The same id listed three times reads like three slots of one approver in a quorum. Whether the page should name each approver once, or per slot, is the lane's call.
Reach
Every approval request a user opens on the routed page.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T02:21Z. ⛔ Not a claim, ⛔ not a dispatch.
Lane: the B1 page and its details rendering are objectui's (a368ccb1a, objectui#12045's build round), so this is domain:ui.
Why p3: the same as objectui#12045. The page is readable, and the header names the submitter. Only the "More details" section prints internal state.
What the value is: on objectstack main, sys_approval_request.pending_approvers is a Field.textarea (plugin-approvals/src/sys-approval-request.object.ts, about :291). It holds the stored approver slots. So the generic details section prints it verbatim, and one id three times is one approver's quorum slots.
Direction:
The page does not print the raw slot store. It names the pending approvers, each person once. Or, if the decision panel already names them, it hides the field from the details section.
⛔ No client parsing of the slot format beyond what a published helper exposes. Measure first.
Claim: PM loop round 3
Session: session_01CGZy1BGCjdN5cXqL9cnvB8
Account: os-support-ai
Branch: claude/issue-12077-pending-approver-names
Worktree: objectui-issue-12077
Domain: domain:ui
Seat: domain:ui#3
File surface (on main1b2d0160). The routed approval request page (approvalRequestRoutes in apps/console/src/AppContent.tsx, from objectui#12045's build round a368ccb1) prints sys_approval_request.pending_approvers verbatim under "More details": one id once per quorum slot. Triage's direction (6092668487): name the pending approvers, each person once; or, if the page already names them, hide the field from the details section. ⛔ No client parsing of the slot format beyond what a published helper exposes.
Measure first, then take the smaller route the measurement allows:
(a) Name each pending approver once where the details section draws pending_approvers, on the request page only. Resolve the ids to names with one batched read per page (the way objectui#12067 resolved actor_id), and de-duplicate. The console's inbox (apps/console/src/pages/system/ApprovalsInboxPage.tsx, about :271) already resolves pending_approvers to people: reuse its reading, or the published helper it uses, not a second parser.
(b) Hide the field from the details section on the request page, if the page already names the pending approvers elsewhere. The dev reads what the routed page draws today, including whether DecisionProgressIndicator or the declared actions name them.
The files the dev may touch, each named in the report before editing:
the route's own page wiring in apps/console/src/AppContent.tsx;
the approvals source apps/console/src/services/approvalRequestsDataSource.ts, read-side only, ⛔ never dropping a field the record carries;
the details renderer path the measurement shows draws the field (packages/plugin-detail/src/DetailSection.tsx or packages/app-shell/src/views/RecordDetailView.tsx).
The tests beside these. Pins:
one approver holding three slots renders one name;
two approvers render two names;
control: another object's record page is unchanged.
the decision panel's registration (objectui#12045's page-mount step);
packages/i18n/** (a new key is a stop) and packages/components/src/ui/**.
If neither (a) nor (b) can be done without parsing the slot format or adding a published prop or export, stop and report with measured options.
Container & model: S, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui over these paths: no path-derived mandate; default tier).
Clause-②: no
Responsibility: objectui console: the routed sys_approval_request record page prints pending_approvers' raw slot store (one id per quorum slot) under More details, while its header names the submitter | the platform path: the inbox's existing approver resolution, or the page's own naming of the approvers | every user who opens an approval request on the routed page
Thread-read: 6092668487
Serial constraints cleared: none blocking.
Open objectui PRs, read 2026-10-10T02:48Z: none touches these files.
objectui#12045 (pm:blocked, claim released) owns the request page's mount step; this card fixes what the page draws today.
In-flight claims, read 2026-10-10T02:48Z: none in this repo carries pm:dispatched (serial dispatch).
Why Clause-②: no: a display fix on one console route, with no export, prop, type or pack key changed. If the route needs one, that is a stop.
{
"issue": 12077,
"status": "needs_decision",
"branch": "claude/issue-12077-pending-approver-names",
"pr": null,
"session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent's id)",
"premise_still_valid": true,
"summary": "The defect reproduces. On the real RecordDetailView over the routed approvals source, 'More details' shows 'Pending Approvers' as the raw id three times, and no approver name appears anywhere on the page. Route (b) is not available: nothing on the routed page names a pending approver. The decision panel is not mounted there (its registration is carried to the page-mount step), and even mounted it shows only a got/need count. The approvals hook and DeclaredActionsBar are switched off on a request's own page, and the highlights carry no approver. Route (a) has no in-place hook that stays inside the rulings. The console route can reach the details row only through the objects list and the data source: one re-types the declared field, the other rewrites a field the record carries. Inside app-shell and plugin-detail, the only per-field display slots are `render`, which replaces the whole row and its label, and `value`, which is used only when the row lacks the key. A host-registered cell face would add a cell-registry key, and those keys are counted by registry censuses. So this is a stop with measured options and no code. One correction to the claim: the get route already serves `pending_approver_names` (id to name, from one batched sys_user lookup on the server), so naming needs no extra client read. The server names only user-id slots; `position:`/`role:` slots get no name, and naming them needs app-shell's unpublished `parseApproverRef`.",
"tests": "No code was changed. Measurements: a temporary probe file was mounted beside the existing record-page test, with only the HTTP transport doubled and the real RecordDetailView over createApprovalRequestsDataSource. Row: pending_approvers = the same id three times, pending_approver_names = {id: 'Ada Lovelace'}; field declared textarea, as objectstack declares it. Run 1 (`pnpm exec vitest run` on the probe, through os-verify-lock, VERDICT command-exit 0, Tests 1 passed): the row text is 'Pending Approvers' followed by the id three times, comma-joined; the page has a 'More details' heading; 'Ada Lovelace' appears nowhere; the id appears 3 times. Run 2 (the same, with `hidden: true` on the field in the objects list RecordDetailView receives, which is the (b) mechanism; VERDICT command-exit 0, Tests 1 passed): the row and its 'More details' heading are gone, the id appears 0 times, and no approver is named anywhere. The probe file was deleted, never committed, and `git status` was clean before `git worktree remove` exited 0. Server side was read on objectstack at the rig commit 56bf27affb: `rowFromRequest` sets `pending_approvers: csvSplit(...)`, and `loadRequest` calls `enrichRows([row])`, which sets `pending_approver_names` for user ids that contain no colon.",
"mcp_calls": "0",
"api_writes": "1: POST /repos/objectstack-ai/objectui/issues/12077/comments (this report, through scripts/pm/post-stamped.mjs). Also one `git push` of the empty branch as the write probe (a git push, not a REST write). No pr_create and no label-write: there is no PR.",
"open_questions": [
{
"question": "Route (b) failed its precondition, and route (a)'s smallest in-place hook widens a surface. Which route should clear the raw `pending_approvers` print on the request page?",
"options": [
"A. Name the approvers where the approvals contract is already read, then hide the slot store. The decision panel (app-shell `ApprovalDecisionPanel`, module-internal; no registration change) names each pending approver once, using app-shell's existing single source: `approverChips`, which reads `pending_approver_names` and `useApproverDirectory`, so position slots resolve too. The field is then hidden from the request page's details: producer-side on objectstack's v18 page or object, or through the console route's objects override (`hidden: true`, measured to remove the row; it is route-scoped because only this route hands RecordDetailView that list). Both halves land with objectui#12045's page-mount step, so the hide never ships without the names. Cost: the 17.x console overlay that cloud#2755 would ship to cloud@56bf27affb keeps the raw ids until C7. Reach today is rig-only, per the card.",
"B. An in-place interim for the 17.x synthesized page. app-shell registers a module-internal cell face under a new cell-registry key. Only RecordDetailView's synthesized section entry for sys_approval_request.pending_approvers selects it. The face reads the bound row (useRecordContext), runs the published `bypassedApproverNames`, and de-duplicates. Cost: one new cell-registry key (counted by `listCellRendererTypes` censuses), so the claim's `Clause-②: no` would need an amendment. It adds an object-specific branch to a generic view, and position/role slots stay raw. It does not reach an authored page: objectstack#22567's v18 `sys_approval_request_detail` puts a bare `record:details` in a tab, which reads the declared textarea type. So B is retired at C7.",
"C. Hide only: the console route's objects override sets `hidden: true` on pending_approvers. Measured: the row and its heading go away, and the page then names no pending approver anywhere. That contradicts triage's direction, which allows hiding only when the page names the approvers elsewhere.",
"D. Rewrite the value in the routed source, putting names in place of ids. Rejected: it changes a field the record carries. The decision panel's `eligibleApprovers` (`pending_approvers.length`) and the override confirm's `bypassedApproverNames` (which skips non-string entries) both read the ids."
],
"recommendation": "A, on the four axes. Real business need: reach is rig-only today (the card's own reading). The page users will get on v18 is objectstack#22567's, which by code reading prints the same raw store through the same DetailSection path; A covers it and B does not. Long-term soundness: naming belongs in the block that already reads the request row and its decision_progress. B adds a single-use registry key and an object branch to a generic view, and C7 strands both. Preventing AI errors: A stops a generic surface from printing an engine-internal slot store. B keeps it printing everywhere except one synthesized page, and adds a cell key that no metadata may legally name. Startup focus: A rides a step that is already scheduled, while B is an interim with a retirement date; transitions stay tight, with no staged route. If the maintainer wants the 17.x overlay named before C7, B is the only in-objectui route, and it needs the Clause-② amendment first."
},
{
"question": "If A is taken, which card carries it: this card (re-scoped, Blocked-by the page-mount step), or objectui#12045's page-mount step (with this card closed as carried)?",
"options": [
"A1. Keep this card, add `Blocked-by:` on the page-mount step, and re-claim it with the decision-panel file surface.",
"A2. Fold it into the page-mount step's claim, since the panel mounts there, and close this card as carried."
],
"recommendation": "A1. The pins this card names (three slots render one name, two approvers render two names, another object's page is unchanged) stay separately reviewable, and the page-mount step keeps its scope."
}
],
"out_of_scope_findings": [
"Host reading, as triage asked. 17.x (cloud@56bf27affb, the console from objectui main): the synthesized page renders, measured above. v18: objectstack#22567 (merged as 5495331f) serves `sys_approval_request_detail`, whose Details tab is a bare `record:details`. The v18 object declares no fieldGroups and no `hidden` on pending_approvers (read at that sha), so by code reading the same raw store prints there too. Not measured in a browser, so nothing is filed. carrier: whichever seat takes option A's producer-side hide · noted, not filed.",
"class: none (duplicated reading). The approver naming rule exists twice: module-local in the console inbox (`approverDisplay`/`approverChips`/`formatIdentity` in ApprovalsInboxPage.tsx) and in app-shell (`utils/approverIdentity.ts` plus RecordApprovalsPanel's `approverChips`, whose docblock says it mirrors the inbox). Drift risk only, not observed. carrier: none · noted, not filed. Dedupe words: approverChips duplicate inbox app-shell · formatIdentity two copies · approver naming single source"
],
"gates": [
{ "command": "OS_VERIFY_LOCK_SLOT=dev-12077 bash os-verify-lock.sh -c 'pnpm exec vitest run (temporary probe, run 1)'", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0; Tests 1 passed (1). Measurement probe, not a gate; file deleted." },
{ "command": "same probe with hidden: true (run 2)", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0; Tests 1 passed (1). Measurement probe, not a gate; file deleted." },
{ "command": "no gate run", "exit": null, "verdict": "NOT MEASURED: every gate family. Reason: no diff (a needs_decision stop with no code)." }
],
"deviations": [
"A temporary probe test (apps/console/src/services, zz-probe-12077) was written into the worktree and run twice under the verify lock to measure what the page draws. It was deleted, never committed, and the tree was clean before worktree removal.",
"The branch claude/issue-12077-pending-approver-names was pushed empty (the rule-1 write probe) and stays on the remote at origin/main 1b2d0160 with no commits. This container cannot delete remote refs, per objectui AGENTS.md. A re-dispatch can reuse it.",
"The claim's route (a) named 'one batched read per page' as its resolution path. Measurement shows the get route already serves the names, so no read is needed. Recorded in summary, not acted on.",
"Worktree ../objectui-issue-12077 was removed after measurement (node_modules first, then `git worktree remove` without --force, exit 0), since there is no PR to carry it."
],
"files_changed": [],
"line_budget": "not applicable (no skills/** surface)"
}
Seat decision — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-10T03:09Z. State: pm:dispatched → pm:blocked in this act, with the claim released. Answers the dev's stop (report on this card; no code, no PR).
What the dev measured (the real RecordDetailView over the routed approvals source):
"More details" prints pending_approvers as the raw id three times, and no approver is named anywhere on the routed page.
Route (b), hiding the field only, fails its precondition: nothing else on the page names a pending approver.
The decision panel is not mounted there; its registration waits for objectui#12045's page-mount step.
The approvals hook and DeclaredActionsBar are off on a request's own page.
Hiding the field (hidden: true in the route's objects list) removes the row and leaves no approver named at all.
Route (a) has no in-place hook inside the claim: each one retypes a declared field, rewrites a field the record carries, or adds a cell-registry key.
Correction to the claim: the get route already serves pending_approver_names (id to name, one batched sys_user lookup on the server), so naming needs no extra client read. Only user-id slots get a name. position: / role: slots resolve through app-shell's existing approver directory.
Decision: A, carried as A1. These are order-of-steps and technical-route choices inside triage's direction (6092668487: name each person once, or hide only where the page already names them). No product question is decided, and the maintainer's veto window is open.
A: the page names the approvers where it already reads the approvals contract. The decision panel names each pending approver once through app-shell's existing single source (approverChips over pending_approver_names and the approver directory), and then the raw slot store is hidden from the request page's details.
Both halves land with or after objectui#12045's page-mount step, so the hide never ships without the names.
The hide is route-scoped (the console route's objects override, measured to remove only this row), or producer-side if the page-mount measurement prefers it.
A1: this card stays, pm:blocked on objectui#12045, and is claimed afresh once the page mounts. Its pins (three slots render one name; two approvers render two names; another object's page is unchanged) stay separately reviewable.
⛔ Not B, a 17.x interim cell face. It adds a single-use cell-registry key and an object branch to a generic view, it is retired at the v18 cutover, and the startup rule keeps transitions tight with no staged route. Reach today is rig-only, per the card.
⛔ Not C (hide only: the page would name no approver, against triage's direction). ⛔ Not D (rewriting a field the record carries; the panel and the override confirm read the ids).
Release:session_01CGZy1BGCjdN5cXqL9cnvB8 (account os-support-ai) releases the claim 6092974406.
Reason: the fix waits for objectui#12045's page-mount step.
Destination:pm:blocked with Blocked-by: #12045 in the body. The unlock scan returns the card when objectui#12045 closes. The next claim's surface:
the decision panel (packages/app-shell/src/views/approval-decision/), naming approvers through app-shell's approverChips single source;
the request route's hide of pending_approvers;
the three pins above.
The branch claude/issue-12077-pending-approver-names stays on the remote, empty, for reuse.
Where this card's report now lives: objectui#12482, face 1 of the ruling. Its acceptance reads "No raw user id is shown anywhere on the page (objectui#12077's report)". This card's measurement, seat note 6093164273, is cited there.
State: closed as duplicate in this act, with pm:blocked removed in the same stroke. domain:ui, area:workflow and the type label stay. Reopening is free if the maintainer disagrees.
Activity
objectstack-fleet commentedon Oct 10, 2026
Triage: first grade,
bug·priority:p3·domain:ui·area:workflow·pm:queueTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-10T02:21Z. ⛔ Not a claim, ⛔ not a dispatch.a368ccb1a, objectui#12045's build round), so this isdomain:ui.main,sys_approval_request.pending_approversis aField.textarea(plugin-approvals/src/sys-approval-request.object.ts, about:291). It holds the stored approver slots. So the generic details section prints it verbatim, and one id three times is one approver's quorum slots.sys_approval_request's detail page as a slotted page through the manifestpages, and declare the thread reply asapproval_comment(objectui#12045 B1, ruling 乙) objectstack#22473 (in flight) authors a platformsys_approval_request_detailpage on the v18 line. cloud stays on framework56bf27affbuntil C7, so it keeps this page.objectstack-fleet commentedon Oct 10, 2026
Claim: PM loop round 3
Session:
session_01CGZy1BGCjdN5cXqL9cnvB8Account:
os-support-aiBranch:
claude/issue-12077-pending-approver-namesWorktree:
objectui-issue-12077Domain:
domain:uiSeat:
domain:ui#3File surface (on
main1b2d0160). The routed approval request page (approvalRequestRoutesinapps/console/src/AppContent.tsx, from objectui#12045's build rounda368ccb1) printssys_approval_request.pending_approversverbatim under "More details": one id once per quorum slot. Triage's direction (6092668487): name the pending approvers, each person once; or, if the page already names them, hide the field from the details section. ⛔ No client parsing of the slot format beyond what a published helper exposes.pending_approvers, on the request page only. Resolve the ids to names with one batched read per page (the way objectui#12067 resolvedactor_id), and de-duplicate. The console's inbox (apps/console/src/pages/system/ApprovalsInboxPage.tsx, about:271) already resolvespending_approversto people: reuse its reading, or the published helper it uses, not a second parser.DecisionProgressIndicatoror the declared actions name them.apps/console/src/AppContent.tsx;apps/console/src/services/approvalRequestsDataSource.ts, read-side only, ⛔ never dropping a field the record carries;packages/plugin-detail/src/DetailSection.tsxorpackages/app-shell/src/views/RecordDetailView.tsx)..changeset/12077-*.md(patch).⛔ Not on it:
sys_approval_request's detail page as a slotted page through the manifestpages, and declare the thread reply asapproval_comment(objectui#12045 B1, ruling 乙) objectstack#22473's platform page is the v18 host. If that page needs the same treatment, the seat leaves a pointer there and does not change the in-flight card;packages/i18n/**(a new key is a stop) andpackages/components/src/ui/**.If neither (a) nor (b) can be done without parsing the slot format or adding a published prop or export, stop and report with measured options.
Container & model:
S,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier).Clause-②: no
Responsibility:
objectui console: the routed sys_approval_request record page prints pending_approvers' raw slot store (one id per quorum slot) under More details, while its header names the submitter | the platform path: the inbox's existing approver resolution, or the page's own naming of the approvers | every user who opens an approval request on the routed pageThread-read: 6092668487
Serial constraints cleared:
noneblocking.pm:blocked, claim released) owns the request page's mount step; this card fixes what the page draws today.pm:dispatched(serial dispatch).Why
Clause-②: no: a display fix on one console route, with no export, prop, type or pack key changed. If the route needs one, that is a stop.Generated by Claude Code
objectstack-fleet commentedon Oct 10, 2026
os-dev-report
{ "issue": 12077, "status": "needs_decision", "branch": "claude/issue-12077-pending-approver-names", "pr": null, "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 (subagent mode: the parent's id)", "premise_still_valid": true, "summary": "The defect reproduces. On the real RecordDetailView over the routed approvals source, 'More details' shows 'Pending Approvers' as the raw id three times, and no approver name appears anywhere on the page. Route (b) is not available: nothing on the routed page names a pending approver. The decision panel is not mounted there (its registration is carried to the page-mount step), and even mounted it shows only a got/need count. The approvals hook and DeclaredActionsBar are switched off on a request's own page, and the highlights carry no approver. Route (a) has no in-place hook that stays inside the rulings. The console route can reach the details row only through the objects list and the data source: one re-types the declared field, the other rewrites a field the record carries. Inside app-shell and plugin-detail, the only per-field display slots are `render`, which replaces the whole row and its label, and `value`, which is used only when the row lacks the key. A host-registered cell face would add a cell-registry key, and those keys are counted by registry censuses. So this is a stop with measured options and no code. One correction to the claim: the get route already serves `pending_approver_names` (id to name, from one batched sys_user lookup on the server), so naming needs no extra client read. The server names only user-id slots; `position:`/`role:` slots get no name, and naming them needs app-shell's unpublished `parseApproverRef`.", "tests": "No code was changed. Measurements: a temporary probe file was mounted beside the existing record-page test, with only the HTTP transport doubled and the real RecordDetailView over createApprovalRequestsDataSource. Row: pending_approvers = the same id three times, pending_approver_names = {id: 'Ada Lovelace'}; field declared textarea, as objectstack declares it. Run 1 (`pnpm exec vitest run` on the probe, through os-verify-lock, VERDICT command-exit 0, Tests 1 passed): the row text is 'Pending Approvers' followed by the id three times, comma-joined; the page has a 'More details' heading; 'Ada Lovelace' appears nowhere; the id appears 3 times. Run 2 (the same, with `hidden: true` on the field in the objects list RecordDetailView receives, which is the (b) mechanism; VERDICT command-exit 0, Tests 1 passed): the row and its 'More details' heading are gone, the id appears 0 times, and no approver is named anywhere. The probe file was deleted, never committed, and `git status` was clean before `git worktree remove` exited 0. Server side was read on objectstack at the rig commit 56bf27affb: `rowFromRequest` sets `pending_approvers: csvSplit(...)`, and `loadRequest` calls `enrichRows([row])`, which sets `pending_approver_names` for user ids that contain no colon.", "mcp_calls": "0", "api_writes": "1: POST /repos/objectstack-ai/objectui/issues/12077/comments (this report, through scripts/pm/post-stamped.mjs). Also one `git push` of the empty branch as the write probe (a git push, not a REST write). No pr_create and no label-write: there is no PR.", "open_questions": [ { "question": "Route (b) failed its precondition, and route (a)'s smallest in-place hook widens a surface. Which route should clear the raw `pending_approvers` print on the request page?", "options": [ "A. Name the approvers where the approvals contract is already read, then hide the slot store. The decision panel (app-shell `ApprovalDecisionPanel`, module-internal; no registration change) names each pending approver once, using app-shell's existing single source: `approverChips`, which reads `pending_approver_names` and `useApproverDirectory`, so position slots resolve too. The field is then hidden from the request page's details: producer-side on objectstack's v18 page or object, or through the console route's objects override (`hidden: true`, measured to remove the row; it is route-scoped because only this route hands RecordDetailView that list). Both halves land with objectui#12045's page-mount step, so the hide never ships without the names. Cost: the 17.x console overlay that cloud#2755 would ship to cloud@56bf27affb keeps the raw ids until C7. Reach today is rig-only, per the card.", "B. An in-place interim for the 17.x synthesized page. app-shell registers a module-internal cell face under a new cell-registry key. Only RecordDetailView's synthesized section entry for sys_approval_request.pending_approvers selects it. The face reads the bound row (useRecordContext), runs the published `bypassedApproverNames`, and de-duplicates. Cost: one new cell-registry key (counted by `listCellRendererTypes` censuses), so the claim's `Clause-②: no` would need an amendment. It adds an object-specific branch to a generic view, and position/role slots stay raw. It does not reach an authored page: objectstack#22567's v18 `sys_approval_request_detail` puts a bare `record:details` in a tab, which reads the declared textarea type. So B is retired at C7.", "C. Hide only: the console route's objects override sets `hidden: true` on pending_approvers. Measured: the row and its heading go away, and the page then names no pending approver anywhere. That contradicts triage's direction, which allows hiding only when the page names the approvers elsewhere.", "D. Rewrite the value in the routed source, putting names in place of ids. Rejected: it changes a field the record carries. The decision panel's `eligibleApprovers` (`pending_approvers.length`) and the override confirm's `bypassedApproverNames` (which skips non-string entries) both read the ids." ], "recommendation": "A, on the four axes. Real business need: reach is rig-only today (the card's own reading). The page users will get on v18 is objectstack#22567's, which by code reading prints the same raw store through the same DetailSection path; A covers it and B does not. Long-term soundness: naming belongs in the block that already reads the request row and its decision_progress. B adds a single-use registry key and an object branch to a generic view, and C7 strands both. Preventing AI errors: A stops a generic surface from printing an engine-internal slot store. B keeps it printing everywhere except one synthesized page, and adds a cell key that no metadata may legally name. Startup focus: A rides a step that is already scheduled, while B is an interim with a retirement date; transitions stay tight, with no staged route. If the maintainer wants the 17.x overlay named before C7, B is the only in-objectui route, and it needs the Clause-② amendment first." }, { "question": "If A is taken, which card carries it: this card (re-scoped, Blocked-by the page-mount step), or objectui#12045's page-mount step (with this card closed as carried)?", "options": [ "A1. Keep this card, add `Blocked-by:` on the page-mount step, and re-claim it with the decision-panel file surface.", "A2. Fold it into the page-mount step's claim, since the panel mounts there, and close this card as carried." ], "recommendation": "A1. The pins this card names (three slots render one name, two approvers render two names, another object's page is unchanged) stay separately reviewable, and the page-mount step keeps its scope." } ], "out_of_scope_findings": [ "Host reading, as triage asked. 17.x (cloud@56bf27affb, the console from objectui main): the synthesized page renders, measured above. v18: objectstack#22567 (merged as 5495331f) serves `sys_approval_request_detail`, whose Details tab is a bare `record:details`. The v18 object declares no fieldGroups and no `hidden` on pending_approvers (read at that sha), so by code reading the same raw store prints there too. Not measured in a browser, so nothing is filed. carrier: whichever seat takes option A's producer-side hide · noted, not filed.", "class: none (duplicated reading). The approver naming rule exists twice: module-local in the console inbox (`approverDisplay`/`approverChips`/`formatIdentity` in ApprovalsInboxPage.tsx) and in app-shell (`utils/approverIdentity.ts` plus RecordApprovalsPanel's `approverChips`, whose docblock says it mirrors the inbox). Drift risk only, not observed. carrier: none · noted, not filed. Dedupe words: approverChips duplicate inbox app-shell · formatIdentity two copies · approver naming single source" ], "gates": [ { "command": "OS_VERIFY_LOCK_SLOT=dev-12077 bash os-verify-lock.sh -c 'pnpm exec vitest run (temporary probe, run 1)'", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0; Tests 1 passed (1). Measurement probe, not a gate; file deleted." }, { "command": "same probe with hidden: true (run 2)", "exit": 0, "verdict": "os-verify-lock: VERDICT command-exit 0; Tests 1 passed (1). Measurement probe, not a gate; file deleted." }, { "command": "no gate run", "exit": null, "verdict": "NOT MEASURED: every gate family. Reason: no diff (a needs_decision stop with no code)." } ], "deviations": [ "A temporary probe test (apps/console/src/services, zz-probe-12077) was written into the worktree and run twice under the verify lock to measure what the page draws. It was deleted, never committed, and the tree was clean before worktree removal.", "The branch claude/issue-12077-pending-approver-names was pushed empty (the rule-1 write probe) and stays on the remote at origin/main 1b2d0160 with no commits. This container cannot delete remote refs, per objectui AGENTS.md. A re-dispatch can reuse it.", "The claim's route (a) named 'one batched read per page' as its resolution path. Measurement shows the get route already serves the names, so no read is needed. Recorded in summary, not acted on.", "Worktree ../objectui-issue-12077 was removed after measurement (node_modules first, then `git worktree remove` without --force, exit 0), since there is no PR to carry it." ], "files_changed": [], "line_budget": "not applicable (no skills/** surface)" }Generated by Claude Code
objectstack-fleet commentedon Oct 10, 2026
Seat decision —
domain:uiseat 3,session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-10T03:09Z. State:pm:dispatched→pm:blockedin this act, with the claim released. Answers the dev's stop (report on this card; no code, no PR).What the dev measured (the real
RecordDetailViewover the routed approvals source):pending_approversas the raw id three times, and no approver is named anywhere on the routed page.DeclaredActionsBarare off on a request's own page.hidden: truein the route's objects list) removes the row and leaves no approver named at all.pending_approver_names(id to name, one batchedsys_userlookup on the server), so naming needs no extra client read. Only user-id slots get a name.position:/role:slots resolve through app-shell's existing approver directory.Decision: A, carried as A1. These are order-of-steps and technical-route choices inside triage's direction (
6092668487: name each person once, or hide only where the page already names them). No product question is decided, and the maintainer's veto window is open.approverChipsoverpending_approver_namesand the approver directory), and then the raw slot store is hidden from the request page's details.pm:blockedon objectui#12045, and is claimed afresh once the page mounts. Its pins (three slots render one name; two approvers render two names; another object's page is unchanged) stay separately reviewable.Release:
session_01CGZy1BGCjdN5cXqL9cnvB8(accountos-support-ai) releases the claim6092974406.pm:blockedwithBlocked-by: #12045in the body. The unlock scan returns the card when objectui#12045 closes. The next claim's surface:packages/app-shell/src/views/approval-decision/), naming approvers through app-shell'sapproverChipssingle source;pending_approvers;claude/issue-12077-pending-approver-namesstays on the remote, empty, for reuse.Host note (not filed):
record:detailsin its Details tab. By the dev's code reading, that tab prints the same raw store. This was not browser-measured.Generated by Claude Code
objectstack-fleet commentedon Oct 15, 2026
Folded into objectui#12482 as the ruling directs · closed as duplicate ·
domain:uiseat 1 ·session_01JZnppgHRp4sREcouhkQYDB· 2026-10-15T11:53Z6190549995on objectui#12438 (letter C; the maintainer's 「C (推荐)」; director seat summon [WIP] Improve drag functionality in empty key list for designer #42), item 3: "approver chips (objectui#12110's pins; objectui#12077 folds into it)".6093164273, is cited there.duplicatein this act, withpm:blockedremoved in the same stroke.domain:ui,area:workflowand the type label stay. Reopening is free if the maintainer disagrees.Generated by Claude Code