Repository navigation
plugin-approvals: the request and action list views show an Object column with the target object's API name (object_name, such as showcase_announcement), the type half of the record pointer pair, drawn as plain text #24501
Copy link
Copy link
Closed
Labels
area:workflowApprovals and automation — the work that runs without a person driving itApprovals and automation — the work that runs without a person driving itdomain:servicespriority:p2Medium: important, M3Medium: important, M3
Description
Filing gate ①, class (a): a user-visible machine name with a named producer on a served surface. This is the list-view position of the family #24264, #24281 and #24375 closed on the approval request page. Found by #24375's dev (report on #24375, out-of-scope finding 1; PR #24500). Filed by domain:services seat 2 (seat post #21118) · os-warren · session_01LR1cD9JqgkeqY7k9rrZH8s. ⛔ Not a claim. Grade, lane and area:* are triage's.
reach:named producer. The positions, read on PR fix(plugin-approvals): the approval request page's highlights strip draws no Object chip; the Details tab's record card names the target object by its label #24500's head5f21f062f, whose list views are unchanged fromorigin/main:packages/plugins/plugin-approvals/src/sys-approval-request.object.ts: the list viewsall_requests,my_pending,submitted_by_meandcompleted(about:100,:109,:123,:133) declareobject_nameas a column next torecord_id.packages/plugins/plugin-approvals/src/sys-approval-action.object.ts:recentandall_actions(about:57and:77) do the same. plugin-approvals: serve display labels for the approval lists — the step and flow labels, "Waiting on", the Action History record pointer andacted_as#23889 added that pair.object_nameis a text field that holds the target object's API name, andrecord_iddeclaresreferenceVia: 'object_name'.
- What the console draws (a static reading at objectstack-ai/objectui pin
4016370af3c9, not a screen reading):ObjectGrid'srecordPointerFace(packages/plugin-grid/src/ObjectGrid.tsx:470) gives the pointer face only to the id half. Theobject_namecolumn is a plain text field and draws its stored string. So the Requests and Action History lists show an Object column readingshowcase_announcement. - The record page no longer shows it. PR fix(plugin-approvals): the approval request page's highlights strip draws no Object chip; the Details tab's record card names the target object by its label #24500 (for plugin-approvals: the approval request page's Object chip shows the target object's API name (
object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375) removesobject_namefrom the page's highlights strip and the object'shighlightFields, because the Details tab's pointer card heads the target record with its object's label (RecordPreviewCard,objectLabel()). The list views were outside that card's rule and are unchanged. - Reader who acts: triage grades this card and sets its lane. The two routes have the same shape as plugin-approvals: the approval request page's Object chip shows the target object's API name (
object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375's:- drop the
object_namecolumn where therecord_idpointer cell already names the record; - or name the object by its label in the list. That needs a served label column, or the console drawing the pointer pair's type half by its object's label. The second is an objectui change.
- plugin-approvals: the approval request page's Object chip shows the target object's API name (
object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375's constraint carries over: "⛔ No console-side mapping: the served page must not declare a machine-name chip."
- drop the
- Precedent: ruling B of plugin-approvals: an approval request's notification names the record by its raw id (
crm_opportunity/<id>), and opening one on an empty slot logs "cannot advance" just before routing to the administrators #23556 / security(approvals): the inbox's subject record_title is resolved under the system context and served to every approver without their field-level security, against payload-redaction's serve-time contract and #7497's ruling C #23594 names a record by "object label + id" (as plugin-approvals: the approval.reminder and approval.sla_breached notification bodies still name the record as object_name/record_id — the ruled "object label + id" form (#23556 / #23594 ruling B) reached approval.requested only #23978 applied it).
Dedupe
- objectstack, MCP
search_issues"approval request list view Object column shows API name object_name showcase_announcement all_requests my_pending": 8 hits, closed included. Positive control plugin-approvals: the approval request page's Object chip shows the target object's API name (object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375 came back. The others are approvals: "My Pending" never lists a request routed to a position — the console filters withapproverId=role:<p>, the request storesposition:<p>, and the list filter matches literally #21350, plugin-approvals: an approval request's notification names the record by its raw id (crm_opportunity/<id>), and opening one on an empty slot logs "cannot advance" just before routing to the administrators #23556, plugin-approvals: the served sys_approval_request page's Details tab ends with arecord:jsonpanel of the request payload, gated onstudio.access(objectui#12490, face 4 of objectui#12438 letter C) #23746, approvals: a request opened underonEmptyApprovers: 'admin_rescue'is in no one's pending queue —listRequests/countRequestshave no arm that returns it to the callers who can decide it #22725, finding(plugin-approvals): Setup → Approvals → Requests opens sys_approval_request's caller-scoped first view my_pending, so an administrator sees only requests pending on themselves (#21972's eighth family member) #21984, plugin-approvals: serve display labels for the approval lists — the step and flow labels, "Waiting on", the Action History record pointer andacted_as#23889 and [approvals]assignedToMe=trueis not a supported list filter on/api/v1/approvals/requests— silently ignored, returns every request #7527, all closed; plugin-approvals: serve display labels for the approval lists — the step and flow labels, "Waiting on", the Action History record pointer andacted_as#23889 added the action pointer pair and none of them covers the column. - objectui, MCP
search_issues"referenceVia pointer pair type half drawn as plain text in grid list column object name machine name": 1 hit, objectui#12693 (closed: Studio machine names, a different surface).
Dedupe words: approval request list Object column API name; object_name list view column showcase_announcement; sys_approval_action recent all_actions object_name column; referenceVia type half plain text grid.
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:workflowApprovals and automation — the work that runs without a person driving itApprovals and automation — the work that runs without a person driving itdomain:servicespriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 19, 2026
Triage: p2 ·
domain:services·area:workflow·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T08:55ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
origin/main7e58e0a279.packages/plugins/plugin-approvals/src/sys-approval-request.object.ts:98,:107,:121and:131listobject_namebesiderecord_idin all four list views.record_iddeclaresreferenceVia: 'object_name'(:261). The premise holds.object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375: a user-visible machine name on a served surface.object_namecolumn where therecord_idpointer cell already names the record is the one-repo route. It mirrors PR fix(plugin-approvals): the approval request page's highlights strip draws no Object chip; the Details tab's record card names the target object by its label #24500's choice for the record page, and it honours plugin-approvals: the approval request page's Object chip shows the target object's API name (object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375's "⛔ No console-side mapping".findingcomes off with this grade.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 2 · 2026-10-19T09:29Z
Session:
session_01LR1cD9JqgkeqY7k9rrZH8sAccount:
os-warren(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24501-approval-list-object-columnWorktree:
objectstack-issue-24501Domain:
domain:servicesSeat:
domain:services#2(seat post #21118)File surface:
packages/plugins/plugin-approvals/src/sys-approval-request.object.ts(the four list views'columns) andsys-approval-action.object.ts(therecentandall_actionsviews'columns), with the pins beside them; on the label route only, the served label column and its writer and backfill in the same two object files plusapproval-service.ts's row builders, declared before any edit; a changeset; ⛔ notapproval-node.ts, and ⛔ notapproval-service.tson the drop route; ⛔ not objectstack-ai/objectui, ⛔ notpackages/spec/**(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(the default tier;dispatch-gates --tierprinted no path-derived mandate for this surface)Clause-②: no
Responsibility:
plugin-approvals' list views, which declareobject_nameas a column beside therecord_idpointer (this lane) | none: the pointer cell draws the record, and the separate column draws the stored API name | every user of the approval request and Action History lists in the console; live todayThread-read: 6263481224
Serial constraints cleared: PR #24500 (#24375), which edited
sys-approval-request.object.ts, landed as666283aeae, the order triage set (6263481224). No open PR among the 11 touchesplugin-approvals(file scan at this claim). Of the 14pm:dispatchedclaims, only #24497's (domain:engine) namesplugin-approvals, and only as a fallback on the producers (approval-service.ts,approval-node.ts), which this claim keeps out of the drop route. #24321 (seat 1's next,pm:queue) may reachapproval-service.ts's decision path, not the object files.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{ "issue": 24501, "status": "needs_decision", "branch": "claude/issue-24501-approval-list-object-column", "pr": null, "session": "session_01LR1cD9JqgkeqY7k9rrZH8s (subagent: the dispatching seat's session)", "premise_still_valid": true, "summary": "Not built: the drop route that triage and the dispatch name would break the cell it relies on. The console's list rows carry only the view's `$select`, and objectui builds that from the view's `columns` plus fixed harvests, never from the `referenceVia` sibling. So dropping `object_name` from `columns` leaves `record_id` half-addressed, and the Record column draws the raw record id (objectui's own control case), losing the target's icon and name. Any route that removes the machine-name column (drop or label) needs the type half projected some other way, which is wider than this card's surface. The options and the recommendation (objectui harvests the sibling, then this card drops the column) are in `open_questions`; no PR, no file changed.", "readings": { "tree": "objectstack `origin/main` `6b42b6bc8` (`666283aea` plus `820fd5aef` and `6b42b6bc8`, which touch only plugin-approvals' CHANGELOG.md and package.json); objectui `.objectui-sha` = `4016370af3c9`, read with `git show PIN:path`; objectui `main` `6f877f1df4` (09:17Z) re-read for the two projection builders. These are static readings, not a screen reading: this container has no console build (`packages/console/dist` is absent).", "A1_holds": "`sys-approval-request.object.ts` lists `object_name` beside `record_id` in `all_requests` :100, `my_pending` :109, `submitted_by_me` :123 and `completed` :133. `sys-approval-action.object.ts` does the same in `recent` :57 and `all_actions` :77; `by_actor` :67 does not.", "A2_what_the_cell_draws": "`RecordPointerCell.tsx` (header :22-:31, render :277, :309): in the readable state it draws the target object's icon and the record's name, linked, with the raw id as the tooltip. No object label text is drawn. In the unreadable state it draws 'LABEL · record unavailable'. All six showcase approval targets declare an icon (project, invoice, expense_report, task, field_zoo, announcement). So the cell itself tells a reader which kind of record a row is about, through the icon, and the Flow column (`process_label`) mostly names the subject too: 'Project Budget Approval', 'Expense Report Sign-off', 'Announcement Dynamic Approval'.", "A2_what_the_cell_needs": "`resolveRecordPointer` (`fields/src/index.tsx` :3306-:3308) reads the type half from the ROW (`row[via]`) and returns null when it is absent or blank. The grid then draws the stored text, which is the raw id; objectui pins this as 'a half-addressed row keeps the stored text (control)', `ObjectGrid.recordPointerCell-12608.test.tsx` :141. The row carries only the projection. `ListView.tsx` `selectFields` (:2920-:3265) is `id` + authored `columns` (FLS-filtered) + `$expand` roots + harvests for view bindings, grouping, row colour, deadlines, predicates and the concurrency token. It has no `referenceVia` arm. `ObjectGrid.tsx` `getSelectFields` (:2620-:2875, `extraFields` :2842) has the same harvests and no `referenceVia` arm either; objectui `main` `6f877f1df4` is unchanged in both. The adapter forwards `$select` (`data-objectstack/src/index.ts` :4934), and objectstack's data door projects it. `packages/objectql/src/declared-fields.ts` :30-:34 records list rows as the view's `$select` projection, 'sparse, permanently', by decision. Setup's request and action lists read through that door: `routeApprovalRecordReads` routes only a `findOne` of a request and one request's timeline, per the `approvalRequestsDataSource.ts` header. The inbox page (`ApprovalsInboxPage.tsx`) is bespoke, draws `object_label || object_name`, and does not use these views.", "A2_verdict": "Dropping `object_name` from `columns` takes it out of `$select`. Every Setup list row then reaches the cell without its type half, and the Record column changes from 'icon + record name' to the raw record id. That loses what a user reads, and loses it in the record column, not the object column. Triage's premise 'where the `record_id` pointer cell already names the record' holds only while the type half is projected.", "A3": "No declared rule or pin binds list `columns` to `highlightFields`; `sys-approval-request.page.ts` and its pin read `highlightFields` and the page's own timeline columns only. One pin binds the action lists to the pair: `approval-list-display-labels.integration.test.ts` :291 asserts `recent` and `all_actions` contain `object_name`, `record_id` and `acted_as_label` (#23889's case (f)). Any drop route rewrites that line. No lint rule or `scripts/` gate reads `referenceVia` against list columns.", "hiddenFields_probe": "`ListView` subtracts `hiddenFields` only from the drawn set (`effectiveFields` :3780). Its own `$select` reads `schema.columns` before that subtraction, so `hiddenFields: ['object_name']` would keep the type half fetched on that path. But `ListView` hands the grid `fields: effectiveFields` (:3943), and a grid that owns its grouped fetch (`gridOwnsGroupedFetch` :2590) builds `$select` from those fields (`ObjectGrid.tsx` :2872). On that path the type half is not fetched and the cell draws the raw id. Two fetch paths give two answers for one declaration." }, "tests": "None run: no file changed, so there is no behaviour to test and no ablation. Every claim above is a static reading at the named trees, with file:line.", "gates": "`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` at `6b42b6bc8`: exit 2, 'this branch changes nothing against origin/main (merge base 6b42b6bc8) — nothing to derive'. 0 derived, 0 run, so there is nothing to reconcile with `--ran`. No PR, so no check-runs to cite.", "line_budget": 0, "files_changed": [], "deviations": [ "No PR and no changeset: the route was falsified before the first edit (rule 6). The branch is pushed empty at `origin/main` `6b42b6bc8`, as the write-route probe and the claim's landing marker.", "The verdict rests on static readings, with objectui's own pinned control case. The browser screen reading is NOT MEASURED, reason: there is no console build in this container, and one at the pin needs objectui's console build plus the showcase closure.", "Card, thread, #24375 and PR #24500 were read with single-resource `gh api` REST reads. objectui `main`'s head and two files were read through the commits and contents APIs. That is 7 reads in all, and none was an MCP call." ], "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/24501/comments (this report, through `scripts/pm/post-stamped.mjs` on the fleet relay). `git push` of the empty branch is not a REST write.", "open_questions": [ { "question": "Which route takes the target object's API name out of the six approval list views (request `all_requests`, `my_pending`, `submitted_by_me`, `completed`; action `recent`, `all_actions`)? Measured: the `record_id` pointer cell resolves only while `object_name` is in the list's `$select`, and objectui projects only shown columns plus fixed harvests.", "options": [ "A: objectui harvests the `referenceVia` sibling of every projected pointer column into `$select`, in both `ListView.selectFields` and `ObjectGrid.getSelectFields`, behind the declared-field and FLS-readable gates its grouping, row-colour and deadline harvests use. It is pinned beside objectui#12608's cases: a list whose columns omit the type half still draws the record. The console pin then moves (with the SDUI manifest regenerated), and #24501 drops `object_name` from the six `columns` and rewrites pin (f) line 291. #24501 is Blocked-by the objectui card, because landing the drop before the pin moves turns every Setup list's Record column into raw ids. Effort: one small objectui PR (two projection builders and one test), one pin bump (it can ride a scheduled one), then a diff here of about ten lines plus the changeset. Cost: three landings in order.", "B: keep `object_name` in `columns` and add `hiddenFields: ['object_name']` to the six views. This is objectstack only, inside this card's surface, about six lines. Measured cost: it holds only on ListView's own fetch. A grid that owns its grouped fetch projects the effective (post-hiddenFields) fields and draws raw ids. Any objectui change that stops fetching hidden columns reverts every row silently, with no gate to see it. The declaration says 'hide' and means 'fetch for another column's renderer'.", "C: the label route. Declare an `object_label` column on both objects, written in `openNodeRequest` and `actionRow`, filled by a boot backfill, carried in four bundles, and shown in place of `object_name`. Removing `object_name` from `columns` breaks the pointer exactly as above, so C needs A or B as well. It also inherits PR #24500's objections: a stored snapshot beside the approvals get's live `object_label`, which goes stale when the object is relabelled. Widest effort.", "D: no change now. Park #24501 until A lands. The machine name stays visible in the six lists meanwhile." ], "recommendation": "A. By the four axes. Real need: the readers are admins on Setup's Approvals Requests (4 views) and Action History (2 views). A keeps the Record cell (icon + name, or 'LABEL · record unavailable') and removes only the machine-name column. Three sibling objects draw the same machine-name Object column for the same pointer reason (`sys_audit_log` 5 views, `sys_record_share` 6, `sys_share_link` 4), and A unblocks their drops with no further console change. Long-term: A is contract-first, because the renderer fetches what a declared `referenceVia` needs, in the harvest shape the list already uses four times. B holds on one fetch path of two. C adds a second answer for one fact. Making AI mistakes harder: after A, an author who lists an id half without its type half still gets the record, so the trap is gone structurally. Under B, removing the 'unused' hidden column, or grouping the list, silently reverts to raw ids. Startup focus: A adds no column, writer, backfill or gate. B is the cheapest, but it is a staged workaround that 过渡也从紧 rules out. C is the widest. Excluded rather than offered: the console drawing the `object_name` column by its object's label. That is the console-side mapping #24375's carried constraint forbids, since the served list would still declare a machine-name column." } ], "out_of_scope_findings": [ "carrier: #24501 (this decision) · objectui's list projection never asks for a `referenceVia` pointer's type half, so a list view that shows the id half without its sibling draws the raw id (`ListView.tsx` :2920-:3265, `ObjectGrid.tsx` :2620-:2875 at pin `4016370af3c9`, unchanged on objectui `main` `6f877f1df4`). Dormant today: every pointer-pair list view in this repository lists both halves. It goes live the moment option A's drop, or option C, lands without the harvest. Under option A the seat files it in objectui with a back-link, and #24501 carries `Blocked-by:`. Dedupe words: referenceVia sibling select projection list; record pointer half-addressed raw id list; ListView selectFields harvest pointer type half; ObjectGrid getSelectFields referenceVia.", "class: a · reach: named producer: `packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts` :53, :63, :108, :124, :140; `packages/plugins/plugin-sharing/src/objects/sys-record-share.object.ts` :58, :67, :80, :92, :102, :112; `packages/plugins/plugin-sharing/src/objects/sys-share-link.object.ts` :60, :70, :80, :90 · evidence: each view lists `object_name` (a `Field.text` labelled 'Object' that holds the target's API name) as a column, and the console draws it as the stored string. This is the same family and the same pointer constraint as #24501, so it is not a single-point card: fold it into whichever card carries this decision for the family. Dedupe words: audit log list Object column API name; record share list object_name column; share link list object_name machine name; pointer pair type half list column." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Seat answer and Release ·
domain:servicesseat 2 ·os-warren·session_01LR1cD9JqgkeqY7k9rrZH8s· 2026-10-19T09:46ZRelease:
session_01LR1cD9JqgkeqY7k9rrZH8sreleases claim6264078420· reason: the route's premise is falsified (dev report6264306454) · destination:pm:blockedbehind objectstack-ai/objectui#13036 · the branchclaude/issue-24501-approval-list-object-columnsits empty atorigin/main6b42b6bc8, so the next claim may reuse it or cut fresh (Resume-from: none).The dev's
needs_decision, answered by the seat: route A. This is a lane call, not a maintainer question. It restores a declared invariant, that areferenceViapointer resolves, and orders the technical tasks. No option differs in product semantics or in a public contract's shape. The maintainer can veto in the round report.What the dev measured, re-read by the seat at objectui pin
4016370af3c9:ListView.tsxandObjectGrid.tsxhave noreferenceViaarm in their$selectbuilders.resolveRecordPointerreadsrow[via](packages/fields/src/index.tsxabout:3306).ObjectGrid.recordPointerCell-12608.test.tsx:141.So triage's drop route (
6263481224, "where therecord_idpointer cell already names the record") holds only while the type half is projected. Droppingobject_namealone would turn the Record column into raw ids.Why A, by the four axes:
referenceVianeeds, in the harvest shape its lists already use. That is contract-first.Why not the others:
hiddenFields) holds on one of two fetch paths and silently reverts on the other. It is a workaround.object_namecolumn by label is plugin-approvals: the approval request page's Object chip shows the target object's API name (object_name, such asshowcase_announcement), while the get servesobject_label, whichsys_approval_requestdoes not declare #24375's forbidden console-side mapping.Order: plugin-list / plugin-grid: a list's
$selectnever asks for areferenceViapointer's type half, so a list view that shows the id half without its sibling column draws the raw record id objectui#13036 adds the harvest in both projection builders, with pins. objectstack's.objectui-shathen moves past it; the pin moving is the install. Then this card dropsobject_namefrom the list views'columns. Landing the drop before the pin moves breaks every one of these lists. The body carriesBlocked-by: objectstack-ai/objectui#13036. The unlock also reads.objectui-shapast that fix, not only the closure.This card now collects the family (the dev's out-of-scope finding 2; one card for the family, not a card per object). The positions, read at
origin/main6b42b6bc8by the dev, each listingobject_name(aField.textlabelled "Object" holding the API name) as a list column:plugin-approvals/src/sys-approval-request.object.ts:all_requests:100,my_pending:109,submitted_by_me:123,completed:133.plugin-approvals/src/sys-approval-action.object.ts:recent:57,all_actions:77.plugin-audit/src/objects/sys-audit-log.object.ts::53,:63,:108,:124,:140.plugin-sharing/src/objects/sys-record-share.object.ts::58,:67,:80,:92,:102,:112.plugin-sharing/src/objects/sys-share-link.object.ts::60,:70,:80,:90.At re-dispatch:
referenceViaid half to keep.plugin-sharingobject files.approval-list-display-labels.integration.test.ts:291, which asserts the pair inrecent/all_actions, is rewritten.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
State change ·
pm:blocked→pm:on-hold·domain:servicesseat 2 ·os-warren·session_01LR1cD9JqgkeqY7k9rrZH8s· 2026-10-19T13:45ZRestart-when: objectstack
origin/main's.objectui-shahas objectuife11eb12e578fe38cff8ba454de6507bd99daa2a(PR objectstack-ai/objectui#13042, the fix for objectstack-ai/objectui#13036) as an ancestorRestart-touch: .objectui-sha
$selectnever asks for areferenceViapointer's type half, so a list view that shows the id half without its sibling column draws the raw record id objectui#13036 closed when objectui PR [worklist] Re-close the tool.json liveness ledger — every citation points into the cloud runtime's service-ai, which this repo's checkout does not contain #13042 merged asfe11eb12e5. That PR fixed the list projection (it adds thereferenceViapointer's type half to$select)..objectui-shaonorigin/mainis4016370af3c9, committed at 2026-10-19T03:42Z, before the fix (committed at 2026-10-19T11:29Z). In the objectui clone,git merge-base --is-ancestor fe11eb12e5 4016370af3c9answers exit 1. That clone is shallow, so the commit dates, not the ancestry exit, are the reading here.3b086e76f(chore(objectui): move the console pin from 0707b4ae3712 to 4016370af3c9, the newest green objectui main and the first pin past objectui#12957 #24476).pm:on-holdwith the two machine-read lines above, by this seat's judgment. The body'sBlocked-by: objectstack-ai/objectui#13036line is replaced with them.6264371362and checks the epic's territory for the twoplugin-sharingobject files. The drop then follows that comment's plan.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 4 · 2026-10-19T14:27Z
Session:
session_01LR1cD9JqgkeqY7k9rrZH8sAccount:
os-warren(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24501-approval-list-object-columnWorktree:
objectstack-issue-24501Domain:
domain:servicesSeat:
domain:services#2(seat post #21118)File surface: the list views'
columnsinpackages/plugins/plugin-approvals/src/sys-approval-request.object.ts,sys-approval-action.object.ts,packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts,packages/plugins/plugin-sharing/src/objects/sys-record-share.object.tsandsys-share-link.object.ts, the pins beside them (includingapproval-list-display-labels.integration.test.ts's pair line), and a changeset; ⛔ notapproval-service.ts/approval-node.ts(#24321 and #24519 hold them), ⛔ not objectstack-ai/objectui, ⛔ not.objectui-sha(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus(the default tier;dispatch-gates --tierprinted no path-derived mandate for this surface)Clause-②: no
Responsibility: the five objects' list views, which declare a pointer pair's type half (
object_name, an API name) as a shown column (this lane) | objectstack-ai/objectui#13036 (closed): objectui PR #13042 (fe11eb12e5) now fetches the type half without the column | every Setup user of these lists; live todayThread-read: 6268722760
Serial constraints cleared: no open PR touches any of the five object files (file scan of all 11 open PRs at this claim). No
pm:dispatchedclaim names them: #24421 (plugin-sharing) holdssharing-rule-service.ts, and the C2/C3 epic territory (#15194) namessharing-rule-service.ts, the bootstrap seeder andsharing-plugin.ts's boot region, not these object files. Landing waits on the pin: the PR stays draft until objectstack's.objectui-shahas objectuife11eb12e5as an ancestor, because a drop before then draws raw ids in these lists. That condition replaces the hold'sRestart-when:line, which leaves the body in this act.State change, recorded here:
pm:on-hold→pm:dispatched. The maintainer asked why dispatch had stopped ("为什么不继续派发"). The pin wait now governs landing only, and the work is written now.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{ "issue": 24501, "status": "done", "branch": "claude/issue-24501-approval-list-object-column", "pr": "https://github.com/objectstack-ai/objectstack/pull/24600", "session": "session_01LR1cD9JqgkeqY7k9rrZH8s (subagent: the dispatching seat's session)", "premise_still_valid": true, "summary": "Route A's second half is done: `object_name` (the target object's API name) leaves `columns` in the 20 list views where it sat beside its `record_id` pointer id half. They are request 4, action 2, audit log 4, record share 6 and share link 4. `sys_audit_log.config_changes` lists `object_name` without an id half, so it is not this pattern and is left as is. Each package gains an enumerating pin: no list view shows a `referenceVia` sibling beside its id half, and the family's views still show the id half. Pin (f) is rewritten to the new contract. Draft PR #24600 is parked, because objectstack's `.objectui-sha` (`4016370af3c9`) does not yet have objectui `fe11eb12e5` as an ancestor (exit 1; the control leg `4016370af3c9~30` gave exit 0).", "readings": { "A1": "Confirmed on `origin/main` `de4352460`. All 20 views list `object_name` immediately before `record_id`, and `record_id` declares `referenceVia: 'object_name'` on each object: request :263, action :154, audit log :321, record share :172, share link :168. `sys_approval_action.by_actor` never listed it. `sys_audit_log.config_changes` (:124) lists `object_name` with no `record_id`. Its rows are `config_change` (`sys_setting` or `sys_platform_setting`, `record_id: null`) and `import` (`sys_user`, no `record_id`). That view is reported and left as is.", "A2": "Holds, read from objectui `fe11eb12e5` with `git show` (read only). `ListView.tsx` `selectFields` loops over the FLS-surviving `cols` and adds `objectDef.fields[c].referenceVia` through `addSpeculative`. That covers ListView's own fetch. `ObjectGrid.tsx` `getSelectFields` adds a `referenceViaFields` harvest (shown columns, `passesProjectionGate`, `isProjectableField`) into `extraFields`. That covers the grid-owned grouped fetch and a standalone `object-grid`. `fe11eb12e5` is an ancestor of objectui `origin/main` `8aa8e3e1e5` (exit 0), and both arms are present there.", "A3": "Done. Case (f) now asserts `arrayContaining(['record_id', 'acted_as_label'])` and `not.toContain('object_name')` for `recent` and `all_actions`.", "pin_state": "`.objectui-sha` is `4016370af3c9`, committed at 03:42Z; the fix was committed at 11:29Z. In the shallow objectui clone, `git merge-base --is-ancestor fe11eb12e5 4016370af3c9` gave exit 1. On the same clone, the control `4016370af3c9~30` (`b5153f44ea`) gave exit 0." }, "tests": "All runs are at `c62273124` and went through `os-verify-lock.sh`. (1) Builds: the three packages' dependency closure gave VERDICT command-exit 0, and the three packages themselves gave VERDICT command-exit 0. (2) `pnpm --filter @objectstack/plugin-approvals exec vitest run --maxWorkers=2`: Test Files 81 passed (81), Tests 1114 passed (1114), exit 0. (3) plugin-audit had 56 files and 899 tests pass; plugin-sharing had 49 files and 1163 tests pass. Both exited 0 (VERDICT command-exit 0). (4) Typecheck: `pnpm --workspace-concurrency=1 --filter` over the three packages, `run typecheck`, gave VERDICT command-exit 0. check:test-typecheck was OK for approvals (324 errors over 8 files, unchanged), audit (0) and sharing (3 errors over 2 files, unchanged). (5) Ablation ran through `scripts/ablation-replace.mjs` in wrap mode at the committed HEAD, one leg per package. Each leg put `object_name` back: sharing `all_shares`, audit `record_views`, approvals `all_requests`. Each mutation landed (anchor x1 to x0, blob changed). Each turned exactly one test red, `no list view shows a referenceVia sibling beside its id half` (`expected [ Array(1) ] to deeply equal []`), with vitest exit 1, 1 and 1. Each file was restored to blob == HEAD with an empty `git diff HEAD`. The tests import the objects by relative src path, so no rebuild was needed.", "gates": "Local: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` ran at `c62273124` with no paths (merge base `de4352460`) and derived 67 commands. A runner recorded each exit code before any pipe. On the first pass 65 exited 0. `pnpm check:i18n` and `pnpm check:dual-build-cjs-loads` exited 3 (PREREQUISITE NOT MET). After a full `turbo run build --filter='!@objectstack/docs'` under the lock (VERDICT command-exit 0), both re-ran with exit 0. `--ran ran-final.list` exited 0: '67 derived, 67 run, 0 NOT-MEASURED, 0 UNRUN'. CI: all 31 check-runs on PR head `c62273124` were `queued` at report time (in_progress). They include the Lint & Repo Gates lanes, the Type Check lanes, Test Core 1-6/6, Build Core, Check Changeset and Governed Surface Queue Guard. None had concluded.", "line_budget": 253, "files_changed": [ ".changeset/24501-list-object-column.md", "packages/plugins/plugin-approvals/src/approval-list-display-labels.integration.test.ts", "packages/plugins/plugin-approvals/src/sys-approval-action.object.ts", "packages/plugins/plugin-approvals/src/sys-approval-request-pointer-pair.test.ts", "packages/plugins/plugin-approvals/src/sys-approval-request.object.ts", "packages/plugins/plugin-audit/src/objects/sys-audit-log.object.ts", "packages/plugins/plugin-audit/src/sys-audit-log-pointer-pair.test.ts", "packages/plugins/plugin-sharing/src/objects/sys-record-share.object.ts", "packages/plugins/plugin-sharing/src/objects/sys-share-link.object.ts", "packages/plugins/plugin-sharing/src/sharing-pointer-pairs.test.ts" ], "deviations": [ "pr_create through the relay exited 6 (UNCONFIRMED): run 39280081714 still read `queued` after 300 s. No second dispatch was sent. A read of the target confirms PR #24600: created by objectstack-fleet[bot] at 15:43:23Z, draft, assignee os-warren, head `c62273124`. The read-back body matches the sent body byte for byte, apart from the reader's trailing newline.", "The enumerating pin is three per-package pins, not one file. The five objects live in three packages, and a single file would need cross-package imports outside the claimed surface. Each pin enumerates its whole package: approvals reads the `ApprovalsServicePlugin` manifest, and audit and sharing read `objects/index.ts`. So a list view added later is judged too.", "Worktree: the local branch already existed at `6b42b6bc8`, left by the first dev and equal to the remote. The worktree was added on it and fast-forwarded to `origin/main` `de4352460` instead of being created with `worktree add -b`. No force-push.", "`test:repo` was not run locally: the derivation does not name it, so it is declared to CI (Test Core). The dogfood battery was not run, because it is not a PR check (it runs in main's push battery).", "Browser reading NOT MEASURED. The bundled console at the pin predates the fix, and a reading against objectui `main` needs an objectui worktree build. That reading belongs to the unlock.", "Attribution follows AGENTS.md: the commit carries the model-free `Claude-Session` / `Co-authored-by` pair, and the PR body ends with the session-URL footer form. The harness reminder's model-named trailer and other footer form were not used; AGENTS.md outranks the reminder, as the reminder itself states.", "A shell slip, contained. The first attempt to compose this report used an unquoted heredoc, so bash ran the backtick spans in the text as commands, from `/home/user` (not a git repository). None of them reached a write: the relative `scripts/pm/*` paths did not resolve, `git` refused outside a repository, `POST` was not found, and pnpm rejected the typecheck spelling. One `pnpm --filter @objectstack/plugin-approvals exec vitest run` was started from `/home/user` outside the lock. No vitest results were written in any checkout after it (the newest `results.json` is this worktree's, from 15:02), and no process of it remains. `/home/user` and the shared checkout's `git status` are unchanged. The report was then written from a file." ], "mcp_calls": "0", "api_writes": "2 relay dispatches, each a `POST /repos/objectstack-ai/objectstack/dispatches`, sent through `scripts/pm/with-fleet.sh --via dispatch` and `scripts/pm/post-stamped.mjs`. They executed: (1) `POST /repos/objectstack-ai/objectstack/pulls` (draft, opened #24600) and `POST /repos/objectstack-ai/objectstack/issues/24600/assignees` (os-warren); (2) `POST /repos/objectstack-ai/objectstack/issues/24501/comments` (this report). The branch was also pushed twice with `git push`, which is not a REST write.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: named producer (static reading, not a screen reading) · evidence: same family as #24375 and this card. These served surfaces still name a pointer's target by its API name, outside the list `columns` this card covers. `sys-record-share.object.ts`: :45 `titleFormat: '{object_name}/{record_id} → {recipient_id} ({access_level})'`, with no `nameField`, so it is the record title; :46 `highlightFields` lists `object_name`; the `by_object` view groups and sorts on `object_name`, so its group header reads the API name. `sys-share-link.object.ts`: :51 `titleFormat: '{object_name}/{record_id} ({permission})'`, with no `nameField`; :52 `highlightFields`. `sys-audit-log.object.ts`: :44 `titleFormat: '{action} · {object_name}'` (its `nameField` is `action`); :45 `highlightFields`; `config_changes` lists `object_name` with no id half. Line numbers are after this PR. This is a family finding, not a single-point card: fold it into whichever card carries the family's record-page and grouping positions. The record-page half follows #24375's route, where the Details tab's pointer card names the object by its label. The `config_changes` and `by_object` positions need a decision, because no label column exists to show or to group by. Dedupe words: record share title format object_name record_id; share link highlightFields object_name; record shares by object grouping API name; audit log config changes Object column sys_setting." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Landed ·
domain:servicesseat 2 ·os-warren·session_01LR1cD9JqgkeqY7k9rrZH8s· 2026-10-19T23:20Z.objectui-shaonmain12dc7b47c340(PR #24660, #24644), which carries objectuife11eb12e5(git merge-base --is-ancestor, exit 0): the list projection fetches areferenceViapointer's type halfauto_merge_enabled2026-10-19T22:56Z →added_to_merge_queue2026-10-19T22:59Z →merged2026-10-19T23:20Zorigin/main92ce3af404is an ancestor (git merge-base --is-ancestor, exit 0)completedby the PR'sFixes #24501; this act clearspm:dispatchedand the assigneeACCEPT
6271464866is on the PR. The record-page and grouping half of this family is #24611.Generated by Claude Code