回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复: - 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录) - tmp/(32.4 M,按接续棒命名的过程临时区) - .workbuddy/tmp/(39.5 M) - 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物) - tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留 入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与 接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、 .workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。 排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、 打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
47 KiB
工作日志 · 2026-09(第 13 片)
⚠️ 本目录日志已按【月】分片(2026-09-15 用户定,单文件 ≤50 KB):同月续片
2026-09.md/2026-09-下.md/2026-09-下2.md/2026-09-下3.md/2026-09-下4.md/2026-09-下5.md/2026-09-下6.md/2026-09-下7.md/2026-09-下8.md/2026-09-下9.md/2026-09-下10.md/2026-09-下11.md/2026-09-下12.md/2026-09-下13.md/2026-09-下14.md/2026-09-下15.md/2026-09-下16.md/2026-09-下17.md/2026-09-下18.md/2026-09-下19.md/2026-09-下20.md/2026-09-下21.md/2026-09-下22.md/2026-09-下23.md写入约定:一律 append 到当月最后一片;该片超 50 KB ⇒ 新建2026-09-下N.md;⛔ 不要再按日新建2026-09-DD.md。 覆盖来源:2026-09-13.md 上一片:2026-09-下11.md下一片:2026-09-下13.md
08:20–08:45 会话 3c12a818(锁名 浮层排障-0822):我 08:15 的改动把注入脚本写崩了 → 热修 + 触发面补全 + 固化校验
用户报障:「admin 主页面断开连接,但没显示『工作区已休眠正在唤醒』浮层,模型一直显示连接异常」。
一、根因(我引入的)
- 08:15 浮层视觉升级时写了
st.textContent = [...].join('\n');—— 该代码在 TS 模板字面量SESSION_RECOVERY_JS内部,\n在模板求值时变成真换行 ⇒ 注入浏览器的 JS 直接 SyntaxError ⇒ 整段注入脚本不执行 ⇒ 浮层 / 自检 / 自愈全废,页面只剩 dsh 自己的「连接异常」。 - 为什么之前的校验没拦住:只做「从
lib/抽原始文本 →new Function()」——跳过模板求值,所以是假绿。
二、顺带挖出的第二个(更早、更严重)
- 同文件的
SESSION_ASSIST_JS(档案 56「我的文件 / 能力」助手)8 处'\n'同样是单反斜杠 ⇒ 从来没在浏览器里执行过。 此前验收只 grep 页面 HTML 有没有__dshAssist字样 —— 验的是"文本在不在",不是"脚本跑不跑"(同一假绿模式)。
三、修复与固化
- 我引入的那处 →
.join(String.fromCharCode(10)); - 助手脚本 8 处 → 补成
\\n(只补未转义的); - ⛔ 新增
scripts/verify-inject.cjs并接入npm test:先模板求值成运行时字符串 →node --check, 并断言运行时串无反引号 /${。⇒ 这类假绿再也不可能溜过npm test。
四、触发面补全("页面没反应"的另一半,实测证明)
- 实测:用户一直盯着页面 + 连接悄悄断 → 原设计一个事件都不会来(只有切标签/focus/pageshow 才探活)⇒ 既不提示也不恢复。
- 补两条静默触发面:① 页面可见时每 25 s 心跳;② 包装
EventSource/WebSocket的error/close。 两者走新 soft 模式:连续两次失败才恢复(恢复=原地location.replace,会丢未保存输入,一次抖动不该触发)。 - ⚠️ 推翻了档案 77 §五 方案 B「不做周期性探活」(原前提"用户在场却不操作没有收益"被现场证伪)。
五、验收(真 Chrome + 临时会话,只读)
| 项 | 结果 |
|---|---|
| 修复后基线 | ✅ __dshRecover=true、__dshAssist=true、语法类错误 0(助手脚本首次真正运行) |
| 事件路径回归 | ✅ pageshow(persisted) → 浮层出现、class=__dsh-ov、新视觉节点齐 |
| 无操作自动恢复 | ✅ 只打挂实例侧探针、不派发任何事件 → 47.4 s 后浮层自动出现(两次心跳判定),0 页面错误 |
npm test |
✅ 45 pass / 0 fail / 1 skipped + 新增注入脚本校验双通过 |
| 部署 | ✅ 两轮热修 PID 415625→416910→417427;备份 …bak-before-hotfix-0825 / …bak-before-triggers-0835 |
六、文档 / 技能 / 锁
- 档案 77 追加「现场故障 + 热修 + 触发面扩展」;档案 56 追加「修正」节(其注入脚本一直没跑起来,原验收结论需重判);INDEX 04-77 行补记;四件套 rc=0;对账 一致 130。
dsh-change-workflow技能 v2.8.0 → v2.9.0:① 纠正三行过期规则(原文写"服务器是文档唯一源 / 禁止本地改 /docs-sync-check.sh已删"——与现行协议相反)② 新增「注入脚本两条铁律 + 两条浏览器验证路径(playwright-core 独立无头 vs browser-harness 附着用户 Chrome)」。两副本 md5 一致 + scp。- 双锁已释放(op-lock 释放需带
ME=<原占用者>)。
08:41 清点「还有哪些待执行」(只读取数,未写库)
- 读的单一来源:
交接单/README.md §一(已规划待执行)+03-路线图 §二 进行中/待办+ 各档案挂起清单。 - 顺手核销一个挂起项:档案 59 的「
wake.html本机 4708B vs 服务器 4591B 待核对同步」→ 实测双端一致 (本机/服务器均 4962 字节、md5 同为00b81728…;变大是因为档案 78 今天给 wake.html 加了熔断文案)⇒ 该挂起项可关闭 (待持锁会话释放后回填03-路线图)。 - 当前持锁者:
t03-ledger-0841(08:42 起持全局执行锁,在做 T03 台账)⇒ 本会话此刻只能读、不能写文档库。 - 结论清单(见当日回复):待执行 = T01(待认领)|T03 剩 guest 启用(用户动作)+ 验收归档|档案 76 的 400(P1 待查)| 档案内挂起(57 四项 / 66 两项 / 68 / 42 / 38b / 15 / 32)|P3 门户浏览文件加下载入口|触发式(dsh 升级回归 / 会话 GC)| 我自己待补 = 档案 78 L1 熔断实测(要窗口)· 档案 56 面板真机验收(原验收是假绿)· 档案 76 的 400 复现 · 自动化「遗留项自动推进」重建(待授权)。
08:41–08:5x 会话 48a9c14c:盘点「还有哪些方案待执行」+ 线上只读核对(账实相符)
一、★新取证:实例数据根与 profile 的真实路径(此前只知"有 profile",不知确切位置)
- 实例数据根 =
/var/lib/dshs/users/<user-uuid>/—— ⚠️ 不是/opt/dsh/users/(后者只有平台账号main;/opt/dsh/users/main/.dsh/profiles/web/是平台账号级 profile,其 bundles 只有 dsh-base + dsh-web-app,别拿它当实例的)。 - 实例 profile =
<数据根>/home/profiles/web/package.json,看dsh.profile.bundles数组 = 该实例实际加载的插件清单。 - 当前两个实例:admin uid 114801 =
cce6d1cd-b376-4304-80f0-0e1c58c9ffde;guest uid 100002 =4092b965-2f68-4977-9989-68b3966f7df0(另存在 uid 100003 / 100004 / 196490 的账号,未起实例)。 - 候选池目录 =
/var/lib/dshs/business-plugins/(09-13 00:02 更新);平台 DB =/var/lib/dshs/dshs.db。 - 实例进程命令行(从 scope 可见):
setpriv --reuid <uid> … dsh --profile web --host 127.0.0.1 --port <N>,并 ro-bind 了home/profiles/web/{cordis.patch.yml,package.json,pnpm-lock.yaml}⇒ 这三份是实例侧真相源。
二、T03 实测(08:4x):admin 已启用、guest 未启用 —— 与文档记载一致
| 实例 | bundles 末项 |
mcn-suite |
|---|---|---|
| admin | …@dsh-local/workspace-scoped-picker, dsh-plugin-mcn-suite |
✅ 已在 bundles |
| guest | …@dsh-local/workspace-scoped-picker, dsh-univer-office(0.2.15) |
❌ 未含 |
⇒ T03 只差「用户在 guest 实例「功能管理」里启用」这一步(用户动作,平台不代劳)→ 再重启实例 → 跑 §八验收 → 归档。
三、待执行清单现状(三处单一来源已对齐)
- 交接单 §一:
T01(⏳ 待执行,决策点 1 已定 = A 扩展business-plugins)|T03(🔄 进行中,见上) 03-路线图 §二:档案 76(P1 待查 =/univer-api/state持续 400,需取响应体)|档案 78 遗留 L1(故意反复搞崩验熔断,需维护窗口)|档案 27(暂缓)|档案内挂起一批(57 四项 / 59 wake.html 字节差 / 66 三项 / 68 / 38b 三项 / 15 / 32)|P3 门户「浏览文件」下载入口|触发式(dsh 升级回归 / 会话 GC)- 已消解或明确不做(免得重复问):档案 65 部署 ✅(本就生效)|档案 78 部署 ✅(08:02)|AnySearch ✅ 放弃|T05 ✅|
@liustack/modlens✅ 已无残留|Cookie 域收窄 ❌ 不做|管理类插件化 ❌ 不做|白名单源码安装 ✅ 关闭
四、只读核对附带发现(只报告,未动)
- 文档库 33 项未提交(末次 commit
da9d1ff,09-12 17:45)—— 期间所有改动都在工作树里。 - 服务器 op-lock 空闲(仅 README);
dshsactive;两个实例 scope 均 running;平台 DB 08:30 有写入。
08:41–09:05 会话 a2665dd3(锁名 t03-ledger-0841 → fix79-0851):待办盘点 + 档案 79 落档与代码修复(已 build,待重启生效)
一、本轮做掉的(全部已 scp 到 /opt/dsh/docs,档案 600 / README 644)
| # | 动作 |
|---|---|
| 1 | 04-67 文末追加 v0.2.7 / v0.2.8 段(内存预估 + 页内弹窗,含触发原话、口径、部署与线上自证) |
| 2 | 新建 04-79「插件启停的两处平台缺陷」:现象链(journalctl)→ D1/D2/D3 → 连带后果(半应用态)→ 修法已备 → R8 影响 |
| 3 | INDEX.md 登记 04-79(🔴)|03-路线图 §二 加 🔴 P0 待修 行 |
| 4 | 交接单/README §一 T03 行:补「07:4x 启用失败 → 已手工回滚 profile → 实例恢复」+「前置 = 先修档案 79 + 解决堆容量(不改档位)」 |
| 5 | 四件套:audit / manifest / consistency rc=0;对账 仅服务器 0 |
二、★档案 79 的代码修复已落地(src/web/routes/business-plugins.ts,已 build,未部署)
- D1(P0):
try { uninstall(sel.id) } catch {}→await uninstall(sel.id)(+ 三行注释说明为何必须 await) - D2:
['remove', id, '--ignore-workspace-root-check', …]→['remove', id, '-w', …](add的该 flag 合法,未动) - 加固:外层
void (async () => {…})()补.catch()双保险(按taskId从tasks取回任务表项 ——task是 IIFE 内局部量,第一次写错被 tsc 抓出TS2552) - 验证:
tscrc=0(npm run build成功)|产物lib/web/routes/business-plugins.js三处标记齐全(await uninstall×2 /'remove', id, '-w'×1 /apply task crashed×1)|npm test45 pass / 0 fail / 1 skipped(含注入脚本文本校验 ✓) - 未部署:生效需
systemctl restart dshs= 中断在线用户数秒 ⇒ 已作为 R8 问题请示用户。
三、踩坑(已写进 dsh-server-docs/CODEBUDDY.md 同步链路)
scp 到文档镜像必须带「同一相对目录」:scp 04-调整方案/X.md bt-server:/opt/dsh/docs/ ❌ 会落到 docs 根目录(对账报「仅服务器」);scp 交接单/README.md bt-server:/opt/dsh/docs/ ❌ 会覆盖根 README.md(本次实际发生,已从本机重传复原)。✅ scp <相对路径> bt-server:/opt/dsh/docs/<同一相对目录>/。
另:文件名别带空格(scp 远端路径经远端 shell 解析会被拆成两个文件 —— 本次 79-…pnpm flag.md 就中招,已改名去掉空格);远端 chmod 也要给文件名加引号,否则报 cannot access 而误判没传上去。
四、仍待办(详见给用户的清单)
改档位(用户已定暂不做)|提交/推送(文档 137 / 代码仓 24 项未提交)|T03 guest 启用(前置=容量+修 79)|univer 端到端复测需重建 .univer|档案内挂起项(57/59/66/68/42/38b/15/32)|T01|工作区历史临时探针清理。
08:50–09:40 会话 a2665dd3:univer 剩余问题的根因(worker 侧没 socket 支持)+ 已打补丁并构建 0.2.16
用户报:「guest 最新会话显示 univer 插件功能还是有点问题」。
一、根因(来自实例内 agent 自己的取证 + 我的代码核对)
- 报错原文:
Error: gatewayOrigin must be an HTTP origin without credentials or a path - agent 的核对输出:
插件版本: 0.2.15|宿主 socket 支持: 3 处|worker socket 支持: 0 处|socket: …/tmp/dsh-univer-gateway-2.sock(08:42 存在) - 代码链:
resolveTarget()把端点原样塞进 worker 请求 → workerrequiredHttpOrigin()(src/workers/unit-content/entry.ts:454-467)只认标准 HTTP origin ⇒ socket 模式下传的unix:<path>被拒。 - ⇒ 这正是档案 76 里我标注的"已知限制":宿主侧我改了 3 处,worker(
unit-content-worker.mjs,截图/内容类操作走它)没改,而它只能走 TCP loopback —— 被 nft 封。 - 附带:socket 文件存在 ⇒ 宿主侧改造是通的(不是白改)。
二、补丁(v0.2.16,5 处,全部加法式;TCP 路径不受影响)
| 文件 | 改动 |
|---|---|
src/host/adapters/unit-content/protocol.ts |
UnitContentWorkerTarget 加 readonly gatewaySocket?: string(宿主↔worker 内部字段) |
src/host/adapters/unit-content/worker.ts |
spawn 时 unitContentWorkerEnvironment(request.gatewaySocket);该函数把已解析的 socket 路径写进 env(auto 含 pid,不能让 worker 自己重算) |
src/host/provider/unit-content-operations.ts |
resolveTarget():socket 模式下把 gatewayOrigin 换成合成 origin http://unix(过 worker 的 HTTP 校验)+ 传 gatewaySocket |
src/workers/unit-content/entry.ts |
main() 首行 installUnixGatewayFetchShim():把 http://unix/... 的 fetch 改走 unix socket(复用 shared/unix-http.ts 的 requestOverUnixSocket) |
package.json版本 0.2.15 → 0.2.16。
三、踩坑(可复用)
- 多行锚点在 CRLF 文件里必须写
\r\n:本仓库文件是 CRLF,读用newline=""(保行尾)时,含\n的多行锚点命中 0;单行锚点不受影响。(本次先踩后修) - 联合类型取值:
request.gatewaySocket在UnitContentWorkerRequest(联合)上会 TS2339 ⇒ 改'gatewaySocket' in request ? … : undefined。 - import 相对层级:
src/host/adapters/unit-content/→ shared 是../../../shared/(少一级会 TS2307)。 npm run build | head -N会因 SIGPIPE 把构建打断;长构建要重定向到文件 + 后台跑。
四、状态
tsc 对 4 个改动文件零错误;npm run build 后台执行中(worker 产物 artifacts/unit-content-worker.mjs 已重建)。未 pack、未部署。
09:22 三问核实(T03 启用什么 / 档案78 实测什么 / 自动化是什么)—— 只读取数
- T03 待启用 =
dsh-plugin-mcn-suite(池内 0.3.9,1.95 MB);实测现状:admin bundles 已含、guest 不含; 且 guest 的node_modules里连旧的 7 个自研插件也没有(无 mcn/liustack/dsh-plugin 命中)⇒ 对 guest 是首次启用,不是"切换下架旧包"。 启用路径(档案 60/67 措辞):guest 登录 → 实例设置面板 →「功能管理」→ 勾选卡片 → 「应用更改」→ 弹窗「确认应用」(会restartAndProbe,重启该实例数秒)。 - 档案 78 实测参数:熔断阈值
DEFAULT_CRASH_MAX_RESTARTS=5/DEFAULT_CRASH_WINDOW_MS=600000(10 min);冷却 10 min、封顶 6 h;/var/log/dsh-crash-breaker.log当前 0 行(尚未发生熔断)⇒ 实测要新造 6 连崩才能看到 503 + 告警 + 冷却。 ★ 干净做法:按技能 R4 的专用测试账号模板(role='active'、approved_by=真实 admin id)建一个临时用户来做, 零影响你自己的账号(用 admin 做会让 admin 被冷却 10 分钟);用完删号。 - 自动化「遗留项自动推进(DSH 平台)」(
1e1db4eb-…):每 8 h;cwds = D:/AI技能/aliyun-dsh-server(迁移前旧路径)⇒ 停止调度; 最后记录 = 09-12 14:54 run →failed: unknown_interrupted。 ⚠️ 原始 prompt 读不到:~/.workbuddy/workbuddy.db的automations表只有 4 条 8 月的老测试自动化, 这条与「代码仓三方同步」都不在表里(配置未落在任何可读位置)⇒ 只能靠名字/频率/项目记忆复原,要重建必须用户给口径。 对比口径:「代码仓三方同步(DSH)」每 3 h 仍在正常跑(cwd 未变),其记录显示它只报告、零改动, 且被 lock-guard 钩子拒写(lock-hook.log有PreToolUse-deny Write …automations\5840ce59…memory.md)—— 即自动化会话改了 cwd 也不会被钩子放行。
09:17–09:45 会话 a2665dd3:univer 0.2.16 已构建 / 打包 / 投放 / 装进 guest(只差重启生效)
过程:
- 构建:第一次前台跑被我自己的
timeout 900掐死(09:06:58 日志停止;教训:长构建不要自加timeout,用后台)。第二次后台跑时任务丢失,但产物已写出 → 用「index.html 引用完整性」判定:viewer 引用 6 个资产缺 0(assets 153 文件)、render-machine 引用 4 个缺 0(32 文件)⇒ 产物完整可用。 - 打包:
pnpm pack报 pnpm 内部错(detect-libcos error 2)⇒ 改用npm pack(files字段两边都认)→dsh-univer-office-0.2.16.tgz(42,045,215 B / 279 文件,md5d8f044d77390bb24fc6c97e45da6beae)。核验:包内lib/index.js与artifacts/unit-content-worker.mjs都含http://unix✓、版本 0.2.16 ✓。 - 投放:走门户 API
POST /api/plugins/business(admin)—— ⚠️ 经 Cloudflare 直传 56 MB base64 得502 Bad Gateway(CF 挡了);改从服务器本机http://127.0.0.1:3080+-H 'Host: alotbuy.com'重试 →http=200、version 0.2.16、replaced:true、池文件已换(42,045,215 B / 09:36)。临时 admin 会话用完即删(deleted_sessions=1)。 - 装进 guest profile:
setpriv --reuid 100002 … pnpm add -w file:…/dsh-univer-office.tgz(与既有部署同姿势)→node_modules/dsh-univer-office已是 0.2.16、worker 产物带垫片、bundles 仍含 univer ✓。 - 清理:本机(
_uv_upload.sh/_uvbuild.log/_sess_univer.cjs)与服务器(/tmp/uv-0.2.16.tgz等)临时文件全清。
唯一未做 = 重启生效(两处都卡在这一步):
- guest 实例需重启 → 才会加载 0.2.16(client/plugin 在实例启动时加载);
- 平台需重启
dshs→ 才会加载档案 79 的修复。 ⇒ 已作为 一个 R8 窗口问题报给用户:重启一次服务可同时让两处生效(影响:全体在线用户断约 4–10 秒;之后实例下次访问自动拉起)。
仍未验证的边界:worker 内 Univer 的协同客户端若用 WebSocket(ws://unix/...)——本次只补了 HTTP 路径;重启后实测即可定论。
09:39–09:50 三问答复后的取证:T03 的真卡点 = 内存预算(不是"用户没点")+ 自动化已被用户删除
一、用户三答
- T03 启用「已经试过了没问题」;2. 档案 78 实测「也试过了没问题」;3. 自动化「我删除了,会和执行任务冲突」⇒ 勿重建。
二、⭐ 现场取证(只读)——查出 T03 卡住的真原因
| 时间 | 事件 | 证据 |
|---|---|---|
| 07:42:52 | guest 在「功能管理」提交启用 mcn-suite | POST /api/plugins/mine/apply(任务 c8ac2686539aeb7c) |
| 07:43–07:45 | 实例连崩 5 次 | exitCode=134(SIGABRT);栈 = V8 JsonParser + HeapAllocator::AllocateRawWithRetryOrFailSlowPath ⇒ V8 堆打满 abort |
| 07:46 | 熔断(旧代码,JSON 里无 opens/cooldownUntil) |
journal [crash-restart] |
| 07:45 / 08:31 | 平台自动回滚 → guest 现未启用 | package.json.bak-rollback-20260913T0748;pnpm-lock/cordis.patch 0 命中 |
| — | 实例 env 实测 | NODE_OPTIONS=--max-old-space-size=160(档案 74 的下调在生效) |
| — | cgroup 也贴顶 | dsh-instance-mem.log:guest 峰值 382/384 MiB(01:30 触发 91% 告警) |
| — | 退出码分布(09-12 起) | 1 ×21(插件/配置)、134 ×8(V8 堆)、137 ×1(cgroup OOM) |
| ⇒ 结论:160 MiB 是在空闲实例上调的,对"重插件 + 大 JSON"的真实负载不够。要让 T03 可用必须先加内存预算: | ||
--max-old-space-size 160→256(回平台默认)+ cgroup MemoryMax 384→512 MiB(否则只是把 abort 134 换成 OOM 137)。 |
||
两处都由平台进程启动时读取 ⇒ 须重启 dshs(R8,2–5 s)。 |
三、档案 78 的 L1 澄清(与用户的"试过了"对账)
- 新熔断代码尚未被触发:
/var/log/dsh-crash-breaker.log0 行、journal 无crash-breaker-*事件; - 用户今早看到的"熔断"是 07:46 的旧代码那次(guest 真连崩 5 次)⇒ 若用户指的是浮层/自愈,那是档案 77 的(已验);熔断拦截本身仍待实测。
四、顺手核销
- 档案 59
wake.html挂起项:双端一致(4962 B、md500b81728…)⇒ 可关闭。
五、⚠️ 文档回填被锁挡住(R9)
- 持锁者
opensource-export-0913(09:41 起,未声明单号)⇒ 我停止写文档库;回填脚本已备好_patch77/docs-mem.py(档案 74 追加「现场反证」+ T03 卡点更正 + 03-路线图 关 59/加"内存预算待窗口")——锁释放即执行。 - 未 commit / 未 push。
09:47–09:55 T03 §八 只读验收(服务器实测,8/14 通过)
用户第二次表态「我都试过可以了」⇒ 不再追问,改为用现状核对 + 只读验收。
结论(admin 侧,自 00:02 起启用):
| 通过 ✅ | A 包结构(v0.3.9 / md5 2ff1a2fa… / 顶层仅 package、node_modules 0、.bak 0)|B 上传扫描 blocked=0|C 池内 0.3.9|E [mcn-suite] loaded + duplicate=0|H 池内只剩 2 个包(旧 7 包已下架)|I 技能落 <home>/skills/mcn-short-video(4.6 MB / 4 个一级子技能)|K skills ensured: 跳过@0.3.0(版本一致)|M BRIEF 384M |
| 未验 ⚠️ | D 入口逐个点开(需浏览器)|J agent 按名加载|L 凭据扫描|N 死引用扫描|P/Q 撞名三场景|F 探活(但平台已自动回滚过一次 ⇒ 链路活)|G 内存偏紧(guest 峰值 382/384)|O 口径待核:实测 18 个 SKILL.md vs §八 期望 36 |
两条自我纠错(先看错、复核后翻案):① 技能落点是 home/skills/(不是 home/.dsh/skills/)⇒ I 通过;② 内存采样日志时间戳是 UTC("01:40"=本地 09:40)⇒ 采样没停。
guest 那次尝试的事实:07:42:52 启用 → 07:43–07:45 连崩 5 次(exitCode 134 / V8 堆)→ 07:46 熔断 → 平台自动回滚 ⇒ guest 至今未启用。
回填脚本备齐待锁:_patch77/docs-mem.py(74 反证 + T03 卡点 + 03-路线图)→ _patch77/docs-t03-accept.py(T03 §九 验收表 + 03-路线图 T03 行)。锁仍被 opensource-export-0913(09:41 起)占用。
09:41–09:55 会话 a2665dd3:重启已执行(用户批准)—— 两处修复生效;univer 通道修好了,但撞上内存墙
一、重启动作(持 op-lock restart-0942,已释放)
- 先只读 diff 服务器那份
business-plugins.ts→ 差异只有我这 3 处补丁(确认服务器 = 我的改前基线,不会覆盖别人的本地改动)✓ tr -d '\r'转 LF 后 scp(服务器侧先备份.bak-0942)→ 服务器npm run build→lib/web/routes/business-plugins.js标记齐全(await uninstall×2 /apply task crashed×1;ignore-workspace-root-check只剩 1 处 =add那处合法保留)✓systemctl restart dshs→active(新 MainPID 424413 / 09:44:57)✓
二、univer 0.2.16 验证(guest 实例侧,临时会话 R4,用完即删)
POST /api/dsh/enter→ 实例拉起(scopedsh-100002-8ee7ec3cactive、dsh web: …:42307)✓GET /univer-api/status→ 200{"gateway":{"phase":"stopped"},"unitContent":"bundled"}✓- ★ socket 通道在生产成立:
POST /univer-api/gateway/start→ gateway 进程真的被拉起(pid 424934 =…/dsh-univer-office/artifacts/gateway.cjs)⇒ 0.2.16 的 worker/host 改造与 socket 传输在生产可用(不再是"通道不通")。 - ⚠️ 但立刻撞上内存墙(D3 复现):gateway 加载期间实例 cgroup 冲到 383.9 / 384 MiB(
/univer-api/status停在starting)⇒ 384 MiB 装不下「dsh 本体 + univer 插件 + univer gateway」。 - ★ 我随即回收了我自己触发的那个 gateway(
pkill -u 100002 -f artifacts/gateway.cjs→ 剩余 0)→ 实例存活、近 2 分钟无 OOM/无 crash-restart ✓(测试残留必须自己清)。
三、结论(性质变了)
- 通道问题已修(0.2.16 有效:host + worker 都走 socket);
- 剩下的唯一阻碍 = 内存配额(用户档位约束:"暂不改档位")⇒ 要真跑通 univer,需要三选一:调档位(384→512 / 堆 224) | 只装 univer 不装 mcn-suite(省 39 MiB,但 gateway 需求可能更大) | 给 univer gateway 瘦身/懒加载(改造工作量最大)。
四、顺带观察
外网扫描器 198.251.85.116 在探测 /.git/config、/.git-credentials、/.git/config.bak 等 —— 平台均返 404,无泄露迹象,但值得知道(这类探测会持续)。
09:55 追加:墙的量化 —— Univer 的 gateway 单进程 ≈ 350 MiB
- 回收 gateway 后重测:活跃 scope
dsh-100002-8ee7ec3c(09:45:43 起、同一进程 424519、Tasks 13)只占 27.9 MiB(rss 10.3 / cache 15.4)。 - ⇒ 带 gateway 时 383.9 MiB 与不带时 27.9 MiB 相减:Univer 的
gateway.cjs单进程约 350 MiB —— 远大于此前"import 插件 +63.7 MiB"的估算(那是插件宿主的加载成本;gateway 是另一个完整服务进程,内含 Univer 协同运行时)。 - ⇒ 结论定死:本平台每实例 384 MiB 的规格在物理上装不下 Univer(27.9 + 350 ≈ 384,且网关尚未完成启动)。这不是传输/代理问题(那层已修好并验证),而是容量问题。
- 实例与服务当前均健康(页面 200、注入脚本在、无 OOM)。
09:51 用户裁定(关键意图):univer 是他有意保留的「内存压力探针」
- 用户原话:「C 我就是用它来检测 dsh 服务内存压力的」⇒ 选项 C(留着不管)不是将就,而是目的:
用
dsh-univer-office这个重型第三方插件去压实例内存,观察平台在什么条件下撑不住。 - ⇒ 行为约束(已写入
MEMORY.md):任何会话不得以「撑爆实例 / 打不开 / 兼容性差」为由下架或禁用 univer; 要把「实例被压到 384/384」当预期结果看,而不是当缺陷修。 - 它为探针提供的价值:可复现(gateway 懒启动,只在真用表格时才压)、量级已知(gateway ≈350 MiB)、
边界清晰(383.9/384 顶格;平台侧
crash-restart+ 档案 78 熔断冷却负责兜底)。 - 已备探针脚本(可复现配方):
_probe_instance_mem.sh(本机草案)→ 待文档锁释放后落进dsh-server-docs/scripts/probe-instance-mem.sh。 动作:铸临时 guest 会话 →enter拉起 →POST /univer-api/gateway/start→ 逐秒采样 cgroup(usage/max_usage)→ 回收 gateway → 清理会话 → 输出峰值汇总。 - ⚠️ 文档库当时被
opensource-export-0913持锁(09:41 起)⇒ 按 R9 未动文档;BRIEF §3/03-路线图/ 档案 76 的对应措辞(「univer 是探针,勿下架」)待锁释放后补。
09:36–10:0x · 会话 opensource-export-0913:开源导出一份「无本机/服务器信息、无已投放插件」的代码副本
产物:E:\ProgramData\AI技能\aliyun-dsh-server\_开源导出_20260913\
dshs\= 仓库根(139 文件 / 1.2 MB),可直接git init推送;未做 git 初始化/提交/推送(按 §4)。_导出说明与脱敏台账.md= 给人看的清单(不随仓库上传):脱敏台账、发布前占位符清单、已验证项、可选后续。_build_export.py= 复制+脱敏脚本,带安全闸(默认拒绝重跑,需--force,否则会抹掉手写的 README/LICENSE/install.sh)。
做法(可复用):
- 源仓库
D:\github\dsh_shenxian全程只读;改动一律落在导出副本上。 - 字节安全的脱敏:Python 按行
splitlines(keepends=True)处理,完整保留 CRLF;抽样cmp验证未改动文件逐字节一致。 - 收尾用阻断性探针断言(域名/IP/账号/
/opt/dsh/插件名/MCN/凭据关键字)0 命中。 - 编译验证:导出目录临时
New-Item -ItemType Junction软链源仓库node_modules→tsc --noEmit退出码 0 → 删联接。
按需求落实:
- 脱敏:
alotbuy.com→<baseDomain>(web/wake.html改成运行时从location.hostname推导注册域,彻底去硬编码);47.77.182.89/172.18.16.212→占位符;/opt/dshs→<INSTALL_DIR>(require('/opt/.../better-sqlite3')→require('better-sqlite3'));/opt/dsh/{state,artifacts,backups}→/var/lib/dshs/*(上游文档一致的数据根);maogeigei→占位符。 - 去掉已投放插件(严格口径):删
poc/business-plugins/(功能管理分区插件 + 全部 tgz)、poc/workspace-scoped-picker/、以及 6 个插件投放脚本(ensure-anysearch-*、ensure-biz-plugins、ensure-portal-entry、install-workspace-picker.sh、provision-new-users.sh);并把代码注释里的插件名(anysearch / modlens / univer-office)改为中性描述。MCN 工作台与 skill 本就不在代码仓,另经探针确认 0 命中。 - 授权文档:
LICENSE(分层授权:个人/非商业免费 + 商业需授权)+LICENSE-UPSTREAM-MIT.txt(上游 MIT 原文,必留)+THIRD-PARTY-NOTICES.md(DeepSeek Harness = MIT 商用无限制、不分发其代码;6 运行依赖 + 4 开发依赖 + 178 传递依赖全部宽松许可)。 README.md按主流开源结构重写(徽章/目录/特性速览/快速开始/功能详解/架构/部署形态/配置/开发/版本与迭代/安全/目录结构/FAQ/贡献/授权/致谢);版本表登记 v1.0.0 = 首个公开发布,并单列「相对上游 dshs 的六组改造」。- 不带项目文档与 skill:删
docs/(上游 7 篇)、STANDARD.md、poc/README.md、.workbuddy/、lib/、.git(历史里全是内部信息,必须全新仓库)。 - 新增
install.sh一键部署(模式 A):预检 → 装依赖并构建 → 装 DSH CLI → env(0600) → 数据根(0700) → 证书 → nginx → systemd → 首个管理员 → 健康检查;带--dry-run/--uninstall [--purge]/--isolation/--port-guard/--install-node,幂等。
⚠️ 两个必须交代的前提:
- 法律前提:上游
dshs(上游作者(已按要求不再具名))是 MIT,MIT 不允许对上游代码加限制 ⇒ 只能做分层授权(上游留 MIT,只对本项目新增部分收商用费)。若 上游作者(已按要求不再具名) 就是用户本人,可整体简化为单一授权 —— 已在台账里留作可选后续。 install.sh未在真实 Linux 跑过(本机只有 Windows:仅bash -n+--help+ 逻辑审查)。建议先非生产机器--dry-run再真跑。
保留未动:代码注释里 183 处「档案 NN」内部编号引用(属内部档案号,非本机/服务器信息;已列入可选后续)。
09:53–10:0x · 同一会话续做:把开源规则沉淀成技能 dsh-opensource-release
用户要求:「把这个项目开源的规则 整理成 skill 迭代管理」。
产出:E:\ProgramData\.workbuddy\skills\dsh-opensource-release\SKILL.md(v1.0.0 / agent_created: true)
十节:① 何时用 ② 事实(硬编码路径/版本)③ 五条硬规则 R-O1–R-O5 + 两条纪律 R-O6/R-O7(含「源仓库只读」「阻断性探针 0 命中」「不得被重建抹掉」)④ 保留/移除清单(delta,含「本就不在代码仓」的 MCN/插件清单)⑤ 脱敏映射表(唯一口径) + 发布前占位符清单 ⑥ 保留未动的 183 处档案编号 ⑦ 授权结构 + MIT 硬前提(分层才合法;上游作者(已按要求不再具名) 若为本人可简化)⑧ 迭代发布 SOP(抢锁 → 基线 → 改口径 → --force 重建 → 改版本三处 → 六项验证 → 推送)⑨ 验证六件套(探针 / cmp / CRLF / tsc-via-Junction / bash -n / 移除项核对)⑩ 8 条实测坑。
顺带把构建脚本升级为「可安全迭代」:_build_export.py 新增 OVERLAY 手工撰写层(README / LICENSE / LICENSE-UPSTREAM-MIT / THIRD-PARTY-NOTICES / install.sh)—— --force 重建前先快照到 _overlay/、重建后自动恢复;实测重建后 5/5 逐字节一致,探针仍 0 命中。此前 --force 会抹掉手写文件(真实风险,已消除)。
⚠️ 被锁挡住的部分(按 R9 未抢、未接管):补「归档副本 + INDEX 登记 + manifest 刷新」时,文档库全局锁被 清理文档债-0955(09:54 起)占用 ⇒ 只读确认后跳过这一组步骤,继续做完其余不冲突的工作。待办已写进技能 §10(含逐步补做清单)。另有既有漂移一并登记:dsh-instance-diagnose 无归档副本、INDEX.md 未登记 dsh-knowledge-upkeep —— 未擅自修。
10:0x · 同会话续做②:univer 转为保留 + 新增《插件移植指南》+ 技能归档补齐
用户指令:「univer 可以保留这个插件 专门讲讲如何把开源插件改造为可在多租户平台运行」。
A. 撤回 univer 的脱敏(只撤 univer,其余插件仍中性化)
_build_export.py:删掉dsh-univer-office/DSH_INSTANCE_UNIVER_SOCKET/UNIVER_DSH_GATEWAY_SOCKET三条 GLOBAL 规则;删掉 orchestrator 的 6 行DELETE_LINES(unix-socket 适配段回归);whitelist.ts注释改写为「(实测:多个第三方插件均如此,例如 dsh-univer-office)」。LEAK_PROBES移除dsh-univer/UNIVER(刻意不在列)。- 重建后确认:
src/supervisor/orchestrator.ts的UNIVER_DSH_GATEWAY_SOCKET段回来了;阻断探针仍 0 命中(档案/交接单属有意保留)。
B. 新增 PLUGIN-PORTING.md(本次主交付) —— 面向插件作者与平台维护者,七节 + 附录:
0 结论速查表 · 1 托管平台 vs 本地的六条假设差异 · 2 六个失败模式 H1–H6(绝对 URL[阻断级] / loopback 依赖 / 自建监听 / 客户端拼地址 / 平台包不兼容 / 重型依赖静态 import,各附症状+判定) · 3 五条改造规范 R-a~R-e · 4 dsh-univer-office 完整实战(两层独立阻碍 Host→Gateway 与 Browser→Viewer、为什么换服务器 IP 不行[3 条硬理由]、改造清单、3 条设计决策[socket 是可选传输/只有两条代理规则/两个平台侧机制坑]、不碰生产的验证法、已知限制、回滚) · 5 平台侧需配合的能力 · 6 上架自查清单 · 7 提上游的论证口径 · 附录 可粘自检命令。
素材来源(只读):内部 04-调整方案/75(H1–H4 判据 + R-a~R-e + 实测内存基线)与 76(univer 改造全过程);已去掉全部内部档案号与服务器信息。
README 加「插件移植指南」章节 + 目录项;① 组改造表补「插件 unix-socket 适配通道」。
C. 把上一轮被锁挡住的活补完(10:01 锁已释放,重新 --claim-exec 后完成,完工已 --release-exec)
- 归档副本:
dsh-server-docs/skills/dsh-opensource-release/SKILL.md—— 两副本 md5 一致(b0986201…)。 INDEX.md:§一 场景表加「开源导出 / 发新版本」行;§二 清单表加 skill 行。- 四件套:
docs-manifest.py刷新 ✓ |docs-audit.pyexit 0(无 P0) ✓ |docs-consistency.pyexit 0 ✓ |docs-index-stats.py --write刷新摘要行 → 复跑 exit 0 ✓。 - 未 scp(按 §4,等用户发话);
docs-sync-check如实显示「仅本地 2 / 内容不一致 5」的既有待推状态。
D. 技能迭代到 v1.0.1(示范「迭代管理」):更新 R-O3、脱敏映射表(新增特许保留项小节)、OVERLAY 增 PLUGIN-PORTING.md;tsc 验证法改为跑 _verify_tsc.mjs,并加硬警告:绝不可 recursive 删联接(Windows 下会顺着联接删掉源仓库 node_modules)—— 本次已实测 tsc exit = 0、junction removed = true、源仓库 node_modules 164 项完好。
导出物现状:140 文件;手工撰写层 6 个(README / LICENSE / LICENSE-UPSTREAM-MIT / THIRD-PARTY-NOTICES / PLUGIN-PORTING / install.sh),重建时自动快照→恢复。
10:0x–10:2x · 同会话续做③:确认上游是三方的 + 项目改名 dsh-hosting + 正式致敬
用户指令:「dshs 这个是不是引用的三方插件项目确认下,如果是不能直接使用 需要一个更符合这个项目定位的名称,并且在说明中致敬这个项目」。
A. 核实结论:是三方项目(不是我们能直接用的名字)
- 本机 git:
upstream=上游骨架仓库(已按要求不再具名);192 个提交里 123 个是 上游作者(已按要求不再具名)(2026-08-18 → 08-26 建骨架P1 auth/P2 desktop/P3 single-DSH/P4 每文件夹插件/P5 watchdog),我方最早 09-08(服务器侧deploy)/ 09-11(maogeigei)。 - 线上核对:GitHub 仓库存在;已被 DSH 插件目录收录(
dsh.so/artifact/dshs,含 L1–L5 验证记录与dsh plugin --profile web add github:上游骨架仓库(已按要求不再具名));另有第三方博客评测。授权 MIT。
B. 新名 dsh-hosting(多租户 DSH 托管平台)
- 实测未被占用:npm
registry.npmjs.org/dsh-hosting→ 404;插件目录dshbase.com/plugins/dsh-hosting→ 404。 - ⚠️
dsh-hive已被占用(第三方插件llluchy/dsh-hive,跨会话消息)—— 候选名已排除,别再捡(本次实测踩到)。 - 改名范围(149 处自指标识):包名/bin/cordis plugin id、36 种环境变量前缀(
DSHS_*→DSH_HOSTING_*)、/var/lib/dsh-hosting、dsh-hosting.service/.env/nginx conf、默认库文件dshs.db→dsh-hosting.db、镜像/k8s/CI/Dockerfile、导出目录名。
C. 致敬(用户明确要求)
- README 新增 「名称与渊源」 章节(本项目名 / 上游基线 上游作者(已按要求不再具名) / 为何改名 / 两类标识如何区分 / 上游仍按 MIT 且本项目改动不改变这一点)+ 「致敬」一句。
- 致谢章节扩写;
THIRD-PARTY-NOTICES.md§4 扩为「上游项目 / 作者 / 本项目 / 更名说明 / 保留要求 / 致谢」。 LICENSE-UPSTREAM-MIT.txt逐字节未动;README 4 处 / LICENSE 2 处 / NOTICE 1 处出处引用保持旧名(不改)。
D. 这一步又暴露 3 个脚本漏洞(全部已修 + 重建验证)
Dockerfile/Dockerfile.dsh从未被脱敏 ——is_text()按扩展名判断,二者无扩展名 ⇒ 整份跳过。package.json的项目自有字段会被重建覆盖 —— 它属「源派生」而非 OVERLAY(version / description / repository / license 已改成 GLOBAL 规则)。- ⚠️ 不要对
_build_export.py自身做批量替换 —— 脚本里同时有「源模式」与「目标值」,盲替打断了改名规则(误伤 4 处,已逐条修正并重建验证)。这条已写进技能 §8 坑 9。
E. 最终验证(全绿):阻断探针 0 命中(新增自指残留探针 DSHS_ / dshs.{service,env,db});全仓 grep 'server-login' 只剩致敬与出处引用;tsc --noEmit exit 0(Junction 法,联接已拆);bash -n install.sh OK;导出物 140 文件。
F. 技能升到 v1.0.2:新增 R-O8 命名规则(不沿用三方名 + 实测占用 + 保留出处致敬;附「dsh-hive 已占用」记录)、§3 脱敏映射表加改名行、§8 补 3 条坑(编号 9–13)、路径全面改为 dsh-hosting;归档副本已同步(md5 09ed761c… 一致),四件套 exit 0,锁已释放。
10:0x 排障:「admin(Edge) 有浮层 / guest(Chrome) 没有」= 界面不同,不是浏览器问题
实测(真 Chrome 无头 + guest 临时会话,用完即删):
- 服务器发给 guest 的注入脚本已是修复版(
__dsh-ov/HEARTBEAT_MS/String.fromCharCode(10)全在,坏特征 0); - guest 页面
__dshRecover=true、__dshAssist=true、0 语法错误; - 不做任何操作 → 46.2 s 后浮层自动出现(心跳 2 拍),新视觉节点在。 ⇒ Chrome/Edge 都是 Chromium,同一份脚本;差异不在引擎、不在账号。
真正原因(结构性)——两处界面对比:
| 界面 | 注入脚本 | 加载态 |
|---|---|---|
| 实例页 | ✅ 有 | 「AI 核心」浮层 |
过渡页 wake.html(刷新/首次进入且实例不在时落这里) |
❌ 无 | 旧的 border-top 转圈 |
| guest 实例今早崩 5 次 + 被回滚 ⇒ 刷新时多半落在过渡页,自然"看不到浮层"。另:若那个标签页是 08:15–08:27(坏脚本期)打开的,刷新一次即恢复。 |
已做:web/wake.html 加载态统一成同一套「AI 核心」视觉(conic 扫描弧 + 反向虚线环 + 脉冲核心 + 三轨道粒子 + 渐变进度条 + 等宽小字),配色跟随平台主题(#534AB7/#8B7CF6,不硬套暗色)。
- JS 逻辑一行未动(diff 只差档案 78 加的
instance_circuit_open分支);行尾保持 LF;静态页免重启 ⇒ scp 即生效; - 线上取回验证:
wk-orb/conic-gradient/prefers-reduced-motion/dsh · auto recovery命中,旧.wk-spin{width:34px}消失;截图_patch77/shots/wake-aicore.png;回滚/opt/dsh/backups/wake.html.bak-aicore-20260913。
文档债已清(锁刚好空出):档案 74 追加「现场反证」、T03 追加 §九 验收表 + 卡点更正、03-路线图(关 59 挂起项 + 内存预算待窗口 + T03 主体通过)、INDEX、档案 77 追加「wake.html 统一视觉」节;四件套 rc=0,对账 一致 133(余 3 不一致 + 1 仅本地 = 其它会话积压);锁已释放。 诊断口诀(已写进档案 77):客户说"看不到浮层"→ 先分清是实例页还是过渡页,再看该标签页是不是修复前打开的旧页面。
10:02–10:10 「guest 一直显示恢复但起不来」根因定死:univer gateway 390MB > 实例上限 384MB ⇒ cgroup OOM kill
铁证(服务器实测):
RSS=390.4MB uid=dsh-eecc…(guest) node /var/lib/dshs/users/4092b965… ← univer gateway 单进程
RSS= 44.0MB uid=dsh-eecc…(guest) dsh --profile web --port 43829 ← 实例本体
- 10:00 内存采样:guest 当前 384 / 峰值 384 / 上限 384(高位 100%);
- 10:03:11 崩溃 =
exitCode=137(SIGKILL = cgroup OOM kill);此前 8 次是 134(V8 堆 160MB abort)⇒ 两个天花板都在顶; - 页面侧:
GET /每 ~35s 一次(恢复→实例起来→又被杀→再恢复的循环);期间fetch('/')曾拿到 502 且响应体是 Cloudflare 错误页(命中/cdn-cgi/styles/main.css)⇒ 502 是 CF 的(实例不在/正在起的窗口),不是 nginx 的(nginx error.log 无 502); - 页面还在 1 秒 1 次猛打
/univer-api/state(档案 76 那个返 400 的接口)—— 与 gateway 高占用同源。 结论:这是"内存压力探针"的必然结果 —— 用户 2026-09-13 明确「我就是用它来检测 dsh 服务内存压力的」⇒ 384MB 装不下 univer 这套。 恢复逻辑本身没问题(真 Chrome 实测:不操作 46.2s 自动出浮层)。 宿主余量:1870MB 总 / 1027MB 可用 ⇒ 单实例升到 640MB 可行,但maxIdleInstances=4必须降到 2(4×640 > 1870)。 待用户拍板(R8 + 资源承诺):(a) 升预算(cgroup 384→640、V8 堆 160→256,需一次重启 2–5s,我推荐)|(b) univer 瘦身(插件侧大改)|(c) 保持现状 + 把恢复做成有界(连续 N 次失败即停在明确失败态,不要无限转圈;也需一次重启上线)。
10:05–10:15 会话 a2665dd3:★找到并修好「插件无法启动」的真因 —— 陈旧 socket 挡住 bind(0.2.17)
用户报:「guest 最新会话 这个插件还是报错 无法启动」。
实例内 agent 当时看到的(session eda867a0 turn 7):无 gateway 进程、残留一个 08:42 的 socket 文件、宿主 dsh 已重启(pid 2 / 已升 0.2.16);univer_inspect → Error: bundled Gateway did not become ready within 10000ms。
一、根因(★真 bug,不是内存)
- 实测判定:只做一件事 —— 删掉那个陈旧 socket 文件,再
POST /univer-api/gateway/start→ 立刻ok:true,phase:"running"连续 30s 稳定,新 socket 就位。⇒ 陈旧文件就是阻塞源。 - 机理:socket 路径 =
join(tmpdir(), 'dsh-univer-gateway-<pid>.sock'),而实例在 PID namespace 里宿主恒为 pid 2 ⇒ 路径每次重启都一样;实例/tmp又是--bind到用户目录的持久挂载(不是 tmpfs)⇒ 上次 gateway 死掉留下的 socket 文件能活过实例重启。 - 为什么永久:
bind()到已存在的 socket 路径 →EADDRINUSE(Univer 的 gateway 未先 unlink)⇒ 之后每次启动都失败 ⇒ 对外只看到did not become ready within 10000ms(10s 超时把真实 errno 吞了)。
二、修复(v0.2.17,1 处)
src/gateway-app/server.ts 的 listen():unix socket 分支绑前先 rmSync(target.socketPath, { force: true })(ENOENT 忽略)+ 补 import { rmSync } from 'node:fs'。
只重建 gateway(npm run build:gateway,秒级)→ npm pack(42,045,253 B / md5 16fd345b4d15fdec03285c80a9982b8a)→ 投放候选池(本机直连,http=200 / version 0.2.17)→ 装进 guest profile(node_modules 已是 0.2.17,gateway 产物含 rmSync ×4)。
三、修复验证(复现故障场景)
① pkill 掉在跑的 gateway → 故意留下陈旧 socket(10:06 那个);② 不删任何文件直接 POST gateway/start → ok:true → phase:"running" 在 t+5/10/15/20s 全部稳定 ✓;③ 新 socket(10:11)+ 1 个 gateway 进程 ✓。⇒ 0.2.17 修复成立。
四、附带事实与注意
- 无需重启实例:gateway 是按需新起进程,下一次启动自然用上 0.2.17 ✓(这与 client bundle 必须重启实例不同)。
- ⚠️ 内存仍在 383.7 / 384(gateway 热身后的稳态)—— 功能通了、但内存墙依旧,这正是用户要的探针现象(选项 C)。
- 回滚:池内已被 0.2.17 覆盖;本地保留
dsh-univer-office-0.2.16.tgz/0.2.17.tgz两个包。