Files
workbuddy_skills/改包纪律.md
T
admin d81f75f173 技能包:配置与代码分家 —— 每包自建 env/ 放本机专属配置,scripts/ 不再写死本机路径
用户 2026-10-11 原话:
· 19:22「这个环境都是针对一台机器的,同步到别的机器把环境都搞坏了」
· 19:28「不用挪出 用env文件夹区分就行,重点是 脚本是脚本 配置是配置」
· 19:29「每个技能 需要环境配置的 都有自己的 env文件夹」
· 19:30「修改完成后要仔细检查 避免调整后 各技能脚本运行失败」

改动:
1、session-mechanism 新增 env/(roots.env=本机真身不入库 + roots.env.example=样例入库),
   install.py 的 ROOTS_ENV 改指 env/roots.env;全包脚本/hook 的配置定位统一为
   「向上 4 层 × env/roots.env 优先 → 包根 roots.env 兼容 → 技能库那份兜底」。
2、去硬编码:collabctl / keepalive / supervise-launch / board-launch 里的本机路径与本机工作区
   清单全清,改为 DSH_AIROOT(兜底 dirname(DSH_WS_ROOT))+ 扫 <AIROOT>/*/.workbuddy/collab/
   自动发现;保活任务名按 collabd-keepalive-<工作区名> 现推;启动器默认值改 ~/.workbuddy 形态。
3、browser-harness:bh_chrome_keepalive.py 默认值全部改 env 驱动,新增 env/bh.env.example。
4、.gitignore:env/ 下只放行 *.example(三行三种层级)+ 兜住旧位置的包根 roots.env。
5、改包纪律.md 新增「四、包结构:脚本是脚本,配置是配置」,立为全仓通用规矩。
6、文档同步:SKILL.md / deploy.md(新增 §3b 配置层级、§6 换机器必查 6 件事)/ rules.md /
   pitfalls.md / supervise-persistence.md。

验收(本机):py_compile 34 个 py 全过;selftest PASS 109 / FAIL 0;
逐文件实证 8 个 loader 命中 env/roots.env;preflight-lock.sh 同目录实测解出两个根;
install.py --manifest 77 份、语法失败 0。

异机验证(包拷成「新克隆」(只有 *.example)+ 另造假工作区 ws-alpha/ws-beta):
install.py --apply 自生成该机 env/roots.env;collabctl/keepalive 自动发现的确实是
ws-alpha/ws-beta、任务名现推(写死清单确已消除);部署副本本地无 roots.env 时靠
CODEBUDDY_CONFIG_DIR 兜底读到技能库那份;整套 selftest 有宿主库时 PASS 108 / FAIL 1
(唯一 FAIL=该区没有常驻心跳,环境所致;本机常驻在跑时同一套为 PASS 109 / FAIL 0)。
2026-10-11 21:49:28 +08:00

159 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 改包纪律(多会话共写 · 2026-10-08 立)
> 本仓被多个会话同时写,推进以分钟计。这份文件是把 2026-10-08 那次真事故的防线写下来 —— 谁来这个仓干活,先读这一份。
## 一、为什么立这一份
2026-10-08 22:22,一个会话把「说人话新稿」落地到 `product-planning`,**整文件覆盖**了 7 个文件。那份新稿是**基于较早版本**写的,于是**晚于新稿编写时点的改动全被抹掉**:
1、**「单一可信源」类声明 5 处 → 1 处**。最重的一处是 `references/stage-delivery/SKILL.md` 的 `## 供给(唯一权威处 · 改供给只改这一块)` —— 整节标题连同六行供给表一起被换成了另一种三列表。
2、**供给口径被翻转**。用户定案是「默认主线 = `oil-ui-pro`(基础层),`open-design` 只是随段携带的**可选件**、选了才用」;覆盖版写成了「`open-design` = 本段默认主线」。
3、`references/stage-delivery/references/execution-runbook.md` §7 完成标准**丢了两条勾选项**(「供给能力边界已核对」、「页型已判…每条都要附取值记录」)。
4、`3c` 子步名被改成「会诊」,但**没同步** `scripts/check_naming.py` 的 `STAGES` 表 ⇒ 直接报 FAIL。
5、**9 条「复述」类 FAIL 与 2 条废路径(`strategy/`、`ux/`)重新长回来** —— 权威声明一被削弱,复述就不再被视为违规。
⚠️ 当时提交信息写的是「按**合并**落地」,实际效果是覆盖。这**不是恶意,是流程缺陷**:新稿的编写时点早于被覆盖文件的修改时点,落地时不做三方比对,就必然丢东西。
## 二、五条硬纪律
### 1、⛔ 不许整文件覆盖
落地「新稿 / 改版 / 批量替换」时,⛔ 不许把手上那份稿子直接盖到目标文件上。
✅ 正确做法:把新稿当**改动意图**,逐节与目标文件的**当前内容**比对,只把有意的改写落进去,其余保持原样。宁可分多次小提交,也不要一次整文件替换。
### 2、落地前先比对时点
先回答两个问题,答不出来就别落:
1、这份新稿是什么时候写的?依据的是哪个版本的包?
2、目标文件自那以后被改过吗?`git log --oneline <新稿编写时点>..HEAD -- <目标路径>`
只要第 2 问的答案是「改过」,就**必须逐节比对**,⛔ 不许直接覆盖。
### 3、改完必跑闸门
`product-planning` 包改完,必跑:
```
cd E:/ProgramData/.workbuddy/skills/product-planning
E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe scripts/check_naming.py --root . --ws "<工作区绝对路径>"
```
- ⚠️ `--ws` **必带**(不带则找不到含 `docs/pm` 的那一层,会整包 FAIL)
- 期望 `失败 0`;有 FAIL 就修完再提交,⛔ 不许带 FAIL 提交
- ⛔ 但也别只看闸门绿不绿 —— 闸门查的是**命名一致性**,查不出「结构被删」这类损失(见第 4 条)
### 4、收到「覆盖性」提交后,先做结构体检
闸门绿 ≠ 没丢东西。覆盖性提交的典型特征:要么报一堆复述类 FAIL,要么因为权威处被一起删而集体失效。
体检方法(**比看闸门更早跑**):
```
cd E:/ProgramData/.workbuddy/skills
git grep -c "唯一权威处" <rev> -- product-planning
git log --oneline -3 -- product-planning
git diff --stat <上次收口提交> HEAD -- product-planning
```
拿「唯一权威处」这类**结构标记的计数**与上次收口版本比。计数掉了 ⇒ 先查结构,再看内容。
### 5、写 / 改规则文件:一律用肯定表述(2026-10-09 用户令)
**写或改**技能与规则的文字时,**写"要什么、怎么做"**,让读者照着就能做对;**新建、生成时同样适用**。
- ✅ 例:「要点名到具体是哪份文件」。
- ✅ **例外(按文件性质定)**:**以「经验沉淀」或「红线/避坑」为目的**的技能与规则(踩坑记录 ·
红线清单 · 反例库)可以写负向 —— 写法是「**先写正向目标,再把踩过的坑放括号里当依据**」。
- **为什么**:这类文字是**每轮注入面 / 自动匹配面**(技能描述、注入块、钩子文案都在其中)。
把「不要 X」喂进去 ⇒ **反而把 X 拉高命中**。实测形态:某技能描述里列了「不用于普通插画/海报/故事板」
⇒ 用户说"做个海报"时它更容易被选上;2026-10-09 我在注入块里写了一整段负向表述,同族。
- 规则正文(唯一权威)⇒ `session-mechanism/references/rules.md §9`。
## 三、出事后怎么修(照 2026-10-08 那次的流程)
1、**先定性,别急着改**。用可复现的方式坐实「是谁引入的」:
```
cd E:/ProgramData/.workbuddy/skills
for c in <上次收口提交> <可疑提交>; do
rm -rf /tmp/pp-$c && mkdir -p /tmp/pp-$c
git archive $c product-planning | tar -x -C /tmp/pp-$c
printf "=== %s ===\n" "$c"
(cd /tmp/pp-$c/product-planning && \
E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe \
scripts/check_naming.py --root . --ws "<工作区绝对路径>" 2>&1 | tail -2)
done
```
两个版本各跑一次,`全过 / 失败 N` 的对比就是铁证。
2、**⛔ 不要在当前(被覆盖的)版本上逐项修补**。基线本身是错的,补得越多越像在旧稿上刷漆。
3、**回退**:`git checkout <上次收口提交> -- product-planning/`(只重置该包,⛔ 不碰别人正在改的文件)
4、**先存档再回退**。覆盖版里若有值得保留的内容(措辞改写之类),⛔ 不许无痕丢掉:
- 导 `git diff <上次收口提交> <覆盖提交> -- product-planning` 作对照
- 导覆盖版的全文快照
- 写一份说明,讲清「哪些能采纳、哪些不能」,结构损坏项必须逐条列出
- 参考实例:工作区 `归档/技能包-说人话改写-被覆盖存档-20261008/`
5、**回退后立刻提交推送**,并把体检结果写进提交信息。⛔ 别攒着 —— 攒着就会被下一次覆盖顺手带走。
## 四、包结构:**脚本是脚本,配置是配置**(2026-10-11 立 · 全仓通用)
**每个需要环境配置的技能,都在自己的包内建一个 `env/` 文件夹**,专放「每台机器各不同」的值;
`scripts/`(代码)只放通用逻辑,值从 `env/` 读。
用户原话(2026-10-11):
- 19:22「这个环境都是针对一台机器的,同步到别的机器把环境都搞坏了」
- 19:28「不用挪出 用env文件夹区分就行,重点是 脚本是脚本 配置是配置」
- 19:29「每个技能 需要环境配置的 都有自己的 env文件夹」
### 1、配置放哪
- **真配置** ⇒ `<技能包>/env/<名>.env`,本机生成、**不入库**
- **样例** ⇒ `<技能包>/env/<名>.env.example`,**入库**(只有占位符,无本机路径)
- 仓根 `.gitignore` 已有对应规则:`**/env/*` + `!**/env/*.example` ⇒ `env/` 下只放行 `*.example`
### 2、代码怎么写
- 脚本头部放一个 `_xx_load_env()`:从 `__file__` 向上找 `<包>/env/<名>.env`,逐行 `KEY=VALUE`
以 **setdefault** 注入 ⇒ **宿主 env 优先,文件兜底**(与本仓 `session-mechanism/scripts/**` 的
`_sm_load_roots()` 同一套写法,照抄即可)。
- 值一律**从 env 读**,代码里只留**通用兜底**(用户目录用
`os.environ.get("CODEBUDDY_CONFIG_DIR") or os.path.expanduser("~/.workbuddy")` 这类跟着机器走的写法)。
(依据:把本机路径/本机工作区清单写进入库代码 ⇒ 同步到别的机器会按不存在的路径建计划任务,用户 19:22 报的那次。)
- **同包内的兄弟文件**用 `Path(__file__).resolve().parent / "x.py"` 定位;解释器用 `sys.executable`
或它的同目录兄弟 `pythonw.exe`。
- 解析不到必需值时:**把原因写进日志 + 非零退出码**,让人一眼看出缺什么
(依据:静默兜底会去建指向空路径的任务,比报错难查得多)。
### 3、判断一个技能「需不需要建 `env/`」
问一句:**这个技能里有没有「换一台机器就该变」的值?**
- **有**(路径 / 端口 / 用户名 / 工作区清单 / 解释器位置)⇒ **建 `env/`**,把它们全挪进去
- **没有**(纯文档、纯算法、只读上游接口)⇒ **不建** —— 空目录只会变成噪声
### 4、首轮审计(2026-10-11 · 本目录工作区)
- ✅ **已建 `env/`**:`session-mechanism`(`env/roots.env`)|`browser-harness`(`env/bh.env`)
- ✅ **判为不需要**:`humanizer` `humanizer-zh`(纯文档,0 个脚本)|`oil-ui-pro` / `video-capture` /
`draw-ui` / `oil-motion` / `ai-daily-report`(有脚本,但零本机值)|`product-planning`(脚本里只有注释提到路径,无实际读取)
- ⚠️ **本仓白名单之外的目录里也有同类值**(2026-10-09 已撤出仓库,本轮不动):
`dsh-local-env/references/dsh-env-bootstrap/resident-rules.py`(有本机常量)、
`dsh-workflow/references/dsh-auto-handoff-chain/audit-mirror.py`(默认根写死)、
`dsh-knowledge/references/dsh-knowledge-upkeep/split_skill.py`(仅文档示例里的路径)。
⇒ 将来若要收编,按上面第 1~2 条改。
## 五、一句话
**新稿是意图,不是内容。落地 = 把意图逐节落到当前版本上,⛔ 不是把文件换掉。**