Filed by the domain:metadata PM seat on behalf of #7823's dev, which measured this while doing that card's objectui console-SPA check but could not file it — the objectstack-ai org has no Claude GitHub App connection, so cloud dev containers are blocked from the GitHub API.
⚠️Authored by the PM from the dev's measurements (its own draft could not be relayed). The measurements and file/line anchors below are the dev's; the framing is mine. Correct me rather than the dev if the framing is off.
The defect
A row action declaring recordIdField gets undefined for it, because the grid never projects that column.
useConsoleActionRuntime.tsx:322-325 reads rowRecord[action.recordIdField] — a generic read, correct in itself.- The grid builds
$select from listView columns + id + predicate fields only (ObjectGrid.tsx:677-722, predicate-fields.ts:141-170). recordIdField is not harvested into that projection. - So for any action whose
recordIdField is not already a listView column, the row object has no such key and the action sends undefined.
Measured instance — sys_session.revoke_session
sys_session declares revoke_session with recordIdField: 'token', and token is in no listView. So the action sends no token, better-auth's revoke-session (session.mjs:441-443) matches nothing, deletes nothing — and still answers { status: true }.
⇒ "Revoke Session" reports success and revokes nothing. A security control that silently no-ops while reporting success.
Two things worth separating
- The general defect is the projection gap: any
recordIdField outside the listView is silently undefined. sys_session is the instance that surfaced it, not the whole of it. ⚠️ Whoever picks this up should enumerate the other declarations rather than fixing the one — a per-action patch leaves the class open. - The silent success is arguably its own defect: an action that identifies no record should not answer
{ status: true }. That half may be better addressed upstream of the projection fix.
⚠️ It interacts with #7823 — read this before choosing a fix
#7823 proposes internal: true on sys_session.token. If that lands, the obvious repair here — "harvest recordIdField into $select" — is foreclosed for this instance, because an internal field is stripped from result rows regardless of projection. The generic projection fix would still be correct for every other recordIdField; sys_session.revoke_session would need a different mechanism (an action that names the record by id and lets the server resolve the token, for instance).
⚠️#7823 is currently a design exit awaiting a maintainer ruling on whether internal: true needs a mint-path exemption, so the interaction is live rather than hypothetical. ⛔ Do not assume either card's outcome when scoping this one.
Establishment level, stated honestly
The projection gap and the missing harvest are read from code (grep for recordIdField in the projection builders returns nothing; the control grep for sys_session in the same file set returns hits, so the search reaches objectui source). The end-to-end "click Revoke Session, observe nothing revoked" was not run. Reproduce before fixing.
Routing
The projection fix lands in objectui (packages/app-shell), not in this repo. The sys_session.revoke_session declaration lives in packages/platform-objects here. Filed without a domain: label so the triage seat can route it — it may need to be split across the two repos.
Filed by the
domain:metadataPM seat on behalf of #7823's dev, which measured this while doing that card'sobjectuiconsole-SPA check but could not file it — theobjectstack-aiorg has no Claude GitHub App connection, so cloud dev containers are blocked from the GitHub API.The defect
A row action declaring
recordIdFieldgetsundefinedfor it, because the grid never projects that column.useConsoleActionRuntime.tsx:322-325readsrowRecord[action.recordIdField]— a generic read, correct in itself.$selectfrom listView columns +id+ predicate fields only (ObjectGrid.tsx:677-722,predicate-fields.ts:141-170).recordIdFieldis not harvested into that projection.recordIdFieldis not already a listView column, the row object has no such key and the action sendsundefined.Measured instance —
sys_session.revoke_sessionsys_sessiondeclaresrevoke_sessionwithrecordIdField: 'token', andtokenis in no listView. So the action sends no token, better-auth'srevoke-session(session.mjs:441-443) matches nothing, deletes nothing — and still answers{ status: true }.⇒ "Revoke Session" reports success and revokes nothing. A security control that silently no-ops while reporting success.
Two things worth separating
recordIdFieldoutside the listView is silentlyundefined.sys_sessionis the instance that surfaced it, not the whole of it.{ status: true }. That half may be better addressed upstream of the projection fix.#7823 proposes
internal: trueonsys_session.token. If that lands, the obvious repair here — "harvestrecordIdFieldinto$select" — is foreclosed for this instance, because aninternalfield is stripped from result rows regardless of projection. The generic projection fix would still be correct for every otherrecordIdField;sys_session.revoke_sessionwould need a different mechanism (an action that names the record byidand lets the server resolve the token, for instance).internal: trueneeds a mint-path exemption, so the interaction is live rather than hypothetical. ⛔ Do not assume either card's outcome when scoping this one.Establishment level, stated honestly
The projection gap and the missing harvest are read from code (
grepforrecordIdFieldin the projection builders returns nothing; the control grep forsys_sessionin the same file set returns hits, so the search reachesobjectuisource). The end-to-end "click Revoke Session, observe nothing revoked" was not run. Reproduce before fixing.Routing
The projection fix lands in
objectui(packages/app-shell), not in this repo. Thesys_session.revoke_sessiondeclaration lives inpackages/platform-objectshere. Filed without adomain:label so the triage seat can route it — it may need to be split across the two repos.