- Shipped
- September 7, 2026 at 3:22 AM UTC
- Author
- Kamo
- Commit
- 94288d8
The tenancy check is gone from visibleOr404 and from all four queries, so every organization can read, comment on and vote on every report. SystemBugIdentityPolicy is what replaces it, and it is three ORed terms: a TeamMember of the platform org sees everything; a report filed BY the platform org names itself to everybody (which is how "KamoCRM Inc. + the member who posted it" falls out with nothing hardcoded — the top-level org's own title is already that string); and your own organization is never anonymous to you, which is exactly what a tenant sees today. The policy never asks the SUBJECT's member type, only their organization, and that is deliberate: SystemBug.getReporter() is a lazy association, so `proxy instanceof TeamMember` answers false for every row in the estate and a rule written that way would have redacted everything, consistently enough to look intentional. The viewer's type is safe to test because requireMember resolves them through findById. Redaction is cosmetic unless it reaches every surface a name travels on, and there were four. The row's senderName; the actorName baked into a stored status-event payload, which SystemMessage renders directly; the parentSenderName on a reply quote, read from a different row than the message it sits on; and the raw member ids in a reaction row, which nobody reads as identity. All four are handled, and withheld speakers are numbered per report — the reporter pinned to #1, the rest by first message, from the whole thread rather than the requested page so asking for page 2 cannot renumber anybody. The thread's NATS frame loses senderName too, because one payload fanned out to every subscriber cannot be redacted per viewer and /topic/chat/session is not among StompDestinationAuthz's guarded prefixes. It costs nothing — the console re-reads the page over REST on any frame. The member id and body deliberately STAY: ChatEmailNotifier consumes the same subject and drops an event missing either, so stripping them would silently stop the mail telling somebody their report was answered. Voting is improvements-only and refuses a defect, a voided report, and anything but 1/-1/0. Filing an improvement casts the reporter's upvote as a real row, so they can change their mind later without anything special-casing them. create_system_bug_vote.sql is the hand-applied DDL — ddl-auto is none and initializerservice is not deployed. Already applied to the live database: table, column, indexes, and 30 backfilled reporter upvotes.