fix(session-mechanism): 常驻读不到宿主库 ⇒ 检查会话永不建

- init_workspace.py 生成配置时写 host_db(宿主 env → 本包 env/roots.env);旧配置留空则补,已写值不动
- collabd._wb_db() 去掉 ~/.workbuddy 回落(本机无此文件),取不到改为占位路径 + 限流留痕
- _sm_load_roots() 先读 COLLABD_CONFIG 所指配置的 host_db,再试 <CODEBUDDY_CONFIG_DIR>/skills/session-mechanism/env/roots.env,最后才上跳
- pitfalls 新增 P0-99(含「新工作区验收跑一次脱环境探针」通则)

实测:deepwrite-harness 新建区 2091 条「读库失败」、11.5 小时零检查会话;修复后五区重启读库失败归零,检查会话建棒并把目标置「已完成」
This commit is contained in:
admin committed 2026-10-17 11:36:13 +08:00
1 parent 8160f91559
commit 310a964a94
3 files changed
+111 -3

No files matched your search

@@ -72,6 +72,33 @@ SK = _resolve_skill_dir(SK)
def _resolve_host_db() -> str:
"""宿主库绝对路径(写进本区配置的 `host_db`)。
为什么必须写进配置(2026-10-17 deepwrite-harness 实测,2091 条读库失败):
计划任务起的常驻拿不到 `CODEBUDDY_CONFIG_DIR`,而本区副本住在
`<工作区>/.workbuddy/collab/`、与技能包**没有相对关系** ⇒ 启动器第③级
「上跳找 `env/roots.env`」恒落空 ⇒ `collabd._wb_db()` 回落
`~/.workbuddy/workbuddy.db`(本机无此文件)⇒ 闸② 恒判「有会话在跑」
⇒ 检查会话永不建。配置里写死这一项是第②级兜底,单区生效、不依赖环境。
取值顺序:宿主 env `CODEBUDDY_CONFIG_DIR` → 本包 `env/roots.env`。
两处都取不到 ⇒ 返回空串(交启动器报错留痕,⛔ 不猜 `~/.workbuddy`)。
"""
cfg = (os.environ.get("CODEBUDDY_CONFIG_DIR") or "").strip()
if not cfg:
_roots = SK.parent / "env" / "roots.env"
try:
for _ln in _roots.read_text(encoding="utf-8", errors="replace").splitlines():
_ln = _ln.strip()
if _ln.startswith("CODEBUDDY_CONFIG_DIR="):
cfg = _ln.split("=", 1)[1].strip()
break
except Exception:
pass
return str(Path(cfg) / "workbuddy.db") if cfg else ""
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("workspace")
@@ -196,6 +223,7 @@ def main() -> int:
% ("有" if _old_cfg else "⛔无", "有" if _old_goal else "⛔无"))
# ② 部署配置(**补缺式**:以旧配置为底,只加现行键;⛔ 不动用户改过的值)
_host_db = _resolve_host_db()
cfg = {
"_说明": "本文件=**本工作区**的协作机制部署配置(⛔ 不属于技能)。由 `init_workspace.py` 生成;"
"`COLLABD_CONFIG` 必须指向它,否则 `collabd.py` 不认这个工作区。",
@@ -205,6 +233,7 @@ def main() -> int:
"taskgraph": "交付物/任务图-会话协作自检.json",
"targets": {},
"singleton_port": port,
"host_db": _host_db, # 🔴 二级兜底:计划任务环境没有 CODEBUDDY_CONFIG_DIR
"interval": 10, "idle_min": 12, "stuck_min": 30, "vacuum_min": 5, "health_every": 300,
"supervise_interval": 10,
"wake_enable": False, # 🔴 唤醒/投递整套已退役
@@ -218,6 +247,8 @@ def main() -> int:
_added = [k for k in cfg if k not in _old_cfg]
cfg["workspace"] = ws_s # 这两项必须以本次为准(工作区可能搬过家)
cfg["singleton_port"] = port # ⚠️ 纠偏时**必须以本次为准**(旧值可能在 `_old_cfg` 里,会被 update 盖回去)
if not (cfg.get("host_db") or "").strip():
cfg["host_db"] = _host_db # 旧配置留空 ⇒ 补上(空串会让常驻读不到宿主库)
cfgp.write_text(json.dumps(cfg, ensure_ascii=False, indent=1), encoding="utf-8", newline="")
print("② 部署配置:%s%s(端口 %d,%s)"
% (cfgp.relative_to(ws), (" 补了 %s" % _added) if _added else " 已最新",