Files
dsh_ai1net_server/交付物/分发与更新-S4落地与三轮回执-20260926.md
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

25 KiB
Raw Permalink Blame History

S4「接进既有的分发与更新机制」· 落地与回执(2026-09-26 · 第 42 棒)

线 / 棒次:插件投放与分库线 · 第 42 棒(执行棒)|会话 插件投放与分库线-42 执行依据:规格书 D:/github/dsh_shenxian/dsh-server-docs/05-交接单/交接单_包规格书_20260926.md(§〇 / §五 A / §五 C) + 方案 交付物/功能打包到基础插件-分步实施方案-20260926.md §3.10.6(S4 逐步照做唯一权威)+ 方案 S4 段 + §4 C 类坑 C1–C6 前置:第 41 棒 S3「数据面」已落地(建库 dshs_pl_ai1net → 迁移 M1→M5 → 对账差集双空,三轮全绿) 产物:拉取器 tmp/p42/puller.mjs(照抄版)+ 沙箱 Manager tmp/p42/mgr-mock.mjs + 编排 tmp/p42/run-s4.mjs + 真机锚点 tmp/p42/anchor-real.mjs 读数:tmp/p42/读数-20260926.txt(S4 编排,53 ✅ / 0 ❌)|tmp/p42/尺读数-S4-20260926.txt(尺子)|tmp/p42/real-anchor/(真机包) 包内改动:零。S4 全部落在「分发侧 + profile 装配侧」,⛔ 未改 E:/ProgramData/AIProject/dsh-plugin-ai1net/ 任何文件。


一、一句话结论

包能被平台「对账 + 增量拉取 + 原子换上」,落地后两端指纹逐字一致;三条反例判据全过(清单拿不到 ⇒ 本地零改动/单包失败 ⇒ 其余照常更新/extra ⇒ 只告知不删)。

判据表(退出码即结论):

