|
| 1 | +--- |
| 2 | +"@objectstack/platform-objects": patch |
| 3 | +--- |
| 4 | + |
| 5 | +fix(platform-objects): remove the System Overview board's permanently-empty "Permission Changes" tile (#8148, #7675) |
| 6 | + |
| 7 | +<!-- adr-0087: not-required (no-migration-prescription) A widget is removed from |
| 8 | +a platform-shipped dashboard, and four hand-authored locale bundles drop the |
| 9 | +matching `dashboards.system_overview.widgets.widget_permission_changes` subtree. |
| 10 | +No authorable KEY changes: `DashboardWidgetSchema` is untouched, nothing is |
| 11 | +renamed or tombstoned, and the retirement of the `sys_audit_log.action` VALUE |
| 12 | +this tile filtered was registered by #8147 as a SEMANTIC entry |
| 13 | +(`17.audit-log-action-enum-retired`). This change is the UI half of that already |
| 14 | +registered retirement, so it prescribes no migration of its own. --> |
| 15 | + |
| 16 | +The System Overview dashboard shipped a "Permission Changes" metric tile |
| 17 | +filtering `sys_audit_log.action = 'permission_change'`. **The tile could never |
| 18 | +report anything but `0`, on any deployment that has ever existed** — the value |
| 19 | +had no writer anywhere in the repo. There are exactly two `sys_audit_log` |
| 20 | +writers: `plugin-audit`'s generic hook writer, whose `actionFor` maps |
| 21 | +afterInsert/afterUpdate/afterDelete to `create`/`update`/`delete` and nothing |
| 22 | +else, and `plugin-auth`'s admin user-import. Neither has ever emitted |
| 23 | +`permission_change`. #8147 then retired the value from the action enum outright, |
| 24 | +so the tile's filter now names a value the platform does not even declare. |
| 25 | + |
| 26 | +**An empty tile on a compliance surface is worse than a missing one.** A |
| 27 | +permanently-`0` "Permission Changes" count does not read as "this platform does |
| 28 | +not track permission changes" — it reads as a *negative finding*: an auditor |
| 29 | +concludes the platform watched for permission changes over the selected window |
| 30 | +and found none. The number was live and the query was real; the question it |
| 31 | +answered was one no row could ever be an answer to. 审计面宁窄勿谎 — a narrow |
| 32 | +audit surface beats a lying one. |
| 33 | + |
| 34 | +**Removed rather than refiltered onto a live action.** Permission and role edits |
| 35 | +*are* captured today, as ordinary `create` / `update` rows written by the generic |
| 36 | +hook against the permission objects — so the honest lens on them is `object_name` |
| 37 | +on the audit list view, a row-level question rather than a single-number KPI. |
| 38 | +Approximating one as a tile would have put a second not-quite-true number on the |
| 39 | +same board. The two surviving Row 2 tiles ("Login Events", "Config Changes") |
| 40 | +split the 12-column row in half instead of leaving a gap where the removed tile |
| 41 | +sat. |
| 42 | + |
| 43 | +The by-action tile's description stops naming `permission` among its example |
| 44 | +actions, in the source **and in all four locale bundles** — the translations are |
| 45 | +the strings actually served, so correcting only the source would not have reached |
| 46 | +a single user. |
| 47 | + |
| 48 | +⚠️ **`import` is deliberately untouched.** It was named in the same ruling as |
| 49 | +`permission_change`, but its retirement premise was falsified during #8147: it |
| 50 | +has a live writer (`plugin-auth`'s admin user-import writes a run-level row) and |
| 51 | +a shipped list view that filters it. Removing it from the dashboard while the |
| 52 | +platform still emits it would produce the exact inverse defect — an audit action |
| 53 | +that can be written but cannot be found. |
| 54 | + |
| 55 | +Both directions are pinned. A tombstone refuses any board widget filtering a |
| 56 | +retired action value, with a live-action control so it cannot pass on a board |
| 57 | +that has no widgets or whose predicates moved. The app/dashboard translation |
| 58 | +parity test gains the **reverse direction it was missing** for dashboard widgets |
| 59 | +— it asserted every declared widget has a translation, but nothing stopped a |
| 60 | +translation outliving its widget, which is precisely what these four locale |
| 61 | +entries would have done. |
0 commit comments