Symptom
Only CRUD actions ever materialize in sys_audit_log. On a fresh boot:
- Sign up + sign in a member, then as admin
GET /api/v1/data/sys_audit_log?$filter={"action":"login"} → total 0; the only trace is an unattributed update sys_user row (user_id null) diffing last_login_at.
PUT /api/settings/branding {"workspace_name":"X"} → 200, then filter {"action":"config_change"} → total 0; the event went to sys_setting_audit with action set instead.
Both reproduced twice. Action census over all 57 rows: {'create':48,'update':7,'delete':2}. The delete half is correct (full old_value, actor, tenant).
Net effect: four enum values (login, logout, permission_change, config_change; also export/import), two shipped list views (auth_events, config_changes) and two dashboard widgets (system_overview.dashboard.ts L89 + L109) are permanently empty. The console makes it worse by listing login/config_change in its own ACTION_OPTIONS — it offers filters for rows the server never writes.
The tamper-proofing half is solid: POST/PATCH/DELETE to sys_audit_log all 405 OBJECT_API_METHOD_NOT_ALLOWED, list total unchanged.
Root cause
Located by the run. packages/plugins/plugin-audit/src/audit-writers.ts subscribes only to the ObjectQL wildcard before*/after* CRUD lifecycle events, so it can emit create/update/delete/restore and nothing else. A repo-wide search finds no writer for login, logout, permission_change, config_change, export or import, though all are declared in the action enum of sys-audit-log.object.ts. Settings writes are audited by settings-service-plugin.ts:315 into sys_setting_audit, never sys_audit_log, while settings-service.types.ts:16 documents the service as "Emit sys_audit_log rows for every successful write."
Confirmed on origin/main: audit-writers.ts docblock still states it subscribes to the before*/after* lifecycle; settings-service-plugin.ts still inserts into sys_setting_audit (~L320) while settings-service.types.ts:16 still carries the contradicting doc line.
Reproduction
- Fresh boot; sign up + sign in a member.
- As admin
GET /api/v1/data/sys_audit_log?$filter={"action":"login"} → total 0.
PUT /api/settings/branding {"workspace_name":"X"} → 200; filter {"action":"config_change"} → total 0 (the row is in sys_setting_audit, action set).
Suggested fix
Either add writers for the declared non-CRUD actions (auth, permission, config, export/import) into sys_audit_log, or reconcile the declared enum, the two list views, the two widgets, and the console ACTION_OPTIONS with what is actually written — and reconcile settings-service.types.ts:16's contract with the sys_setting_audit destination.
Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).
Symptom
Only CRUD actions ever materialize in
sys_audit_log. On a fresh boot:GET /api/v1/data/sys_audit_log?$filter={"action":"login"}→ total 0; the only trace is an unattributedupdate sys_userrow (user_idnull) diffinglast_login_at.PUT /api/settings/branding {"workspace_name":"X"}→ 200, then filter{"action":"config_change"}→ total 0; the event went tosys_setting_auditwith actionsetinstead.Both reproduced twice. Action census over all 57 rows:
{'create':48,'update':7,'delete':2}. The delete half is correct (fullold_value, actor, tenant).Net effect: four enum values (
login,logout,permission_change,config_change; alsoexport/import), two shipped list views (auth_events,config_changes) and two dashboard widgets (system_overview.dashboard.tsL89 + L109) are permanently empty. The console makes it worse by listinglogin/config_changein its ownACTION_OPTIONS— it offers filters for rows the server never writes.The tamper-proofing half is solid: POST/PATCH/DELETE to
sys_audit_logall 405OBJECT_API_METHOD_NOT_ALLOWED, list total unchanged.Root cause
Located by the run.
packages/plugins/plugin-audit/src/audit-writers.tssubscribes only to the ObjectQL wildcardbefore*/after*CRUD lifecycle events, so it can emitcreate/update/delete/restoreand nothing else. A repo-wide search finds no writer forlogin,logout,permission_change,config_change,exportorimport, though all are declared in the action enum ofsys-audit-log.object.ts. Settings writes are audited bysettings-service-plugin.ts:315intosys_setting_audit, neversys_audit_log, whilesettings-service.types.ts:16documents the service as "Emit sys_audit_log rows for every successful write."Confirmed on
origin/main: audit-writers.ts docblock still states it subscribes to thebefore*/after*lifecycle; settings-service-plugin.ts still inserts intosys_setting_audit(~L320) while settings-service.types.ts:16 still carries the contradicting doc line.Reproduction
GET /api/v1/data/sys_audit_log?$filter={"action":"login"}→ total 0.PUT /api/settings/branding {"workspace_name":"X"}→ 200; filter{"action":"config_change"}→ total 0 (the row is insys_setting_audit, actionset).Suggested fix
Either add writers for the declared non-CRUD actions (auth, permission, config, export/import) into
sys_audit_log, or reconcile the declared enum, the two list views, the two widgets, and the consoleACTION_OPTIONSwith what is actually written — and reconcilesettings-service.types.ts:16's contract with thesys_setting_auditdestination.Source
Extracted from the QA run #7637 (framework 92f26f7, console 09987b680).