feat: add project learning lifecycle

This commit is contained in:
dafang
2026-08-01 23:39:29 +08:00
parent 9ca7273472
commit 45521f915b
9 changed files with 753 additions and 4 deletions
@@ -0,0 +1,228 @@
---
status: active
created: 2026-08-01
work: ../work/epic-cs-continuous-learning-lifecycle.md
---
# CodeStable 持续学习生命周期
## 起点与目标
四个 task skill 已会检索项目 lesson`cs-keep` 也有证据、查重与合并门槛,但闭环停在“读过”和
“写下”任务中不会稳定识别真正的晶化时刻lesson 再次命中后不验证真伪,也没有项目内迁移
效果的因果证据。现有 eval 每个 cell 只有一次 agent invocation不能证明任务 A 的经验改善了
fresh 任务 B。
本 Epic 先落地项目内三步闭环:
```text
任务内静默观察 -> 强信号候选 -> 显式授权后写 observed lesson
-> fresh 任务 read-repair -> validated / retired
-> 测试、checker、项目文档、ADR 等 canonical owner
```
最终用 paired cross-session 实验证明A 形成的 lesson 在不传递聊天上下文、不向 B 泄题时,能
提高 fresh agent 完成 B 的正确率。跨项目、团队级与 CodeStable 全局方法论只预留边界。
## 范围与非目标
范围:
- `cs-feat``cs-issue``cs-refactor``cs-epic` 的静默信号识别、read-repair 与收尾 UX。
- `cs-keep` 的 lesson 创建、验证、反证、晋升、退役与清理。
- 项目内 session candidate -> lesson -> canonical owner 的迁移。
- 维护者侧 paired/sequential eval runner 与 `cs-learning-transfer-001`
- ADR、双语公开文档、契约/eval 测试与 package 回归验证。
非目标:
- 不新增第九个 skill不扩大 `cs` 最小决策核,不让 task skill 读取 sibling skill 文件。
- 不恢复 `cs-feedback`、production feedback importer、transcript 扫描、状态机或自动上传。
- 不创建 `.codestable/learning/`、全局 lessons、常驻索引、后台 telemetry 或集中 runtime。
- 不持久化未收敛讨论、原始问答、完整思考过程或候选分支。
- 不自动跨项目共享;脱敏反馈包、团队知识库与 shipped skill 上游更新留给后续 Epic。
- 不用更醒目的文字代替能落成测试、lint、checker、类型或 deterministic helper 的约束。
## 核心模型
| 对象 | 生命周期与 owner |
|---|---|
| Learning signal | 当前任务内的可核实事件;未过门槛即丢弃 |
| Crystallization candidate | 会话内有界候选;不是项目事实,不自动获得写入授权 |
| Lesson | 项目级 staging一条一文件只保留尚未被更强 owner 完整承接的经验 |
| Canonical guard | 测试、checker、lint、类型或 helper机械阻止同类错误 |
| Canonical knowledge | 项目既有文档、glossary、ADR 或 `attention.md` 中的唯一事实 owner |
| Transfer evidence | fresh B 在有/无 lesson 的同源仓库上产生的 paired 结果 |
检索次数、模型自评置信度和“本次讨论过”不算学习证据。lesson 是可删、可纠偏的 staging
canonical guard/knowledge 才是稳定归宿。
## 行为契约
### 开工:有效命中必须说明影响
只有 scope 符合、未退役、经当前代码/测试/canonical 文档核实,并真实改变计划或验证的条目才算
有效命中。四个 task skill 必须报告:`经验命中:{path}{status});核验:{fact};影响:
{plan_or_check}`。纯关键词碰撞不报告为有效命中,也不能把“读过”冒充“采用”。
应用前 read-repair`retired` 不应用;`observed` / `validated` 先核实再用;只是相关但没有改变
行为时不制造复用证据;当前事实明确反证时立即停止应用并走窄退役,证据不足时不猜。
### 任务中:静默识别晶化时刻
任务内只在内存保留最多 3 条候选,按新证据替换低价值项,不暂停或询问。已有普通 work 时可
复用证据节;不得为候选新建 work、transcript 或状态文件。
强信号限于owner 纠正实际改变方案/代码/术语/验证;可复现证据推翻根因;同一路径失败两次后
更换假设blocking/important finding 暴露未编码不变量;新 red -> green 捕获可复发失败lesson
真实改变本次行为或被反证;重复 workaround方法显著降低重试、成本或风险。
候选还必须同时有可追溯证据、能写成未来动作、适用于本次精确 diff 之外、且没有现成 canonical
owner。网络波动、拼写、泛化口号、活动记录和已被机械 owner 完整覆盖的事实直接丢弃。选择时先看
失败后果,再看证据与复发可能,最后优先低成本机械化,不生成伪精确分数。
### 收尾:低打扰与机械化优先
- 普通任务只在强信号成立时展示最高价值一条,首行固定 `晶化候选:{rule}`,并给证据、范围与
建议归宿;无强信号完全不显示模板。没有记忆写入授权时不落盘,候选随会话结束消失。
- 用户已明确说“记住 / 更新 / 退役”时同轮按 `cs-keep` 处理,不重复确认。
- Epic 子项不展示、不询问;每个子项至多把一条去重候选写入既有游标证据区,最终毕业清单一次
处理并复用最终 owner gate。
- 当前任务范围内能直接落成 red -> green 测试/checker 的约束优先机械化,不另写重复 lesson
会扩大范围时只给候选,不借学习名义扩权。
## Lesson 生命周期与授权
新 lesson 最小格式:
```markdown
---
status: observed
scope: 模块 / 命令 / 场景关键词
date: YYYY-MM-DD
---
规则:未来可执行的结论。
适用 / 不适用:边界与停止应用信号。
证据最多三个代表性路径、测试、diff 或任务指针。
候选归宿test | checker | attention | project-doc | adr | codestable-eval
```
| status | 判据 |
|---|---|
| `observed` | 单次任务有证据,尚未在独立后续任务验证 |
| `validated` | 非创建该 lesson 的任务和 agent invocation 中有效命中,真实改善行为并验证成功 |
| `retired` | 被事实反证、范围完全失效或已被更强 owner 替代;不得应用且不再复活原结论 |
旧 lesson 缺 `status``observed` 读取,不批量迁移;只有真实状态变化或 `cs-keep` 本来就要更新
时才补字段。不得保存原始对话、逐次命中日志或无限 evidence history。
创建、改写规则/scope、晋升、删除与跨项目反馈仍须用户显式 `cs-keep` 诉求、接受普通候选,或
Epic 最终毕业 gate。为实现不中断的 read-repair仅对已有且有效命中的 lesson 开放两种窄维护:
- `observed -> validated`:独立后续任务确实采用并验证成功,只补一次代表性证据;
- `observed|validated -> retired`:当前仓库事实直接反证,只写原因与替代/反证指针。
窄维护不新建事实、不改规则、不扩 scope、不新增 gate随当次代码、证据和游标进入同一语义原子
milestone最终报告文件变化稳定 validated 命中不写文件。需要改写结论或证据不足时只给候选。
任务内发现已有 canonical owner 时先 retire删除留给 `cs-keep``cs-keep` 显式晋升则先验证新 owner
再在同一更新中直接删除重复 lesson。新结论不得通过复活 retired 条目获得 validated 身份。
`cs-keep` 继续负责查重、合并与约 50 条预算,并按以下顺序路由:机械 guard 优先;高频必读事实进
`attention.md`≤25 条);同时满足难回退、缺少上下文会令人意外、源于真实取舍的结构性决定进
ADR其他方法进项目既有文档。目标不存在时请 owner 选择,不发明目录。`codestable-eval` 只标记
未来上游候选,本轮不导出、不上传、不改 skill。
## 项目内跨会话迁移实验
现有 runner 每 cell 只调用一次 agent。新场景增加 `answerType/task.kind: learning-transfer`,由独立
sequence 模块承载fixture 明确 A/B owning skill每次 invocation 只注入该 skill 的冻结快照。
每个 paired cell
1. 从 seed repo 运行 A机械验证结果并捕获最多一条候选普通任务读最终输出的 `晶化候选`
Epic 子项读既有游标证据区A 失败计入失败,不得丢弃。
2. 复制完全相同的 post-A repo 为 treatment/control。
3. 先验证候选确属 lesson 类;若应进 attention/ADR则标 fixture invalid不算 skill failure。
4. 仅 treatment 用 fresh `cs-keep` invocation 接收候选、证据和显式“记录”授权;除 lesson 外的
mutation 视为失败。
5. 可选 `between_tasks` hook 必须同样作用于两份 repostale guard 用它制造真实版本反证。
6. treatment/control 各启动 fresh Bskill snapshot、任务文本和 prompt hash 相同,不点名 lesson
不继承 A、curation 或彼此上下文,唯一处理变量是 lesson。
7. 临时目录销毁前跑 hidden/deterministic checksB diff 白名单为任务改动、必要 work 证据,以及
matched lesson 的窄状态/证据迁移,禁止改规则/scope 或破坏 schema。checkpoint key 含 phase
半 pair 不算完成treatment/control 顺序按 k 交替;只存结构化指标、必要 diff 与哈希。
Epic 正向 fixture 不豁免 owner gateseed 提供 `active` 永久 Epic、有效批准 hash、完整执行策略和至少
两个已批准子项A/B 只执行边界内子项。这样测试恢复与学习,不伪造 owner/reviewer 授权。
`cs-learning-transfer-001` 至少含四个正向场景feat/issue/refactor/epic和无关、stale 两个 guard。
正向 fixture 的 golden 必须全绿naive 只在目标不变量上红;真实运行前冻结 fixture、hypothesis、
primary metric、预算与失败判据禁止看到结果后删案例。
主 oracle 均为 `[measured]`A 结果、候选唯一性、lesson schema/mutation、B treatment/control hidden
pass、paired win/loss、stale retirement、prompt equality 和回归。语义质量只作 `[soft]`;统计不足时
整体 verdict 标 `[underpowered]`。dry-run 成本必须累加 A、curation、B×2 及场景 hook 的实际 invocation
不得沿用 one-shot 估算。校准可用 `k=2`,但不能形成接受证据。
最终运行至少两个 model family、每 fixture `k >= 5`,使每个 family 在四个正向 fixture 上至少有
20 个完成 pair任一 primary aggregate 仍标 `[underpowered]` 时扩大 fixture/repeat 后重跑,不能接受
Epic。只有 treatment 比 control 高至少 25pp、两个 family 都为正、losses 不多于 wins、两 guard
无回退、隔离检查 100% 通过,才能完成;失败保留负结果并继续修正。
## 子项契约
- `LEARN-1`featADR-006、晶化算法、窄维护授权、四 task skills以及 skill/architecture
等集与负向契约测试无依赖测试先红Epic 不新增暂停lesson 状态变更进入当次 milestone。
- `LEARN-2`feat`cs-keep` schema/lifecycle/晋升与清理;依赖 LEARN-1同时拥有 WORKFLOW、
README、SKILL_CATALOG、why-codestable 双语同步及 documentation tests测试先红。
- `LEARN-3`featADR-003 paired 增量、sequence runner/scorer、fixture 校验、成本模型、eval 单测与
`cs-learning-transfer-001` 真实跨模型实验;依赖 LEARN-1/2runner/fixture 测试先红。
## 影响面
必须修改:
- 五个 shipped skills`cs-feat``cs-issue``cs-refactor``cs-epic``cs-keep`
- `docs/adr/003-cs-skill-evaluation-loop.md`;新建 `docs/adr/006-project-learning-lifecycle.md`
- `WORKFLOW*``README*``SKILL_CATALOG*``docs/why-codestable*` 中英文。
- `tests/test_skill_contracts.py``test_v2_architecture_contract.py``test_v2_documentation_contract.py`
- `.claude/skills/eval-cs-skill/SKILL.md` 与 scripts 的 `runner.py``fixtures.py``buildprompt.py`
`_model.py``config.py``metrics.py`、scorer registry、新 sequence/scorer 模块。
- `tests/test_cs_skill_eval.py`;新建 `experiments/cs-learning-transfer-001/`
需要验证:`cs``cs-onboard``cs-review`、alias、AGENTS/CLAUDE 与 build-cs-skill 不变8 skills、
README 精简结构、全部 Markdown ≤300、plugin/package/distribution tests 继续成立。发布元数据只在 owner
决定发布时处理。
仍待调查LEARN-3 dry-run 核实两个 model family 的 adapter 与预算;不可用时按 ADR-003 报告,
不得用单模型冒充跨模型结论。
## 验收标准
- 四 task skills 对有效命中报告路径、核验与具体影响候选静默、普通最多一条、Epic 最终处理。
- 三态可解析且按需迁移退役不再应用validated 稳定命中无 churn机械化与单一 owner 优先。
- 新 lesson 与跨项目分享保持显式授权;无 transcript、feedback runtime、global lessons 或新 skill。
- paired 单测证明四类 invocation 独立、B prompt 相同、只有 lesson 差异、半 pair 不完成、成本不低估。
- 冻结实验在两个 model family 上以非 `[underpowered]` 证据满足 verdict否则本 Epic 保持未完成。
- 中英文契约对称;相关/全量 pytest、分发测试、plugin check 与 `git diff --check` 通过。
- 最终由 fresh reviewer 按最新批准版本做 acceptance review再由 owner 整体验收。
## 关键决策
- 持续学习靠任务证据与按需 read-repair不靠后台采集或每任务仪式。
- 已有 lesson 的两种窄状态维护可静默进行;新知识与跨项目分享仍须显式授权。
- 项目到全局的未来路径必须经过脱敏 packet、fixture、跨模型 eval 与 regression本轮不实现。
## 最终交付索引
待执行后以 ADR、diff、测试与 `experiments/cs-learning-transfer-001/` 指针填写,不复制完整日志。
## 整体验收
待全部子项完成后填写。
## 遗留风险
- 模型可能漏掉信号;以低打扰换取较低召回,不用 transcript 扫描补偿。
- thin harness 无 runtime 强制;契约测试与 paired eval 是主要回退防线。
- 校准小样本可能只能给 `[underpowered]` 证据;必须扩大最终运行后才能接受,不得隐藏该标签。
@@ -0,0 +1,52 @@
---
epic: ../epics/cs-continuous-learning-lifecycle.md
phase: executing
approved_revision: 4b0b8e8e0596e7ee42611864843512ecd9402970bb3682b5605f0dc0f8dcf01a
current_item: LEARN-2
next_action: implement LEARN-2 with tests first
blocked_by: null
item_progression: continuous
milestone_commit: authorized
remote_publish: each-milestone
---
## 子项进度
- [x] LEARN-1
- [ ] LEARN-2
- [ ] LEARN-3
## 临时决策与证据
- 现有四个 task skill 只有 lesson 检索与笼统收尾推荐,没有 read-repair 或强信号筛选。
- 现有 eval runner 每个 cell 只有一次 invocation无法证明跨会话迁移。
- 设计调研已核对 domain-modeling、teach、diagnosing-bugs、prototype、neat-freak 与现有 ADR-003
只借鉴晶化、证据晋级、机械化优先与 read-repair不引入它们的默认目录或全局状态。
- design review round 1Paseo `ceb5d5d6-4c74-4825-b600-64d5111b2f48`
`claude-fable-5` / `plan-high`,冻结 SHA-256 `a660265a...e7ffd`1 blocking / 4 important 已处理。
- revised proposed Epic SHA-256`a0107b6da2079556024c1a4807365e93a365149d37bedbbed7987188af45aa45`
- design review round 2Paseo `50bf355c-fbbb-4ef0-a9fd-ec3d9c560e9f`
`claude-fable-5` / `plan-high`,冻结 SHA-256 `a0107b6d...aa45`0 blocking / 3 important 已处理。
- final design review round 3Paseo `00358ef1-46a8-4976-abe6-8a2d4b783a07`
`claude-fable-5` / `plan-high`,冻结 SHA-256 `2c023c22...62cd`0 blocking / 0 important / 3 nit
结论可交 owner 确认。
- accepted nit interpretationEpic 游标候选沿用 `晶化候选:` marker25pp 是总体聚合阈值且每个
model family 方向必须为正;“等集测试”指四 task skills 的一致契约断言。
- owner 于 2026-08-01 确认 proposed Epic并选择 `continuous` / `authorized` /
`each-milestone`;激活后批准版本 SHA-256 为
`4b0b8e8e0596e7ee42611864843512ecd9402970bb3682b5605f0dc0f8dcf01a`
- LEARN-1 tests-first新增契约测试先得到 `4 failed, 2 passed`,实现后定向契约
`25 passed`、全量 `130 passed, 1 skipped`、分发 `3 passed, 1 skipped`plugin package check 与
`git diff --check` 通过;四个 task skill 与 ADR-006 均未超过 300 行。
- LEARN-1 晶化候选无。Markdown 换行造成的锚点误判已通过空白归一化 helper 机械化,不另写
重复 lesson。
- LEARN-1 diff review round 1Paseo `8a20cd70-9f55-4331-9b69-90e63bed4913`
`claude-fable-5` / `plan-high`,冻结 staged patch SHA-256 `eff4faae...5d02`
`0 blocking / 1 important / 3 nit`。已补齐 canonical-owner 退役、候选证据/范围/归宿、显式记忆
诉求同轮处理、窄维护报告,并加入旧 lesson 缺 `status` 的独立安装兼容;新增锚点先红后绿。
- LEARN-1 修复后验证:三份契约套件 `37 passed`、全量 `130 passed, 1 skipped`、分发
`3 passed, 1 skipped`plugin package check 与 `git diff --check` 通过。
- LEARN-1 diff review round 2fresh Paseo `76255cc7-43b3-44d7-86af-90a2fffd3284`
`claude-fable-5` / `plan-high`,冻结 staged patch SHA-256 `e3490e44...7deb`
`0 blocking / 0 important / 4 nit`,结论可合。保留的 nit 仅为排版、授权来源概括、测试冗余和
范围外 cs-review 旧推荐句,不影响行为或授权边界。
+155
View File
@@ -0,0 +1,155 @@
---
adr: "006"
title: "CodeStable 项目内持续学习生命周期"
status: Accepted
date: 2026-08-01
applies-to:
- "plugins/codestable/skills/cs-feat/"
- "plugins/codestable/skills/cs-issue/"
- "plugins/codestable/skills/cs-refactor/"
- "plugins/codestable/skills/cs-epic/"
- "plugins/codestable/skills/cs-keep/"
- ".codestable/lessons/"
- ".codestable/work/"
enforcement: test
stage: [author, execute, keep, review]
lint: "python3 -m pytest tests/test_skill_contracts.py tests/test_v2_architecture_contract.py tests/test_v2_documentation_contract.py"
---
# ADR-006: CodeStable 项目内持续学习生命周期
## Context
四个 task skill 已会检索项目 lesson`cs-keep` 也有证据、查重与合并门槛,但现有闭环只保证
“读过”和“写下”。任务中不会稳定识别值得复用的晶化时刻lesson 再次命中后没有统一的核验、
纠偏与退役规则;命中次数和模型自评也无法证明旧经验真实改善了后续任务。
与此同时,自动保存对话、每次任务都询问是否记录,或把所有经验长期留在 lesson会制造隐私、
噪声、双重真相和流程中断。项目需要一个低打扰、证据驱动且最终收敛到更强 owner 的学习周期,
而不是新的 feedback runtime、后台采集系统或全局知识库。
## Decision
### 生命周期对象与唯一 owner
项目内学习采用以下分层:
| 对象 | 生命周期与 owner |
|---|---|
| Learning signal | 当前任务内的可核实事件;未过门槛即丢弃 |
| Crystallization candidate | 会话内有界候选;不是项目事实,也不自动获得写入授权 |
| Lesson | 项目级 staging一条一文件只保留尚未被更强 owner 完整承接的经验 |
| Canonical guard | 测试、checker、lint、类型或 deterministic helper机械阻止同类错误 |
| Canonical knowledge | `attention.md`、项目既有文档、glossary 或 ADR 中的唯一事实 owner |
| Transfer evidence | fresh 后续任务在有、无 lesson 条件下产生的 paired 结果;实验机制归 ADR-003 |
检索次数、“讨论过”和模型自评置信度都不是学习证据。lesson 是可删除、可纠偏的暂存层;同一事实
不得同时把 lesson 与 canonical guard/knowledge 当作并列真相。
### 强信号与晶化候选
四个 task skill 在任务中静默观察,内存中最多保留 3 条候选,并用新证据替换较低价值项,不为
候选创建 work、transcript 或状态文件。强信号只包括:
- owner 纠正真实改变了方案、代码、术语或验证;
- 可复现证据推翻根因,或同一路径失败两次后更换假设;
- blocking/important finding 暴露尚未编码的不变量;
- 新 red -> green 验证捕获了可复发失败;
- 已有 lesson 真实改变本次行为,或被当前事实反证;
- workaround 重复出现,或某方法显著降低重试、成本或风险。
候选还必须同时具备可追溯证据、可写成未来动作、适用于本次精确 diff 之外,且尚无现成
canonical owner。网络波动、拼写、活动记录、泛化口号和已被机械 owner 完整覆盖的事实直接丢弃。
排序先看失败后果,再看证据与复发可能,最后优先低成本机械化;不得生成伪精确分数。
普通任务仅在强信号成立时,于收尾展示最高价值的一条,首行固定为
`晶化候选:{rule}`,并给出证据、范围和建议归宿;无强信号时不显示空模板。候选不暂停任务,
没有记忆写入授权就随会话结束消失。用户已明确要求“记住 / 更新 / 退役”时,同轮按 `cs-keep`
处理,不重复确认。
### Lesson 三态
新 lesson 必须声明 `status``scope``date`,正文只保留可执行规则、适用/停止应用边界、最多
三个代表性证据指针和候选归宿。状态只允许:
| status | 判据 |
|---|---|
| `observed` | 单次任务有证据,尚未在独立后续任务验证 |
| `validated` | 非创建该 lesson 的后续任务和 agent invocation 中有效命中,真实改善行为并验证成功 |
| `retired` | 被仓库事实反证、范围完全失效,或已被更强 owner 替代;不得再应用 |
旧 lesson 缺少 `status` 时按 `observed` 读取,不批量迁移;只有真实状态变化或 `cs-keep` 本来就要
更新时才补字段。`retired` 结论不得复活并继承 `validated` 身份;新结论必须重新从 `observed` 开始。
### Read-repair 与窄维护授权
task skill 应用 lesson 前必须 read-repair`retired` 不应用;`observed` / `validated` 先用当前代码、
测试或 canonical 文档核实。只有条目 scope 符合、事实仍成立且真实改变计划或验证时,才报告
`经验命中:{path}{status});核验:{fact};影响:{plan_or_check}`;纯关键词碰撞或只是读过不算
有效命中。
创建 lesson、改写规则或 scope、一般晋升、删除及跨项目反馈仍需用户显式 `cs-keep` 诉求、接受
普通任务候选,或 Epic 最终毕业 gate。为使 read-repair 不中断任务,仅对已有且有效命中的 lesson
开放两种无需新增确认的窄维护:
- `observed -> validated`:独立后续任务确实采用并验证成功,只补一次代表性证据;
- `observed|validated -> retired`:当前仓库事实直接反证,或发现已有 canonical owner只写退役原因
与替代/反证指针。
窄维护不得新建事实、改规则、扩 scope 或新增 gate必须与当次代码、证据和游标组成同一语义原子
milestone并在最终报告列出文件变化。稳定的 `validated` 命中不写文件。证据不足或需要改写结论时
只形成候选;发现 canonical owner 时 task skill 先 retire删除与合并仍由 `cs-keep` 负责。
### 机械化优先与 canonical 归宿
当前任务范围内能直接落成 red -> green 测试或 checker 的约束,必须优先机械化,不再写重复
lesson机械化会扩大任务范围时只给候选不借学习名义扩权。`cs-keep` 按以下顺序迁移:
1. 能机械阻止的规则进入测试、checker、lint、类型或 owning skill 的 deterministic helper
2. 高频必读且稳定的项目事实进入 `attention.md`,并维持不超过 25 条的预算;
3. 同时满足难回退、缺少上下文会令人意外、源于真实取舍的结构性决定进入项目 ADR
4. 其他稳定方法进入项目既有文档;目标不存在时请 owner 选择,不发明目录;
5. `codestable-eval` 仅标记未来上游候选,本轮不导出、不上传,也不修改 shipped skill。
新 owner 写入并验证后,应在同一更新中删除完全重复的 lesson若由 task skill 发现,则先退役,留待
显式 `cs-keep` 清理。`cs-keep` 继续执行查重、合并和约 50 条 lesson 预算。
### Epic 聚合
Epic 子项不得展示或询问晶化候选。每个子项至多把一条去重候选写入既有 Epic 游标的证据区,
不得为此新建 work该记录只是临时毕业输入不是项目事实。全部子项完成后毕业清单统一处理
lesson、guard、项目文档与 ADR 的归宿,并复用 Epic 最终 owner gate不新增逐项暂停或确认。
### 隐私与跨项目边界
不得保存原始对话、原始问答、完整思考过程、候选分支、逐次命中日志或无限 evidence history
不得扫描 transcript 来补召回率。除上述有界 Epic 游标证据外,未获写入授权的候选只存在于当前
会话内。
本 ADR 只建立项目内 session candidate -> lesson -> canonical owner 的闭环。不创建
`.codestable/learning/`、全局 lessons、常驻索引、后台 telemetry、集中 runtime 或第九个 skill
也不自动跨项目、团队或向 CodeStable 上游分享。未来跨项目路径必须另行获得显式授权,并经过脱敏
packet、fixture、跨模型 eval 与 regression本 Epic 只保留这一边界,不实现上传或同步。
## Consequences
- task skill 会说明经验如何被当前事实核验、又如何改变行为,避免把检索命中冒充学习效果。
- lesson 可以随新证据晋升、纠偏和退役,最终迁移到单一机械或文档 owner减少陈旧知识与双重真相。
- 普通任务只有高价值候选才出现一次提示Epic 则聚合到最终 gate持续学习不会增加常规暂停点。
- 两种窄维护会让已有 lesson 随任务 diff 一起变化;实现与审查必须核对其证据、状态转换和原子性。
- 不做 transcript 扫描、后台采集和自动跨项目共享会降低召回率,但同时限制隐私、噪声和权限风险。
- thin-harness skills 缺少集中 runtime 强制,契约测试与 ADR-003 的 paired cross-session eval 是主要
回退防线;未达到跨模型、非 `[underpowered]` 的验收证据时,不得宣称学习迁移有效。
## Rejected alternatives
- **每个任务固定询问是否沉淀**。拒绝:高频仪式会打断主任务,并把弱信号升级成噪声。
- **自动保存候选、对话或反馈流**。拒绝:扩大隐私与持久化边界,并重新引入本 Epic 明确排除的
feedback runtime、状态机和后台采集。
- **把 lesson 当作永久、只增不减的知识库**。拒绝事实变化后会继续误导且与测试、ADR、项目
文档形成多个 owner。
- **命中一次或模型自评后直接标记 validated**。拒绝:没有独立后续任务的行为与验证证据,无法
区分复用效果和自我确认。
- **自动同步到全局或其他项目**。拒绝:项目事实、隐私与适用范围尚未经过脱敏和跨模型回归验证。
- **用更醒目的规则文本代替机械 guard**。拒绝能由测试、checker、类型或 helper 阻止的错误,
不应继续依赖 agent 记得阅读。
+29 -1
View File
@@ -18,6 +18,35 @@ argument-hint: "[大需求描述]"
- handoff 只用于起草 proposed 永久 Epic 文档,不替代 fresh design review、批准 hash 或第一道 owner gate。
- 澄清需求:只问会改变拆解方向的问题(目标边界、优先级、验收口径),一次最多 3 个,形成共识即停。
## 持续学习
检索到 lesson 后先做 read-repair。只有 scope 符合、未退役、经当前代码/测试/canonical 文档核实,
并真实改变计划或验证的条目才算有效命中;按
`经验命中:{path}{status});核验:{fact};影响:{plan_or_check}` 报告。`retired` 不应用;
`observed` / `validated` 先核实再用;旧 lesson 缺 `status``observed` 读取,不批量迁移。只是相关
但没有改变行为时不制造复用证据;当前事实明确反证时立即停止应用,证据不足时不猜。
任务内只在内存保留最多 3 条候选按新证据替换低价值项不暂停或询问。强信号只包括owner
纠正实际改变方案/代码/术语/验证;可复现证据推翻根因;同一路径失败两次后更换假设;
blocking/important finding 暴露未编码不变量;新 red -> green 捕获可复发失败lesson 真实改变本次行为
或被反证;重复 workaround方法显著降低重试、成本或风险。
候选还必须同时有可追溯证据、能写成未来动作、适用于本次精确 diff 之外、且没有现成 canonical
owner。网络波动、拼写、泛化口号、活动记录以及已被机械 owner 完整覆盖的事实直接丢弃。
创建、改写规则/scope、晋升、删除与跨项目反馈仍须用户显式授权。为不中断 read-repair仅对已有且
有效命中的 lesson 开放两种窄维护:`observed -> validated` 仅在独立后续任务确实采用并验证成功时
发生,只补一次代表性证据;`observed|validated -> retired` 仅在当前仓库事实直接反证或发现已有
canonical owner 时发生,只写原因与替代/反证指针。窄维护不新建事实、不改规则、不扩 scope、不新增
gate随当次代码、证据和
游标进入同一语义原子 milestone稳定 validated 命中不写文件。需要改写结论或证据不足时只给
候选,新结论不得通过复活 retired 条目获得 validated 身份;窄维护必须在最终报告列出文件变化。
当前任务范围内能直接落成 red -> green 测试/checker 的约束优先机械化,不另写重复 lesson会扩大
范围时只给候选。用户已明确说“记住 / 更新 / 退役”时,同轮按 `cs-keep` 处理不重复确认。Epic
子项不展示、不询问;每个子项至多把一条去重候选写入既有游标证据区,使用 `晶化候选:{rule}`
marker最终毕业清单一次处理并复用最终 owner gate。
## 双层 Epic 文档
Epic 天然跨会话,但稳定上下文和活动状态不得混写:
@@ -90,4 +119,3 @@ owner 确认 proposed 文档与上述策略后,主流程机械置 `active`
- owner 接受后先把最终范围、关键决策、交付索引、整体验收、遗留风险与毕业清单写入永久 Epic再用终态更新置 `accepted` 并移除 `work` 指针。稳定产品契约进 canonical requirement/项目文档,结构性决策进 ADR经验进 lessons目标位置不存在时请 owner 选择,确定前结论留在永久 Epic。
- 终态 `accepted` / `superseded` / `cancelled` 是不可恢复执行的持久信号。无论中断时还剩 work 指针、游标或所属子项 work都从仓库事实幂等续做补齐终态记录与毕业清单、移除指针、删除 Epic 游标,再按 frontmatter `epic:` 清理全部子项 work不得恢复执行或创建重复 Epic永久 Epic 文档不得删除。
- 不恢复 `cs-goal` 入口、goal package、`state.yaml`、逐轮 iteration 报告或 legacy runtime gate目标契约、恢复游标、owner gate 和终态验收都由上述双层文档承担。
- 本轮若踩坑或被纠偏,推荐用 cs-keep 沉淀一条;用户拒绝即跳过。
+29 -1
View File
@@ -18,6 +18,35 @@ argument-hint: "[功能描述]"
- 动手前先定归属:这能力属于哪里、沿用现有词汇叫什么——不丢进最近的文件、不起新同义词。结构与取舍拿不准时读 `references/code-design.md``references/economy.md`(最小充分 ≠ 最小 diff有界简化必须记上限、触发与方向
- 对照检查:目标、现场上下文、边界与取舍、证据要求、验收标准。缺少会改变实现方向的事实时先问,一次最多 3 个问题,形成可执行共识即停;不问不影响方向的细节。
## 持续学习
检索到 lesson 后先做 read-repair。只有 scope 符合、未退役、经当前代码/测试/canonical 文档核实,
并真实改变计划或验证的条目才算有效命中;按
`经验命中:{path}{status});核验:{fact};影响:{plan_or_check}` 报告。`retired` 不应用;
`observed` / `validated` 先核实再用;旧 lesson 缺 `status``observed` 读取,不批量迁移。只是相关
但没有改变行为时不制造复用证据;当前事实明确反证时立即停止应用,证据不足时不猜。
任务内只在内存保留最多 3 条候选按新证据替换低价值项不暂停或询问。强信号只包括owner
纠正实际改变方案/代码/术语/验证;可复现证据推翻根因;同一路径失败两次后更换假设;
blocking/important finding 暴露未编码不变量;新 red -> green 捕获可复发失败lesson 真实改变本次行为
或被反证;重复 workaround方法显著降低重试、成本或风险。
候选还必须同时有可追溯证据、能写成未来动作、适用于本次精确 diff 之外、且没有现成 canonical
owner。网络波动、拼写、泛化口号、活动记录以及已被机械 owner 完整覆盖的事实直接丢弃。
创建、改写规则/scope、晋升、删除与跨项目反馈仍须用户显式授权。为不中断 read-repair仅对已有且
有效命中的 lesson 开放两种窄维护:`observed -> validated` 仅在独立后续任务确实采用并验证成功时
发生,只补一次代表性证据;`observed|validated -> retired` 仅在当前仓库事实直接反证或发现已有
canonical owner 时发生,只写原因与替代/反证指针。窄维护不新建事实、不改规则、不扩 scope、不新增
gate随当次代码、证据和
游标进入同一语义原子 milestone稳定 validated 命中不写文件。需要改写结论或证据不足时只给
候选,新结论不得通过复活 retired 条目获得 validated 身份;窄维护必须在最终报告列出文件变化。
当前任务范围内能直接落成 red -> green 测试/checker 的约束优先机械化,不另写重复 lesson会扩大
范围时只给候选。用户已明确说“记住 / 更新 / 退役”时,同轮按 `cs-keep` 处理,不重复确认。普通任务
只在强信号成立时展示最高价值一条,首行固定 `晶化候选:{rule}`,并给出证据、范围和建议归宿;无
强信号完全不显示模板,没有记忆写入授权时不落盘。
## 默认执行
理解相关事实 → 实现 → 运行相称的验证 → 交付结果。普通任务不生成 CodeStable 产物git diff、测试输出和交付说明就是证据。
@@ -50,4 +79,3 @@ argument-hint: "[功能描述]"
- 报告:做了什么、改动文件、验证结果、遗留事项。
- 高风险任务的 work 文档在设计对齐时已建立;其余任务需要跨会话继续、多人交接或用户要求留痕时补建 `.codestable/work/feat-{slug}.md`work 文档一律带类型前缀 feat- / issue- / refactor- / epic-整理时按前缀分流去向。work 文档含目标 / 现场 / 边界 / 证据 / 验收 / 状态与未决六节,随进展更新("状态与未决"记录进度与待用户确认项,供跨会话恢复);完成后先在最终报告列**毕业清单**——哪条结论进了哪个项目文档、沉了哪条 lesson无可毕业内容则明说——然后才删除 work 文档;不列清单不得删。毕业目标位置不存在时不擅自发明目录:清单中给出建议落点请用户拍板,**拍板前 work 文档保留不删**。用户要求留档则保留。
- 属于某个 Epic 的子功能时:独立子功能 work 文档的 frontmatter 标 `epic: {epic-slug}`;日常进展和完成状态只更新 Epic work 游标中对应稳定 ID 的进度与证据指针。永久 Epic 文档在 `active` 期间保持冻结,不因日常进度或子功能 work 回链而修改;需要改变子项定义、依赖或验收时交 `cs-epic` 走边界重确认。
- 本轮若踩坑或被纠偏,推荐用 cs-keep 沉淀一条;用户拒绝即跳过。
+29 -1
View File
@@ -16,6 +16,35 @@ argument-hint: "[问题描述]"
- 对照检查:目标(期望行为)、现场(复现条件与环境)、边界(哪些不能动)、验收(怎么算修好)。缺少会改变修复方向的事实时先问用户,一次最多 3 个问题,形成共识即停。
- 诉求其实是新增能力而不是坏掉的行为时,转 `cs-feat`,不在 issue 里偷做。
## 持续学习
检索到 lesson 后先做 read-repair。只有 scope 符合、未退役、经当前代码/测试/canonical 文档核实,
并真实改变计划或验证的条目才算有效命中;按
`经验命中:{path}{status});核验:{fact};影响:{plan_or_check}` 报告。`retired` 不应用;
`observed` / `validated` 先核实再用;旧 lesson 缺 `status``observed` 读取,不批量迁移。只是相关
但没有改变行为时不制造复用证据;当前事实明确反证时立即停止应用,证据不足时不猜。
任务内只在内存保留最多 3 条候选按新证据替换低价值项不暂停或询问。强信号只包括owner
纠正实际改变方案/代码/术语/验证;可复现证据推翻根因;同一路径失败两次后更换假设;
blocking/important finding 暴露未编码不变量;新 red -> green 捕获可复发失败lesson 真实改变本次行为
或被反证;重复 workaround方法显著降低重试、成本或风险。
候选还必须同时有可追溯证据、能写成未来动作、适用于本次精确 diff 之外、且没有现成 canonical
owner。网络波动、拼写、泛化口号、活动记录以及已被机械 owner 完整覆盖的事实直接丢弃。
创建、改写规则/scope、晋升、删除与跨项目反馈仍须用户显式授权。为不中断 read-repair仅对已有且
有效命中的 lesson 开放两种窄维护:`observed -> validated` 仅在独立后续任务确实采用并验证成功时
发生,只补一次代表性证据;`observed|validated -> retired` 仅在当前仓库事实直接反证或发现已有
canonical owner 时发生,只写原因与替代/反证指针。窄维护不新建事实、不改规则、不扩 scope、不新增
gate随当次代码、证据和
游标进入同一语义原子 milestone稳定 validated 命中不写文件。需要改写结论或证据不足时只给
候选,新结论不得通过复活 retired 条目获得 validated 身份;窄维护必须在最终报告列出文件变化。
当前任务范围内能直接落成 red -> green 测试/checker 的约束优先机械化,不另写重复 lesson会扩大
范围时只给候选。用户已明确说“记住 / 更新 / 退役”时,同轮按 `cs-keep` 处理,不重复确认。普通任务
只在强信号成立时展示最高价值一条,首行固定 `晶化候选:{rule}`,并给出证据、范围和建议归宿;无
强信号完全不显示模板,没有记忆写入授权时不落盘。
## 硬门槛
- **没有稳定、快速、能明确变红的验证,不许猜根因、不许改代码。** 优先失败测试;无法自动化时与用户确认一个手工复现步骤。
@@ -38,4 +67,3 @@ argument-hint: "[问题描述]"
- reviewer 创建后绑定该运行并记录 run identity目标有效、能力仍满足且 reviewer 状态为 running`Awaiting` 携带可查询的同一 run identity 且查询仍为活动态时为健康状态健康时等待终态报告不因后来发现更优创建方式而取消、重复创建或并行补发。仅在运行明确失败或终止无报告、idle / `Awaiting` 且无可恢复 run identity、能力不满足或目标失效时本轮失败且不计轮次不得盲目重发先检查 task packet 与 agent 状态,再决定一次有界重试、更换创建方式或交用户。
- 报告:根因一句话、改动文件、验证结果。
- 需要跨会话继续时写 `.codestable/work/issue-{slug}.md`(目标 / 现场 / 边界 / 证据 / 验收 / 状态与未决六节work 文档一律带类型前缀。完成后先在报告列毕业去向结论进哪、lesson 沉哪,或明说无可毕业)再删除;目标位置不存在时在清单中建议落点请用户拍板,拍板前不删。用户要求留档则保留。
- 本轮若踩了新坑或被用户纠偏,推荐用 cs-keep 沉淀一条;用户拒绝即跳过。
+29 -1
View File
@@ -15,6 +15,35 @@ argument-hint: "[重构目标]"
- 先确认诉求真是行为不变:一旦包含"顺便支持 X / 改成 Y",把那部分拆出去转 `cs-feat``cs-issue`,不夹带。
- 结构好坏用**深度**衡量:小接口承载大行为是深,接口和实现一样复杂是浅;重构应让调用方用更少认知换更多能力,不为"看起来干净"搬家,不把模块越拆越碎。
## 持续学习
检索到 lesson 后先做 read-repair。只有 scope 符合、未退役、经当前代码/测试/canonical 文档核实,
并真实改变计划或验证的条目才算有效命中;按
`经验命中:{path}{status});核验:{fact};影响:{plan_or_check}` 报告。`retired` 不应用;
`observed` / `validated` 先核实再用;旧 lesson 缺 `status``observed` 读取,不批量迁移。只是相关
但没有改变行为时不制造复用证据;当前事实明确反证时立即停止应用,证据不足时不猜。
任务内只在内存保留最多 3 条候选按新证据替换低价值项不暂停或询问。强信号只包括owner
纠正实际改变方案/代码/术语/验证;可复现证据推翻根因;同一路径失败两次后更换假设;
blocking/important finding 暴露未编码不变量;新 red -> green 捕获可复发失败lesson 真实改变本次行为
或被反证;重复 workaround方法显著降低重试、成本或风险。
候选还必须同时有可追溯证据、能写成未来动作、适用于本次精确 diff 之外、且没有现成 canonical
owner。网络波动、拼写、泛化口号、活动记录以及已被机械 owner 完整覆盖的事实直接丢弃。
创建、改写规则/scope、晋升、删除与跨项目反馈仍须用户显式授权。为不中断 read-repair仅对已有且
有效命中的 lesson 开放两种窄维护:`observed -> validated` 仅在独立后续任务确实采用并验证成功时
发生,只补一次代表性证据;`observed|validated -> retired` 仅在当前仓库事实直接反证或发现已有
canonical owner 时发生,只写原因与替代/反证指针。窄维护不新建事实、不改规则、不扩 scope、不新增
gate随当次代码、证据和
游标进入同一语义原子 milestone稳定 validated 命中不写文件。需要改写结论或证据不足时只给
候选,新结论不得通过复活 retired 条目获得 validated 身份;窄维护必须在最终报告列出文件变化。
当前任务范围内能直接落成 red -> green 测试/checker 的约束优先机械化,不另写重复 lesson会扩大
范围时只给候选。用户已明确说“记住 / 更新 / 退役”时,同轮按 `cs-keep` 处理,不重复确认。普通任务
只在强信号成立时展示最高价值一条,首行固定 `晶化候选:{rule}`,并给出证据、范围和建议归宿;无
强信号完全不显示模板,没有记忆写入授权时不落盘。
## 硬门槛
- **先有能自证等价的验证,再动代码**:覆盖目标行为的测试、类型检查或可对照的输出基线。没有就先补验证或与用户确认等价判据,不许裸改。
@@ -36,4 +65,3 @@ argument-hint: "[重构目标]"
- 报告:改了什么结构、等价性证据(验证输出)、遗留事项。
- 需要跨会话继续时写 `.codestable/work/refactor-{slug}.md`(目标 / 现场 / 边界 / 证据 / 验收 / 状态与未决六节work 文档一律带类型前缀。完成后先在报告列毕业去向结论进哪、lesson 沉哪,或明说无可毕业)再删除;目标位置不存在时在清单中建议落点请用户拍板,拍板前不删。用户要求留档则保留。
- 本轮若踩坑或被纠偏,推荐用 cs-keep 沉淀一条;用户拒绝即跳过。
+143
View File
@@ -13,6 +13,7 @@ SKILLS = ROOT / "plugins/codestable/skills"
LOCAL_SKILLS = ROOT / ".claude/skills"
TASK_SKILLS = ("cs-feat", "cs-issue", "cs-refactor", "cs-epic")
ORDINARY_TASK_SKILLS = ("cs-feat", "cs-issue", "cs-refactor")
LEGACY_KNOWLEDGE_DIRS = {
".codestable/roadmap/",
".codestable/features/",
@@ -25,6 +26,54 @@ LEGACY_KNOWLEDGE_DIRS = {
".codestable/feedback/",
}
LESSON_READ_REPAIR_CONTRACT = {
"经验命中:{path}{status});核验:{fact};影响:{plan_or_check}",
"旧 lesson 缺 `status` 按 `observed` 读取",
"`retired` 不应用",
"`observed` / `validated` 先核实再用",
"只是相关但没有改变行为时不制造复用证据",
"当前事实明确反证时立即停止应用",
"证据不足时不猜",
}
CRYSTALLIZATION_SIGNAL_CONTRACT = {
"任务内只在内存保留最多 3 条候选",
"不暂停或询问",
"owner 纠正实际改变方案/代码/术语/验证",
"可复现证据推翻根因",
"同一路径失败两次后更换假设",
"blocking/important finding 暴露未编码不变量",
"新 red -> green 捕获可复发失败",
"lesson 真实改变本次行为或被反证",
"重复 workaround",
"方法显著降低重试、成本或风险",
"可追溯证据",
"能写成未来动作",
"本次精确 diff 之外",
"没有现成 canonical owner",
"网络波动、拼写、泛化口号、活动记录",
"已被机械 owner 完整覆盖",
}
NARROW_LESSON_MAINTENANCE_CONTRACT = {
"仅对已有且有效命中的 lesson",
"`observed -> validated`",
"独立后续任务确实采用并验证成功",
"只补一次代表性证据",
"`observed|validated -> retired`",
"当前仓库事实直接反证",
"发现已有 canonical owner",
"只写原因与替代/反证指针",
"不新建事实",
"不改规则",
"不扩 scope",
"不新增 gate",
"稳定 validated 命中不写文件",
"需要改写结论或证据不足时只给候选",
"新结论不得通过复活 retired 条目",
"最终报告列出文件变化",
}
THIN_SKILL_SAFETY_INVARIANTS = {
"cs": (
"同轮直转",
@@ -103,6 +152,10 @@ def _read_skill(path: Path) -> tuple[dict[str, object], str]:
return yaml.safe_load(frontmatter), body
def _contains_contract(text: str, anchor: str) -> bool:
return "".join(anchor.split()) in "".join(text.split())
def test_active_skills_do_not_use_legacy_frontmatter_contracts() -> None:
for root in (SKILLS, LOCAL_SKILLS):
for path in sorted(root.glob("*/SKILL.md")):
@@ -213,6 +266,96 @@ def test_task_skills_retrieve_legacy_knowledge_read_only() -> None:
assert "批量迁移" in kickoff, skill_name
def test_task_skills_share_the_complete_lesson_read_repair_contract() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in LESSON_READ_REPAIR_CONTRACT
if _contains_contract(body, anchor)
}
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == LESSON_READ_REPAIR_CONTRACT, skill_name
def test_task_skills_share_the_bounded_strong_signal_contract() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in CRYSTALLIZATION_SIGNAL_CONTRACT
if _contains_contract(body, anchor)
}
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == CRYSTALLIZATION_SIGNAL_CONTRACT, skill_name
def test_crystallization_closing_is_quiet_and_prefers_mechanical_guards() -> None:
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"当前任务范围内能直接落成 red -> green 测试/checker",
"优先机械化",
"不另写重复 lesson",
"会扩大范围时只给候选",
):
assert _contains_contract(body, anchor), skill_name
for skill_name in ORDINARY_TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"普通任务只在强信号成立时展示最高价值一条",
"`晶化候选:{rule}`",
"证据、范围和建议归宿",
"无强信号完全不显示模板",
"没有记忆写入授权时不落盘",
):
assert _contains_contract(body, anchor), skill_name
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
for anchor in (
"用户已明确说“记住 / 更新 / 退役”",
"同轮按 `cs-keep` 处理",
"不重复确认",
):
assert _contains_contract(body, anchor), skill_name
_, epic = _read_skill(SKILLS / "cs-epic/SKILL.md")
for anchor in (
"Epic 子项不展示、不询问",
"每个子项至多把一条去重候选写入既有游标证据区",
"最终毕业清单一次处理",
"复用最终 owner gate",
"不得询问“是否继续下一项”",
"不得把普通子项完成当作终态返回",
):
assert _contains_contract(epic, anchor)
def test_task_skills_allow_only_two_narrow_lesson_maintenance_paths() -> None:
signatures = {}
for skill_name in TASK_SKILLS:
_, body = _read_skill(SKILLS / skill_name / "SKILL.md")
signatures[skill_name] = {
anchor
for anchor in NARROW_LESSON_MAINTENANCE_CONTRACT
if _contains_contract(body, anchor)
}
assert _contains_contract(body, "创建、改写规则/scope、晋升、删除与跨项目反馈仍须")
assert _contains_contract(body, "随当次代码、证据和游标进入同一语义原子 milestone")
assert len({frozenset(signature) for signature in signatures.values()}) == 1
for skill_name, signature in signatures.items():
assert signature == NARROW_LESSON_MAINTENANCE_CONTRACT, skill_name
def test_keep_never_writes_v1_compound() -> None:
_, keep = _read_skill(SKILLS / "cs-keep/SKILL.md")
assert "`.codestable/compound/` 是只读历史知识源" in keep
+59
View File
@@ -8,6 +8,7 @@ import yaml
ROOT = Path(__file__).resolve().parents[1]
SHIPPED_SKILLS = ROOT / "plugins/codestable/skills"
def _frontmatter(path: Path) -> dict[str, object]:
@@ -94,3 +95,61 @@ def test_v1_feedback_promoter_is_explicitly_legacy_only() -> None:
assert "not a CodeStable v2 production-feedback entry" in promoter
assert "仅用于显式导入冻结的 v1" in eval_skill
assert "新反馈如何进入 regression 不在当前协议中定义" in eval_skill
def test_project_learning_lifecycle_is_an_accepted_narrow_staging_contract() -> None:
adr6 = ROOT / "docs/adr/006-project-learning-lifecycle.md"
assert adr6.is_file()
assert _frontmatter(adr6)["status"] == "Accepted"
text = adr6.read_text(encoding="utf-8")
for anchor in (
"在任务中静默观察",
"最多保留 3 条候选",
"read-repair",
"必须优先机械化",
"`observed -> validated`",
"`observed|validated -> retired`",
"显式授权",
"feedback runtime",
"transcript",
"全局 lessons",
"集中 runtime",
"第九个 skill",
"不新增逐项暂停或确认",
):
assert anchor in text
def test_project_learning_does_not_restore_feedback_or_global_runtime_state() -> None:
active_skills = {
path.parent.name for path in SHIPPED_SKILLS.glob("*/SKILL.md")
}
assert active_skills == {
"cs",
"cs-code-review",
"cs-epic",
"cs-feat",
"cs-issue",
"cs-keep",
"cs-onboard",
"cs-refactor",
"cs-review",
}
for path in (
SHIPPED_SKILLS / "cs-feedback",
ROOT / ".codestable/learning",
ROOT / ".codestable/global-lessons",
ROOT / ".codestable/state.yaml",
ROOT / ".codestable/session-state.yaml",
):
assert not path.exists(), path
runtime_artifacts = {
path.relative_to(SHIPPED_SKILLS).as_posix().lower()
for path in SHIPPED_SKILLS.rglob("*")
if path.is_file()
and ("transcript" in path.name.lower() or path.name == "state.yaml")
}
assert runtime_artifacts == set()