|
| 1 | +--- |
| 2 | +"@objectstack/plugin-audit": patch |
| 3 | +--- |
| 4 | + |
| 5 | +fix(plugin-audit): say where the audit system tables were provisioned, and stop skipping provisioning silently (#4887) |
| 6 | + |
| 7 | +`AuditPlugin.provisionSystemTables()` created `sys_audit_log` / `sys_activity` / |
| 8 | +`sys_comment` at `kernel:ready` and then said **nothing** — not on success, and |
| 9 | +not when it skipped the work entirely (`typeof engine.syncObjectSchema !== |
| 10 | +'function'` returned silently). `syncObjectSchema()` itself returns `void` and |
| 11 | +has three silent exits of its own — the object is not in the registry, no driver |
| 12 | +resolves for it, or the resolved driver has no `syncSchema` — none of which |
| 13 | +throw. So "provisioned three tables" and "provisioned nothing at all" produced |
| 14 | +byte-identical logs, and the only way to tell them apart was to go looking in a |
| 15 | +database. |
| 16 | + |
| 17 | +#4887 is what that costs. `sys_audit_log` and `sys_activity` were reported as |
| 18 | +never provisioned because they were absent from the primary SQLite file, with |
| 19 | +the silent `typeof` bail named as the likely cause. Neither was true: |
| 20 | +`sys_audit_log` (`lifecycle.class: 'audit'`) and `sys_activity` |
| 21 | +(`lifecycle.class: 'telemetry'`) are routed by **ADR-0057 §3.6** to the |
| 22 | +dedicated `telemetry` datasource whenever one is registered, and `os dev` |
| 23 | +registers one by default as a *sibling file* (`dev.db` → `dev.telemetry.db`). |
| 24 | +Both tables had been created — in the other store. `sys_comment` carries no |
| 25 | +lifecycle class, stays on the primary, and was the one that "existed". Nothing |
| 26 | +in the log connected those three facts. |
| 27 | + |
| 28 | +Provisioning now reports itself: |
| 29 | + |
| 30 | +- **Wholesale skip is a `warn`, naming the consequence** — the tables stay |
| 31 | + lazy-created on first WRITE, so an env that READS one first (the home page |
| 32 | + activity feed queries `sys_activity` before any mutation) logs "no such |
| 33 | + table" until something writes. |
| 34 | +- **One `info` line per boot listing where each table landed** — |
| 35 | + `sys_audit_log→telemetry, sys_activity→telemetry, sys_comment→sqlite`, |
| 36 | + resolved through the engine's own `getDriverForObject`, so the log states the |
| 37 | + routing rather than leaving it to be inferred. |
| 38 | +- **A second `info` line when the ADR-0057 split is in effect**, saying |
| 39 | + explicitly that those tables live in a different store — on SQLite, a |
| 40 | + different *file* — and that anything reading them without naming the object |
| 41 | + (raw SQL against the default datasource) will report "no such table" even |
| 42 | + though provisioning succeeded. |
| 43 | +- **An object that resolves to no driver is a `warn`** — `syncObjectSchema()` |
| 44 | + returns without issuing any DDL in that case and throws nothing, so the |
| 45 | + per-object `catch` never fires; from outside the engine this is the only place |
| 46 | + it can be observed. |
| 47 | + |
| 48 | +Behaviour is otherwise unchanged: the same three objects are synced, per-object |
| 49 | +failures stay isolated, and an engine without on-demand DDL still degrades |
| 50 | +instead of failing `start()`. |
0 commit comments