CMDCSkillEngine.Store.Backend.SQLite (cmdc_skill_engine v0.3.0)

Copy Markdown View Source

基于 SQLite 的 Skill 档案后端(持久化)。

exqlite 直连 SQLite, 把 SkillRecord 的身份/血统/计数器/历史分析全部落到单一 .db 文件:

  • 跨进程重启保留:GenServer 崩溃后数据仍在
  • 跨节点共享:多个 Erlang 节点可指向同一 SQLite 文件(注意:不同节点写入需自己 协调,SQLite 默认锁 wait 2s)
  • 无 Ecto 依赖:轻量级、直连裸驱动,避免 schema migration 仪式

v0.3 多租户切片

v0.3 起表新增 scope 列 + 复合索引 (scope, skill_id),所有读写按 scope 过滤实现 租户隔离。skill_id 仍是表 PRIMARY KEY:依赖 cmdc 主库 CMDC.Skill.discover/1 生成的 <name>__imp_<rand_hex> skill_id 全局唯一性。不同租户即使有同名 Skill (如 weekly_report_writer),各自的 skill_id 也不同(因随机后缀),互不冲突。

限制:如果调用方手工构造 SkillRecord 并显式指定一个跨 scope 重复的 skill_id,写入会发生 INSERT OR REPLACE 冲突,覆盖另一 scope 的数据。 这种情况不推荐 —— 走 CMDCSkillEngine.register_skill/2 让 skill_id 由 cmdc 主库随机生成即可避免。

选项

  • :path — SQLite 文件路径(必填);支持 :memory: 运行内存数据库(测试用)
  • :pragma — 额外 PRAGMA 列表(默认 [journal_mode: :wal, synchronous: :normal]

Schema

单张表 skill_records。复合字段(lineage / recent_analyses / tags 等) 以 JSON 字符串序列化,兼顾灵活性与可读性(可用 sqlite3 CLI 直接查询):

CREATE TABLE IF NOT EXISTS skill_records (
  skill_id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  ...
  lineage TEXT NOT NULL,          -- JSON
  recent_analyses TEXT NOT NULL,  -- JSON
  ...
  scope TEXT NOT NULL DEFAULT 'global',
  metadata TEXT NOT NULL DEFAULT '{}'
);
CREATE INDEX idx_skill_records_scope ON skill_records(scope, skill_id);

用法

children = [
  {CMDCSkillEngine.Store,
    backend: CMDCSkillEngine.Store.Backend.SQLite,
    backend_opts: [path: "./priv/skills.db"]}
]