# cmdc_skill_engine Changelog
本项目遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/) 与
[Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/) 规范。
## [0.3.0] - 2026-05-22
**多租户 Skill 数据切片 + `:telemetry` 事件契约。**
向后兼容的 minor 版本(除 `Store.Backend` behaviour 签名变更外),
集成方零改动可平滑升级;多租户场景显式传 `:scope` 即可启用硬隔离。
### Added
#### `:telemetry` 事件契约(`CMDCSkillEngine.Telemetry`)
暴露 4 个标准事件:
- `[:cmdc_skill_engine, :analyzer, :analyze, :start]`
- `[:cmdc_skill_engine, :analyzer, :analyze, :stop]` — 含 `duration_ms` /
`task_completed` / `suggestion_count` / `fallback?`
- `[:cmdc_skill_engine, :evolution, :emitted]` — 含 `evolution_type` /
`skill_id` / `scope` / `parent_skill_ids`
- `[:cmdc_skill_engine, :store, :record_updated]` — 含 `operation`
(`:save | :counters_incremented`)
所有事件 metadata 自动注入 `:schema_version`(当前 `1`)。提供
`attach_logger/1` 用于开发期;生产建议直接 `:telemetry.attach_many/4`
接入 Langfuse / Datadog / Phoenix Channel 等。
#### 多租户切片(`:scope`)
`CMDCSkillEngine.Store` 公共 API 全部新增 `:scope` keyword(默认 `"global"`):
```elixir
{:ok, _} = Store.list_active(scope: "tenant_a")
{:ok, _} = Store.get_record(id, scope: "tenant_a")
{:ok, _} = Store.get_records(ids, scope: "tenant_a")
{:ok, _} = Store.get_version_chain(id, scope: "tenant_a")
:ok = Store.update_counters(id, [selections: 1], scope: "tenant_a")
```
- ETS 后端:表 key 形如 `{scope, skill_id}`,`list_active(scope:)` 走
`:ets.match_object/2` 直接命中目标 scope(基线 p99 ≤ 16µs,100 scope × 100
records / scope 场景,详见 `benchmark/scope_lookup.exs`)
- SQLite 后端:新增 `scope` / `metadata` 列 + 复合索引 `(scope, skill_id)`;
`list_active(scope:)` 在 100 scope × 100 records 数据上 p99 ≤ 1 ms(远低于
5 ms 契约)
- 跨 scope 查询返回 `:not_found` —— 强制租户隔离
`CMDCSkillEngine.Types.SkillRecord` 新增字段:
- `:scope :: String.t()`,默认 `"global"` —— 数据切片维度
- `:metadata :: map()`,默认 `%{}` —— 集成方自由扩展字段(建议
`"<namespace>.<field>"` 命名空间约定)
`CMDCSkillEngine.Analyzer` / `SkillRanker` / `SkillRanker.Semantic` 自动
从 `ctx.user_data.user_id`(或 `ctx.scope`)提取 scope,与 cmdc_memory_pg
`EpisodicMemoryBackend` 的租户切片维度对齐。
`CMDCSkillEngine.register_skill/2` 新增 `:scope` / `:metadata` 选项:
```elixir
CMDCSkillEngine.register_skill(skill, scope: tenant_id, metadata: %{"studio.created_by" => "..."})
```
#### SQLite idempotent migration
升级 v0.2 → v0.3 老 .db 时,启动通过 `PRAGMA table_info` 探测缺失列,
自动 `ALTER TABLE` 补 `scope` / `metadata` 列;新建 .db 走 CREATE TABLE
全字段,零副作用。老数据自动归入 `scope = "global"`。
#### Benchmark
- `benchmark/scope_lookup.exs` — ETS / SQLite 多 scope 切片读 / list 基线
脚本,详见 `benchmark/README.md` 实测表
### Changed (Breaking — Backend behaviour)
- `CMDCSkillEngine.Store.Backend` callback 签名加 `scope` 参数(**hard break**
vs v0.2.x):
- `get_record(state, scope, skill_id)`(从 `get_record(state, skill_id)`)
- `list_all(state, scope)`(从 `list_all(state)`)
- `update_counters(state, scope, skill_id, increments)`(从
`update_counters(state, skill_id, increments)`)
- `save_record(state, record)` — 签名不变(scope 由 `record.scope` 字段
携带)
- `reset/1` / `init/1` / `terminate/1` — 签名不变
内置 ETS + SQLite 后端已迁移;第三方 backend 实现需要按新签名适配。
- `CMDCSkillEngine.Store` 公共 API 全部加 `:scope` keyword(默认 `"global"`),
调用方零改动可平滑升级。
- `CMDCSkillEngine.Analyzer.handle_event(:session_end, ...)` 自动透传 scope
到 `process_analysis/2` → `Store.get_record(scope: ...)` 调用链。
- `CMDCSkillEngine.Evolver.evolve/2` 新建 SkillRecord 时自动从 `context[:scope]`
继承 scope;`lookup_parent/2` 限定同 scope 查找。
### Migration
- **老调用方零改动**:所有 Store API 默认 `scope = "global"`,行为完全等价 v0.2.x
- **老 .db 文件**:首次启动自动 idempotent migration,归入 `scope = "global"`
- **第三方 Backend 实现者**:按 `CMDCSkillEngine.Store.Backend` 新 callback 签名
调整即可(参考 `CMDCSkillEngine.Store.Backend.ETS` / `Backend.SQLite`)
### Notes
- 跨 scope 聚合查询(`list_all_scopes/0`、`scope: :all` 特殊值)暂不支持,
留 v0.4+ 按集成方实际需求评估
- `metadata` 字段命名空间约定(如 `"studio.tenant_name"`)当前不强制校验,
留首次冲突时收紧
## [0.2.2] - 2026-05-18
**Patch release** — repository URL normalization + documentation cleanup.
No code changes, no behavior changes.
- Repository URL → `https://github.com/tupleyun/cmdc_skill_engine`
- Module moduledoc rewritten to neutral technical description
- CHANGELOG sections rewritten to neutral technical descriptions
## [0.2.1] - 2026-05-16
**Compatibility patch** — 让 `cmdc_skill_engine` 与 cmdc 0.4 主线生态
对齐,并补 benchmark 工具链(v0.2.0 后 commit 但未发布)。
### Changed — cmdc 依赖范围升级
- `{:cmdc, "~> 0.2"}` → **`{:cmdc, "~> 0.4"}`**
- **背景**:`~> 0.2` 严格语义 `>= 0.2.0 and < 0.3.0` 阻塞与 cmdc
0.3/0.4 共存。用户同时引入 cmdc 0.4 + cmdc_skill_engine 0.2 会
触发 Hex 版本冲突
- **兼容性核实**:本库依赖的 cmdc 抽象(`CMDC.Plugin` behaviour +
`CMDC.SystemPrompt` Skills 注入接口)都在 v0.1 起稳定,且 v0.2-v0.4
无 breaking change(除 v0.3 #B21 facade tuple,本库不调 facade)
- **无运行时行为变更**
### Added — Benchmark 工具链
- 新增 `benchmark/quality_update.exs` — 100 skills × 10 轮 quality_update
传播 Benchee suite(Store + QualityTracker 热路径性能基线)
- `benchmark/README.md` — benchmark 运行指引
- `:benchee, ~> 1.3` 加入 `dev / test` 依赖
### Migration
- 老用户仍用 cmdc 0.2 → 锁 `{:cmdc_skill_engine, "0.2.0"}` 即可
- 想用 cmdc 0.4 → 升级到 `{:cmdc_skill_engine, "~> 0.2.1"}`
## [0.2.0] - 2026-04-25
**真实自进化闭环** —— Agent learning & adaptation:质量追踪 + 自动停用 +
FIX/DERIVED/CAPTURED 三动作进化。
### Added
- `CMDCSkillEngine.Store.Backend` behaviour — 存储后端抽象层,定义
`init/1 / get_record/2 / save_record/2 / list_all/1 / update_counters/3 /
reset/1 / terminate/1` 契约。
- `CMDCSkillEngine.Store.Backend.ETS` — v0.1 的默认后端,单节点开发/测试首选。
- `CMDCSkillEngine.Store.Backend.SQLite` — 基于 `exqlite` 的持久化后端,自动
创建 schema + 索引,支持 JSON 字段序列化(lineage / recent_analyses / tags)。
- `CMDCSkillEngine.Analyzer.LLM` — ReqLLM `generate_object/4` 驱动的结构化
分析器;强制输出 `task_completed / execution_note / tool_issues /
skill_judgments / evolution_suggestions`;自带超时控制与 `:generate_fn`
注入钩子便于离线测试。
- `CMDCSkillEngine.SkillRanker.Semantic` — 新的 Selector 实现,结合 BM25
关键词相关性、`effective_rate` 质量反馈与可选 `ReqLLM.embed/3` 语义向量
相似度(`:embedding_model` 未配置时自动退化为 BM25 + 质量加权)。
- `CMDCSkillEngine.QualityTracker.should_deactivate?/2` +
`update_from_analysis/3` — 新增自动停用规则:达到 `min_samples` 后,若
`applied_rate < applied_min` 或 `effective_rate < effective_min` 且
`trend != :improving`,自动把 `is_active = false`。
- `CMDCSkillEngine.Evolver` fix 链长度上限(默认 5);超过时返回
`{:error, {:fix_chain_too_long, generation, max_depth}}`,防止进化链
失控膨胀。
- `example/skill_evolution_demo.exs` — 10 轮会话的完整自进化演示,无 LLM
依赖,可 `mix run` 复现。
- `test/cmdc_skill_engine/stress_test.exs` — 1000 轮收敛压力测试,验证
QualityTracker 能在合理轮次内识别并停用低质量 Skill。
### Changed
- `CMDCSkillEngine.Store` 重构为委托结构:GenServer state 保存
`{backend_module, backend_state}`,所有 CRUD 操作通过 Backend 契约转发;
公共 API 完全向后兼容。
- `CMDCSkillEngine.Analyzer` 集成 LLM 路径:当 `analysis_model` 是 LLM
spec(非 `nil / "builtin" / "manual" / "rule" / ""`)时,`:session_end`
走 LLM 分析;任何失败(超时 / HTTP / schema / 异常)自动降级到规则分析,
不打断 Agent 正常结束流程。
- `CMDCSkillEngine.Analyzer` state 新增 `:messages` 字段,累积
`:before_prompt / :after_response` 消息,作为 LLM 分析上下文。
- `CMDCSkillEngine.QualityTracker.update_from_analysis/2` 改为三元参数版本
`update_from_analysis/3`(第三参数可选 `keyword()`),保持对现有调用方
向后兼容。
- `Application.start/2` 支持 `:start_store` 配置开关,测试环境默认关闭
自动启动以避免与 ExUnit 测试隔离冲突。
### Fixed
- Store GenServer 初始化时默认启动逻辑与测试隔离机制冲突,导致多个测试
互相竞争同一 ETS 表 —— 现通过 `start_store: false`(test 环境)+
`test_helper.exs` 里的单次 `start_link` + `Process.unlink/1` 修复。
### Deps
- 新增 `{:exqlite, "~> 0.27"}`、`{:jason, "~> 1.4"}`(SQLite backend
+ JSON 序列化)
### 测试覆盖
- 105 个测试全部通过(3 个 `@moduletag :stress` 压力测试默认排除)
- Store Backend 契约共 32 个测试(ETS × 16 + SQLite × 16)
- Analyzer.LLM 10 个单元测试(全部通过 `:generate_fn` stub,无真实 LLM)
- Analyzer 集成 15 个测试(LLM 命中 + 失败降级 + 规则关键字保护)
- SkillRanker.Semantic 9 个测试(BM25 / 质量回退 / embedding 注入)
- QualityTracker 15 个测试(计数器 + trend + deactivation 门控)
- Evolver 10 个测试(FIX / DERIVED / CAPTURED + fix chain 上限)
## [0.1.0] - 2026-04-23
### Added
- 初始版本:ETS Store、规则 Analyzer、QualityTracker、Evolver
(FIX/DERIVED/CAPTURED)、SkillRanker(按 effective_rate 排序)。
- 完整数据模型:SkillRecord / SkillLineage / ExecutionAnalysis /
SkillJudgment / EvolutionSuggestion。