Repository navigation
finding: an approver routed a request can be unable to open the record it concerns — the inbox's record link dead-ends on "Record not found" #7345
Description
Activity
Findings triage: escalated —
findingremoved, nowneeds-user-decision; routing stays deliberately open (the ruling decides the landing: objectui suppression or message, identity grant, or accept-as-is).- Why now: this seat's 09:20Z and 10:20Z round briefs allowed the card two rounds unrouted before escalation, and this round is that deadline. Leaving it finding-held keeps a real UX-vs-security fork invisible to every lane; the four dispositions are written and mutually exclusive — a decision card's exact shape.
- The four options (from the card): 1. leave it (approvals decide from the drawer snapshot by design — the decision path itself works); 2. suppress the record link when the viewer cannot read the target (needs a per-row readability probe the inbox does not do today); 3. keep the link, fix only the landing message — distinguish "not visible to you" from "does not exist" (smallest user-facing improvement, no security change; the platform already renders the honest message elsewhere); 4. implicit approver read on the record for the life of the request (a real security-model change — approver routing would become a source of record visibility). Recommendation: option 3 — honest, small, forecloses nothing; option 4 must not ride in as a UX fix.
- Premise: measured 2026-08-10 on the showcase run (framework
88154bee1, console pin8aad9fd5); the mechanism — approver resolution routes on positions, record visibility is a separate gate, nothing reconciles the two — is structural, not fixture-specific. No staleness concern. - Dedup: The Account app's Notifications entry 403s for every non-admin — no permission set grants sys_inbox_message #7344 (missing
sys_inbox_messagegrant, escalated this round) and [console] Four remaining inbox/activity entries still hardcode/apps/setup/..., so a business user without setup access has no working "all notifications" or "all activity" link #7266 (bell routing) are adjacent-but-distinct inbox-family cards; objectui#4110 (popover filter regression) likewise. Cross-linked. Clean.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
Maintainer ruling — 2026-08-11. From the four-lens decision review (platform long-term coherence / measured business pull / AI-agent error-resistance / startup scope discipline); the maintainer accepted the recommendation set in full.
Ruling: two halves, split. (1) The short-term half is queued on THIS card: the approvals inbox renders an honest "record not visible to you" state on the record chip instead of dead-ending on "Record not found" — a UI-truthfulness fix, no security-model change. Lands in the console (routing label
repo:objectuiapplied). (2) The model question — does approver routing imply record read visibility — is deliberately NOT ruled quickly; it is now #7497 (needs-user-decision, approvals), explicitly not v17.State:
needs-user-decision→pm:queue+repo:objectui.Recorded by the triage seat Routine (#5474 pilot) on the maintainer's direct instruction — ruling record, not a claim.
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 os-support-ai commented
on Aug 18, 2026 CollaboratorMore actionsMoved to
objectstack-ai/objectui#5211— closing here asmoved, not as resolved. Undecided and unfixed.Provenance, three parts: whose instruction — the maintainer's; verbatim — 「转」, following 「objectstack 仓库中还有很多 objectui 任务为什么没关掉」; where — said directly to the
repo:objectuiPM seat in sessionsession_01RV6yuVCxymHYE16PL9vQkE, 2026-08-18, under the standing direct-dispatch authorisation.Why moved: of the four candidate dispositions, the two that are genuinely polish — suppressing the record link when the viewer cannot read the target, and distinguishing "not visible to you" from "does not exist" on the landing page — both land in
objectui. Disposition 1 is "leave it" and needs no repo. So every actionable branch except one lives in the destination repo.⚠️ The exception, carried across deliberately: disposition 4 — granting an approver implicit read on the record under approval — is a security-model change, as the original body says plainly, not a UX fix. If that is ever the chosen direction it comes back to this repo as a contract-first split, and ⛔ must not be implemented inobjectuias a polish item. That warning is reproduced in the moved card so it cannot be lost by someone reading only the destination.One label did not survive: the original carried
approvals, which does not exist in the objectui repo. ⛔ I did not mint it — the association is recorded in prose on the moved card instead. Flagging because a label-based query for approvals work will no longer find this card.The 2 comments here stay readable and were not copied. Anyone tracking this: follow
objectstack-ai/objectui#5211.
Generated by Claude Code
Observation-class finding recorded during the #7331 browser verification run. Filed unassigned, no
pm:queue— for triage to grade. It is not a routing regression from #7213; the routing half was verified correct and is stated below so the next reader does not re-derive it.What happens
A non-admin who is a pending approver opens the Approvals Inbox, sees the request, and clicks the record chip in its row (
INV-1002). The record page renders "Record not found — The record you are looking for does not exist or may have been deleted."The record exists and the request is live.
The routing is correct — that part was ruled out first
The rendered href is exactly what #7213 intended: it carries the current app's segment, the right object and the right record id.
Loading the same URL shape under the same app with a record the persona can read renders the record page normally (verified with
showcase_project/record/1YtAy4jz7Wsi9m9kundercom.objectstack.account). So the account app can host a record page for a foreign business object; nothing about the app segment is wrong.The real cause: record-level visibility
The authoritative server answer for that persona is a 404, not a 403:
The persona holds
contributor, whoseshowcase_invoicegrant is owner-scoped; the invoice is owned by another user, so it is filtered out of the row set before the by-id read. The same read as admin returns the record. Transferringowner_idto the persona did not change the outcome either (the seeded showcase rows carryorganization_id: null), so the showcase fixture makes this easy to hit — but the general shape is not showcase-specific: approver resolution routes on positions, record visibility is a separate gate, and nothing reconciles the two.Why it is worth recording rather than shrugging at
The drawer degrades well: it carries the request's payload snapshot (record title, object, subtotal, account, status), so an approver can decide without opening the record, and the decision itself works — the run approved this exact request from the drawer successfully. So this is not a blocked approval.
What is unsatisfying is the affordance: the inbox offers a record link that, for the person it is offered to, leads to a page saying the record may have been deleted. The message is also the least useful of the available truths — the honest one is "you do not have access to this record", which the platform renders elsewhere (
sys_inbox_messagerenders exactly that for the same persona).Candidate dispositions (not decided here)
No option recommended; 4 in particular is a security-model change, not a polish item.
Evidence
Measured 2026-08-10,
examples/app-showcase, framework88154bee1, console dist stamp8aad9fd50b16750aebdd294392ff79540f17cd32. Non-admin persona holdingcontributor+finance. Screenshots of the "Record not found" landing, of the same URL shape rendering a readable record, and the paired API reads were captured in the run.Generated by Claude Code