# 判据 期望 实测 判
S4-1 与权威实现逐段对得上(⛔ 不自创第二套) 逐字 11 段逐字照抄(见 §二) ✅
S4-2 四步 happy path 跑通 rc=0 对账→取包→原子换→回报 全通 ✅
S4-3 依赖写 link:<绝对路径>,两端逐字同形 逐字相同 两端字符串 100% 相同 ✅
S4-4 补 @deepseek-ai/* 软链 指向本机 scope linked=1 / kept=3 / relinked=1(负控) ✅
S4-5 三条反例判据 全过 全过(见 §五) ✅
S4-6 装配后实例页「能力管理」栏出现 需真壳 ⚠️ 未取到(rc=3) ⚠️
— 尺子:装配端A / 端B + 取数 + 回调 + v-baseline 全绿 5/5 rc=0 + baseline rc=0 ✅
— 包内门禁 build.mjs --check-only rc=0 rc=0 ✅
— 真机锚点:本份指纹实现 vs 真机权威 treeSha256 逐字相同 两包都相等(storyforge 117 / mcn-suite 659,§六) ✅

二、S4-1「照抄」逐段对照表(⛔ 判据 = 逐段对得上)

权威 = D:/github/dsh_shenxian/src/worker/agent.ts(节点侧)+ src/supervisor/plugin-assembly.ts(软链自足)+ src/web/routes/business-plugins.ts(Manager 侧)。

# 段 权威位置 落到本棒哪里 改了什么
1 hashTreeAt() agent.ts:241-260 puller.mjs 逐字(仅去 TS 类型)
2 envNumOr() + SHARED_PULL_* 7 个常量 agent.ts:194-227 puller.mjs 逐字(默认值一字未改:20 000 / 300 000 / 900 000 / 64 KiB/s / 2 / 2 000 / stable)
3 NODE_PULL_STATE_NAME / MAX_PACK_BYTES / 拉取记录读写 agent.ts:262-298 puller.mjs 逐字
4 errText / PackError / isRetryable / defaultSleep / backoffOf agent.ts:365-393 puller.mjs 逐字
5 effectiveDownloadTimeout() agent.ts:412-421 puller.mjs 逐字
6 pullOnePack()(原子换六动作) agent.ts:423-525 puller.mjs 逐字(含 tar 用 cwd+相对名的纪律、gzip 魔数、成员白名单、chown 仅 Linux、graveyard 回滚)
7 syncSharedLayerOnce() agent.ts:539-733 puller.mjs 逐字 + 新增 1 个测试缝 __dumpPullStateTo(只多写一份记录,⛔ 不改算法/默认值)
8 resolveDshPackageRoot() / resolveHostDshScopeDir() plugin-assembly.ts:1185-1233 puller.mjs 逐字同源副本(权威文件是 .ts,Node 跑不了;两文件均纯 Node 零框架依赖)
9 ensureSharedScopeLink() plugin-assembly.ts:1265-1311 puller.mjs 逐字
10 healSharedLayerSelfSufficiency() plugin-assembly.ts:1330-1365 puller.mjs 逐字
11 sharedDirNameOf()(flat 名口径) plugin-assembly.ts:871-873 puller.mjs 逐字

沙箱 Manager 侧(mgr-mock.mjs):hashTree() ← business-plugins.ts:242-259 逐字|sharedLayerDiff() ← 同 :789-798 逐字|产物口打包口径 ← 同 :2528 起(tar -czf - --owner=0 --group=0 --numeric-owner <flat>,cwd=root)|对账端点口径 ← 同 :2432 起(inventory 指纹只认 64 hex,其余 null="不知道";pull = missing + stale)。

✅ 自查:本棒产出没有第二套机制 —— 全部是照抄 + 一个测试缝。


三、S4-2 四步实现(happy path)

对账 → 取包 → 落地(原子换六动作)→ 回报,全部走既有链路口径:

  1. 对账:POST /api/plugins/shared/node/sync(头部带 x-dsh-agent-token / x-dsh-host-id / x-dsh-pull-channel;body 带 inventory)。清单拿不到 ⇒ 早退,⛔ 什么都不动。
  2. 取包:GET /api/plugins/shared/node/pack/<flat>?version=<v>;对账 20 s 与下载 300 s 两套超时分开(syncTimeoutMs / downloadTimeoutMs),并带 packBytes 量级提示动态放宽、封顶 900 s、最低速率 64 KiB/s(§4-C2)。
  3. 落地(原子换六动作):① 落 .pull-stage-<hex> ② tar -xzf ③ 成员白名单(必须全在 <flat>/ 下,挡 ../ 与绝对路径)④ 自算 hashTreeAt 与平台告知的 treeSha256 逐字比 ⑤ chown root:root(仅 Linux)⑥ rename 原子换(旧目录挪 graveyard → 新的就位 → 成了再删旧的;换失败把旧的挪回来);finally 只清 stage ⇒ 最坏结果 = "没更新",⛔ 绝不留下半包。
  4. 回报:有失败才 POST /api/plugins/shared/node/result(⛔ 不参与任何判定)。

happy path 原始输出(节选自 tmp/p42/读数-20260926.txt)

════ B · happy path(四步:对账 → 取包 → 落地原子换 → 回报) ════
  ✅ ok=true  —— reason=null
  ✅ missing = 两个包(本地全空)  —— ["_dsh-local_ai1net","_dsh-local_probe2"]
  ✅ stale 全空(本地无记录 ⇒ 只能是 missing,⛔ 不会被折算成"一致")  —— []
  ✅ extra 如实告知本地自有目录(⛔ 平台不据此删 —— 见 C-③)  —— ["_dsh-local_leftover"]
  ✅ pulled = 两个包  —— ["_dsh-local_ai1net","_dsh-local_probe2"]
  ✅ failed 空  —— []
  ✅ channel = stable  —— stable
  ✅ 回报端点:无失败 ⇒ 平台侧零回报  —— resultCalls=0
  ✅ 产物口调用 2 次(每包一次)  —— ["_dsh-local_ai1net","_dsh-local_probe2"]
  ✅ 落地后指纹逐字相同 · _dsh-local_ai1net  —— node=6f9e6fb121433adc2b29d6f58c2ff9b130b796f3fa70810fd99d4a384ca13d09 mgr=6f9e6fb121433adc2b29d6f58c2ff9b130b796f3fa70810fd99d4a384ca13d09
  ✅ 落地后指纹逐字相同 · _dsh-local_probe2  —— node=cd3bd919577b85e09c810cb3ff2ef511eda45504136eadb518c8c2bec19445d5 mgr=cd3bd919577b85e09c810cb3ff2ef511eda45504136eadb518c8c2bec19445d5
  ✅ .node-pull.json 记下了两包的 treeSha256(形状同真机 NodePullEntry)  —— {"_dsh-local_ai1net":"6f9e6fb12143","_dsh-local_probe2":"cd3bd919577b"}
  ✅ 第二轮:ok=true 且 pull 清单为空  —— pulled=[] missing=[] stale=[]
  ✅ 第二轮:产物口零调用(不重拉 = C1 判据的正面)  —— packCalls=2

🔴 「指纹逐字相同」是本节的核心判据:节点侧解包后自算的 hex 与沙箱 Manager 独立实现算出的 hex 逐字相等(36 字节全串,不是前 12 位摘要)⇒ 这同时是 §4-C1 的正面证明。

§4-C1 的机验(两侧算法必须同规则)+ 三条负控

════ A · 指纹算法两侧逐字一致(§4-C1) ════
  ✅ 两侧 hex 逐字相同 · _dsh-local_ai1net  —— fileCount 8=8
  ✅ 两侧 hex 逐字相同 · _dsh-local_probe2  —— fileCount 5=5
  ✅ 负控①:不归一化 `\` ⇒ 与权威 hex 不等(判据能变红)
  ✅ 负控②:"只哈希文件名清单" ⇒ 与权威 hex 不等  —— C1 点名的近似物之一
  ✅ 负控③:改一个字节内容 ⇒ 权威 hex 变(指纹对内容敏感)  —— 并已还原 ⇒ 指纹可复现

⚠️ 首版负控写的是"去掉排序 ⇒ 应不等",实测失败(该 fixture 只有 5 个文件,readdirSync 顺序恰好等于排序序)⇒ 已换成 C1 点名的两类真近似物(不归一化 \ / 只哈希文件名清单)⇒ 均能变红。教训:负控要挑"真会翻车的写法",不是随便改一刀。


  • 端A = 桌面 profile 实件副本(E:/github/dsh-desktop-0.1.7rc2/.../home-adapt/profiles/desktop/package.json,只读引用,未改真件)+ 追加本包;
  • 端B = 平台侧形态(profiles/web 键位:bundles + dependencies 的 link:,patchReload: live);
  • 🔴 两端 dependencies["@dsh-local/ai1net"] 逐字相同,且指向 拉下来的那一份(不是源包目录)⇒ 闭环成立:
  ✅ 两端 `link:` 值**逐字相同**(§4-C3)
     A=link:E:/ProgramData/AIProject/aliyun-dsh-server/tmp/p42/node-shared/_dsh-local_ai1net
     B=link:E:/ProgramData/AIProject/aliyun-dsh-server/tmp/p42/node-shared/_dsh-local_ai1net
  ✅ 端A / 端B 链接均解析到落下来的那一份
  • flat 名口径实测:sharedDirNameOf('@dsh-local/ai1net') = _dsh-local_ai1net;与真机既有包实读同形(_dsh-local_storyforge / _dsh-local_im-conversation-tabs / _softspark_dsh-file-preview)⇒ ✅ 口径一致。
  • ⚠️ 真机平台侧的真值形态 = link:/var/lib/dshs/bundled-plugins/_dsh-local_ai1net(/var/lib/dshs/bundled-plugins 为真读值)。本沙箱用本地等价绝对路径代替 —— 这是建模,⛔ 不等于"真机装配已通"。

五、S4-5 三条反例判据(⛔ 不验不算完成)

① 清单拿不到(黑洞)⇒ 本地零改动

════ C-① 反例:清单拿不到(黑洞)⇒ 本地文件**零改动** ════
  ✅ ok=false 且 reason 指明"取不到"  —— reason=sync_unreachable: The operation was aborted due to timeout
  ✅ pulled 空(一个包都没拉)  —— []
  ✅ 本地文件零改动(全树 sha256 前后逐字一致)  —— 23b0ab26f2788194 → 23b0ab26f2788194(31 项)
      留痕条数 31 ⇒ 31;含软链快照,⛔ 不是只看文件

做法:黑洞服务收请求永不响应(比"连接被拒"更狠,连 HTTP 层都不给);实测走的是 AbortSignal.timeout(syncTimeoutMs) 那条真实路径。 ⚠️ "零改动"口径:用自写强留痕(每个文件的 size + mtimeMs + 内容 sha256 + 每条软链的目标)算全树单值 —— ⛔ 不能只用 hashTreeAt,因为它刻意不计软链,会漏掉"软链被动了"这一类改动。

② 单个包失败 ⇒ 其余包照常更新

════ C-② 反例:单个包失败 ⇒ 其余包**照常更新**(不是整轮放弃) ════
  ✅ stale 含两包(都对不上权威)  —— ["_dsh-local_ai1net","_dsh-local_probe2"]
  ✅ 主包**照常更新**(pulled 含它)  —— pulled=["_dsh-local_ai1net"]
  ✅ 主包新指纹=权威新指纹(逐字)
  ✅ 失败只记备包一项(不是整轮放弃)  —— ["_dsh-local_probe2"]
  ✅ 失败原因是**永久性**(错误页打进产物口 ⇒ pack_not_gzip)  —— pack_not_gzip
  ✅ 永久性错误**不重试**(attempts=1;§A-3 语义)  —— attempts=1
  ✅ ok=false 且 reason = partial:…(部分失败语义)  —— reason=partial: _dsh-local_probe2=pack_not_gzip
  ✅ 备包**旧版仍在、零改动**(半包绝不落地)  —— 5356194d200f01fb → 5356194d200f01fb
  ✅ 失败已回报平台侧(/node/result 1 次)  —— resultCalls=1 failed=["_dsh-local_probe2"]

加演(同族、语义相反):把坏体换成截断 gzip ⇒ tar 抛裸异常 ⇒ 判为瞬态 ⇒ 会重试:

  ✅ 加演:截断 gzip ⇒ 判为**瞬态**并重试(attempts=3)  —— attempts=3 err=Command failed: tar -tzf pack.tgz

⇒ 永久性 vs 瞬态的分流是真的在起作用(同一个 flat,两种坏体,两套行为),⛔ 不是"一律重试"也不是"一律放弃"。

③ extra(本地多出来的包)⇒ 平台只告知,本地一个文件没被动过

════ C-③ 反例:`extra`(本地多出来的包)⇒ 平台只告知,本地**一个文件没被动过** ════
  ✅ 对账告知了 extra 含它  —— ["_dsh-local_leftover"]
  ✅ 该目录**仍存在**(⛔ 没被删)
  ✅ 该目录内容与 mtime **零改动**  —— 92cc4a9d4bb63109 → 92cc4a9d4bb63109
  ✅ extra ⛔ 不进 pull 清单(不会去拉它)

六、🔴 真机锚点:本份指纹实现 = 真机权威指纹(⛔ 不是近似物)

flat 真机台账 treeSha256(读 /var/lib/dshs/bundled-plugins/.manifest.json) 本份 hashTreeAt 实算 文件数 tgz 字节 判
_dsh-local_storyforge 1c45c8418875df50a687359806b5b44e5125ffaf7f54c405a566a17d90b1ac3c 同串 117 1,766,902 ✅
dsh-plugin-mcn-suite 27f6c6d7ee84f14666ff966750a7d7d41379d280aef72544ce154bc9f49fac9f 同串 659 7,689,968 ✅
════ 真机锚点 · _dsh-local_storyforge ════
取包命令:ssh [email protected] 'tar -czf - -C /var/lib/dshs/bundled-plugins _dsh-local_storyforge'
{"flat":"_dsh-local_storyforge","tgzBytes":1766902,"fileCount":117,
 "got":"1c45c8418875df50a687359806b5b44e5125ffaf7f54c405a566a17d90b1ac3c",
 "want":"1c45c8418875df50a687359806b5b44e5125ffaf7f54c405a566a17d90b1ac3c","equal":true}
rc=0

════ 真机锚点 · dsh-plugin-mcn-suite ════
{"flat":"dsh-plugin-mcn-suite","tgzBytes":7689968,"fileCount":659,
 "got":"27f6c6d7ee84f14666ff966750a7d7d41379d280aef72544ce154bc9f49fac9f",
 "want":"27f6c6d7ee84f14666ff966750a7d7d41379d280aef72544ce154bc9f49fac9f","equal":true}
rc=0

(原始读数:tmp/p42/真机锚点-20260926.txt)

做法(全程只读):ssh 47 'tar -czf - -C /var/lib/dshs/bundled-plugins <flat>'(与产物口逐字同口径的打包)→ 本机解开 → 本份 hashTreeAt() 算 → 与真机台账逐字比。⇒ 这一步把"照抄"从"看起来一样"变成"算出来一样",是本节最强的一条证据。两个包(117 / 659 文件)都逐字相同。

⚠️ 两处如实(都不影响上述判据):

  1. 首版清场把判据的退出码污染了:解包暂存目录带 659 个文件,本机的安全删除护栏会拦"一次删 >50 个文件"(SAFE_DELETE_BULK_CONFIRM_REQUIRED)⇒ rmSync 抛错 ⇒ 脚本在 equal:true 之后仍以 rc=1 退出。 ⇒ 已把清场改成 best-effort(清场失败只打日志,退出码只由 equal 决定)。教训:辅助动作(清场)不许影响判据的退出码。
  2. 中途一次误读已被纠正:护栏那次"拦截"实际已部分删除了暂存树 ⇒ 事后想复用那份解包物复算,算出 415 文件 / 指纹不符。那不是指纹问题(当时比对是 659 文件 / equal:true),而是素材已被动过 ⇒ 已改为重新解包再算,结论以上表为准。教训:"复用旧素材复算"前先确认素材没被动过。

七、尺子回归(⛔ 未改尺子一行)

面 靶子 / 入口 rc 说明
装配 · 端A 客户端形态 --profile-json tmp/p42/端A-客户端形态/package.json 0 解析到 tmp/p42/node-shared/_dsh-local_ai1net/lib/index.js 8405 B
装配 · 端B 平台形态 --profile-json tmp/p42/端B-平台形态/package.json 0 同上(两端解析到同一份落下来的产物)
取数(via 端B) 同上 0 真实 import + 真实模块求值;inject=['connection'] ✅
取数(via 端A) 同上 0 两端加载同一份 ⇒ 一致
回调(via 端B) 同上 0 真实 apply(ctx),routeCalls 逐字记录 {"path":"/api/ai1net/ping","methods":["GET"]}
v-baseline.sh 47 共享层 + 本机 desktop profile 0 平台侧 4 包;客户端侧 4 bundle
包内门禁 node scripts/build.mjs --check-only(包目录) 0 「✅ 门禁通过」(含数据面 ①d 段,DECL_DIGEST=88c752a3e12597b3…)

⇒ S2 / S3 的绿没被本棒弄红(尺子一行未改,用 P39_OUT 把读数引到 tmp/p42/ruler/,⛔ 未覆盖 p40/p41 读数)。

⚠️ 未取到 / 不成立(如实)

项 结果 原因
S4-6 实例页「能力管理(插件/技能)」栏开始出现 ⚠️ 未取到 需真壳在跑;启动器属客户端线(dsh-ai1net-desktop/.workbuddy/_devkit/launch-desktop-dev-017.mts),本线 ⛔ 不代启
v-ui.sh(浏览器级) ⚠️ rc=3 未取到 CDP 127.0.0.1:9330 不可达 ⇒ 本机无运行中的真壳(与前两棒同因)
v-plugin.sh 运行 面 ⚠️ 不成立(空真) 可用启动日志 mtime = 2026-09-25T09:19:43,早于本包存在 ⇒ "无失败条目"不构成证据
真机投放(把包真投到 47/106) ⛔ 刻意不做 属硬边界「⛔ 不代用户起实例 / 不碰把包装进去」;且包尚在沙箱验证阶段

八、🔴 平台既有链路的真实行为 vs 沙箱建模(逐条标注 · ⛔ 不许把建模当"已通")

项 平台既有链路的真实行为(读码 + 真机只读取证) 本棒做法 是否 = 真实
对账/产物/回报三个端点 真端点存在且在跑:真机 .node-sync-reports.json 有 w-106 的汇报行(authoritative:4 missing:[] stale:[] extra:[]),时间 09-26 沙箱同口径建模(本机 http) ⚠️ 建模
指纹算法 hashTree(Manager)与 hashTreeAt(节点)两份实现、同算法,靠 test/shared-layer-sync.test.mjs 钉住 两份都照抄,互相对照 + 真机锚点验证 ✅ 真实(见 §六)
flat 名/link: 目标 /var/lib/dshs/bundled-plugins/<sanitizeFileName(pkg)>,真机实读 4 个 flat 口径照抄,路径本地等价 ⚠️ 口径真实、路径建模
@deepseek-ai 软链 真机 4 个包全部已有:→ /usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai 本机真 scope 目录(见 §九) ✅ 形态与目标形状一致
鉴权 真平台查 dsh_hosts.agent_token 表(nodeIdentity) 沙箱只比固定令牌 ⚠️ 建模
版本 / 通道 / 钉版 真平台有 .versions/ 归档 + channel{stable,canary} + pinnedHosts(真机台账实读 dsh-plugin-mcn-suite 两个键都在) + resolveSharedTarget(钉版 > 通道 > 现役) 沙箱只做"现役一版" ⚠️ 未覆盖 B-1/B-2/B-3 三条路
审计落库 真平台写 app.db.audit(shared_layer_report) 沙箱只写文件 ⚠️ 建模
传输 真平台走公网 / relay(47↔106) 回环 ⚠️ 建模

🔴 结论纪律:本棒能断言的只有 —— 「照抄的那段拉取逻辑,在既有口径下四步跑通、三条反例成立、指纹与真机权威同源」。⛔ 不能据此断言「真机投放已通」「门户链路已通」「跨机对账已通」。真机投放属 S9/部署面。


九、S4-4 @deepseek-ai/* 软链(缺链现象 = "包在但加载不了")

════ S4-4 ════
  ✅ 解析到**本机真实** dsh scope 目录(⛔ 不是造一个)
       scope=E:\github\dsh-desktop-0.1.7rc2\apps\desktop\.desktop-build\development\project-adapt\node_modules\@deepseek-ai\dsh\node_modules\@deepseek-ai
  ✅ scope 的父链确是 `<dsh 包根>/node_modules/@deepseek-ai`(用权威 isDshPackageDir 的同一判据)
       dsh 包根 package.json name=@deepseek-ai/dsh
  ✅ scope 目录**名字层**含 dsh 宿主子包(dsh-base / dsh-agent)  —— 共 119 项
  ✅ (预置后)三包链都在 ⇒ 本轮全 kept,一个字节没动
  ✅ 软链指向本机 scope · _dsh-local_ai1net / _dsh-local_probe2 / _dsh-local_leftover
  ✅ 缺链 ⇒ 补齐(linked=1),即"包在但加载不了"会被自愈
  ✅ 幂等:第二轮全 kept,一个字节没动
  ✅ 负控:指歪的链被纠正(relinked=1)
  ✅ 软链不计入 treeSha256(补链不改变指纹 ⇒ ⛔ 不会因此永远 stale)

🔴 为什么"必须每轮全量补"(照抄段注释):软链不进指纹 ⇒ 缺链的老包永远不会被判 stale ⇒ 只在铺装那一步补的话,老包会永远缺这一条。 ⚠️ 一处如实:本机这份 dev 副本的 scope 里,这些条目是 pnpm 软链指向 monorepo packages/**,而该路径在本机不存在(悬空)—— 那是客户端线 dev 构建的现状,与本棒无关。本棒验证的不变量是"链指向本机解析出的 scope",⛔ 不验证 scope 内部是否可用。


十、§4-C1–C6 坑对表(逐条)

# 现象 本棒怎么处理 证据
C1 永远 stale / 每轮全量重拉(指纹算法两侧不一致) 两份实现都照抄;跨实现互算 + 真机锚点;3 条负控证明判据能变红 §二 / §三 / §六;第二轮 packCalls 停在 2(不重拉)
C2 对账与下载共用一个超时 syncTimeoutMs / downloadTimeoutMs 分开,packBytes 提示动态放宽、封顶、最低速率 —— 全部可被环境变量覆盖、⛔ 不写死 逐字照抄;黑洞反例走的是同步超时那条路径
C3 link: 目标两机不同 ⇒ 装配失配 两端 link: 字符串逐字相同;flat 名与权威 sharedDirNameOf 同口径 §四
C4 ERR_MODULE_NOT_FOUND(包在但加载不了) 补链 + 缺链补齐 + 指歪纠正 + 幂等 四条判据 §九
C5 「不知道」被折算成「一致」 节点侧无记录 ⇒ 报 null(⛔ 不报假 hex);平台侧指纹只认 64 hex,其余当 null ⇒ 判 stale 重拉一次自愈 逐字照抄;实测第二轮 stale=[] 且 packCalls 未增
C6 失败一轮全放弃 / 删了不该删的 三条语义纪律逐条实测:① 取不到 ⇒ 零改动 ② 单包失败 ⇒ 只记 failed,其余照常 ③ extra ⇒ 只告知、⛔ 不删 §五

十一、硬边界自查 / 遗留 / 回滚

  • ⛔ 未改官方 dsh 主程序与缓存(R2):本棒只读 D:/github/dsh_shenxian/src/**(照抄来源)与本机 desktop 构建的 dev 副本,零写。
  • ⛔ 未重造分发与更新机制:全部照抄(§二 对照表 11 段 + Manager 侧 4 段)。
  • ⛔ 未代用户起实例;⛔ 未把包装进任何 profile(装配用的是 沙箱 profile,真件 profile 只读引用)。
  • ⛔ 未改客户端工作区 dsh-ai1net-desktop / dsh-desktop-0.1.7rc2 任何文件(只读引用;端A 是 profile 副本)。
  • ⛔ 包内零改动:E:/ProgramData/AIProject/dsh-plugin-ai1net/ 一字未动。
  • ⛔ 未 commit / 未 push;真机侧零写(只读 tar 取包 + 读 .manifest.json / .node-sync-reports.json / ls -l 软链)。
  • ⚠️ 红线门禁:本棒未触发任何一项 —— 未重启控制面、未中断在线用户、改动文件数 < 10、无不可逆操作(沙箱目录可整体 mv 归档)。
  • 🔴 停点:S4 的 P1 已解除(09-26 13:30 用户拍板 = A「放开桌面只读读包权」);S9 的 P2 仍待拍板,⛔ 本棒未跨过。
  • 遗留(如实):① S4-6 / v-ui.sh 仍欠一笔真壳取证(客户端线窗口)② 沙箱未覆盖版本/通道/钉版三条路(真平台有,属 S9/发布面)③ tmp/p42/real-anchor/_x-* 是真机锚点的解包暂存(含 mcn-suite 659 文件树),因安全删除护栏(一次删 >50 文件需确认)保留未删 ⇒ 随 tmp/ 7 天口径处理,⛔ 未绕过护栏。
  • 回滚:本棒 无生产副作用 ⇒ 回滚 = mv tmp/p42/ 归档/(按 §七 规格书回滚口径,⛔ 不用 rm)。沙箱外部唯一变化 = 沙箱共享层里的软链与 profile 副本,全在 tmp/p42/ 内。

十二、出处

  • 规格书:D:/github/dsh_shenxian/dsh-server-docs/05-交接单/交接单_包规格书_20260926.md
  • 方案:交付物/功能打包到基础插件-分步实施方案-20260926.md §3.10.6 / S4 段 / §4 C 类
  • 前置回执:交付物/数据面-S3落地与三轮回执-20260926.md
  • 权威实现(只读):D:/github/dsh_shenxian/src/worker/agent.ts|src/supervisor/plugin-assembly.ts|src/web/routes/business-plugins.ts
  • 本棒产物(⛔ 不入库):tmp/p42/{puller,mgr-mock,run-s4,anchor-real}.mjs|tmp/p42/读数-20260926.txt|tmp/p42/尺读数-S4-20260926.txt|tmp/p42/real-anchor/