承接 52566c7(技能仓):两个看板整包搬进 session-mechanism/boards/。
工作区侧不留第二份实现(同族 P0:一份规则两处实现 ⇒ 必然漂):
* project-board.py 38380B 完整实现 → 薄转发(解析技能根 → 设变量 → runpy 真身)
* project-board.html 54102B 真身页面 → 路标页(说明三处位置,⛔ 别再当源文件改)
* project-board-launch.py 上一轮已改薄转发
计划任务不用改:动作指向本目录 project-board-launch.py(薄转发会转到技能包真身)——
留这一层的目的就是路径稳定(技能升级/换机时只改一处)。
验收:
* python 交付物/项目管理界面/project-board.py --once ⇒ 4 个项目全列出(与技能包真身同读数)
* HTTP / 200 · 54102 字节(=技能包真身那份,证明确实是转发)· /api/projects 出数据 · /healthz ok
* 计划任务重起:pid 35080 → 23596
原件备份 ⇒ tmp/pm-board-bak-20261014/
34 KiB
2026-10-14 工作日志
主会话 · 排查「执行/检查会话批量操作不能归档、不能删除」(07:2x~07:4x)
用户提问:为什么会话机制创建的执行会话和检查会话,批量操作时不能归档也无法删除。
取证路径(全部只读,未改任何代码与数据):
- 只读打开宿主库
E:\ProgramData\.workbuddy\workbuddy.db,查sessions表结构与取值分布。 - 读出 asar 头部索引(13910 文件),自建
tmp/asar-extract.js/tmp/asar-grep.js做定点抽取与全量检索。 - 抽取并核实
main/conversations.js、main/handlers.js、main/server.js、renderer/assets/adapters-*.js、renderer/assets/DataManagementPanel-*.js、renderer/assets/ui-docs-viewer-*.js。
结论(产品层设计,非本项目机制缺陷):
- 产品没有会话的批量归档/批量删除接口 ——
archiveSessions/deleteSessions/batchArchive全量检索 0 命中。 - 归档可用性判据(
ui-docs-viewer):_n = e => !((e.status??'').toLowerCase()==='archived' || e.projectId || I4n(e, 空间))⇒archived/projectId非空 /I4n命中,三者任一即不可归档。I4n(e,t) = e.transport==='cloud' ? false : e.spaceType==='assistant' || M4n(e.cwd,t)。 - 归档只改
status,deleted_at保持NULL;而保留策略自动清理对已归档项是archivedSkipped += 1; continue⇒ 归档不会让会话消失,只移出默认列表。 - 「删除」在本地是软删(
SET deleted_at = ?,transport='local'),行仍留在sessions表 ⇒ 从库里看「像没删掉」。deleted_at = -1是另一套语义(云端索引WHERE deleted_at = -1表未删)。 DataManagementPanel的批量交互操作的是「归档列表项」,按kind分流;readonly项(origin为project/cloud)结构上不渲染操作按钮。
现场读数:sessions 412 行,deleted_at IS NOT NULL 319 行;
[执行]/[检查] 会话全部 is_background_automation=1 + transport='local'。
产出:tmp/会话批量归档删除-排查-20261014.md(完整证据链与可复现取证方法)。
未做(等拍板):机制层加「批量归档/清理已完结执行·检查会话」的动作 —— 属直接改宿主库,
须守活库改动铁律(停 app 或 backup() API,⛔ 禁文件级 cp)。
本机坑(再次命中):⛔ 别把 MSYS 路径(/e/…)交给 Windows 原生 node,会落到 E:\e\…;一律传 E:/…。
主会话 · 排查「mcn-aigc-ontology 为什么自己创建了一个主会话」(07:34~07:40)
用户提问:mcn-aigc-ontology 为什么这个工作区运行会话项目机制,自己创建了一个主会话。
现场读数(全部只读):
- 该区已装机制:
.workbuddy/collab/collabd.config.json在位,supervise.switch=on。 sessions表里该cwd只有 1 条会话:9e069caf「加载会话技能」,status=working,is_background_automation=None(不是机制建的),created_at07:12:14 —— 这条就是当前用户在用的主会话本身。- 该区
automations只有 2 条:473c13a3「[主]-super-i卡片采集-主会话」recurringFREQ=DAILY;BYHOUR=09;BYMINUTE=0cwds=["E:/ProgramData/AIProject/mcn-aigc-ontology"],created_at07:31:11,last_run_at=None(下次触发 09:00,从没跑过)。prompt 逐字:「你是本工作区的主会话……要推进就直接建[执行]排期拉起任务会话」。5e16f0de「[执行]-super-i卡片采集-全量抓取与落盘」once,scheduled_at=2026-10-14T07:35,created_at07:31:19。
- 常驻:
logs/supervise-heartbeat.json→pid=38624、started_h=07:30:37、round=25、argv0指向本区.workbuddy/collab/collabd.py(argv0 合规)。 - 🔴
logs/_collabd.log每 10 s 一条all_sessions_idle 读库失败 no such table: sessions—— 典型「启动器丢了CODEBUDDY_CONFIG_DIR」故障(读 0 字节空库 ⇒ 检查程序静默失效)。
结论:机制没有"自己创建主会话"。 真实发生了四件事,被误读成"机制自创主会话":
🔴🔴 2026-10-14 07:53 订正(用户点破):本行结论只对了一半,且说偏了。 用户原话:「那就更不对了,技能中没有任何创建主会话的机制,除非是创建接续会话」。 「机制运行中没有偷偷建主会话」这半句对;但技能文档里确实存在"排期创建主会话"这条路(写成了合法场景), 那才是真问题。⇒ 别照本行往下读,改看本文件末节《订正「技能里存在"创建主会话"这条路"》》。 (本行保留仅为留痕 —— 「过程 ≠ 成品」同理:错结论⛔ 不删,加状态块指向订正处。)
- 07:12 用户自己在该区开了一条会话(标题「加载会话技能」)= 本区真主会话。
- 07:30 该区常驻被拉起(
pid 38624),随即把这条 07:12 的主会话登记进 goal.json (日志逐字:登记主会话 9e069caf(创建目标时顺手登记))。 - 07:31 该会话(或同轮动作)新建了一条 recurring 排期
[主]-super-i卡片采集-主会话,cwds指本区、每天 09:00 触发 —— 这条排期到点会真的开出一条新的主会话类型会话。 - 同一分钟还建了一条
[执行]once 排期(07:35 触发)。
⇒ 「自己创建了一个主会话」的可见现象=排期台账里那条 [主]-…-主会话;
它尚未运行(last_run_at=None),不是已经多出来一个窗口。
风险(实测,未处置):
- 该 recurring 排期每天 09:00 会开一条新会话;若长此以往 ⇒ 每天多一条"主会话"⇒ 与用户实际在用的
9e069caf并存, 变成"一个工作区两个主会话"。技能口径:主会话由用户手动开,⛔ 不该由排期生产。 _collabd.log的no such table: sessions⇒ 该区检查程序(建检查会话那条腿)静默失效。 与该排期是否清理是两件独立的事。
本机机制层观察:排期 scheduled_at 给了毫秒级时间戳;rrule 为空串(once)。
主会话 · 修复 mcn-aigc-ontology 两项(07:35~07:45)
用户令:「两个问题都按照建议进行修复」⇒ 按倾向 A 执行。
修复一:撤掉每日主会话排期
[主]-super-i卡片采集-主会话(id473c13a3)已置PAUSED,next_run_at清空。- 用
automation_update改状态(⛔ 未用 rm/sqlite,符合机制铁律);零删除、可逆(改回 ACTIVE 即恢复)。 - 那条
[执行]-super-i卡片采集-全量抓取与落盘(5e16f0de)保持 ACTIVE,07:35:09 已正常触发建出执行会话c6226e12。
修复二:常驻读库故障(no such table: sessions)
- 真因(证据链):
supervise-launch.py的默认值在 10-11 被改成~/.workbuddy, 而本机C:\Users\Administrator\.workbuddy\workbuddy.db是 0 字节、零张表(实测); 真库在E:\ProgramData\.workbuddy\workbuddy.db(124 MB)。ai1net 区没炸是因为它 config 里host_db兜住了。 - 修法(双保险,与技能 P0-73 口径一致):
①
supervise-launch.py:默认值改回真库绝对路径E:\ProgramData\.workbuddy(setdefault语义保留,宿主 env 优先); ②collabd.config.json:补"host_db": "E:/ProgramData/.workbuddy/workbuddy.db"(本该有的单区兜底)。 - 改前备份:
supervise-launch.py.bak-configdir-20261014-073619、collabd.config.json.bak-hostdb-20261014-073619。 - 重启:计划任务
collabd-keepalive-mcn-aigc-ontology(pythonw.exe,合规)⇒ 旧pid 38624→ 新pid 28628。
验收(三条对齐,非恒绿):
- 启动器解析出的库 =
E:/ProgramData/.workbuddy/workbuddy.db,sessions413 行读通。 - 重启后日志:
all_sessions_idle:还有 1 条 working(c6226e12)⇒ 不算全结束—— 正常读到库, 本轮no such table0 条(重启前是每 20s 一条、连续 25+ 轮)。 - 变异对照:旧形态(
~/.workbuddy+ 无host_db)⇒ 复现no such table: sessions; 新形态 ⇒ 读通 413 行。⇒ 判据有效,不是恒绿。
遗留(技能/其他区层面,本轮未动):
- 🔴 技能源
E:\ProgramData\.workbuddy\skills\session-mechanism\scripts\supervise-launch.py第 30 行仍是os.environ.setdefault("CODEBUDDY_CONFIG_DIR", os.path.expanduser("~/.workbuddy"))⇒ 凡是照技能源部署的新区,都会命中同一个空库故障。本区已单区修好,技能源未动 = 待拍板。 - 各区部署副本形态不一(实测):
ai1net-dsh-server/contentm_agent/mcn-aigc-ontology(已修)= 写死E:\ProgramData\.workbuddy+ config 有host_db;aigc-idea-impression= 写死绝对路径但 config 无host_db(靠启动器那条腿活着,实测日志正常);vibe-product= 未部署启动器。 - 本机
~/.workbuddy/workbuddy.db那个 0 字节空文件仍在(无害,但会持续误导"以为~是活动环境")。
终态复核:写法定为与 contentm_agent 逐行一致(setdefault + 绝对路径),语法 OK、重启后 pid 38428、读库失败 0 条。
主会话 · 技能源相对化 + 四区统一部署(07:45~07:52)
用户令:「按照建议处理,技能中 文件路径 必须用相对路径」⇒ 该条推翻了上一轮"给各区写死绝对路径"的做法。
动因:上一轮为救 mcn 区把技能源里的 ~/.workbuddy 换成写死绝对路径 —— 这本身是把「一台机器的环境」焊进技能,
与既有的 collabctl.py::_resolve_airoot() 口径(⛔ 不在代码里写死盘符/目录)冲突。用户第四条指令正是纠这个。
改法:HERE 相对基准 + 三级外置取值 + ⛔ 禁回落 ~
HERE = os.path.dirname(os.path.abspath(__file__)) # 全部路径以 HERE 为基准(相对)
CB = <HERE 推导出的 collabd.py>;CFG = <HERE 推导出的 collabd.config.json>
_resolve_config_dir() 三级:
① os.environ["CODEBUDDY_CONFIG_DIR"] —— 宿主 env 已给 ⇒ 直接用,⛔ 不动
② 本区 collabd.config.json 的 host_db —— 取其父目录
③ 包内 env/roots.env 的 CODEBUDDY_CONFIG_DIR —— 向上最多 7 层找 env/roots.env
三级全空 ⇒ 置空 + stderr 告警,⛔ 绝不回落 ~/.workbuddy(那是 0 字节空库)
- 三级取值均外置(宿主 env/本区配置/包内 env),代码内零绝对路径。
- 保留
setdefault语义的反面:宿主 env 优先级最高(命中①时原样不动)。 - docstring 里示例路径改写为正斜杠(
E:/ProgramData/.workbuddy)—— 顺带解掉\Uunicodeescape 报错。 - 新增
import json。
验证(探针,非纸面):造临时区跑探针 ⇒
① 宿主 env 命中(D:/fake/host/env,原样采用);
② 无宿主 env 但有 host_db ⇒ 解析出 E:\ProgramData\.workbuddy;
③ 三者皆无 ⇒ CODEBUDDY_CONFIG_DIR 为 None 并打出告警(fail-safe 方向正确:宁可报错也不静默读空库)。
分发与终态:
deploy_code.py --ws <区>分发四区,自动备份旧副本 ⇒ 四区supervise-launch.pymd5 统一bfa03b2f。aigc-idea-impression补"host_db": "E:/ProgramData/.workbuddy/workbuddy.db"(JSON 校验通过)—— 这是四级兜底里它原本缺的一环。- 技能包
env/roots.env第 9 行已含CODEBUDDY_CONFIG_DIR=E:/ProgramData/.workbuddy⇒ 第③级在位,无需补。
四区常驻重启终验:
ai1net-dsh-server 旧 20680 → 37280 07:50:41 ✅ 读库正常
mcn-aigc-ontology 旧 38428 → 4728 07:50:46 ✅ 读库正常
aigc-idea-impression 旧 29364 → 20304 07:50:52 ✅ 读库正常
contentm_agent 旧 27092 → 29400 07:50:58 ✅ 读库正常
日志实证:all_sessions_idle:还有 1 条 working(f920d73e)⇒ 不算全结束 / no such table 共 0 条
🔴 必须记住的一条口径:技能源改动只影响将来部署的新区;已在跑的四区是靠部署副本 + 重启生效的。
⇒ 以后改技能源,动作永远是「改源 → deploy_code.py 分发 → 重启常驻 → 验心跳 started_h 晚于部署时间」,三步缺一即未生效。
遗留:~/.workbuddy/workbuddy.db(0 字节)仍在,无害但会持续误导;vibe-product 未部署启动器。
沉淀(跨区通用,供后续同类问题直接引用)
- 🔴 读写宿主库的脚本,路径一律「外置 + 相对基准」:代码里只认
CODEBUDDY_CONFIG_DIR/本区host_db/包内env/roots.env, ⛔ 不写死盘符、⛔ 不猜~。判据:把区整个搬到另一台机器仍能跑通 ⇒ 合格。 - 🔴 绝对路径修复是「治好了但焊死了」:同一症状下次换机器/换盘符必复发 ⇒ 只能作应急,须在同轮内补上相对/外置改造。
- 🔴
~/.workbuddy在本机是空壳(0 字节库),凡代码里出现expanduser("~/.workbuddy")一律视为高危默认值。
主会话 · 订正「技能里存在"创建主会话"这条路」(07:53~08:00)
用户订正原话:「那就更不对了,技能中没有任何创建主会话的机制,除非是创建接续会话」。 ⇒ 我上轮把那条排期说成"多出来的主会话(只是还没跑)",说岔了 —— 用户的点不在"它跑没跑", 而在技能里根本就不该有"排期创建主会话"这条路。核实结论:用户判断正确,技能里确实有这么一条(错的)路。
病灶(四处,同源):supervise-persistence.md 早期把「定时任务创建主会话」与「用户手动创建主会话」
并列成两种合法场景,SKILL.md §⑥ 顺着抄了一遍 ⇒ 读到的人(或 AI)会理解成"这条路是允许的",于是照做。
事故链条(mcn-aigc-ontology,全部实测):
- 07:12 用户手动开
9e069caf「加载会话技能」= 该区真主会话(is_background_automation=None)。 - 07:30
init_workspace.py装机制(goal.json的lifecycle_why逐字「init_workspace.py 新建」), 常驻拉起并顺手登记主会话(日志逐字「登记主会话 9e069caf(创建目标时顺手登记)」)。 - 07:31:11 建出
recurring排期[主]-super-i卡片采集-主会话(FREQ=DAILY;BYHOUR=09;BYMINUTE=0), prompt 逐字:「你是本工作区(…)的主会话,只负责目标与方向,不亲自干活。……职责:判断与派活 (要推进就直接建[执行]排期拉起任务会话)」 ⇒ 这是"主会话"的口径,被套到了一条排期身上 —— 排期开出来的会话恒是任务会话那一档。 - ⇒ 每天 09:00 会开出一条顶着主会话名头的任务会话;长期跑 ⇒ 台账里"主会话"越积越多,用户那边没多窗口。
权威口径(技能里本来就有,只是被上述那处盖住了):SKILL.md《三类会话》类别表逐字
——「主会话 | 用户手动开 | 管目标与方向、派活 | 用户关窗」;
architecture.md §1 同款;排期只服务派活线([执行]-…)与检查线([检查]-…)。
「接续会话」是主会话撞阈值时由它自己建出来的形态(角色继承),⛔ 不是第三条建主会话的路。
修复(三件,已全部落地并验收):
① 改文档(4 处):
references/supervise-persistence.md §〇:表格从"场景 A/场景 B 两列"改成只有一列(「用户手动打开主会话」), 并新增《为什么⛔ 不能"用排期拉起主会话"》小节 —— 含事故回放 + 明确写「本档早期表格是病灶,2026-10-14 已改掉」。- 同档 §八 对照表:删掉「B · 定时任务创建主会话」那一行,只留有价值的读数(
once过期即哑)。 SKILL.md §⑥:那句「用户手动创建主会话 / 定时任务创建主会话」改成 「形态只有一种:主会话由用户手动开 —— ⛔ 排期拉不出主会话」。references/architecture.md §1:新增 🔴🔴 段《主会话怎么来:只能由用户手动开》,含判据指针。
② 加判据(第 ⑬ 条,session-rules-check.py):
- 扫本区排期,命中
name以[主]开头或含"主会话" ⇒fail(还在 ACTIVE)/warn(已非 ACTIVE 的留痕)/否则ok。 - ⚠️ 扫描面 recurring 与 once 都含(当年 ⑧ 只扫 recurring 才看不见机制建的 once 排期,同类坑)。
- 变异对照(证明非恒绿):喂 mcn 区真数据三种输入 —— 原样 PAUSED ⇒
warn;伪造成 ACTIVE ⇒fail; 无此类排期的区 ⇒ok。三档全判得出。夹具tmp/probe-main-sched-judge.py。 SKILL.md §体检清单从「查三类、十二项」改成「十三项」;变异对照记录补上 ⑬ 那行。
③ 分发与验收:
deploy_code.py分发四区,session-rules-check.pymd5 统一4b53c88d(技能源同值)。- mcn 区用部署副本真跑 ⇒ 第 ⑬ 条按预期报
warn(那排期现为 PAUSED)。 - 顺带抓出另一条真隐患:那条排期
model_id=deepseek-v4.1-flash+model_is_thinking=0⇒ 每次触发必被服务端拒(判据 ⑧ 报fail)。⚠️ 该排期现已 PAUSED ⇒ 不触发,但若哪天改回 ACTIVE 必须同时改模型。
沉淀(本机口径):
- 🔴 主会话只能由用户手动开。排期开出来的会话恒是任务会话那一档(
is_background_automation=1); 名字里带[主]/"主会话"不改变它的档位。判据=排期名,见第 ⑬ 条。 - 🔴 技能文档里"并列两种合法场景"的写法极危险 —— 它会把一条本该唯一的路读成"二选一"。 ⇒ 写"形态"类内容一律单列;要留旧形态只作事故回放/留痕,并明确写"⛔ 别照做"。
主会话 · 三项拍板执行(09:46~09:55)
用户令(逐字):「1、A / 2、确认调整无误 就更新 / 3、不需要就删除,避免创建无效文件」。
① 排期保持 PAUSED(候选 A)
- mcn 区
[主]-super-i卡片采集-主会话保持 PAUSED 不动(next_run_at=None⇒ 不触发;零风险、可逆)。 - 终态复核:该区 4 条排期 ——
[主]-…PAUSED|[执行]-…第2棒ACTIVE(next_run_at已排)|[检查]-第1棒ACTIVE|[执行]-…全量抓取与落盘(首棒)已跑完。链路正常。
② 核实无误后更新(推送技能总仓)
- 入库前必查三件(全部通过):白名单核对
git ls-tree -d= 7 个技能目录、与.gitignore放行条逐条对上; 凭据扫描(password/token/secret/api_key/PRIVATE/x-access-token/ghp_/sk-)零命中;两个 py 语法编译通过。 - 错口径清零复核:
SKILL.md/architecture.md里「定时任务创建主会话」「场景 B」零命中;supervise-persistence.md剩 4 处全是事故回放/留痕(明写「⛔ 别照做」)。 - 编号冲突复核:体检清单 ⑬ 唯一;
pitfalls.md里那套 ⑦~⑬ 是t_srsm_busy夹具的独立编号,不冲突。 - 提交:
053a6a6「session-mechanism:主会话只能由用户开(撤掉"排期建主会话"那条路)」,5 files / +180 / -26。 - 推送:
[email protected]:admin/workbuddy_skills.git⇒20eacef..053a6a6 master -> master(成功)。 - 终验:本地 HEAD = 远端
origin/master=053a6a67231fe39bc6fcbcfe983d8ab5b6438196;git status干净。
③ 删除 0 字节空壳库(避免误导)
- 清单:
C:\Users\Administrator\.workbuddy\workbuddy.db—— 0 字节、2026-10-03 00:06 建、零张表、无 WAL/SHM 伴生 (该目录其余MEMORY.md/device-id/logs/observe/pending-telemetry一律不动)。 - 做法:送回收站(
SHFileOperationW+FOF_ALLOWUNDO,⛔ 不直删)。 - ⚠️ 删前加了一道自检:脚本先查大小,非 0 字节就拒绝执行(防误删真库)。
- 结果:
rc=2(SHFileOperation的"部分成功"语义),原位已不存在。 - 影响面复核:真库
E:\ProgramData\.workbuddy\workbuddy.db在位(sessions416 行/automations341 行); 四区常驻读库正常 ——no such table最后一次出现分别是 10-05 12:14(ai1net)与 今天 07:37(mcn), 均为重启前历史行,aigc/contentm 为 0 条。本轮删除未造成任何新故障。
临时文件清理(用户令「避免创建无效文件」)
- 送回收站:
who-created-main-sched.py/main-sched-prompt.py/trash-empty-db.py/cleanup-20261014.py(清理脚本自身也一并送走)。 - 保留 1 个:
tmp/probe-main-sched-judge.py—— 技能文档已把它登记为判据 ⑬ 的变异对照夹具, 删了以后 ⑬ 的红绿对照就没法复现(技能纪律:夹具"跑完即弃"指不占常驻位置,⛔ 不等于删掉证据)。
主会话 · 核实「行尾符与同源冲突」接手单(11:09~11:20)
来件:C:\Users\Administrator\Desktop\workbuddy_skills-行尾符与同源冲突-交仓库会话.md
(另一个环境留下的接手单;用户令「确认是否有相关问题」⇒ 只要核实结论,⛔ 不动手改)。
⚠️ 来件与实际不符的一处(先说清):单子写本机仓是 D:\.workbuddy\skills,
实际该路径不存在;D 盘那个仓在 D:/github/_alotbuy-gitea/workbuddy_skills(remote 指向 work.alotbuy.com,与本机用的不是同一个 origin)。
更要紧的是:单子称该仓「本地领先远端 2 个提交」1774693 / 886d99a —— 这两笔提交在 D 盘仓里不存在
(git cat-file 报 Not a valid object name),且该仓 origin/master..HEAD 与 HEAD..origin/master 双向为空(既不领先也不落后)。
⇒ 单子里第三条("有 2 笔提交停在本地待同步")在本机无法证实,⛔ 不作为待办。
核实结论:三条里第一、二条属实,且第一条比单子描述更严重。
① 行尾符 —— 属实,实测读数(仓 E:/ProgramData/.workbuddy/skills):
.gitattributes不存在;core.autocrlf = true;.gitattributes属性列 ���仓为空(零覆盖)。- 全仓入库形态统计:
i/lf4576 /i/crlf244 /i/-text28 /i/none5 /i/mixed1。 - CRLF 244 个的分布:
product-planning/references/占 237 个(冲突重灾区),session-mechanism/scripts5 个、session-mechanism/references1 个、product-planning/SKILL.md1 个。 - 🔴 单子没提到的一个更糟样本:
product-planning/references/stage-requirements/references/create-prd.md是i/lf+w/crlf(入库 LF、工作副本 CRLF)⇒ 这正是"本地一改就整文件 diff / 合并整块冲突"的最典型形态。 - 另两处同批读数:
stage-delivery/SKILL.md=i/crlf w/crlf;stage-discovery/.../grill-me.md=i/lf w/lf。 - 本机当前无受害症状:
git status干净(0 行)、无冲突标记残留 ⇒ 隐患在位、尚未发作。 - ⚠️ 我自己上一笔提交
053a6a6的 5 个文件全部i/lf w/lf,不受影响。
② session-mechanism/SKILL.md frontmatter —— 属实:
- 实况:第 6 行
last_change: 2026-10-05 10:5x · 🔴🔴 …是一行超长标量, 其后12 行以·开头且无缩进 ⇒ 顶层出现无键的行,不是合法 YAML(单子描述准确)。 - 同文件其它字段(
name/description/version/updated_at)写法正常,确属孤例。
③ 同源冲突(两份各写一版)—— 本机无异常:
- 单子列的 4 个冲突文件路径写少了一层(实际都在二级
references/下):stage-delivery/SKILL.md、stage-delivery/references/execution-runbook.md、stage-discovery/references/grill-me.md、stage-requirements/references/create-prd.md。 - 本机仓里这 4 个文件无未提交改动、无冲突标记(
grep '^<<<<<<<'零命中)⇒ 当前是合好的状态。 - 单子那句"动手前先
git fetch、同一件事只在一处定稿"是作业纪律,本机已在守(本轮推送前就跑了git fetch)。
待办(⛔ 本轮未动,属另一个仓/需出方案):见本轮回复末尾的待拍板项。
主会话 · 执行「行尾符 + frontmatter」三项修复并推送(11:22~11:40)
用户令:「修改完成后 检查无误 推到技能仓库」⇒ 按上一轮三项的倾向 A 全做。
① .gitattributes(新文件,仓根)
- 内容:默认
* text=auto eol=lf,再对文本类逐类显式声明(md/py/sh/json/css/html/js/mjs/yml/yaml 等);.bat/.cmd保留 CRLF(Windows 批处理对 LF 敏感);图片/字体/压缩包/音视频/数据库一律binary。 - 🔴
.gitignore同步放行!/.gitattributes—— 本仓是「先/*全挡再逐个放行」的白名单模式, 不放行 ⇒ 这个文件根本进不了库;而它跟.gitignore同属仓级规则,必须入库, 否则别的机器取仓后仍按各自core.autocrlf各行其是。 - 提交
cf0ec41(2 files, +68)。
② 本机 core.autocrlf 设 false(立刻止血)
true→false(仓级配置,只影响本仓)。- 验:
git ls-files --eol的attr列从空变成attr/text eol=lf⇒ 属性真的生效了(⛔ 不是只写了文件)。
③ --renormalize 重新规范化(单独一笔)
- 实跑改动 245 个文件:
product-planning239 /session-mechanism6。 - 🔴 关键验收:纯行尾符,零内容改动 ——
git diff --cached --numstat --ignore-cr-at-eol输出为空; 且insertions 44412 / deletions 44412完全对称(行尾符转换的数学特征)。 - 复核没碰二进制与资源(
grep -E '\.(png|jpg|ttf|woff2?|zip|gz)$'零命中)。 - 提交
9e779c4。单独一笔的理由:把「改规则」与「按规则刷数据」分开, 将来撞车时可直接回退这一笔而不牵连.gitattributes。 - 行尾符终态:
i/crlf244 → 0;i/lf4822;剩i/-text28(二进制)+i/none5。
④ session-mechanism/SKILL.md frontmatter 合法化(内容一字不动)
- 原形态:
last_change:一行超长标量 + 其后 12 行以·开头无缩进 ⇒ 顶层无键行 12 处。 - 🔴 顺带发现接手单没提的第二处:
agent_created:前面还夹着一行游离的· **本包自身**:install.py …—— 同样是顶层无键行(改前共 12 处,接手单只指出了前 11 行)。 - 改法:块标量
last_change: |-+ 续行统一两格缩进(含那行游离内容)。 - 验收四条(改前 vs 改后逐字比对):
① 顶层无键行 12 → 0;②
last_change正文 12 行逐字一致; ③ 正文(第二个---之后)逐字一致;④ PyYAML 解析通过, 字段=name/description/version/updated_at/last_change/agent_created,last_change3358 字符 / 36 行。 - 提交
5d16c6d(1 file, +14/-13)。 - ⚠️ 验证脚本第一版有 bug(
split("|-")[1]把首段读成空串)⇒ 一度误报"内容不守恒"; 修掉解析后复验才通过。教训:验证脚本自身也要先自证,否则会把"改动正确"误判成"改坏了"。
⑤ 推送与终验
git push origin master⇒d9445b5..5d16c6d(成功)。- 终验:本地 HEAD =
origin/master=5d16c6df706f63543073ff63c50889dd99c55c81;三笔提交在远端齐全;工作区干净。
沉淀(跨项目可用):
- 🔴 白名单
.gitignore模式下,新加仓级文件(如.gitattributes)必须同步放行 —— 否则"写了但没入库", 而且git status里它显示为??(未跟踪),很容易被误读成"已经生效了"。 - 🔴 行尾符规范化的验收判据 =
--ignore-cr-at-eol后零差异 + 增删行数对称。 只看文件数会误判(246 个文件听着很吓人,实际一个字都没改)。 - 🔴 验证脚本要先自证:解析器有 bug 时会产出"看起来很严重"的假红(本轮就撞了一次)。
两个看板整包搬进会话技能 boards/(用户令「1 boards 2 A」)
用户原话:「把这两个看板都纳入会话技能中 ,分两个看板文件夹 放在assert中(判断是否应该放在这里)」 →「1 肯定是整包啊 2 就两个看板 对应两个文件夹」→「但是当前情况 是两个看板最好代码和页面放一起, 要不单独开个 workshop 文件夹 放两个看板」→「这里面有html代码适合放到 scripts中吗」→「1 boards 2 A」。
拍板结果:文件夹名 boards(⛔ 不是 workshop);A = 本区部署与计划任务本轮一起改。
新增第三层分层(判据,已写进 SKILL.md):
scripts/= 可执行程序(被计划任务/hook 调)|assets/= 静态素材(样式、模板)- 🔴
boards/= 自带页面的看板程序(一个看板一个文件夹,页面 + 脚本同处一包) - ⛔ HTML 不进
scripts/:那层是可执行程序层(现有全是.py),session-rules-check.py/install.py会按脚本扫(语法检查、副本比对)⇒ HTML 进去会被误判。
搬了什么:
boards/会话看板/(6 文件):board.py(150141B)/board_ext.py/board-launch.py/board-launch.py.tpl/board.html(151811B)/board-render-probe.js(端口 20099)boards/项目管理界面/(3 文件):project-board.py/project-board.html(54102B)/project-board-launch.py(端口 20100)
🔴 搬迁带出的真缺陷(最重要的一条):
board.py 里 importlib 按 Path(__file__).parent / "collabd.py" 取判据 ——
「与 collabd.py 同目录」这个前提搬走后不成立 ⇒ 静默落到 except 分支里本地抄的那份判据。
危害:判据可能漂(同族"共用同一实现"当场 FAIL),但看板照跑、肉眼完全看不出来。
修法:候选表(同目录 → 包内 scripts/ → DSH_SKILL_ROOT/scripts/)+ 兜底分支
写 stderr 留痕(⛔ 不许静默降级)。CFG_P 同病同治(对齐 collabd.py::load_cfg() 查找顺序)。
selftest.py 的三处假设修正(都源于"一个路径指两处"):
t_scope_parity的子进程代码用一个H同时指 board.py 与 collabd.py ⇒ 拆成H/B两参数selftest.py里HERE / "board.py"27 处 ⇒board_py()(带旧位置兜底)HERE.parent / "assets" / "board.html"15 处 ⇒BOARD_DIR / "board.html"
顺带修一条既有 FAIL(与搬迁无关):判据锚点没跟文档改 ——
supervise-persistence.md 的措辞在 053a6a6 已改成「排期按点拉起主会话这条路不存在」,
判据仍锚旧句「排期代替不了载体」(那句现在只在 SKILL.md 里)⇒ 恒红。
验收读数:
--filter 看板:PASS 110 / FAIL 0(另 1 条报告型不计入)。迭代轨迹 92/18 → 104/6 → 105/5 → 109/1 → 110/0。- 全量:PASS 91 / FAIL 1(同一条报告型「产物落点」,实质 FAIL 0)。
⚠️ 「合计」行缺失的真因=
safe-delete安全闸在收尾时拦了 64 个清理目标(> 阈值 50) ⇒ 本机工具层策略,⛔ 与技能无关。 - 会话看板
board.py --out⇒ 50515 字节快照,无「回落本地判据」告警(证明真从 collabd.py 取)。 - 项目管理界面
--once⇒ 4 个项目全列出;HTTP/200 · 54102 字节 (=技能包真身那份 ⇒ 证明工作区侧确实是转发);/api/projects出数据;/healthzok。
工作区侧改成薄转发(⛔ 不留第二份实现):
交付物/项目管理界面/project-board.py:改成薄转发(原 38380B 完整实现 → 转发壳)交付物/项目管理界面/project-board.html:改成路标页(54KB 真身 → 说明指向)交付物/项目管理界面/project-board-launch.py:上一轮已改薄转发- 原件备份 ⇒
tmp/pm-board-bak-20261014/ - 🔴 计划任务不用改:动作指向工作区启动器(薄转发会转到技能包真身)⇒ 稳定路径正是留这一层的目的。
重起后 pid 35080 → 23596,命令行仍是
pythonw.exe ".../project-board-launch.py"。
入库:提交 52566c7(9 新文件 + 3 改名 + 6 修改),推送 5d16c6d..52566c7 成功。
- 🔴
.gitignore无需放行boards/—— 白名单放的是整包!/session-mechanism/,包内新增目录自动被包含。 - 凭据扫描:
token命中全是文案里的普通词(「0 token」「SyntaxError: Unexpected token」),无真凭据。 - 行尾符:
git ls-files --eol全部i/lf w/lf attr/text eol=lf✅。
沉淀(跨项目可用):
- 🔴 搬家会静默破坏"同目录"隐式前提 —— 这类 import 都有
except兜底, 于是行为看着正常、判据却已漂。判据=「搬迁后必须有一条用例专门验『真的从模块取、不是本地抄』」; 正解 = 兜底分支必须留痕(⛔ 宁可见地坏,不可静默降级)。 - 🔴 一个路径常量指两处 = 下一次搬家的地雷。判据:凡
HERE / "x.py"里HERE是"包根/脚本目录" 这类位置代称,就该问一句"另一个文件搬家时它还成立吗"。 - 🔴 判据锚点必须逐字抄原文(本轮第三次栽):文档改措辞后判据恒红, ⛔ 别把"判据红"直接读成"实现坏了"——先问"是不是锚点过期了"。