fix(plugin-audit): 让 provisioning 说出表建到了哪个 datasource (#4887) - #5035
Merged
Conversation
…ned (#4887) `provisionSystemTables()` said nothing on success and returned silently when the engine exposed no `syncObjectSchema`, so "provisioned three tables" and "provisioned nothing" produced byte-identical logs. `syncObjectSchema()` itself returns `void` with three silent exits of its own (object unregistered / no driver / driver without `syncSchema`), none of which throw, so the per-object `catch` could not observe them either. #4887 is what that silence costs. `sys_audit_log` (`lifecycle.class: 'audit'`) and `sys_activity` (`lifecycle.class: 'telemetry'`) were reported as never provisioned because they were absent from the primary SQLite file. They were provisioned: ADR-0057 §3.6 routes both to the dedicated `telemetry` datasource whenever one is registered, and `os dev` registers one by default as a sibling file (`dev.db` -> `dev.telemetry.db`). `sys_comment` carries no lifecycle class, stays on the primary, and was the one that "existed". Nothing in the log connected those facts. Provisioning now reports itself: - the wholesale skip is a `warn` naming the consequence (tables stay lazy-created on first WRITE; a read-first env logs "no such table"); - one `info` line per boot listing where each table landed, resolved through the engine's own `getDriverForObject`; - a second `info` line when the ADR-0057 split is in effect, stating that those tables live in another store and that anything reading them without naming the object will report "no such table" even though provisioning succeeded; - an object that resolves to no driver is a `warn` — `syncObjectSchema()` issues no DDL in that case and throws nothing, so from outside the engine this is the only place it can be observed. Behaviour is otherwise unchanged: the same three objects are synced, per-object failures stay isolated, and an engine without on-demand DDL still degrades rather than failing `start()`. Refs #4887 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015W6nhsDrz6zWQc8je12a1t
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4887
TL;DR —— issue 的表象不成立,真因在别的车道
#4887 报告 "plugin-audit 从不 provision
sys_audit_log/sys_activity",并猜测是provisionSystemTables()里那个静默的if (typeof sync !== 'function') return;提前返回了。实测下来两条都不成立。 provisioning 是好的,
syncObjectSchema被正常调用、表被正常创建 —— 只是创建在了另一个物理库里。真正的缺陷在service-analytics的原始 SQL 桥接,已另开 #5033(未认领,不在本车道)。本 PR 只做本车道该做、且 issue 明确要求的那件事:把 provisioning 的静默改成可听见,让下一个人不必重走这条弯路。
诊断:两个 sqlite 文件
examples/app-showcase,main@e001a1f,SqlDriver(better-sqlite3),单租户:启动横幅
Plugins: 47 loaded里同时有TelemetryDatasource和Audit。这是关键 —— 磁盘上有两个库:原因是 ADR-0057 §3.6(P3 separation,#2791 已实现):
sys_audit_log的lifecycle.class是audit,sys_activity是telemetry,引擎getDriver()第 3 步把这两类对象路由到名为telemetry的 datasource;而os dev在 file-backed sqlite 主库上默认provision 这个兄弟文件(packages/cli/src/utils/telemetry-datasource.ts:dev.db→dev.telemetry.db)。sys_comment没有lifecycle.class,留在主库 —— 所以报告人看到的正是"两个缺、一个在"。同一个对象,两条读路径给出两个答案:
49 条记录真实存在,安全看板显示 0。 这就是 issue 观察到的现象,但成因是
service-analytics的executeRawSql自动桥接拿到了objectName却把它丢掉了(packages/services/service-analytics/src/plugin.ts:267),导致 dataset 的原始 SQL 永远打在默认 datasource 上。同一文件里的executeAggregate桥接调用engine.aggregate(objectName, …),路由是对的 —— 两条路径对"这个对象在哪个库"给出了不一致的答案。详细复现与建议方向见 #5033。那是
packages/services/service-analytics/**,不是本车道,本 PR 不碰。本 PR 改了什么
syncObjectSchema()返回void,并且自己有三个静默出口(对象不在 registry / 没有驱动 / 驱动没有syncSchema),都不抛错 —— 所以调用方只 catch 异常是分辨不出"建好了"和"什么都没干"的。再叠加本侧那个静默的typeof提前返回,结果是:provisioning 全跳过和 provisioning 正常工作,打出来的日志一模一样(都是空)。这正是本 issue 被误诊的机制。现在 provisioning 会自述:
warn,并说清后果 —— 表退回"首次 WRITE 时懒建",先 READ 的环境(首页活动流在任何写入之前就查sys_activity)会一直打no such table;info,列出每张表落到了哪个 datasource —— 通过引擎自己的getDriverForObject解析,不靠推断;info,明确说这些表在另一个 store(SQLite 上就是另一个文件),以及"任何不指名对象去读它们的路径(默认 datasource 上的原始 SQL)会报no such table,尽管 provisioning 是成功的";warn—— 这种情况syncObjectSchema()不发 DDL 也不抛错,per-object 的catch永远不会触发,从引擎外面只有这里能观测到。真实运行时的输出(本分支,
pnpm dev全新库):行为本身没变:同样 sync 这三个对象,per-object 失败依然互相隔离,没有 on-demand DDL 的引擎依然降级而不是让
start()失败。测试
新增
AuditPlugin — provisioning is audible (#4887)5 个用例,覆盖:整体跳过要 warn 且点名后果、逐对象 datasource 落点上报、全在默认 datasource 时不误报拆分、解析不到驱动要 warn、单个对象 sync 失败不影响其余上报。反向验证(防空转):把
audit-plugin.ts还原成main的版本后重跑,新增 5 个用例全部失败、旧用例全绿 —— 新测试确实在测新行为。范围之外
service-analytics的executeRawSql桥接丢弃objectName。这是 plugin-audit never provisions sys_audit_log / sys_activity — Setup "System Overview" audit widgets silently render zeros #4887 现象的真因,影响面覆盖所有lifecycle.class ∈ {audit, telemetry, event}的对象以及任何显式外挂 datasource 的业务对象。🤖 Generated with Claude Code
https://claude.ai/code/session_015W6nhsDrz6zWQc8je12a1t
Generated by Claude Code