docs(compat): 进入公测期,开发心智翻新为保证对外兼容 + bump 0.11.1
- CLAUDE.md「开发阶段心智」从"开发期可随意 break、不写兼容层"改为: 对外契约(用户数据/DB schema/对外 API/CLI·env·文件布局)必须向后兼容, 仅纯内部实现仍以最优为准放手重构;拿不准 → 当对外契约处理 - 版本号段:公测保持 0.x,1.0 留给对外冻结行为 / 正式 GA - PROGRESS 加一条;bump 0.11.0 → 0.11.1 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f12df1bd82
commit
0259f0ce92
26
CLAUDE.md
26
CLAUDE.md
|
|
@ -24,16 +24,24 @@ PowerShell here-string `@'...'@` **只在 PowerShell 工具里有效**;用 Bash
|
||||||
|
|
||||||
理由:开发期需求漂移快,写到一半被推翻代价高 —— 口头对齐方案是最低成本的纠偏机会。
|
理由:开发期需求漂移快,写到一半被推翻代价高 —— 口头对齐方案是最低成本的纠偏机会。
|
||||||
|
|
||||||
## 开发阶段心智
|
## 开发阶段心智(公测期:保证对外兼容)
|
||||||
|
|
||||||
当前处于**开发测试期**(开发自用 + 内部测试,DB 已有真实测试数据)。改需求 / 重构时,**以最优实现为准,不为旧数据 / 旧字段 / 旧 API 留兼容层**,但**不删现有数据**:
|
**已进入公测期**(对外真实用户在用,DB 里是真实用户数据 + 线上正在跑的会话)。心智从"开发期可随意 break"切换到**对外面必须向后兼容、对内部实现仍以最优为准**。判断一处改动能不能随意改,先问:**它是不是外部用户能感知 / 依赖的契约?**
|
||||||
- DB schema 变 → 直接改 model + 写一条干净的 migration:加列 / 改列结构 OK;**不要 truncate / DELETE FROM 现有表 —— 测试数据要保留**
|
|
||||||
- 删字段(DROP COLUMN)前:若该列是当前唯一持有该信息(如累计型 tokens 列),先 backfill 到新位置再删;若纯冗余(从其他列能推出)直接删 OK
|
|
||||||
- 字段语义变 → 全量替换 + migration 把旧值映射到新值(不留 `legacy_xxx` / `*_v2` 并存)
|
|
||||||
- CLI / REPL 选项变 → 直接改,不留 deprecated 别名
|
|
||||||
- 只有当用户明确说"这条要保留兼容"时才写兼容代码
|
|
||||||
|
|
||||||
理由:兼容层是技术债;但测试数据是观察新代码行为的依据 —— 一次 truncate 后再回去查"上周那 task 烧了多少 token / 哪条消息触发的 bug",就只能瞎猜。
|
**对外契约 —— 必须保证兼容,break 前先有迁移路径**:
|
||||||
|
- **用户数据**:绝不 truncate / DELETE FROM / 重置现有表 —— 这是用户的东西,丢了无法恢复
|
||||||
|
- **DB schema**:加列 / 改列 OK,但要写干净 migration 且**平滑兼容线上存量数据**;删字段(DROP COLUMN)前先 backfill 到新位置,确认无引用再删
|
||||||
|
- **字段语义变**:全量替换 + migration 把旧值映射到新值,且要考虑**线上正在跑的旧请求**读到该字段时不崩
|
||||||
|
- **对外 API(HTTP 接口 / 请求·响应 schema)**:不改既有字段语义、不删字段、不改 URL;要变先加新字段 / 新端点,旧的留一个废弃窗口
|
||||||
|
- **CLI / REPL 选项、env 变量、文件布局**:改名 / 删除前保留 deprecated 别名一个版本,并在 RUN.md 标注废弃;直接 break 会打断正在用的人
|
||||||
|
|
||||||
|
**对内部实现 —— 仍以最优为准,放手重构**:
|
||||||
|
- 纯内部模块 / 函数 / 私有数据流(外部不可见、无人依赖)→ 该重写重写,不留 `legacy_xxx` / `*_v2` 并存
|
||||||
|
- 内部重构只要**对外行为不变**(同样的输入 → 同样的输出 / 同样的 schema),不算破坏兼容
|
||||||
|
|
||||||
|
**拿不准是"对外契约"还是"内部实现"时 → 当成对外契约处理(先对方案,见上一节)。** 只有用户明确说"这条可以 break / 不用兼容"才走破坏式改法。
|
||||||
|
|
||||||
|
理由:公测后"随意 break"的前提(只有自己的测试数据、坏了重来)已不成立 —— 现在每次破坏式改动都可能弄丢真实用户数据或打断线上请求。兼容层确实是技术债,但比起搞坏用户数据,这点债值得背;等正式打 1.0、对外冻结行为后再统一清理废弃面。
|
||||||
|
|
||||||
## 文档维护
|
## 文档维护
|
||||||
|
|
||||||
|
|
@ -46,7 +54,7 @@ PowerShell here-string `@'...'@` **只在 PowerShell 工具里有效**;用 Bash
|
||||||
- patch(`0.8.x`):bug 修复 / 重构 / 调参 / 新加 skill / 样式
|
- patch(`0.8.x`):bug 修复 / 重构 / 调参 / 新加 skill / 样式
|
||||||
- minor(`0.x.0`):成批新功能 / 明显的对外行为变化
|
- minor(`0.x.0`):成批新功能 / 明显的对外行为变化
|
||||||
- major(`x.0.0`):1.0 正式发版 / 不兼容大重构
|
- major(`x.0.0`):1.0 正式发版 / 不兼容大重构
|
||||||
- 当前 `0.x` 开发期,未正式发版前不进 1.0
|
- 当前 `0.x` **公测期**,1.0 留给"对外冻结行为 / 正式 GA"那一刻;公测中保持 `0.x` 迭代,minor 走新功能、patch 走修复
|
||||||
|
|
||||||
**只有以下情况才动 `DESIGN.md`**(避免把工程笔记沉淀成设计):
|
**只有以下情况才动 `DESIGN.md`**(避免把工程笔记沉淀成设计):
|
||||||
- 架构 / 心智模型变化(如 §7.1 task-primary 重写)
|
- 架构 / 心智模型变化(如 §7.1 task-primary 重写)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。
|
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。
|
||||||
|
|
||||||
最后更新:2026-06-12(admin 管理后台 + 目录/筛选排序/分页/导出 PDF:users.role + require_admin + /v1/admin/* + 独立 admin.html)
|
最后更新:2026-06-12(进入公测期:CLAUDE.md「开发阶段心智」翻新为"对外契约必须向后兼容,仅内部实现仍可最优重写")
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -21,6 +21,10 @@
|
||||||
|
|
||||||
## 已完成关键能力
|
## 已完成关键能力
|
||||||
|
|
||||||
|
### 2026-06-12 / 进入公测期:对外兼容策略
|
||||||
|
|
||||||
|
- 项目进入公测(对外真实用户在用)。`CLAUDE.md`「开发阶段心智」从"开发期可随意 break、不写兼容层"翻新为**对外契约(用户数据 / DB schema / 对外 API / CLI·env·文件布局)必须向后兼容,仅纯内部实现仍以最优为准放手重构**;拿不准 → 当对外契约处理。版本号段同步:公测保持 `0.x`,1.0 留给"对外冻结行为 / 正式 GA"。同条记忆 `feedback_dev_phase_no_compat` 一并翻新。bump 0.11.0 → 0.11.1。
|
||||||
|
|
||||||
### 2026-06-12(傍晚)修上下文压缩投毒 → run_python 空转报错
|
### 2026-06-12(傍晚)修上下文压缩投毒 → run_python 空转报错
|
||||||
|
|
||||||
- **根因(DB 实测,60 个 task 命中 83 次 `[Error] bad arguments to run_python: code or script_path must be provided`)**:`core/context.py` 把旧 assistant `tool_call.arguments`(>800 字符)压成 `{"_compacted":true,"original_chars":N,"note":...}` marker 发给 LLM。模型在长 doc/ppt 任务里看到几十次"过去的 run_python 长这样",就**照葫芦画瓢把 marker 当真实参数原样吐出来** → executor 拿不到 code/script_path → 报错空转。83 次里 **61 次是模型仿写 marker**(铁证:抓到 `{"_compacted":true,"original_chars":85}`——85<800 压缩器根本不会出手、且缺 `note` 字段,压缩器必带 → 只能是模型伪造),22 次是真·空 `{}`。这正是代码里早已为 `task_progress` 单独豁免、注释明写"会毒化模型"的同一个坑,只是 run_python 没豁免。
|
- **根因(DB 实测,60 个 task 命中 83 次 `[Error] bad arguments to run_python: code or script_path must be provided`)**:`core/context.py` 把旧 assistant `tool_call.arguments`(>800 字符)压成 `{"_compacted":true,"original_chars":N,"note":...}` marker 发给 LLM。模型在长 doc/ppt 任务里看到几十次"过去的 run_python 长这样",就**照葫芦画瓢把 marker 当真实参数原样吐出来** → executor 拿不到 code/script_path → 报错空转。83 次里 **61 次是模型仿写 marker**(铁证:抓到 `{"_compacted":true,"original_chars":85}`——85<800 压缩器根本不会出手、且缺 `note` 字段,压缩器必带 → 只能是模型伪造),22 次是真·空 `{}`。这正是代码里早已为 `task_progress` 单独豁免、注释明写"会毒化模型"的同一个坑,只是 run_python 没豁免。
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||||
# 改版本只动这一行。
|
# 改版本只动这一行。
|
||||||
__version__ = "0.11.0"
|
__version__ = "0.11.1"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue