session-mechanism:主会话只能由用户开(撤掉"排期建主会话"那条路)
用户报障:「技能中没有任何创建主会话的机制,除非是创建接续会话」。
病灶:supervise-persistence.md §〇 早期把「定时任务创建主会话」与「用户手动
创建主会话」并列成两种合法场景,SKILL.md §⑥ 顺着抄了一遍 ⇒ 读到的人会理解成
"这条路是允许的",于是照做。
实测事故(mcn-aigc-ontology 2026-10-14 07:31):init_workspace 装机制后建出
recurring 排期 [主]-super-i卡片采集-主会话(FREQ=DAILY;BYHOUR=09),prompt 里
写着「你是本工作区的主会话……要推进就直接建 [执行] 排期拉起任务会话」——
主会话的口径被套到了一条排期身上。排期开出来的会话恒是任务会话那一档
(is_background_automation=1)⇒ 台账里多一条"主会话",用户那边没多窗口。
改动:
- SKILL.md §⑥:改成「形态只有一种:主会话由用户手动开」,⛔ 排期拉不出主会话
- supervise-persistence.md §〇:表格两列改一列 + 新增事故回放小节
- supervise-persistence.md §八:删掉「B · 定时任务创建主会话」整行
- architecture.md §1:新增《主会话怎么来:只能由用户手动开》段
- session-rules-check.py:新增判据 ⑬ main_sched(扫排期名以 [主] 开头或含
"主会话" ⇒ ACTIVE 报 fail、非 ACTIVE 报 warn);扫描面 recurring 与 once 全含
- SKILL.md 体检清单:十二项 → 十三项,补 ⑬ 变异对照记录
判据验收(非恒绿):喂 mcn 区真数据三种输入 —— 原样 PAUSED ⇒ warn;
伪造成 ACTIVE ⇒ fail;无此类排期的区 ⇒ ok。
同批带上的既有改动:supervise-launch.py 路径相对化 + 三级取值(禁回落 ~)。
This commit is contained in:
1 parent
aa89ee0333
commit
053a6a6723
5 files changed
+178
-24
No files matched your search
@@ -625,6 +625,37 @@ def check_orchestration():
|
||||
else:
|
||||
rec("cwd", "C", "ok", "`cwds` 归属同形", "本工作区的排期都写在同一条路径上")
|
||||
|
||||
# ⑬ 🔴🔴 「顶着主会话名字的排期」—— 2026-10-14 加(用户报障「技能中没有任何创建主会话的机制」)
|
||||
# 口径(`SKILL.md`《三类会话》类别表逐字):
|
||||
# **主会话 | 用户手动开 | 管目标与方向、派活 | 用户关窗**
|
||||
# ⇒ 排期**开不出主会话**:它开的会话恒是任务会话那一档(`is_background_automation=1`)。
|
||||
# 症状(mcn-aigc-ontology 2026-10-14 实测):
|
||||
# 07:31 建出 `[主]-super-i卡片采集-主会话`(`recurring` `FREQ=DAILY;BYHOUR=09`),
|
||||
# prompt 里写着「你是本工作区的主会话……要建 `[执行]` 排期拉起任务会话」
|
||||
# ⇒ 每天 09:00 开出一条**顶着主会话名头的任务会话** ⇒ 台账里主会话越积越多,
|
||||
# 而用户那边**根本没多窗口** ⇒ 用户报「机制自己创建了一个主会话」。
|
||||
# ⚠️ 与「旧前缀 `[主]`」区分:`[主]` 本身没作废(现役主会话可写成 `[主]-…` 或 `主控 · …`),
|
||||
# 本判据抓的是**它出现在排期名里**这件事,⛔ 不抓会话名。
|
||||
# ⚠️ 扫描面**必须含 `recurring` 与 `once` 两种**(当年就是只扫 `recurring` 才看不见机制建的 `once` 排期)。
|
||||
_mainlike = [a for a in _allmine
|
||||
if (a.get("name") or "").startswith("[主]")
|
||||
or "主会话" in (a.get("name") or "")]
|
||||
if _mainlike:
|
||||
_st = ["%s(%s)" % ((a["name"] or "")[:30], a.get("status") or "?") for a in _mainlike]
|
||||
# ACTIVE 才算真隐患;已 PAUSED 的留痕只提示
|
||||
_act = [a for a in _mainlike if (a.get("status") or "") == "ACTIVE"]
|
||||
if _act:
|
||||
rec("main_sched", "C", "fail",
|
||||
"排期顶着「主会话」的名字 ⇒ 主会话只能由用户开(2026-10-14 口径)",
|
||||
"本区 %d 条在 ACTIVE:%s" % (len(_act), "、".join(_st[:3])))
|
||||
else:
|
||||
rec("main_sched", "C", "warn",
|
||||
"排期曾顶着「主会话」的名字(现已非 ACTIVE,留痕非隐患)",
|
||||
"本区 %d 条:%s" % (len(_mainlike), "、".join(_st[:3])))
|
||||
else:
|
||||
rec("main_sched", "C", "ok", "本区没有「顶着主会话名字」的排期",
|
||||
"扫描面 %d 条(recurring + once 全含)" % len(_allmine))
|
||||
|
||||
# ⑩ 投递心跳
|
||||
hbs = [WS + "/.workbuddy/collab/logs/supervise-heartbeat.json",
|
||||
WS + "/.workbuddy/collab/supervise-heartbeat.json"]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
🔴🔴 2026-10-05 **为什么必须要有这个启动器**(本轮实测踩到的坑,P0-73):
|
||||
新形态(计划任务 → `pythonw.exe` → `collabd.py --supervise`)**直起**时,
|
||||
任务环境里**没有 `CODEBUDDY_CONFIG_DIR`** —— 旧看守 `start-supervise.ps1` 里那句
|
||||
`$env:CODEBUDDY_CONFIG_DIR = "E:\\ProgramData\\.workbuddy"`
|
||||
`$env:CODEBUDDY_CONFIG_DIR = "E:/ProgramData/.workbuddy"`
|
||||
在我改成两层形态时**被丢掉了** ⇒ 后果:
|
||||
· `_wb_db()` 落到 `~/.workbuddy/workbuddy.db`(**0 字节空库**)⇒
|
||||
· `_all_sessions_idle()` 每轮报 **`no such table: sessions`** ⇒ 闸② 恒判"有会话在跑"
|
||||
@@ -15,19 +15,86 @@
|
||||
🔴 用 `runpy.run_path`(⛔ 不用 `exec`):`runpy` 会把 `__name__`/`__file__`/`sys.path[0]`
|
||||
都按"真在跑那个脚本"设好 ⇒ `collabd.py` 顶部的 `_sm_load_roots()` 靠 `__file__` 找 `roots.env`
|
||||
与命令行分发(它自己读 `sys.argv`)全对。
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🔴🔴 2026-10-14 **宿主库路径须「相对/外置」,且必须两处兜底**(用户令:技能里的文件路径用相对路径)
|
||||
本文件**只允许**用 `HERE`(=自身所在目录)拼相对路径,⛔ 不写死任何本机盘符。
|
||||
宿主库路径按**下面三级**取,命中即止:
|
||||
|
||||
① 宿主 env `CODEBUDDY_CONFIG_DIR`(宿主进程给了就用它,⛔ 不覆盖);
|
||||
② 本区 `collabd.config.json` 的 `host_db`(单区兜底,**部署时由 init_workspace 按本机根目录生成**);
|
||||
③ 包内 `env/roots.env` 的 `CODEBUDDY_CONFIG_DIR`(本包全局单例,跨区共享)。
|
||||
|
||||
⛔⛔ **禁止回落 `os.path.expanduser("~/.workbuddy")`** —— 本机它是 **0 字节空库**
|
||||
(实测 `C:/Users/Administrator/.workbuddy/workbuddy.db` = 0 字节、零张表;真库在
|
||||
`E:/ProgramData/.workbuddy/workbuddy.db`,124 MB)⇒ 回落即 `no such table: sessions`
|
||||
⇒ 闸② 恒判"有会话在跑" ⇒ **检查会话再也不建**(2026-10-14 mcn-aigc-ontology 实测复现)。
|
||||
⚠️ 10-11 那版写 `expanduser("~/.workbuddy")` 的**动机是对的**(不写死盘符、跟着用户走),
|
||||
但**兜底选错了目录** —— 「不写死盘符」要靠**外置配置**实现,⛔ 不是靠猜 `~`。
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 🔴 启动器所在目录即本区 `.workbuddy/collab`(由 init_workspace 分发到各区)
|
||||
# 本文件内的所有路径一律以 `HERE` 为基准(相对),⛔ 无任何本机盘符字面量。
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
CB = os.path.join(HERE, "collabd.py")
|
||||
CFG = os.path.join(HERE, "collabd.config.json")
|
||||
|
||||
# 🔴 活动环境目录(宿主库所在)—— 这是**旧看守里有、新形态里被我漏掉**的那一条。
|
||||
# 🔴 2026-10-11:默认值改成 `~/.workbuddy` 形态(⛔ 不写死本机盘符)——
|
||||
# 跟着**当前用户**走;宿主 env 里已有的值优先(setdefault)。
|
||||
os.environ.setdefault("CODEBUDDY_CONFIG_DIR", os.path.expanduser("~/.workbuddy"))
|
||||
|
||||
def _resolve_config_dir() -> str:
|
||||
"""宿主库所在目录(`CODEBUDDY_CONFIG_DIR`)。三级取值,⛔ 不写死盘符、⛔ 不猜 `~`。"""
|
||||
# ① 宿主 env 已给 ⇒ 直接用,⛔ 不动
|
||||
given = (os.environ.get("CODEBUDDY_CONFIG_DIR") or "").strip()
|
||||
if given:
|
||||
return given
|
||||
|
||||
# ② 本区配置的 host_db(取它的父目录)
|
||||
try:
|
||||
with open(CFG, encoding="utf-8") as f:
|
||||
_host_db = (json.load(f).get("host_db") or "").strip()
|
||||
if _host_db:
|
||||
return os.path.dirname(os.path.normpath(_host_db))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ③ 包内 env/roots.env(HERE 往上找包根:collab → .workbuddy → 工作区根;再试技能包位置)
|
||||
for _up in range(1, 8):
|
||||
_pkg = os.path.dirname(HERE)
|
||||
for _ in range(_up - 1):
|
||||
_pkg = os.path.dirname(_pkg)
|
||||
_roots = os.path.join(_pkg, "env", "roots.env")
|
||||
if os.path.isfile(_roots):
|
||||
try:
|
||||
with open(_roots, encoding="utf-8", errors="replace") as f:
|
||||
for ln in f:
|
||||
ln = ln.strip()
|
||||
if ln.startswith("CODEBUDDY_CONFIG_DIR="):
|
||||
val = ln.split("=", 1)[1].strip()
|
||||
if val:
|
||||
return val
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
_cfgdir = _resolve_config_dir()
|
||||
if _cfgdir:
|
||||
os.environ["CODEBUDDY_CONFIG_DIR"] = _cfgdir
|
||||
else:
|
||||
# ⛔ 取不到 ⇒ 宁可留空让下游自己报错,⛔ 也不回落 `~/.workbuddy`(那是 0 字节空库)。
|
||||
try:
|
||||
sys.stderr.write(
|
||||
"[supervise-launch] ⚠️ 取不到 CODEBUDDY_CONFIG_DIR"
|
||||
"(宿主 env / 本区 host_db / 包内 roots.env 三处都空)"
|
||||
"⇒ 宿主库不可读,检查程序会静默失效\n"
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
os.environ["COLLABD_CONFIG"] = CFG
|
||||
os.environ["PYTHONIOENCODING"] = "utf-8"
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
|
||||
Reference in new issue
Block a user