回收 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)、记忆修复前备份。
184 KiB
2026-09-18 工作区日志(append-only)
序 ㉗ 执行棒(覆盖网络线 · E3 候选数可查)· 00:3x 收官
依据 = 用户 2026-09-17 23:1x 拍板「2、B」⇒ 授权改 src/worker/relay-tunnel.ts / src/web/server.ts 以暴露候选数(序㉖ 因超 §3.1 在册集、按 §9-5 停下的那一步)。本棒无独立交接单,报告写在入口 接续入口_覆盖网络线_20260916.md §0 最新行。
做了什么
src/worker/relay-tunnel.ts:新增CAND_OBS_PREFIX/candidateObsMs()/candHostsOf()/RelayCandidateSnapshot/RelayCandidateObservation(固定 key 序观测行;只读、零网络 I/O;周期重发上次快照、unref);接入RelayTunnel构造 +ensureMaster()(非阻塞一枪observeCandidatesOnce(),⛔ 启动不依赖网络)+close()。src/web/server.ts:C1(Manager 拨号)接入同一观测器;新增resolveChain()把candidates与refreshOverlay两处调用收口(注释里写了字级等价证明)。scripts/overlay-probe.cjs:新增OBS-21(双判据:该路径有观测行 +count ≥ CAND_MIN)+--candidates-fixture-47/--candidates-fixture-106;前缀不硬编码(r.need('CAND_OBS_PREFIX'))。- 参数表
参数表_覆盖网络_20260917.md:§3.7 新增 5 键 + §6 新增OBS-21+ §11.1 补记。 test/relay-failover.test.mjs:新增 O1–O4(锁 key 序/防刷屏/「从未解析」≠「解析出 0 条」+周期重发零网络/env 解析不静默变 NaN)。
验收
- 先红后绿(原文级):夹具四段 RED ⇒
FAIL(47=3 ✓ / 106=1 ❌)|GREEN ⇒PASS|NOLINE ⇒ FAIL(原文 225 字节 / 含前缀 0 条)|WRONGSCOPE ⇒ FAIL(154 字节 / 含前缀 1 条)。全夹具 RED vs GREEN 只差OBS-21一行。 - 真机先红:新探针对旧生产 ⇒
FAIL OBS-21三路径全部「无观测行(原文字节 0)」。 - 零回归三件套:
npm test201/200/0/1(基线 197/196/0/1 + O1–O4)|--scene all --table12 PASS/0 SKIP/0 FAIL|overlay-probe --table19 PASS/1 SKIP/1 FAIL。
部署
lib/worker/relay-tunnel.js + lib/web/server.js scp 到 5 处(47 /opt/dshs/lib+/opt/dsh-relay/lib、106 /opt/dshs-cluster/lib+/opt/dsh-relay/lib、本机编译产物),md5 全同 = b1bc3e042d8eff1aafc657142e2e99d3 / cf844a2ee312fc167ebadf5b2b9884f2;重启 47 dshs+dshs-worker、106 dshs-worker(动手前取证 47 无活跃实例 scope);回滚点 = 两机 /opt/dsh/backups/seq27-20260918-000259/。⚠️ 重建两次 —— tsconfig declaration: true 且无 removeComments ⇒ TS 注释会进 lib/** ⇒ 纯注释改动也会改产物 md5。
关键发现(本棒最大产出)
🔴 「判据成立」与「冗余建成」已被彻底分开:dshs@47 count=3 hosts=3 ✓ | dshs-worker@106 count=1 hosts=1 ❌。
106 侧根因(106 自己的日志里就可机读):journalctl -u dshs-worker | grep overlay-dir 近 3h 166 行 = ⚠ 拒绝 https://alotbuy.com/dshs-overlay/bootstrap(no-trusted-keys) + ⚠ 取目录全部失败 ⇒ 回落到内置种子地址本身:wss://alotbuy.com/dshs-relay;取证 = /etc/dshs-worker.env 无 DSHS_OVERLAY_DIR_PUBKEYS(计数 0)、无 DSHS_OVERLAY_DIR_CACHE(0)⇒ 目录永远被拒 ⇒ 候选链恒退化为内置种子单点。
⇒ 「建成冗余(≥2 条独立路径)」点名独立后续项 = 序 ㉙(⛔ 未放宽 CAND_MIN 凑绿)。
三条留档(避免后人误判)
- ⚠️ 47 的
nginx.service/bt-server显示 inactive 是正常态 —— 宝塔托管:真正在跑的是bt.service=active,443 上 nginx 在听(pid 在册)、/dshs-relayWS 握手 101、门户经 443 200。⛔ 别拿systemctl is-active nginx判 47 relay 死活(本次演练后核对时差点误判为"演练没还原")。 - ⚠️
OBS-21的hosts= 主机名个数,⛔ 不是独立物理路径数:真机count=3时hosts=3(alotbuy.com与relay-direct.alotbuy.com摘名不同、同落 47),而机器级独立路径只有 2。首轮把它当"独立路径数"写错,已在 4 处修正(类注释 /candHostsOf/Snapshot.hosts/ 探针块注释 / 参数表 §6)。 - 🔴
CAND_OBS_UNITS_47=dshs=manager一项:47 的dshs-worker不是 relay 客户端(grep -c DSHS_RENDEZVOUS_URL /etc/dshs-worker.env= 0、systemctl show … -p Environment里 RENDEZVOUS 计数 0)⇒ 它根本不建RelayTunnel(w-47的跨机面走 Manager 本机LocalRendezvous)⇒ 列进去只会读到"永远无观测行" = 假红。
登记与边界
- 下一棒 = 序 ㉙(执行棒 · 106 候选链建成冗余),automation
cca5c43c-80e6-4bfb-8638-25185608cbbe(一次性 · 2026-09-18 03:00,排在序 ㉘〔01:30〕之后并留足间隔)。⚠️ 已写死:序 ㉘ 收官时 ⛔ 不要再注册 ㉙(号已被占用)⇒ ㉘ 若还有下一棒顺延为 序 ㉚。 - 边界自证:⛔ 未改任何生产值 · ⛔ 未新增公网口(
OBS-11relay 仍只绑回环 1/1、集合多出 0)|⛔ 未改 nft·nginx · 🔴COOLDOWN_MS=0计数 0 · ⛔ 未 commit / 未 push(HEAD04776af)。 - 指纹:参数表
4c78912d03f4f209d417407a80018361→7fc5889341b99fb26bd05cad0313960b(口径 =sed '/^## §10 指纹/,$d' 参数表_覆盖网络_20260917.md | md5sum)|全文 md5 =527b896b11328e68b8e1d2935722cd2c(481 行)|改动源码 md5 =relay-tunnel.ts e7689823a715ca4e489be16fef6761fd/web/server.ts ebd0bb2284644f3d873118383556f128/overlay-probe.cjs e9a6120087a2f0a5719a46372ad04a7f/relay-failover.test.mjs d533b1819bd38c0c6969f5020dfcce98。 - 证据目录 =
_tmp_seq27/(fx*-red/green/noline/wrongscope.txt、leg-*.txt、probe-before/after/final.txt、drill-after.txt、npmtest-after.txt、deploy.sh)。
收口后更正:接续时刻按用户明令压缩(2026-09-18 00:2x ~ 00:3x)
- 用户两次追问排期(原话:「为什么时间要定在3:00」→「㉘ 规划棒 = 01:30 也还有1个多小时呢」→「5-8分钟即可」)。
- 认定 = 我排错了:㉘ 是规划棒,实测同类(序 ⑦/⑨/⑪/⑯/⑱/㉔ 规划棒)6–13 分钟即完成 ⇒ 给它排 2 小时("收口 +
2 h")违反纪律(「接续间隔 = 收口时刻 + 25 分钟」,⛔ 不许拿"留追改窗口"当理由拉长);我随后还按"留 1.5 h 余量"把它推到 03:00 ⇒ 错上加错。 - 更正结果:㉘
b60d5358…01:30 → 00:35(原话 03:00 那一版 ㉙ 也一并前移);㉙cca5c43c…03:00 → 00:43(= ㉘ + 8 分钟)。 - 已同步:接续入口 §0 + §2 两处 ㉙ 行改为"本行为准 ⇒ ㉘=00:35 / ㉙=00:43"+ §2 第 2 棒行的 ㉘ 时刻加更正标注;本日志本行。
- ⚠️ 代价(如实登记):间隔 8 min < 规划棒耗时上限 ⇒ 若 ㉘ 超时未释放锁,㉙ 会按 R9「抢不到 ⇒ 只报告并停」空转一棒。这是用户明令换来的排期,判据 = 用户原话「5-8分钟即可」。
再更正:排期模型理解错了两处(2026-09-18 00:3x)
- 用户第三次澄清(原话):「我说的是首个接续任务 5-8分钟,最好不要建立多个接续任务,一个会话结束时在排下一个」。
- 🔴 我的两处错误:
- 把「5-8 分钟」当成"棒与棒之间的间隔" —— 实际是「从本会话收口到"第一个(唯一一个)"接续任务」的间隔。
- 🔴 同时挂了两个接续棒(㉘ + ㉙)—— 违反「同一时刻只挂一个,下一个由当棒会话收官时再排**」。
- 处置:⛔ 已删除 ㉙ 的 automation(
cca5c43c-80e6-4bfb-8638-25185608cbbe,用automation_update --delete,⛔ 未用任何文件系统手段);㉘ 单独保留,时刻 = 2026-09-18 00:37(≈ 收口 + 5~8 min)。 - E3 冗余项没有丢:已把它整段改写进
接续入口 §0 + §2的 ⏭️ 本线下一项(⛔ 不预登记) 行 —— 含根因 / 取证要求 / 改动首选 / R5 停手条件 / 验收基线,由 ㉘ 在其收官时照此立棒(正好符合"一个会话结束时再排下一个")。 - 规则已固化到
MEMORY.md §三:⛔ 同一时刻只挂一个接续棒;间隔 = 收口 + 5~8 分钟(到首个接续棒)。
接续规则加固:两条铁律从「状态层」升到「规则本体」(2026-09-18 00:3x–00:4x)
触发:用户「看最新会话『覆盖网络线-序27执行棒-E3候选数可查』最后 3 轮对话,发现问题 更新接续会话的规则」。
取证:dd6abea4-3254-4499-a33a-0ac8307efb00.jsonl 的最后 3 轮(记录索引 488 / 491 / 534)。
🔴 真问题(比"我当场理解错"更深一层):上一轮虽然把两条铁律写进了 MEMORY.md §三,但 规则本体(技能 dsh-auto-handoff-chain §3.1.1)里仍是用户已推翻的旧值「2~5 分钟」,且完全没有"同一时刻只挂一个"这一条 —— 换会话 / 换项目时,旧值会被原样再执行一遍。⇒ 规则只写进状态层 = 没落地。
改动(4 个文件 + 1 个镜像)
- 技能
dsh-auto-handoff-chain/SKILL.md(1.3.2 → 1.4.0;md5c16975a0ba31291a5f3318d9ba914ff2,22058 B,纯 LF):§3.1.1 重写为排期两条铁律(① 首个/唯一接续棒 = 收口 + 5~8 分钟,⛔ 不是"棒与棒之间" ② 同一时刻只挂一个,⛔ 不预登记队列)+ 边界表 + 一棒之内两处都犯的事故表;§2 骨架收尾行 / §3 四件套 ② / §4 防护⑤(并新增⑥「预登记多个接续棒」,五条 → 六条)/ §6 落地清单 同步 - 三处同步完成:本机 ↔ 文档库
dsh-server-docs/skills/↔ 47 镜像/opt/dsh/docs/skills/—— md5 全同 会话接续规范_20260916.md§3.2.2 链路图(+2 分钟)→(收口 + 5~8 分钟),并补「登记的两条铁律」表dsh-server-docs/INDEX.md三处:§22 指针行 / §17404-125摘要(旧值 2~5 加更正)/ §185 技能清单(五条 → 六条)- 工作区
CODEBUDDY.md §2指针表新增一行「登记接续棒 / 排下一棒」⇒ 指向技能 §3.1.1
⚠️ 生效性差异(重要):技能是调用时现读 ⇒ 本改动对下一棒立即生效;CODEBUDDY.md 的改动需完全重启 WorkBuddy 才重载。
⚠️ MEMORY.md 注入已实测被截断(>7–8 千字符)⇒ 规则实体不能只靠它承载(本报告的真正动机)。
日志底座评估:amber vs Loki/Alloy vs 不装(2026-09-18 20:4x,用户提问触发)
问题:能否在 106 装 amber 日志服务,它是不是本项目最适合的开源日志服务。
取证(只读,两机实测):
| 机 | CPU | 内存(可用) | 磁盘空闲 | journald 占用 | docker / go |
|---|---|---|---|---|---|
| 106 | 4 | 3.6 G(2.2 G 可用) | 30 G | 130 M | none / none |
| 47 | 2 | 1.9 G(975 M 可用) | 23 G | 768 M | docker ✓ / go ✗ |
amber 事实(github.com/yaop-labs/amber,官网+repo 实测):OTLP 原生日志/追踪/指标单一二进制,Apache-2.0,273 commits、单一维护者 dmedovich、最后提交 2026-08-29;无预编译 release(只能 make build / docker build);metrics 引擎自标 alpha(int64 存储、scale 默认 1000);落盘异步、OTLP at-least-once 且 0.4 明确不做去重;默认 retention.* 全 0(= 不限制),disk_stop_free_bytes 1 GiB。
判定:✅ 能装(106 是两机里唯一放得下的);❌ 但不是最适合,作为本项目日志底座不合适。三条理由: ① 它不是采集器——journald → OTLP 仍要一个 agent(Alloy / Vector / otel-collector)⇒ 组件数并不比 Loki 方案少; ② 成熟度与本项目判据链冲突——本项目大量验收判据是日志原文的字节数/行数,而 amber 是"异步落盘 + at-least-once + 不去重 + 无预编译产物",判据来源会从"系统事实"降级为"新项目 API 输出"; ③ 部署链路更绕——两机都无 Go 工具链,而 47 只剩 ~975 M 内存 ⇒ 构建本身就是代价。
正解排序:C(不装,先补"跨机只读拉取")→ A(Grafana Alloy + Loki 单机版,装 106;Alloy 是 Promtail 的官方后继,Promtail 已于 2026-03-02 EOL,Alloy 用 loki.source.journal 直读 journald)→ B(amber 仅作 106 旁路试点,只绑回环、不进判据链)。
触发条件(到点才上 A):实例数 ≥ ~10 或日志量涨到 GB 级/周,或"跨机时序对齐"类排障反复发生。
🔴 任何新监听口都只绑回环(或走既有 nginx 443 反代)⇒ 不新增公网口、不动 nft/nginx(R5 边界);⛔ 日志底座不放 47(内存不够)。
日志可观测面落地:方案 C 实现(2026-09-18 21:0x–21:4x)
用户决策:选 C(不装 Amber / 不装 Loki+Alloy,用现有 journald + 自研观测面),并要求实现"多节点日志存储 + 实时 bug 监控 + 事后溯源"。
交付物:代码仓 scripts/dshlog.mjs(Node 22 单文件、零第三方依赖、8 个子命令)+ 档案 dsh-server-docs/04-调整方案/129-日志采集与巡检-方案C实现.md。
关键取证(都实测过,别凭记忆)
journalctl --version:47 = systemd 239、106 = 255;两机 NTP 均NTPSynchronized=yes;journald 均 persistent(47 = 769 MB / 106 = 130 MB,都未设上限)。- 🔴 实例
dsh --profile的 stdout 不进 journald ——_SYSTEMD_UNIT=dsh-<uid>-<hash>.scope与journalctl _PID=<实例pid>双证为空,实例fd/1指向socket:[…](被 Worker 接管)⇒ dshlog 抓不到实例层日志,这是本方案最大剩余缺口。 - 当日日志分布:47 =
dshs29k /dshs-worker7.3k /sshd3.8k;106 =user@02.6k /init1.6k。
踩坑(已写进档案 §6,下次别再犯)
- 🔴
ssh -C是硬前提:47 出方向未压缩实测 ~20 KB/s(1.6 MB 要 84 s),开压缩后 11 s(7.6×)。不加会看起来像代码 hang(第一版 3 h 回填超 5 分钟被外层超时杀掉,误判成死锁)。 - 数据/元信息必须双通道:远端
awk转发 stdout(数据)+ 行数写 stderr(__DSHLOG_LINES__)+__DSHLOG_EOF__ rc= errbytes=⇒ "确无日志"与"拉取失败"天然可分。 - 归档必须同步写 + gzip 多成员:
createWriteStream异步管道在收尾时可能未 flush ⇒ 静默丢最后一批;改appendFileSync(gzipSync(...))。 - 回填去重靠
__CURSORSet(实测跳 8100 行重复),续拉靠--after-cursor(精确不重不漏)。 - 校时用 NTP 状态,别自造往返估算:第一版给出 +1337 ms 假偏移(47 的 ssh RTT 3.7 s 且不对称)⇒ 拿它校正会制造错序。
- 版本号解析必须
awk 'NR==1{...}':journalctl --version是多行 ⇒ 变量变"239\n0"⇒[: integer expression expected⇒ 静默退回全字段(体积翻倍)。 - 巡检规则收紧:
fatal裸写会被 sshd 的ssh_dispatch_run_fatal天天命中;Stopped .*裸写会把实例正常退出当崩溃 ⇒ 都已收紧 + 排除sshd/crond/systemd-logind噪声单元。
验收(真机):增量续拉 19.5 s/回填 6 h = 2 分 28 秒/归档 47 = 35,603 行 · 106 = 5,988 行;watch 在 106 上真报出 ⚠ 取目录全部失败(= 序 ㉗ 记录的 E3 缺口),非误报。
边界自证:新增公网监听口 0 · 服务器侧新增常驻进程/安装 0(只用系统 journalctl,脚本走 bash -s stdin)· 生产值改动 0 · 归档在 E:/dsh-logs/(不在仓库内)。
顺带改的一处:技能 dsh-instance-diagnose 加「第 0 层 · 跨机日志取证」(指向 dshlog)+ 三条必知,1.0.0 → 1.1.0;三处同步 md5 一致。⚠️ 同处如实记下:实例层缺口的说明写在技能里,避免下次又以为"日志能覆盖实例"。
待用户拍板:是否挂周期 automation 做"实时"巡检(A 每 30 min ≈ 250–430 积分/天 · B 每天 1 次 · C 不挂、按需手动)。我的倾向 = C,理由 = 实时性的积分成本与当前规模不匹配,且已有 overlay-probe.cjs 承担判据式主动探针。
澄清(用户 21:2x 追问"日志存哪 / 存本机吗 / 启动了哪些服务")
⚠️ 这个误会值得记:用户问"启动了哪些服务",答案 = 什么都没启动。实测取证:
- 服务器侧零安装:47 上
/opt/dsh/scripts/dshlog.mjs、/usr/local/bin/dshlog*、/etc/systemd/system/*dshlog*全不存在。 - 本机零常驻:node 进程数 0、无 pid 文件。
- ⇒ 当前是纯手动按需:跑一条命令 → ssh 拉一批 → 退出。不跑就没有新数据。要"实时"必须挂 automation(= 上面那个未定的拍板项)。
数据存在两处(不是"搬走了"):
| 位置 | 内容 | 现状 |
|---|---|---|
| 服务器本机(原始·权威) | /var/log/journal/<machine-id>/,系统自己写,未被动过 |
47 = 769 MB · 106 = 130 MB;journald.conf 无上限设置 |
| 本机镜像(副本·便捷) | E:/dsh-logs/<host>/<日期>.ndjson.gz(gzip 压缩、按天分片) |
47 = 1.15 MB · 106 = 218 KB · state.json 825 B(游标/时钟状态) |
⚠️ 两个体积不可直接比 —— 服务器那份是全机全历史未压缩(所有单元所有天),本机那份是已抽取的压缩副本。
日志保留策略 = 3 天落地(用户 21:2x 明令「把旧日志清理 只保留3天的日志就行」)
动作:47 / 106 各写 drop-in /etc/systemd/journald.conf.d/10-retention.conf(⛔ 不覆盖主配置)+ journalctl --vacuum-time=3d + restart systemd-journald;本机 dshlog prune --keep 3(默认值已从 14 改为 3)。
MaxRetentionSec=3d | SystemMaxUse:47 = 512M / 106 = 192M | SystemMaxFileSize:47 = 32M / 106 = 8M。
结果:47 768 → 160 MB(释放 608 MB)|106 130 → 70.3 MB(释放 59.5 MB)。两台 journald 均 active,配置已生效。
🔴 踩坑(务必记住,下次别再按错判据估):--vacuum-time 的判据是
「分片起始记录时间」,且按整片删除 ⇒ 实际保留期 = 3 天 −(0 ~ 一片跨度)。
- 我执行前误判为"按末记录判",首次估算偏差 ⇒ 删多了:
- 47 保留跨度只剩 1.35 天(09-17 13:05 起)—— 因默认分片 128M ≈ 1.5 天/片
- 106 保留跨度 2.44 天(09-16 11:29 起)—— 因分片 47M ≈ 3 天/片
- 永久丢失区间(本机归档当时未覆盖 ⇒ 无副本):47 = 09-15 13:33 ~ 09-17 13:05;106 = 09-13 12:54 ~ 09-16 11:29。
- 修法 = 压小分片提高精度(已做);47 的跨度会随新数据每日增长约 1 天,约 1.7 天后自然恢复到 3 天,无需人工干预。
- 已把该判据 + 偏差留档写进
04-调整方案/129-…md §8.1(并 scp 到 47,md5 一致)。
覆盖网络线 · 序 ㉘ 规划棒收官(00:37–00:5x)· 两项架构级改造各出一份执行单
本棒 = 只做规划:⛔ 零代码改动 · ⛔ 零服务器改动(仅两机各一次只读 systemctl list-units --type=scope + systemctl show -p Environment)。
产物(工作区根,各带 8 段模板)
交接单_退出路径不杀实例_20260918.md(单 A · 归档号 129 · §8 前前缀c9aeac82381f569fc8b9effad0fefa99· 落单快照全文 md5b1b93471081e10d9be9c28aa9b5c1d3c/387 行)交接单_组密钥加密_20260918.md(单 B · 归档号 130 · §8 前前缀149596460288ca1a5b7abddc490f7909· 落单快照全文 md540d35357a501596dcd1e6d7e70e8b371/349 行)
归档号现核(⛔ 教训:prompt 写"至 112"已过期) = ls 04-调整方案/ | grep -oE '^[0-9]+' | sort -n | tail -1 ⇒ 128;mkdir .lock-129 / .lock-130 均成功 ⇒ 号可用;⛔ 63 空号不补占已复核。⚠️ 取证:本线 16 份 交接单_*.md 均无 04 孪生(带孪生的是方案类文档,如 123- ↔ 根同名 md5 同值)⇒ 占号窗口落单后释放,收官建档案须重新现核。
本棒三条取证事实(已写进 §0,⛔ 与上游结论冲突时以本棒为准)
- 处②
RemoteSpawner.teardown()已经就是 no-op(与git show HEAD:逐字相同,函数体只有一行注释)⇒ 用户口径"三处一起改"与"处② 已符合"不矛盾:三处都纳入在册 + 都加机器断言,但处② 语义改动 ≈ 0。 - 两机活跃实例 scope =
47:0/106:0⇒ 单 A 的验收必须先在真实形态夹具上做,⛔ 不许拿0 == 0当绿(已写成 §5 反例条款)。 idle-reap缺省启用且 TTL 很长(config.ts:300-302:60 s / 7 天 / 每 host 4;两机 env 未覆盖)⇒ 单 A 的前提"进程长期不重启时由 idle-reap 收"成立但很慢。
单 A 设计要点:三处逐处最小差异(① 真改 ② 只补断言 ③ 拆开"停心跳"与"停实例")|判据三层 P0→P1→P2(🔴 P1「判据成立」与 P2「回收链建成」必须分开报:scanned==0 而计数守恒 ⇒ 必须点名,⛔ 不得写全绿)|对冲项(静态 grep + 动态单测 + OBS-22 三判据)|C 单列一段(含 4 条回头信号 + B→C 四步迁移路径)|与 lease/配额/端口区间/dsh_hosts/provisioner 逐项关系。
单 B 设计要点:组 = 复用序㉔ (network,group);算法栈 = 复用 src/crypto.ts 的 AES-256-GCM;确定性(收敛)加密保证组内密文一致 ⇒ 按哈希共享块仍成立。🔴 本棒纠正一条上游前提:「块 id 用明文哈希 ⇒ 跨组也能共享同一块」在本方案下不成立(组外没有组密钥 ⇒ 拿到密文也解不开;且 E5 本就要求跨组 0 穿透)⇒ 明文哈希净收益 ≈ 0、只剩泄漏块存在性的缺点 ⇒ 推荐密钥相关/密文相关哈希(sha256(密文)),其唯一代价 = 轮换 ⇒ 全量回源(写成参数下限 + 回头条件)。🔴 分发受节点密钥是 ed25519、做不了公钥包裹这一硬约束 ⇒ 本阶段密钥本体不经 relay(走 0600 文件),规模化自动分发登记为回头条件。
收尾:下一棒 = 序 ㉚ 执行棒 · 单 A,automation 11982d2f-6608-456a-b500-a6dfcc6bbb0f(一次性 · 2026-09-18 00:50 = 收口 +6 min);㉙(106 候选链冗余)本轮⛔ 未登记(同一时刻只挂一个棒;cca5c43c 已用 automation_update list 复核确认确已删除),由单 A 收官时登记。定序写死:单A → ㉙ → 单B(单A 是用户 23:3x 纠错的直接产物且结清待拍板阻塞项;㉙ 最小却能让探针转绿、恢复判据灵敏度;单B 最大放最后)。入口 §0/§2 已推进。
顺带(系统要求):MEMORY.md 注入被截断 ⇒ 就地合并压缩 8101 → 7782 字符(合并 §一 表格 8 行→5 行、更新过期值:归档号 112→128、参数表指纹→7fc5889341b99fb26bd05cad0313960b、npm test 基线 176→201),并新增两条:ACTIVE ≠ 待跑、本线交接单不带 04 孪生。⚠️ 四类硬规则(R10/bwrap/数据分层/buffer.write/Playwright/接续两铁律/COOLDOWN_MS=0)已逐条复核仍在。
边界自证:⛔ 零代码改动 · ⛔ 零服务器改动 · ⛔ 未改任何生产值 · ⛔ 未新增公网口 · ⛔ 未改 nft·nginx · 🔴 COOLDOWN_MS=0 计数 0 · ⛔ 未 commit / 未 push(HEAD 04776af)。
2026-09-18 05:3x · 序 ㉚ 执行棒(单 A:退出路径不杀实例)收官
定位:覆盖网络线 · 序 ㉚(执行棒 · 单 A),依据 = 工作区根 交接单_退出路径不杀实例_20260918.md(归档号 129)。
锁:覆盖网络线-序30执行棒-单A(00:50 抢到 → 05:4x 释放)。
做了什么
- 三处
teardown()最小改动:LocalSpawner.teardown()真改(删掉"逐 uid 停实例"循环);RemoteSpawner.teardown()取证已是 no-op(与 HEAD 逐字相同)⇒ 只补守卫标记;LeasedSpawner.teardown()拆开"停心跳"与"停实例"(保留stopHeartbeat())。 - 新增
test/orchestrator-teardown.test.mjs9 用例(⛔ 刻意不进npm test—— 那是硬编码文件列表)。 - 探针新增
OBS-22(静态守卫读部署产物 + 认领面);参数表 §3.8 +6 键(TEARDOWN_*,只被探针读、⛔ 不写 env)、§6 +1 行。 - 单 A 回填 §8.1–§8.12(§8.12 = 回滚路径补正,⛔ §6 正文一字未改以保 §8 前前缀)。
判据(可复现)
- 先红后绿:P1 对旧生产
1 → 0(两机);OBS-22对旧产物 FAIL 并点名orchestrator「await this.stop(userId);」;单测红 3(T1/T5/T6,逐处点名)/ 绿 9,还原为字节级。 - 主判据 P1 + P2 双绿:47 worker
1 → 1、106 worker1 → 1、47 Manager1 → 1(非判别腿);{"scanned":1,"adopted":1,"stopped":0}自洽 +probe OK :20000 / :21000。 - 零回归三件套:
npm test201/200/0/1 |--scene all --table12P/0S/0F | 探针 21P/0S/1F(1F =OBS-21线内在册缺口,⛔ 非本单引入;OBS-09SKIP → PASS)。
部署 / 回滚
- 4 处(47
/opt/dshs/lib+/opt/dsh-relay/lib;106/opt/dshs-cluster/lib+/opt/dsh-relay/lib),md5 全同:orchestrator.js = 1456d1609f5872c2d635ae7cf4f5c26b/remote-spawner.js = 0438afd5738176999d3a4f4f404c9435/leased-spawner.js = 12ba045990b2054aaeebeb2c95d70f83(05:3x 复核未漂移)。 - 回滚点 = 两机
/opt/dsh/backups/seq28-20260918-005909/(6 文件,含relay-*.js旧值)。 - 重启 47
dshs+dshs-worker、106dshs-worker(⛔ 未重启dshs-relay);门户 200。
指纹
- 参数表:
7fc5889341b99fb26bd05cad0313960b→3b295a8c43aafc4a62c6f1a59ea0b43a - 单 A §8 前前缀:
c9aeac82381f569fc8b9effad0fefa99(回填后逐字不变 = 截断点口径自证);全文 md5681b84d503a1578178707a9ba6d87351/584 行(现算)
三条必须记住的
- 🔴 47 的
dshs=LeasedSpawner(new RemoteSpawner(…))(DSHS_DEPLOY_MODE=cluster)⇒ 不构造LocalSpawner⇒ 「47restart dshs」是非判别腿(恒绿假判);判别腿只在两台dshs-worker。 - 🔎
/opt/dsh-relay/lib/supervisor/两机各有一份副本(曾落后 2 版)⇒ 铺 relay 类产物要四处都铺;本次一并铺平,旧值存同一回滚点。 - ⭐ B 的收益边界:实例不被杀 + 用户访问时自然替换,⛔ 不是"重启后可直接进"(
launchToken不可恢复 ⇒enter可能 503);替换窗口内会短暂留 1 条 stale 端点条目(OBS-08/OBS-11该窗口内会红,自愈时延未测)。
独立后续项(登记,⛔ 本棒未扩大)
summary.probeOk恒 0(既有观测面缺陷 ⇒ 判据⛔ 不可用probeOk ≥ 1;修法 = summary 挪到探活回调之后)。- 「自然替换窗口内 stale 端点条目」自愈时延未测。
- 单 A §10 的 6 条未验证项(一条未验)+ 架构目标
C(§7.2,登记不执行)。
接续
- 下一棒 = 序 ㉙(执行棒 · 106 候选链建成冗余),automation
22170b0b-a606-461c-82a7-2f72fea68082(一次性 · 2026-09-18 05:45 = 收口 +~7 min)。定序仍写死:单 A → ㉙ → 单 B(组密钥加密);单 B 由 ㉙ 收官时登记。 - 入口 §0 已插最新刷新行、§2 首段已改写为序 ㉙ 口径(原序 ㉚ 段降级为存档)。
边界自证:⛔ 未改任何生产值(§3.8 六键只被探针读取)· ⛔ 未新增公网监听口 · ⛔ 未改 nft·nginx · 🔴 COOLDOWN_MS=0 计数 0 · ⛔ 未 commit / 未 push(HEAD 04776af)· ⛔ 未删 cleanStaleScopes(uid) · ⛔ 未改 bwrap 参数。
05:3x · 会话数据规模评估 + 「能否同步到 dsh_shenxian_session.git」取证(只读,未动手)
问题:用户问「这个工作空间的 session 有多大,能否同步到 [email protected]:maogeigei/dsh_shenxian_session.git」。
会话库落点(🔴 判据):E:\ProgramData\.workbuddy\projects\<cwd 编码名>\ —— 本工作区 = e-ProgramData-AI技能-aliyun-dsh-server\
(按工作区根路径编码命名;旧 D:\AI技能\... 另有 d-AI技能-aliyun-dsh-server\ 一份残留)。
每会话三件:<id>.jsonl(正文,追加式)+ <id>.meta.json + <id>.file-rollback.ndjson(41 份)。
实测(2026-09-18 05:3x):187 文件 / 245,991,247 B ≈ 235 MiB / 69 个会话 / 活动跨度 09-13 14:37 → 09-18 05:38(≈5 天)
⇒ 粗算 ≈49 MB/天(原始);最大单份 3c12a818….jsonl = 24.2 MB;gzip 实测 6.2x(24.2 → 3.9 MB)⇒ 全量压后 ≈ 40 MB。
旧 D: 盘那份 d-…-aliyun-dsh-server = 76,784,415 B ≈ 73 MiB(09-15 搬迁前)。
🔴 敏感串计数(只数不打印原文):ak_… 6 | sk-… 15 | Bearer … 15 | dsh-auth-… 699 | mksess 6133 | password 1130
⇒ 会话正文确实含可用凭据(含 Redfox API Key)。git 历史永久 ⇒ 推上去即不可撤回。
目标仓库现状(与用户假设不同,必须先说):
dsh_shenxian_session.git 与 dsh_shenxian_doc.git 的 HEAD/main 同为 9b57578(2026-09-14 23:01 maogeigei "docs: 档案 98 治本")
⇒ 该仓现在装的是 09-14 冻结的文档库快照(162 文件、04-调整方案 最大到 98),不含任何 session;
09-15 文档库并入代码仓(dsh_shenxian.git)后,这两份独立文档仓即不再更新。⇒ 往里推会话属"改用途",且不是空仓。
技术可行性:✅ 可推 —— 仓库存在、SSH 可读、单文件最大 24 MB 远低于常见上限;--depth 1 浅克隆实测 935 KB。
未做:未写库、未推、未删该仓既有内容(删除不可逆 ⇒ 需用户明确指令);/e/tmp/dsh_session_probe 探针副本已清理。
待拍板(已在回复末节按 A/B/C 竖排给出):凭据处理方式 —— 原样 / 脱敏 / 加密归档。我的技术已定项:落位用 sessions/<工作区名>/ 子目录,不动既有快照。
06:3x–06:4x · 复盘「为什么又弹授权窗」(用户质问:不是已经授权了吗)
结论:那个弹窗不是 WorkBuddy 的授权闸门,是 git 自己的凭据管理器 GCM。
证据链:
E:\\ProgramData\\.workbuddy\\audit-log\\spool\\audit-spool-40716-2026-09-18.jsonl⇒06:32:34 | command-safety.sandbox-executed | allowed, 内容正是我那条CNB https 探测⇒ 平台已放行(同日 06:30:27 的 hot.ts 探测同样 allowed)。~/.gitconfig:[credential] helper = !"…/mingw64/bin/git-credential-manager.exe"(全局挂 GCM)+[credential "https://work.alotbuy.com"] provider = generic+[http]/[https] proxy = 127.0.0.1:10800。⇒work.alotbuy.com一直走 SSH(key 已通、不进 GCM、从不弹);cnb.cool是没配过凭据的新 HTTPS 主机 ⇒ GCM 必弹。"授权过 SSH" ≠ "所有 git 主机都授权了"。- 反证/验证:改用
git -c credential.helper= + GIT_TERMINAL_PROMPT=0 + SSH重试 ⇒ 秒级明确报错、不再挂起(原来"无输出"就是 GCM 挂着等凭据)。
🔴 新增取证位置:当日审计未 flush 时,正式分片 YYYY-MM-DD.N.jsonl 滞后,最新事件只在
audit-log/spool/audit-spool-<pid>-<date>.jsonl ⇒ 判"某命令到底有没有被平台拦"必须查 spool(此前只查分片 ⇒ 会误判"无记录 = 被拦")。
今天唯一一次"平台弹窗" = 00:04 file-safety.bulk-delete.approved(删 D 盘残留那条),逐次生效、不具传染性。
已沉淀:PLAYBOOK-实例与插件坑.md 新增 §13(GCM 坑 + 判据 + 修法 + ⛔ 别全局关 helper)。
未做:会话数据仍未动(A/B/C 待拍板);cnb.cool:maogeigei/dsh-ai1net-session.git 未确认存在/权限(SSH 返回 Could not read from remote repository,可能是仓库名不对或无权限)。
覆盖网络线 · 序 ㉙ 执行棒收官(2026-09-18 05:45–06:1x):OBS-21 由红转绿
一句话 = 106 侧 relay 候选链从"退化单点"变成 3 条,探针 22 PASS / 0 SKIP / 0 FAIL(rc=0) ⇒ 本线在册红项清零。⛔ 未放宽 CAND_MIN。
根因(序㉗ 已取证、本棒复核一致):106 /etc/dshs-worker.env 无 DSHS_OVERLAY_DIR_PUBKEYS ⇒ 目录取到了也一律被 no-trusted-keys 拒(106 日志近 3h 166 行可证)⇒ 候选链恒退化为内置种子单点。
改动(全序唯一一处) = 106 /etc/dshs-worker.env 追加一行 DSHS_OVERLAY_DIR_PUBKEYS=fd81a6dd…(= 47 同一把;47 真值来源 = /etc/systemd/system/dshs.service.d/overlay-dir.conf,私钥 /etc/dshs/overlay-dir-key.pem)+ restart dshs-worker。回滚点 = 106 /opt/dsh/backups/seq29-20260918-054852/dshs-worker.env.orig(md5 6b509ce447d9519241aa73243e07a69f)。
🔬 先取证再动手(⛔ 未采信"补钥即绿",两条路径各自取证):(a) 公网路径 https://alotbuy.com/dshs-overlay/bootstrap 从 106 curl = 200 / remote 172.67.194.206(CF)/ 443 字节;且 106 的失败码是 no-trusted-keys —— 该码在 directory.ts#fetchDirectory 里位于 fetch → res.json() → parseDirectory 之后 ⇒ "取到了、只是验不过" ⇒ 可达性成立。(b) 直连 47.77.182.89:3080 = timeout(000)(已知 TCP_BLOCKED 边界)⚠️ 但取目录流程根本不用 3080(域名 → 443 → nginx → 回环 3080)⇒ 不构成阻塞。
验收:OBS-21 两条路径 count=3 ≥ 2、rc=0 | npm.cmd test 201/200/0/1 | --scene all --table 12P/0S/0F | 探针 22P/0S/0F。
边界自证:⛔ 未改任何生产值(106 上 RELAY_FAILOVER_|HB_SEC|PRESENCE_|DSHS_REHYDRATE_ 计数 0;env 与备份 diff = 只多 4 行注释+1 行键)· ⛔ 未新增监听口(OBS-11 实际 77 / 多出 0 / nft accept 多出 0)· ⛔ 未动 nft·nginx · 🔴 COOLDOWN_MS=0 两机计数 0 · ⛔ 未 commit / 未 push(HEAD 04776af,git status 33 逐数未变)· 参数表指纹 3b295a8c43aafc4a62c6f1a59ea0b43a 未变(改动落 §11 补记区 ⇒ 在 §10 口径之外)。
🔴 两条必须记住的(后续任何一棒都别踩):① 孤儿端点条目不会自愈(序㉚ 留的"自愈时延未测"至此有答案):relay-tunnel.ts#cancel() 只撤当前进程 forwarded 集里的端口 ⇒ 上一进程遗留的条目无人撤销,只能靠后续一次"重新登记同一端口号"覆盖回 online=true。实测:重启 106 dshs-worker 后旧条目 21000→41831 恒 online=false 约 10 min 未自愈;停掉实例、由 Manager 自动重新拉起(新实例落回 21000 基址)后才转绿。⇒ 重启 worker 后 OBS-08/OBS-09 必红,⛔ 不要误判成"等一会儿就好了";正确的收口顺序 = restart dshs-worker → restart dshs(两客户端归零回 47 relay)→ 一次真实访问(mksess 临时 session + enter)→ 实例落回 21000 基址 ⇒ 全绿。② DSHS_OVERLAY_DIR_CACHE 106 仍为 0(47 亦为 0 且 47 侧一直绿)⇒ 本棒与"已验证有效"的 47 配置逐项对齐;⛔ 按"只做被明确要求的事"未扩范围。缺它的后果 = 目录不可达时没有"过期缓存"档、直接落种子兜底(候选退回 1 条)⇒ 属冗余韧性而非本项判据,若要"CF 抖动期也保住 ≥2"需单独立项。
文档落点:本棒无独立交接单 ⇒ 回报在 接续入口_覆盖网络线_20260916.md §0 最新行 + §2 | 参数表新增 §11.2(状态改判)| 下一棒 = 单 B 执行棒(组密钥加密),依据 = 工作区根 交接单_组密钥加密_20260918.md(§8 前前缀 149596460288ca1a5b7abddc490f7909)。
06:4x–07:0x · 会话日志同步到 CNB 私有仓(已完成)
目标仓:https://cnb.cool/maogeigei/dsh-ai1net-session(Private,09-17 22:26 创建;用 https://api.cnb.cool/<owner>/-/repos 才查出 —— 我先前猜的 dsh_shenxian_session / dshai1netsession 等 7 个名字全是 404)
凭据:用户名 cnb + 用户提供的 token ⇒ 已 git credential approve 存入 GCM(加密),并补 .gitconfig 的 credential.https://cnb.cool.provider = generic ⇒ 日后不再弹授权窗(这就是用户上一轮问的那个弹窗的根治)。
最终远端 = d83ed62「init: WorkBuddy 会话日志全量原样镜像」—— 原样未脱敏,218 文件;本地 .git 66 MB,推送约 300 MB / 53 秒。
内容落位:sessions/e-ProgramData-AI技能-aliyun-dsh-server/(当前工作区)+ sessions/d-AI技能-aliyun-dsh-server/(搬迁前旧工作区);每会话三件(.jsonl 正文 / .meta.json / .file-rollback.ndjson)。附 .gitattributes = * -text 防 CRLF 改行尾破坏 JSONL 结构。
用户口径演变:不用脱敏,这个是私有仓库(原始意图)→ 中途 脱敏就脱敏吧不用重复处理了 ⇒ 最终保留原样版(= 首次指令),未再重复处理。中间那版脱敏(938 处命中)已被覆盖。
🔴 本轮五个坑(都已实证)
- 🔴 批量删除闸门会让脚本「静默半途而废」 —— 单次删除 >50 文件 ⇒
[safe-delete][SAFE_DELETE_BULK_CONFIRM_REQUIRED],删除被拦但脚本继续往下跑:os.makedirs撞已存在目录 ⇒ 脚本报错退出(复制一步没执行);rm -rf .git同样被拦 ⇒git init变 re-init ⇒ 新提交叠在旧内容上,产出「提交信息写着原样、内容其实还是脱敏」的假绿。 ✅ 正解 = 改用全新目录名,不依赖删除;删完必须[ -d ]复检。 - 🔴 杀掉后台任务 ≠ 撤销它已发出的推送 —— TaskStop 报
killed之后,远端 sha 仍从8e88cd2变成d83ed62⇒ 终止后必须重新核对远端状态,不能只看 kill 回执。 - 🔴
git -c credential.helper=会把「已存好的凭据」也一起禁掉 ⇒could not read Username for 'https://cnb.cool'。凭据已入库时不要加这个参数(它只在"不想走 GCM、要显式传 token"时才用)。 - ⚠️
git -C /e/tmp/...不认 bash 的/e/路径 —— git.exe 是 Windows 程序,必须写E:/tmp/...;否则报fatal: cannot change to ...: No such file or directory,会误判"目录不存在"(本轮就被它误导过一轮)。 - ⚠️
git ls-tree中文路径默认转义 ⇒ 取文件名前先git config core.quotepath false(同ls-files那条老坑)。
✅ 一条高效手法(值得复用)
远程核对内容不必克隆 300 MB:git init + fetch --depth 1 --filter=blob:none + git show FETCH_HEAD:<单个路径> ⇒ 只按需拉那一个 blob。本轮就是靠它判定远端到底装的是原样还是脱敏版。
边界自证
⛔ 未动生产(47/106 一个字节没碰)· ⛔ 未动 src/ 与本轮无关的 9 处未提交改动 · ⛔ 未删该 CNB 仓既有内容(本仓原本就是空仓)· ✅ 临时目录(含 2 个 377 MB 镜像)已全部清理 · ✅ 工作区令牌明文扫描 0 命中。
06:4x–07:0x · 会话日志同步到 CNB 私有仓(已完成)
目标仓:https://cnb.cool/maogeigei/dsh-ai1net-session(Private,09-17 22:26 创建;用 https://api.cnb.cool/<owner>/-/repos 才查出 —— 我先前猜的 dsh_shenxian_session / dshai1netsession 等 7 个名字全是 404)
凭据:用户名 cnb + 用户提供的 token ⇒ 已 git credential approve 存入 GCM(加密),并补 .gitconfig 的 credential.https://cnb.cool.provider = generic ⇒ 日后不再弹授权窗(这就是用户上一轮问的那个弹窗的根治)。
最终远端 = d83ed62「init: WorkBuddy 会话日志全量原样镜像」—— 原样未脱敏,218 文件;本地 .git 66 MB,推送约 300 MB / 53 秒。
内容落位:sessions/e-ProgramData-AI技能-aliyun-dsh-server/(当前工作区)+ sessions/d-AI技能-aliyun-dsh-server/(搬迁前旧工作区);每会话三件(.jsonl 正文 / .meta.json / .file-rollback.ndjson)。附 .gitattributes = * -text 防 CRLF 改行尾破坏 JSONL 结构。
用户口径演变:不用脱敏,这个是私有仓库(原始意图)→ 中途 脱敏就脱敏吧不用重复处理了 ⇒ 最终保留原样版(= 首次指令),未再重复处理。中间那版脱敏(938 处命中)已被覆盖。
🔴 本轮五个坑(都已实证)
- 🔴 批量删除闸门会让脚本「静默半途而废」 —— 单次删除 >50 文件 ⇒
[safe-delete][SAFE_DELETE_BULK_CONFIRM_REQUIRED],删除被拦但脚本继续往下跑:os.makedirs撞已存在目录 ⇒ 脚本报错退出(复制一步没执行);rm -rf .git同样被拦 ⇒git init变 re-init ⇒ 新提交叠在旧内容上,产出「提交信息写着原样、内容其实还是脱敏」的假绿。 ✅ 正解 = 改用全新目录名,不依赖删除;删完必须[ -d ]复检。 - 🔴 杀掉后台任务 ≠ 撤销它已发出的推送 —— TaskStop 报
killed之后,远端 sha 仍从8e88cd2变成d83ed62⇒ 终止后必须重新核对远端状态,不能只看 kill 回执。 - 🔴
git -c credential.helper=会把「已存好的凭据」也一起禁掉 ⇒could not read Username for 'https://cnb.cool'。凭据已入库时不要加这个参数(它只在"不想走 GCM、要显式传 token"时才用)。 - ⚠️
git -C /e/tmp/...不认 bash 的/e/路径 —— git.exe 是 Windows 程序,必须写E:/tmp/...;否则报fatal: cannot change to ...: No such file or directory,会误判"目录不存在"(本轮就被它误导过一轮)。 - ⚠️
git ls-tree中文路径默认转义 ⇒ 取文件名前先git config core.quotepath false(同ls-files那条老坑)。
✅ 一条高效手法(值得复用)
远程核对内容不必克隆 300 MB:git init + fetch --depth 1 --filter=blob:none + git show FETCH_HEAD:<单个路径> ⇒ 只按需拉那一个 blob。本轮就是靠它判定远端到底装的是原样还是脱敏版。
边界自证
⛔ 未动生产(47/106 一个字节没碰)· ⛔ 未动 src/ 与本轮无关的 9 处未提交改动 · ⛔ 未删该 CNB 仓既有内容(本仓原本就是空仓)· ✅ 临时目录(含 2 个 377 MB 镜像)已全部清理 · ✅ 工作区令牌明文扫描 0 命中。
07:0x-07:2x · dsh_shenxian 推送改为「原仓 + CNB」双推(已完成)
诉求(用户原话):这个项目推送仓库时 同步推送 @share-html#maogeigei%2Fdsh-shenxian:https://cnb.cool/maogeigei/dsh-shenxian
落地(仓库 D:/github/dsh_shenxian):
origin= fetch 仅[email protected]:maogeigei/dsh_shenxian.git;push 两条= 原仓 +https://cnb.cool/maogeigei/dsh-shenxian.git(原仓在前)⇒ 一条git push同时同步两处。- 首次推送完成:CNB
refs/heads/master=04776af4b130014b0f4db10de89b0ae982300afc(与本地、原远端一致);文档库dsh-server-docs/(223 文件)在本仓内 ⇒ 一并同步。 - 凭据助手 =
C:/Users/Administrator/.cnb/git-cred.sh(配credential.https://cnb.cool.helper):优先~/.cnb/git-token(长期访问令牌)→ 回落~/.cnb/token(连接器登录态,会过期)。 - CNB 走直连:
http.https://cnb.cool.proxy=""(绕开本机127.0.0.1:10800)。
🔴 三个坑(本轮实证)
- 🔴
git remote set-url --add --push会「挤掉」原 pushurl —— 首次执行后remote -v只剩 CNB 一条(原远端 push 没了)⇒ 加完必须核git remote -v并按序补回(先原仓、后 CNB)。 - 🔴 CNB 官方不支持 SSH(
docs.cnb.cool/guide/git-access明写):认证只有「用户名固定cnb+ 访问令牌」一条路。短期 OAuth(cnb_at_…,94 字符)会过期;长期要 CNB 网页生成访问令牌(https://cnb.cool/profile/token/create?tpl=git&expired=forever)。 - ⚠️ 沿用上一轮那条坑(本轮又踩):先用
git -c credential.helper=探测 ⇒ 把已存凭据一起屏蔽 ⇒ 误判"本机无 CNB 凭据",白绕一圈。另外实证 GCM 里那份与.cnb/token是同一个 token(都 94 字符)⇒ 同样 14:28 过期,上一轮"日后不再弹授权窗"的结论有时效。
边界自证
⛔ 未 commit 任何未提交改动(工作树 20+ 在途文件原样保留)· ⛔ 未动生产 · ⛔ 未触碰 dsh-ai1net-session 等其他 CNB 仓(仅核对)· ✅ 临时目录 _tmp_cnb/ 已删 · ⏳ 待用户提供长期令牌
07:2x 覆盖网络线 · 序 ㉘ → 单 B 执行棒收官(组密钥加密 · C 档)
载体 = 工作区根 交接单_组密钥加密_20260918.md(单 B · 归档号 130);automation 65d2fc24-770e-4f33-93a3-db6e739aded7。开工 06:22(抢锁一次成功)→ 收口 07:2x。
做了什么 = 内容载荷层新增组密钥确定性加密(AES-256-GCM):新 content/crypto.ts(0600 文件装载 + 收敛加密 + 双 epoch)|块 id 改 β′ = sha256(密文)|source.ts 唯一解密点|peer.ts epoch 闸门(⛔ 仍只认 sameGroup)|store 只改文档|runtime/main/web 三处装配(缺省不启用 ⇒ 逐字回到序㉔)|overlay-keyring.cjs 加 init/sign/verify-group-key|探针 OBS-23|参数表 §3.9 六键 + §6 一行|test/overlay-content.test.mjs +F 组 16 例。
关键读数 = F1 同明文两次密文 md5 相同(3385e9d0…,长度 = 明文+28)|F3 跨组认证阶段被拒 + decryptRejected=1|F4 ① 命中 0 + ② 反向命中 ≥1|F5 E1 不退化(4×3 全 local 命中 12、零回源)|F6 七例具名失败关闭|三件套 201/200/0/1 · 12P/0S/0F · 23P/0S/0F(22→23)|部署 18 文件 × 四处 md5 不一致 0|回滚点 /opt/dsh/backups/seq28-20260918-065104/。
参数表指纹 = 3b295a8c43aafc4a62c6f1a59ea0b43a → 08c2835a7e9f0faef20f9c1d3e619d55。
三条留档(⛔ 别丢):① 单文内部口径不一致(§4/S6 说"对旧生产 ⇒ FAIL",§5 说"缺省不启用 = SKIP")⇒ 本棒取 SKIP,"先红"由权限腿取得(0600→0640 ⇒ FAIL 点名 47=640 106=600);② 签名动作命令未逐字留痕(47 上无 keyring.cjs、/tmp 无残留)⇒ 只能自证"凭据不含 key + 验签过 + 篡改必败",无法自证"私钥未出机" ⇒ 建议固化为 47 正式子命令;③ §10-1/2(性能开销、轮换回源字节数)仍未验、⛔ 未编数。
下一棒 = 序 ㉛ 执行棒(automation 682e8bb0-fb05-41ba-ad00-e5e7fde4647e,2026-09-18 07:33)—— 补齐 §10 未验证项 + ⑤⑥ 两条口径定稿/固化。
边界自证:⛔ 未改任何生产值(新 drop-in 只 1 行 env)· ⛔ 未新增公网口 · ⛔ 未改 nft·nginx · ⛔ 未放松跨组 · 🔴 COOLDOWN_MS=0 两机 0/0 · ⛔ 未 commit / 未 push(HEAD 04776af,git status 35 处)。临时 session DELETE 3、残留 0。
2026-09-18 07:33–07:5x · 序 ㉛ 执行棒收官(组密钥加密 · §10 未验证项补齐 + 口径定稿)
六项主题全部完成(⛔ 本棒无独立交接单 ⇒ 证据 = 交接单_组密钥加密_20260918.md §8.14;脚本与原始输出 = 工作区 _tmp_seq32/):
① 性能开销(§10-1):同一份 11,363,655 B / 11 块、n = 11 ⇒ 总墙钟 p50 22.636 → 42.782 ms、p95 23.020 → 43.599 ms(1.890× / 1.894×,绝对 +20.1 / +20.6 ms);吞吐 502.02 → 265.62 MB/s;密文固定开销 +28 B/块。⚠️ 单核、页缓存全热、两臂零回源 ⇒ 是"加密层自身成本",⛔ 非端到端承诺。
② 轮换代价(§10-2,结清 §8.13-③):4 组 × 4 节点、包 5,255,225 B / 6 块 ⇒ 冷启动回源 21,021,572 B = 4.0001 × 包 = 1 × 包/组;轮换(块 id 改变 24/24 = 100%)后首轮同值(比值 1.0000)、第二轮 0、对照腿第 3 轮 0(⇒ "回源由轮换引起"可断言);🔴 新发现代价 = 旧 epoch 密文变垃圾且不自清(storeBytes 5,255,393 → 10,510,786 ≈ 翻倍)。
③ 低熵明文定性(§10-3):持钥者可枚举恢复(1000 条 11.644 ms ≈ 85,878 条/秒,域 2³² ≈ 14.7 h)/中继(无钥)枚举不可行(自造字典 0/1000,持 1 对也预测不出别的)但相等性泄露成立(10,000 块 / 100 值域 ⇒ 仅 100 种密文)⇒ 定稿 = "中继看不到明文"成立、"内容不可推断"不成立,⛔ 不写"很安全"。
④ 过渡窗口三档(§10-6):混存 20 块(写 epoch 4 + 历史 1/2/3,时钟注入)⇒ 归零时刻 小 60 s ⇒ +24 h|中 24 h ⇒ +48 h|大 7 d ⇒ +8 d(阶梯衰减;窗口内 epochExpired=0;写 epoch 恒 5/5 可解)。
⑤ 口径定稿:OBS-23 对"缺省不启用"取 SKIP + 留痕;§4/S6 那句「对旧生产 ⇒ FAIL」作废;"真红"腿由权限腿承载(0600→0640 ⇒ FAIL 并点名 47=640 106=600)⇒ 落 §11.5,⛔ §4 / §6 正文零改动。
⑥ 签发固化(结清 §8.13-②):overlay-keyring.cjs 铺 47 两处正式路径(/opt/dsh-relay/scripts/ 就地更新 — 旧版 grep -c sign-group-key = 0;/opt/dshs/scripts/ 此前不存在)⇒ 两处 md5 均 f1855eaef30f71fbca00ac0a92865c0e;在机 sign-group-key rc=0(凭据 274 B、epoch=1 keyId=3560130eb0e5e4aa、密钥本体 0 次)/verify-group-key rc=0/篡改 epoch ⇒ signature-mismatch rc=1/--epoch 9 交叉核对 rc=1;⛔ 未重启任何单元;回滚点 = /opt/dsh/backups/seq31-20260918-073857/。
零回归三件套(都带 --table)= npm.cmd test 201/200/0/1(与基线逐字同)|--scene all --table 12P/0S/0F|overlay-probe --table 23P/0S/0F(rc=0)。⚠️ 收口期间曾出现 19P/1S/3F 与 22P/1S/0F(OBS-09 SKIP,因实例暂落 21001)⇒ 用 /api/dsh/stop + /api/dsh/enter 把实例落回 21000 ⇒ OBS-09/OBS-21 双双转绿(⛔ 未编数、未凑绿)。
参数表:§3.9 CONTENT_EPOCH_GRACE_MS 说明列补三档曲线 + §6 OBS-23 行末补口径定稿 + §7 补"复算仍 0 项" + 新增 §11.3 补记(六条);🔴 §10 指纹 08c2835a… → 52e59df229102d5afa8c8bf01a960398(已现算同步;⛔ 零键零值变更)。
交接单指纹:全文 md5 296c9b0b69a40987104fb1b00c6ad746/724 行;§8 前前缀 149596460288ca1a5b7abddc490f7909 回填 §8.14 后逐字不变 ✅。
⏸️ 未登记下一棒(线内可停):在册红项 0 · 用户定序三棒全收官 · 六项主题全完成 · §8.13 三条全结清 · 唯一剩余 = §10-5(Ed25519→X25519 预研),触发条件 = §9 回头条件 7("规模上来要自动分发组密钥")⇒ 无线内可自主推进项、无待拍板项。
边界自证:⛔ 未 commit / 未 push(HEAD 04776af)· ⛔ 未改任何生产值 · ⛔ 未新增公网口 / 未动 nft·nginx · 🔴 COOLDOWN_MS=0 全程 0 次 · ⛔ 未改 bwrap · 🔴 密钥本体 ⛔ 不经网络 / relay · ⛔ §10-5 未执行(不在写死主题内 ⇒ 未扩范围)。临时 session 残留 0。
2026-09-18 08:0x–08:1x · 仓库同步(用户指令:双推「原仓 + CNB」)
动作 = 精确 git add package.json src scripts test dsh-server-docs(⛔ 未用 git add -A;⛔ 临时产物 _tmp_seq24/、_中间产物_待清理/ 未暂存)⇒ 暂存 38 项(代码 + 脚本 + 测试 + 交接单 序24/25/26 + INDEX/README/SKILL)⇒ commit ⇒ git push origin master(origin 已配双 pushurl)。
结果 = 04776af..09ce76f(master);三处 SHA 逐字一致 = 09ce76f3af9fa6211ec6931c65e5302fda911ecd(本机 HEAD / git ls-remote 原仓 / git ls-remote https://cnb.cool/maogeigei/dsh-shenxian.git)。
提交内容 = 内容块级寻址(src/net/relay/content/{chunker,store,runtime,source,peer,crypto}.ts)+ 组密钥确定性加密 + 三处 teardown() 不再杀实例 + jitter 选路(endpoint-target.ts/jitter.ts)+ 探针 OBS-21/22/23 + 新增 4 个测试文件 + 3 份交接单。
核实:技能 dsh-auto-handoff-chain/SKILL.md 两处 md5 同 = c16975a0ba31291a5f3318d9ba914ff2 ✅。⚠️ CRLF 提示属既有配置:core.autocrlf=true(local + global),.gitattributes 只豁免 dsh-server-docs/** -text ⇒ src/scripts/test 下次 checkout 会变 CRLF(仓库内存 LF,本次提交无字节影响)—— 只报告、⛔ 未顺手改配置(用户偏好:发现额外问题先报告)。
遗留 = ⛔ 未跟踪且未提交:_tmp_seq24/、_中间产物_待清理/(临时产物,待用户确认后清)。
2026-09-18 08:1x–08:2x · 覆盖网络线「功能整体完成情况报告」产出
用户问 = 「覆盖网络的功能全部开发完成了吗,开发完成出个功能整体完成情况的报告(背景目标、技术路线、架构、功能特性、应用场景、性能安全评估、潜在风险)」。
判定 = ✅ 功能主体全部开发完成并落地生产:序 ①–㉛ 全收官(含单 A / 单 B)|在册红项 0(探针 23P/0S/0F)|参数表待测项 0|待拍板区空|⏸️ 线内可停。
产物 = 工作区根 覆盖网络_功能整体完成情况报告_20260918.md(八节:完成度判定 / 背景目标 / 技术路线 / 架构 / 功能特性 / 应用场景 / 性能与安全评估 / 潜在风险 + 单一来源附录)。
如实标明"不算未完成"的三项:① C 档 systemd scope 单一真相源(用户 23:3x 明令登记为架构目标、本阶段不执行)② §10-5 Ed25519→X25519 预研(触发条件 = 规模上来,回头条件 7)③ 档案 112「只做三件事」第三件"游戏服放 L1"(部署形态建议,未落地;前两件 presence / 块级寻址已完成)。
⚠️ 取证发现(只报告未动):dsh-server-docs/BRIEF.md 最后人工核对 = 2026-09-16 10:5x,其「归档编号至 112」「覆盖网络线后续待排期」等行已过期(现核 130)⇒ 报告中已加取证提示:覆盖网络线现行事实以入口文件为准;⛔ 未顺手改 BRIEF(超范围)。
边界自证:本轮为零代码改动取证 + 单文件产出;⛔ 未改代码 / 未改生产值 / ⛔ 未 commit(用户未要求)。
2026-09-18 08:2x–08:3x · 能力对标取证(用户问:能否满足 6 项能力)
⚠️ 本轮最重要的发现(🔴 后续任何一棒别再误以为是"已实现"):
① P2P 内容分发在真机路径上「未接线」 —— 不是"没做",是做了一半:
src/net/relay/content/runtime.ts:22原话:「不做网络取块(peer 的真实取回通道在真机验证阶段由上层接线)」runtime.ts:146:peerfetcher 诚实回"没有"(逐条markDenied后 return undefined)src/web/server.ts:925-930(生产路径):peerfetcher 同样return cands.length === 0 ? undefined : undefined⇒ 恒返回 undefined;且edge/region/origin三个档位未注入- ⇒ 当前内容面实际只有
local档工作;跨机取块无通道 ⇒ ⛔ 不得对外声称"文件走 P2P 分发"
② 「公网 IP 设备自动升级为中继候选」零实现 —— grep -rniE "publicip|promote|升格|自动升级|selfRegister" src/net/relay/ src/config.ts = 0 命中;中继目前 = 47 / 106 两台人工部署(scp + systemd 单元)。⇒ "有公网 IP 者升格中继候选"是参数表口径(设计意图),⛔ 不是已落地能力。
③ 「打洞」确认为范围外 —— grep -i "punch|打洞|directPath" 仅命中 addr-override.ts(443 兜底钉 IP,非打洞)与 rendezvous.ts 同机直连注释 ⇒ 无打洞实现(与"⛔ 不做打洞实现"的用户拍板一致)。
6 项能力逐条判定:公网自动升格 ❌ / 不依赖单点 ⚠️(relay 候选 3 条可互切,但控制面权威状态单点 = 有意设计)/ 自动或手动入最优节点 ⚠️(自动选路 ✅ 含 jitter;手动仅 env,无界面)/ 故障自动切换 ✅(已实现,实测 20.9–23.9 s)/ P2P 分发 ❌(见 ①)/ 全网互联 ⚠️(presence+端点表+中继在,但新节点加入靠人工 + 300 s 收敛期)。
结论口径:6 项中 1 项完全满足(故障切换)+ 3 项部分满足 + 2 项未实现(自动升格 / P2P 分发);两项未实现共用同一前提 = 节点间"找到对方并建连"这一层(打洞)从未做 ⇒ 已按 dsh-feature-first §5.1 结论骨架答复,并把"要不要立项补"作为**边界外(业务优先级 + 会命中新增暴露面门禁)**拍板项上抛。
边界自证:纯只读取证(6 条 grep + 2 处 Read),⛔ 未改任何代码 / 配置 / 生产值;本轮未落文档(用户问的是能不能,未要求产出)。
2026-09-18 09:0x–09:2x · 规划棒 · 「节点一键加入与分组准入」方案产出(用户选 B)
用户需求原话(09:07):「b 要实现开启一台结点服务器,就能连上覆盖网络,这样做这个网络才有价值,结点可以设置分组只允许那些结点加入,既可以成为大覆盖网络也可以建立独立覆盖网络」⇒ 即 选 B(补"设备自动成为节点 + 节点直连"),并给出目标形态。
产物 = 工作区根 交接单_节点一键加入与分组准入_20260918.md(归档号 131;§8 前前缀 085e28b56a08aa1f01999bdb3e238911;落单快照全文 md5 ca4ca8aad292efaf02357e1e2dacb6da/214 行)。
🔴 本棒三条取证(重要,⛔ 别再以为"都没有"):
① 「分组准入」与「独立网络」的底层机制已在代码里 —— src/net/relay/server.ts 头部注释原话:每条会话属于一张网(HELLO.network);会话与端点表按 <network>/<hostId> 索引;DIAL 必须同网且在本网白名单里 ⇒ 跨网连"能不能拨"都走不到(结构性隔离,不是策略性)。dialers 类型 = Map<networkId, Set<hostId>>,没列到的网络一个都拨不动(默认拒绝)。network.ts 已定义 ops / u:<userId> / 其它显式命名三条分支 ⇒ "独立覆盖网络" = 新增一个 networkId,零代码。
② 「一键加入」不存在 —— 加入一台机器现要手工四件事:装单元 / 配密钥 / 写 DSHS_RELAY_DIALERS drop-in / DB 登记;全仓无 join 入口 ⇒ 这就是 P1 的主体。
③ 「直连」与「P2P 取回」都不存在 —— grep -i "punch|打洞|directPath" 仅命中 addr-override.ts(443 兜底钉 IP);内容面 peer 档在生产路径(src/web/server.ts:925-930)恒返回 undefined ⇒ 属 P2。
方案结构(已落单):P1(一键加入 + 分组准入产品化)零新增暴露面、可立即开工;P2(直连 + P2P)命中 R5、放最后(执行到 S5 前会再停一次给具体端口/协议清单 —— R5 硬要求,⛔ 不是重复提问)。判据 J1–J6;分期步骤 S1–S7;在册文件集 9 项(挂 §3.2,⛔ 超出即停)。
登记 = 执行棒 automation cc29cfb9-ae13-42fc-8da6-8b1caef1c382(一次性 · 2026-09-18 09:22 = 收口 +~7 min;nextRunAt = 1789694520000)⇒ 同一时刻只挂这一个棒 ✅。
归档号取证:现核 04 目录最大 128;129 / 130 已被单 A / 单 B 占用 ⇒ ⛔ 不重用;mkdir .lock-131 成功;⚠️ 本棒不落 04 孪生 ⇒ 占号窗口落单后释放。
边界自证:⛔ 零代码改动 · ⛔ 零服务器改动 · ⛔ 未 commit / push(HEAD 09ce76f 未动)· ⛔ 未改任何生产值(纯规划棒)。
序㊱ P1 执行棒(2026-09-18 09:2x–10:0x)· 「节点一键加入 + 分组准入」S1–S4 落地
开工门:state.py ✅|入口 §0/§2 定位 ✅|交接单 §8 前前缀现算 = 085e28b56a08aa1f01999bdb3e238911(MATCH ✅)|抢锁成功(执行棒P1-节点一键加入与分组准入-0918)|基线现核 = HEAD 09ce76f + npm.cmd test 201/200/0/1 + 探针 23P/0S/0F。
产物(8 个在册文件,⛔ 零越界):新增 src/net/relay/registry.ts(S1+S2+S4 核心)/ src/net/relay/join.ts(S3)/ scripts/overlay-node-admit.cjs(控制面 8 条命令)/ scripts/overlay-node-join.cjs(节点侧一条命令)/ test/overlay-join.test.mjs(33 用例);修改 src/net/relay/network.ts(只加 40 行:NetworkKind / networkKindOf / describeNetwork)/ src/net/relay/index.ts(导出)/ scripts/overlay-probe.cjs(OBS-24 五项 + OBS-25 六项)。
判据 = J1–J6 逐条先红后绿(B 组 'wx'→'w' 双红并报 竞态未守住:ok=12(须恰好 1);OBS-24 数据侧+实现侧双红;OBS-25 一次性红)+ 真机端到端链路 _tmp_seq33/chain47.sh rc=0、11 步全绿(收单 pending / 二次收单 invite-already-used / 批准后 DSHS_RELAY_DIALERS="lab-net/lab-1" / 三网零共享 / 私钥出现 0 次 / 节点私钥 600 / 台账 3 ≡ 收单 3)。
零回归三件套 = npm.cmd test 201/200/0/1(与基线逐字一致)|--scene all --table 12P/0S/0F|探针 24P/1S/0F(rc=0)。
🔴 唯一未复原项 = OBS-09 由 PASS 退化为 SKIP:本次运行的零回归演练重启两端 relay/worker ⇒ OBS-01/04/08 转红 ⇒ 执行恢复(47 restart dshs + 106 restart dshs-worker)⇒ 三者回绿,但 106 worker 重注册读数由 accepted=[19000,21000] 变 accepted=[19000](实例端口 21000 的注册未随进程重建)。两端实例 :20000/:21000 均在监听、门户 200 ⇒ 无业务中断。详 ⇒ 参数表 §11.4-② / 交接单 §8.6-3。
🔬 真机缺陷(已修+已补判据):控制面 CLI --file 键名混用(opt('file') 既当注册表文件又当 apply 的申请单入参)⇒ apply --file <申请单> 把注册表也指到申请单 ⇒ 收单炸在第 4 步而 nonce 已被原子占位(对外 = 收单失败 + 同一张邀请再也用不了)。修 = 改名 --registry;先红后绿 = 临时改回 ⇒ 新增 E10(CLI 级真回环) 转红并报出同一句「注册表 …/app.json 形状非法」,还原 ⇒ 33/33 全绿。教训 = 调库式判据(E9)抓不到参数解析类缺陷 ⇒ 必须有 CLI 级真回环。
另两条如实留档:① OBS-24 原拟判「同一 hostId 出现在 ≥2 张网 ⇒ FAIL」实为合法态(跨用户撞名)⇒ 该腿无判别力,降级为信息项,改判「结构性错桶=0」+「派生桶数 ≡ 有 approved 的网数」;② 在册的 src/web/routes/overlay-nodes.ts(管理面 API)自决移入 P2(与 P1 硬门「零新增暴露面」冲突风险最高,S1–S4/J1–J6 均不依赖它;⚠️ 可推翻)。
收口:交接单 §8 全节回填(§8 前前缀回填后仍 085e28b5… ✅)|入口 §0 新增一行、§2 换新棒|参数表 §3.10/§6/§7/§11.4 更新,§10 指纹 52e59df2… → 695dcb4d88a778840322bc221417d339(现算同步)|边界自证 = ⛔ 未 commit / 未 push(HEAD 仍 09ce76f)· ⛔ 未改任何既有 drop-in/env/nft·nginx/bwrap · COOLDOWN_MS=0 计数 7 文件全 0 · 密钥本体不经网络|⚠️ 新增状态目录 /var/lib/dshs/overlay/(登记为「状态」)。
下一棒 = 收口复核棒 automation 8887ac37-6e91-4bf3-ab96-c0a0916fb922(一次性 · 2026-09-18 10:08 = 收口 +~6 min)⇒ 同一时刻只挂这一个棒 ✅;其范围只含「OBS-09 复原核查 + 产物可复现复核」,🔴 ⛔ 不许开工 P2(P2 命中 R5 ⇒ 必须用户拍板)。
序㊱ 收口复核棒收官(2026-09-18 10:0x–10:4x · 覆盖网络线)—— OBS-09 SKIP → PASS
主题 = 复核上一棒(序㊱ P1 执行棒)留下的唯一未复原项 OBS-09(退化为 SKIP)+ 复核产物可复现。抢锁 = 抢到(收口复核棒-序36-P1-OBS09)。
① 开工读数:SKIP OBS-09 在册实例面 无|不在册 2 项:本机:20000,对端:21000|47 中继 /status 端点表 1 条 = w-106 port=19000 localPort=43061 online=true|探针 24P/1S/0F(rc=0)。
② 链路取证(「实例 → 本地 worker 的端口注册」,⛔ 未猜 relay):106 /healthz 原文 = {"hostId":"w-106","instances":0,"tunnel":{"ready":true,"ports":[19000]}} ⇒ worker 自己认不到实例 ⇒ reconcileTunnel()(worker/agent.ts:257-263,20 s 一跳)无 live 端口 ⇒ 永不 forward(21000)。根因 = orchestrator.ts:558 listUserInstances() 取 mains,而 rehydrateAdoptedScopes() 认领时只写 this.adopted(:1492) ⇒ 09:56:28 重启后实例 scope 被认领([rehydrate] adopted … port=21000 + probe OK :21000)但平台侧不可见。⇒ 🔴 这是「退出路径不杀实例」候选 B 已知边界("不被杀 + 访问时自然替换",⛔ 非"重启后直接可用")的直接后果,⛔ 不是 relay 故障(relay 全程正常:OBS-12 RSS ≈70 MB、OBS-11 77/78 口无多出)。
③ 复原(设计内路径,零代码 / 零配置改动):临时 session(/opt/dshs/mksess.cjs guest,R4)⇒ 一次 Host: guest.alotbuy.com 访问 ⇒ 10:18:34 [dsh-child main] Running as unit: dsh-100002-7d1c8cbf.scope(旧 scope dsh-100002-2e9202dd 被 cleanStaleScopes 收掉)⇒ 新实例走正常 launch 路径声明端口:/healthz = {"instances":1,"tunnel":{"ready":true,"ports":[19000,21001]}}、端点表 {19000 ✓,21001 ✓}|用户可见面 200 / 62451 B / 502 标记 0|临时 session 已删(DELETE 1 ⇒ 余 0)。
④ 🔴 一次"假 SKIP"的教训:复原后第一次复跑仍 SKIP —— 替换落点漂到 21001(spawn.ts#findFreePortInRange 从 base 上扫第一个空闲口;替换发起时 21000 仍被旧 scope 占着 ⇒ 顺延),而 OBS-09 的"在册"按表内固定端口 PEER_INSTANCE_PORT=21000 取 ⇒ 对不上。处置 = 事实优先:参数表 PEER_INSTANCE_PORT 实测替换 21000 → 21001(+ PEER_AGENT_PORT 括注同步),⛔ 未为了迁就旧值去重启生产实例 ⇒ 该表 §10 指纹 695dcb4d88a778840322bc221417d339 → 2ae954e2e07b47651a84e597c19a3444。
⑤ 收官读数(全绿):探针 25 PASS / 0 SKIP / 0 FAIL(PASS OBS-09 在册实例面 w-106:42717=401)|npm.cmd test 201/200/0/1|node --test test/overlay-join.test.mjs 33/33|overlay-failover-drill.cjs --scene all --table 12 PASS / 0 SKIP / 0 FAIL(幕4-C 17375 ms / deadline 30000 ms)。
⑥ 演练副作用的同型复现(新发现 · 已点名):--scene all 跑完 47 中继视角 = ep=[] / used=1 / idOk=1 —— 演练把 106 worker 逼到 106 自己的中继(106 中继 sessions=["w-106"] 原文可证);处置 = 停 106 dshs-relay 逼它按候选链回落 47(实测 ~15 s ⇒ used=2 / idOk=2 / ep={19000 ✓,21001 ✓})⇒ 再启回 106 dshs-relay(active);⛔ 未重启任何 worker、⛔ 未换实例(故 21001 的声明保住)。⇒ 由此点名 ② 探针只读 47 的 RELAY_STATUS_URL ⇒ worker 挂 106 中继时 47 视角"端点表为空"⛔ 不等于"覆盖网络断了"(潜在假红)。
⑦ 两条点名(⛔ 本棒未改码):① OBS-09 判据钉死会漂移的实例端口 ⇒ 每次自然替换后都可能假 SKIP(同步表值只治输入、不治判据);② 上条 ⑥ 的观测点假红面。两者 ⇒ 下一棒 = 序㊲。
⑧ 本棒对生产的动作(3 个,均 R8、动手前已声明、无不可逆项):guest 实例一次设计内自然替换 / 106 dshs-relay 停启各一次(~1 min 单中继)/ 参数表文档值同步。边界自证 = ⛔ 未 commit / 未 push(HEAD 09ce76f,git status 10 处与开工逐数相同)|⛔ 未改任何生产配置值(无 drop-in / env / nft·nginx / bwrap)|🔴 RELAY_FAILOVER_COOLDOWN_MS=0 计数 0|⛔ 未开工 P2。
收口:交接单 §8.8(§8 前前缀 085e28b56a08aa1f01999bdb3e238911 回填后逐字不变 ✅;全文 md5 384fa4b1db9eef31fe004830b4a179ab/255 行)|入口 §0 新增一行、§2 换新棒|参数表 §11.4-⑧ + §10 指纹现算同步|下一棒 = 序㊲ 执行棒 automation 7268e6e7-dc5a-4517-bd10-bf7e5557721f(一次性 · 2026-09-18 10:51 = 收口 +~6 min)⇒ 同一时刻只挂这一个 ✅;🔴 ⛔ 不许开工 P2(P2 命中 R5 ⇒ 必须用户拍板)。
11:0x–11:2x · 序㊲ 执行棒收官(覆盖网络线 · 观测面去常量依赖:OBS-09 判据跟随事实 + 观测点假红可分)
判定 =「线内可停」,⛔ 未登记下一棒。做了什么(本棒唯一改动的仓内文件 = D:/github/dsh_shenxian/scripts/overlay-probe.cjs):① OBS-09 的"在册"判据不再读表内固定端口 ⇒ 改为从 /status.endpoints[] 派生「online === true 且 port ∉ {W47_AGENT_PORT, PEER_AGENT_PORT} 的实例端点」,派生的每一个都必须可达(走它自己的 localPort 回环落点,码 ∈ PROBE_CODE_SET);派生为空 ⇒ SKIP + 留痕;派生端口缺码 ⇒ FAIL 并点名(⛔ 不静默放行)。② OBS-08 加「空表可分」:47 视角 endpoints 为空时按对端中继视图(ssh <SSH_TARGET_106> curl <RELAY_STATUS_URL> —— 只读回环、零新增暴露面 / 零新增参数键;⚠️ 只在 47 视角为空时才去读 ⇒ 正常态零额外 ssh)分三态 —— 挂在另一台中继 ⇒ SKIP + 留痕 / 两台中继都无 ⇒ FAIL 并点名 / 对端中继读不回来 ⇒ FAIL 并点名(不可判)。③ --instance-fixture 口径改为按端口映射(旧位置式 <本机码>,<对端码> ⇒ rc=2 硬报错退出,⛔ 不静默解释);新增 --peer-status-fixture。④ remoteFacts 的实例面码改为按派生端口逐个取(旧版写死两个表内端口)⇒ ⛔ 探针不再引用 LOCAL_INSTANCE_PORT / PEER_INSTANCE_PORT(二键降级为快照 / 对账)。
先红后绿(原文级 · 两侧逐行 diff 只差 OBS-09 一行):夹具 = 参数表副本(PEER_INSTANCE_PORT 值格回写成漂移前的 21000)+ 真实 47 /status(事实 = 实例在 21001)⇒ 红 = SKIP OBS-09 在册实例面 无 (阈值 ∈ {200,401})|不在册 2 项:本机:20000,对端:21000;绿 = PASS OBS-09 在册实例面(派生 1 条):w-106:42717=401。可分三态(同一份 47 空表输入 ⇒ 三种输出):真机演练态 SKIP OBS-08 端点表 0 条 ⇒ SKIP + 留痕|…客户端挂在**另一台中继**上(⛔ 非故障)(47 = ep=[] / used=1 / idOk=1;106 = [w-106:19000, w-106:21001])/对端无会话 ⇒ FAIL …(两台中继都无该客户端会话)/未给对端视图 ⇒ FAIL …(不可判)。
零回归三件套 = npm.cmd test 201/200/0/1(rc=0,逐字一致)|overlay-failover-drill.cjs --scene all --table 12 PASS / 0 SKIP / 0 FAIL(幕4-C 18353 ms / deadline 30000)|探针 25 PASS / 0 SKIP / 0 FAIL(rc=0)。复原 = 演练跑完 47 视角确为空 ⇒ 停 / 启 106 dshs-relay(~15 s 后回落 used=2 / 端点 [(19000,39815),(21001,44231)])⇒ 探针回绿(⛔ 未重启任何 worker、⛔ 未换实例);⚠️ 演练态 OBS-01/OBS-04 仍红(计数判据 used=1/idOk=1 < 2,⛔ 与"端点表为空"无关)。
收尾 = 参数表 §11.5(零回归 + 红绿原文 + 可分三态 + 边界自证 + 5 条留档;🔴 §10 指纹 2ae954e2e07b47651a84e597c19a3444 → 71848fad4ee0d6a574d833169e042fd1 现算并同步)|交接单 §8.9(⛔ §8 前前缀 085e28b56a08aa1f01999bdb3e238911 逐字不变 ✅)|入口 §0 新增一行、§2 换「已收官 · 线内可停」。边界 = ⛔ 未 commit / push(HEAD 09ce76f,git status 10 处与开工逐数相同)|⛔ 未改任何生产配置值(参数表值格一律未动)|⛔ 零新增暴露面(OBS-11 多出 0 缺失 0)|🔴 RELAY_FAILOVER_COOLDOWN_MS 命中 0|⛔ 未开工 P2。🔴 在 P2 之前本线无其它在册项(P2 = 直连 + P2P,命中 R5 ⇒ 须用户先拍板权限影响评估)。⚠️ 两项待用户过一眼(均超本棒范围、按纪律只报告不动手):① 探针夹具模式封闭性歧义(OBS-24/OBS-25 分支无 fixture 守卫 ⇒ 未给各自夹具时会真去 ssh 读生产读数;建议二选一,详见参数表 §11.5-⑤-3)② 参数表 DRILL_RELAY_UNIT 键名与用途已不相称(文档项)。📁 证据 = 工作区 _tmp_seq37/。
11:3x–12:0x · 序㊳ 执行棒(两项收口:探针夹具封闭性 + 键名对齐;⛔ 未开工 P2)
来源 = 用户对序㊲ 收官时"两项待你过一眼"的答复原文:1 a 2 改名 3 说下要定的具体内容 ⇒ ① 夹具封闭性选 A 方案(补守卫)|② DRILL_RELAY_UNIT 改名|③ 说明 P2 待拍板内容(⛔ 不动手)。
① 夹具封闭性(A 方案落地) —— OBS-24 / OBS-25 取数改为 if (<夹具> !== undefined) { 读夹具 } else if (fixture) { SKIP + 留痕 } else { ssh }(守卫排在 ssh 之前);文件头新增「封闭性」硬约束段(含"新增可 ssh 取数的 OBS 必须照此顺序写"+"夹具跑里出现任何一次 ssh 即违约"的判据)。先红后绿(两侧同一份 --table 副本:SSH_TARGET_47/SSH_TARGET_106 → 127.0.0.1、SSH_PORT → 1 ⇒ "是否 ssh"变成可观测差异):
🔴 红腿(摘掉守卫 = 还原序㊱ 形态)= FAIL OBS-24 ❌ 注册表**读取失败**(⛔ 与"不存在"可分):Command failed: ssh -p 1 -o BatchMode=yes 127.0.0.1 … + ssh: connect to host 127.0.0.1 port 1: Connection refused(真 ssh 调用 2 次 —— 原文里 Command failed: ssh 计数 = 2);
🟢 绿腿(现产物)= SKIP OBS-24 夹具模式未给 --nodes-fixture ⇒ SKIP + 留痕(⛔ 不去 ssh 读生产)(真 ssh 调用 0 次);两侧逐行 diff 只差 OBS-24/OBS-25 两行。
可分性(新守卫没把"给了夹具但读不到"也吞成 SKIP)= 给不存在的夹具路径 ⇒ FAIL … ❌ 注册表**读取失败**…:夹具不存在:…/NO_SUCH_nodes.json(⛔ 不是 SKIP)。
② 键名对齐 —— DRILL_RELAY_UNIT → RELAY_UNIT_NAME(它记的是"两台机的 relay 单元名"这一事实、被演练脚本与探针 OBS-08 共用 ⇒ 原 DRILL_ 前缀与用途不相称);值格未动(仍 dshs-relay)⇒ ⛔ 零个新增 / 改动生产 env;引用点 3 处全改(overlay-failover-drill.cjs + 原因注释 / overlay-probe.cjs / 参数表 §3.9 + 小节标题注 + §11.5-⑤-4 状态)。⚠️ 文档库档案不改(04-调整方案/117-… 与归档单 T13 记的是当时事实)。真机验证 = 原样命令 ssh -p 22 test106 '… $(systemctl is-active dshs-relay)' ⇒ __RELAY_ACTIVE__=active ✅。
③ P2 待拍板清单(只登记,⛔ 未动手) —— 落 交接单 §8.11:核心两条 =(①)要不要为打洞开「UDP 入站」云安全组规则(A 开 / B 不开)(②)若开,入站 UDP 段的来源范围(甲 0.0.0.0/0 / 乙 仅对端节点 IP / 丙 走已建成的 443/TCP 兜底)。依据 = 实测三条:云安全组拦 UDP 入站(47 的 UDP 观察器 21100/21101 开放 75 s 零收包,⛔ 不是 nft —— input policy = accept)|打洞 2/2 可打洞、对端→本机 10/10 收包、本机→云机取不到|云机↔云机本就是 L1 直连、不是打洞场景(收益面只在"用户设备 ↔ 云节点")。
④ 序㊲ 成果未被本棒破坏(回归自证)—— OBS-08 三态仍可分:对端中继声明端口 ⇒ SKIP OBS-08 … 客户端挂在**另一台中继**上(⛔ 非故障、⛔ 不判红);⛔ 未给对端视图 ⇒ FAIL OBS-08 …(不可判)|… 夹具模式未给 --peer-status-fixture(⛔ 不去 ssh)。
⑤ 零回归 —— npm.cmd test 201/200/0/1(rc=0,与基线逐字一致)。
⑥ 三件套完整读数 = npm.cmd test(Node v22.22.2)201/200/0/1(rc=0)|overlay-failover-drill.cjs --scene all --table 12 PASS / 0 SKIP / 0 FAIL(rc=0;幕4-C 20770 ms / deadline 30000)|overlay-probe.cjs --table(真机)25 PASS / 0 SKIP / 0 FAIL(rc=0)。⚠️ 演练副作用与复原(⛔ 未重启任何 worker、⛔ 未换实例):演练后 47 视角 ep=[] / used=1 / idOk=1 ⇒ 探针 21P / 2S / 2F(2F = OBS-01 / OBS-04 —— 计数判据,⛔ 与"端点表为空"无关)⇒ 停 / 启 106 dshs-relay ⇒ 约 22 s 回落 used=2 / idOk=2 / 端点 [(19000,33213),(21001,42783)] ⇒ 探针回绿。⚠️ localPort 又漂(42717 → 42783;改动后首次真机跑为 44231)⇒ 判据跟着事实走、⛔ 无须改表值 ← 序㊲ 的收益再次自证。🔑 键名改名的真机端到端证据 = 演练态 SKIP OBS-08 原文含「对端中继(test106)声明了端口…」⇒ 判别器真走通了含 systemctl is-active ${RELAY_UNIT_NAME} 的那条 ssh(比手跑单条命令更强的证据)。
⑦ 收尾 = 参数表 §11.6(红绿原文 + 可分性 + 三件套 + 演练复原 + 边界 + 证据;🔴 §10 指纹 71848fad4ee0d6a574d833169e042fd1 → 2275870a5a9eb1964a648f2950dee528 现算并同步)|交接单 §8.10(本棒收口)+ §8.11(P2 待拍板清单 = 用户点名的"要定的具体内容";⛔ §8 前前缀 085e28b56a08aa1f01999bdb3e238911 逐字不变 ✅)|入口 §0 新增一行 + §2 换「序㊳ 已收官」。边界 = ⛔ 未 commit / push(HEAD 09ce76f;git status --short 11 处 = 序㊲ 的 10 处 + 本棒新增 scripts/overlay-failover-drill.cjs 一处 M,逐条可解释)|⛔ 未改任何生产配置值(参数表值格一律未动)|⛔ 零新增暴露面(OBS-11 多出 0 缺失 0、relay 口 1/1 回环)|🔴 RELAY_FAILOVER_COOLDOWN_MS 命中 0|⛔ 未改 bwrap / nft / nginx|⛔ 未开工 P2。📁 证据 = 工作区 _tmp_seq38/。
12:2x–12:3x · 序㊴ 规划棒(P2 拍板落地 + 本线首份 P2 可执行单;⛔ 零代码 / 零服务器改动)
触发 = 用户对 §8.11 两问的答复原文:1 用户可设置,默认开启提示用户 2 乙。
用户口径(⛔ 不许改写):① 打洞能力交给用户自己控制(可设置)+ 默认开启 + 必须提示用户(⇒ ⛔ 不是简单的"开 / 不开")|② 云安全组 UDP 入站仅放行对端节点 IP(⛔ 非 0.0.0.0/0)。
产物 = 工作区根 交接单_覆盖网络直连与P2P_20260918.md(归档号 132 · 239 行 · §8 前前缀 8925c2460810c6dc5cdbc075b6cdaed2)。结构 = §1 用户口径(含 3 条自决的产品口径:设置项落两处 / 缺省开 / 提示必须可行动)|§2 8 条只读前置(全部已取证)|§3 在册文件集(5 新增 / 4 修改 / 不改清单)|§4 技术路线(候选交换复用既有 wss + 内建 dgram 打洞 + 开关与提示 + peer 接线 + 乙方案落地点)|§5 判据 D1–D8|§6 步骤 S5 / S6 / S7|§7 权限影响评估(已拍板)|§8 回报格式|§9 回头条件(8 条)|§10 未验证项(5 条)|§11 指纹与状态。
新增取证(⛔ 与旧印象冲突时以本节为准):
- 🔴
src/零 UDP / 穿透代码 ——grep -rniE "candidate|punch|directPath|natType"在src/net/relay/*.ts仅命中directory.ts的中继候选(⛔ 不是节点候选地址)⇒ 直连从零建。 - 打洞可行性脚本 =
scripts/overlay-holepunch.cjs(序⑥ S4;⛔ 一次性、不进产品路径,头部明写"⛔ 不是本系统打洞成功率")。 peer档有账本、传输走 wss ——peer.ts头注原话:「不做传输(取块走source.ts注入的 fetcher,底层复用既有 wss 通道)」⇒ S6 的真正含义 = 把 fetcher 接上直连。- ⛔ 不引入新依赖(
client.ts用 Node 22 内建WebSocket;addr-override.ts头注明写"不引入undici/ws")⇒ 打洞只用内建dgram。 src/web/routes/overlay.ts(83 行)= P0-2 引导目录端点(只读无鉴权),⛔ 与"管理面 API"overlay-nodes.ts(未建、归 P2)不是同一物。
🔴 一条如实登记的技术现实(同时写进新单 §4.5):乙要求云安全组按"对端节点 IP"放行,而家宽 / 移动节点的公网出口 IP 会变 ⇒ 规则会失效、且云安全组规则数有上限。序㊴ 自决(可推翻) = 乙-1 起步:只对有固定公网 IP 的节点开(云节点 / 专线);家宽节点本期走中继(⛔ 不影响可用性,只影响"它能不能被直连")。乙-2(半自动:平台算清单 + 人工 / 脚本写控制台)与 乙-3(云 API 自动化,🔴 需云 AK/SK)登记为新单 §9 回头条件 —— ⛔ 本棒未请求任何凭据。
收尾 = 新单落盘(占号 132:现核正式档案最大 128、.lock-131 仍在 ⇒ ⛔ 不重用 129/130/131)|旧单 §8.12 拍板落地(⛔ 正文一字未改 ⇒ §8 前前缀 085e28b56a08aa1f01999bdb3e238911 逐字不变 ✅)|参数表 §8 新增 ⑩ 行 + 附注口径更新 + §11.7 补记 + §10 指纹 2275870a5a9eb1964a648f2950dee528 → d408d640246a980f702fe7b0a2895219(现算并同步)|入口 §0 新增一行 + §2 登记下一棒。
下一棒 = 序㊵ 执行棒(P2 · S5:直连候选交换 + 打洞探测),automation d4fa99ac-6f7b-400f-89e7-797de3b7681a(一次性 · 2026-09-18 12:33 = 本棒收口(12:2x)+6 min ⇒ 落在 58 分钟窗口内;nextRunAt = 1789705980000)。
边界 = ⛔ 零代码改动 · ⛔ 零服务器改动 · ⛔ 未 commit / push(HEAD 09ce76f)· ⛔ 未改任何生产值(参数表只加不改)· ⛔ 未开工 P2。⚠️ 一条遗留(仅报告,⛔ 未动手):04-调整方案/.lock-131 仍在(序㊱ P1 占号窗口未释放)⇒ 后续取号者会永久跳过 131。📁 证据 = 工作区 交接单_覆盖网络直连与P2P_20260918.md。
11:4x-12:0x · 安装 Brevo(海外邮箱)官方 MCP 服务(已配好并实测通过)
诉求(用户原话):安装海外brevo邮箱 的mcp服务(附 API Key 的 base64)。
结论:可用,已写入配置。 用户给的是普通 API Key(xkeysib-…,89 字符),经实测可直接驱动 Brevo 官方托管 MCP —— 但必须走 api-key 头,走 Authorization: Bearer 会被拒(invalid_token / Invalid or expired OAuth session)。官方文档只写了 Bearer + 专用 MCP 令牌,没写这条路。
配置落点:E:/ProgramData/.workbuddy/mcp.json(=本机 WORKBUDDY_CONFIG_DIR 下的 MCP 配置;⛔ 非 .mcp.json)。备份 = mcp.json.bak-20260918-brevo。
注册了 8 个分模块端点(共 64 工具)(基址 https://mcp.brevo.com/v1/<module>/mcp):
| server 名 | 模块 | 工具数 |
|---|---|---|
| brevo-campaigns | email_campaign_management | 12 |
| brevo-transac | transac_templates(事务邮件发送,核心) | 18 |
| brevo-templates | templates | 7 |
| brevo-senders | senders | 5 |
| brevo-domains | domains | 5 |
| brevo-contacts | contacts | 6 |
| brevo-lists | lists | 7 |
| brevo-analytics | campaign_analytics | 4 |
⛔ 未采用聚合端点 /v1/brevo/mcp —— 它一次性暴露 282 个工具,会随每轮全量重发烧上下文。⛔ 未纳入 CRM / loyalty / whatsapp / sms / coupons 等非邮箱域(需用时再加模块)。
验证三层全过:① JSON 合法(11 servers)② 8 个端点 initialize + tools/list 全 200 ③ 真实 tools/call:get_senders 回真实数据(sender aisharenet / [email protected],active)、get_domains 回 count:0(该账号未配域名);另用普通 REST api.brevo.com/v3/account 单独验证 Key 有效(账号 [email protected],组织 aisharenet,SMTP relay smtp-relay.brevo.com:587,登录名 [email protected])。
🔴 本轮五个坑
- 🔴 文档没写全鉴权头 ⇒ 别把 401 当"Key 无效":Bearer 401、
X-Api-Key401,api-key200。判别法 = 另打厂商普通 REST API 把"Key 坏"与"头写错"分开。 - 🔴 Cloudflare 1010 拦 Python:
urllib被Error 1010 browser_signature_banned拒(TLS 指纹)⇒ 换 curl 即通。探测一律用 curl。 - 🔴 聚合端点 = 上下文炸弹(282 vs 64)。
- ⚠️ 本机 git 全局代理指向未监听端口(
127.0.0.1:10800)⇒ 探测要--noproxy '*';mcp.brevo.com 直连可达,无需代理。 - ⚠️ 服务端无状态、不返回
mcp-session-id⇒tools/list不带 session 也能调;⛔ 别因缺该 header 判失败。
待用户动作
🔴 改了 mcp.json ≠ 生效 —— 需在连接器管理页右上角「自定义连接器」对 8 个新 server 逐个点「信任」才会激活。 ⚠️ 连接器市场无 Brevo 连接器(已查:仅 QQ邮箱/飞书/钉钉/企业微信等)⇒ 厂商 MCP 是唯一路径。
边界自证
⛔ 未动既有 MCP 条目(baota-mcp ×2 / github-custom 原样保留)· ⛔ 未动生产 · ⛔ 未 commit/push · ✅ 临时目录 _tmp_brevo/ 已删 · ✅ 密钥扫描未落入工作区(仅存在于 mcp.json +其备份,与既有 baota/github 令牌同为明文存放,属既有约定)· ✅ 技能 workbuddy-mcp-install 已建(用户级)。
覆盖网络线 · 序㊵ 执行棒(P2 · S5:直连候选交换 + 打洞探测)· 2026-09-18 12:33–13:2x
判定 = 线内可停 · 🔴 D8(云安全组)待用户拍板。依据 = 工作区根 交接单_覆盖网络直连与P2P_20260918.md(归档号 132;§8 前前缀 8925c2460810c6dc5cdbc075b6cdaed2,回填 §8 后逐字不变 ✅)。
交付(代码) = 新增 src/net/relay/direct/{candidate,punch,index}.ts(候选交换 / dgram 打洞 / 开关·默认值·提示)+ src/web/routes/overlay-nodes.ts(P1 出口项=管理面 API)+ scripts/overlay-direct-probe.cjs(只读观测面)+ test/overlay-direct.test.mjs(10 用例)+ 探针 OBS-26/27/28;修改 src/net/relay/network.ts(只加 isAllowedDialer = 白名单准入的唯一可复用出口,⛔ server.ts 零字节改动)/join.ts/src/net/relay/index.ts/src/web/server.ts/scripts/overlay-node-join.cjs/scripts/overlay-probe.cjs。
读数 = 探针 28 PASS / 0 SKIP / 0 FAIL(rc=0;基线 25P ⇒ +3 = OBS-26/27/28)|npm.cmd test 201/200/0/1(逐字同基线)|--scene all --table 12P/0S/0F(幕4-C 23422 ms / 30000)。部署 4 处(47 /opt/dshs/lib + /opt/dsh-relay/lib;106 /opt/dshs-cluster/lib + /opt/dsh-relay/lib,32 md5 全同、不一致 0)+ 3 脚本到 47 /opt/dshs/scripts/;重启 47 dshs + dshs-worker;回滚点 /opt/dsh/backups/seq40-0918-1255/。
D1–D6 先红后绿:先红 = 旧产物 Error: Cannot find module '/opt/dshs/lib/net/relay/direct/index.js'(入口即缺);后绿 = OBS-26/27/28 三行 PASS。管理层端点 /api/admin/overlay-nodes[/direct] 404 → 401。
🔴 D8 = 唯一红(未实施):云安全组 UDP 入站仍未放行(双向实测均发 20 收 0;nft input policy = accept ⇒ 挡在云侧、非 nft)。拟录 乙-1 两条 = 47↔106 各放行对端节点 IP /32 × UDP 21100/21115,⛔ 零个 0.0.0.0/0。未实施理由 = 属 §1 边界外第 ④ 类(需用户给控制台访问方式 / 审批)⇒ ⛔ 未索取、未硬编码任何云 AK/SK。
🔴 本棒自造过一次生产影响(已修复):首次 --scene all 被 timeout 300 截断 ⇒ 末尾 restore() 未执行 ⇒ 106 dshs-relay 停机约 4 min(13:05:58 → 13:10 发现后 systemctl start 复原;该窗口门户 / 实例面全程 200、无业务中断证据)。教训:--scene all 内含 120 s + 90 s 观察窗口 ⇒ ⛔ 不许套小于 ~8 min 的外层超时。
🔴 本棒修掉两条自造缺陷(均在本棒新建的观测脚本内,不涉既有生产代码):① --ss 是布尔开关却按"带值选项"解析(opt() 只认字符串)⇒ 该腿恒为 null(死代码)、且正对照硬编码 null ⇒ 潜在假绿("关闭态 0 行"在测量坏了时也是 0)⇒ 修 = 按"出现过"判定 + 新增正对照(真绑一个直连口、要求 ss 看得见);② punch 从 direct/index.js(选择性桶导出,不转发 punch 常量)取 DEFAULT_PUNCH_DEADLINE_MS / DEFAULT_DIRECT_COOLDOWN_MS ⇒ undefined ⇒ Number() = NaN ⇒ 冷却构造期断言直接抛(原文「收到 null」是假象 —— JSON.stringify(NaN) === 'null')⇒ 修 = 改从 punch.js 取 + 启动期硬断言(缺常量 ⇒ 具名 exit 2,⛔ 不再静默取缺省)。
⚠️ D7 块 id 复算属 S6 ⇒ 本棒如实登记 未验证(⛔ 不编数;变更面自证 = src/net/relay/content/** 零改动)。
边界自证 = ⛔ 未 commit / 未 push(HEAD 仍 09ce76f;git status --short 17 处与开工逐数相同)|⛔ 未改 server.ts DIAL/白名单语义 · ⛔ 未改 nft(72 行逐字一致)/ nginx / bwrap|🔴 RELAY_FAILOVER_COOLDOWN_MS=0 命中 0|🔴 密钥本体不经网络 / relay|值格一律未动 ⇒ 零个新增 / 改动生产 env(DSHS_OVERLAY_DIRECT 两机命中 0 = 走缺省即开)。
参数表 §10 指纹 d408d640246a980f702fe7b0a2895219 → 6b37bfd506758d882d9f803678f85d23(现算并同步;⚠️ 写 §11.8 不改该指纹 —— §11 在口径之外,已实测复核)。
收尾四件套 = ✅ 交接单 §8 全节|✅ 参数表 §11.8|✅ 入口 §0(新增一行)+ §2(下一棒)|✅ 本日志|✅ --release-exec 释锁。证据落点 = _tmp_seq40/(probe.realmachine*.txt / drill2.txt / npmtest.txt / selfcheck47*.out / local.md5 / udp_recv.js / udp_send.js / table.copy.md / probe.green2.txt / probe.red2.txt),⛔ 未清理("先红后绿"的可复现证据)。
➡️ 下一棒(唯一一个) = 序㊶ 执行棒(P2 · S6:peer 档接线 + D7 块 id 复算),automation 32c2cde1-e5c4-427a-9b9b-e8adab1c8725(一次性 · 2026-09-18 13:34 = 收口 +~7 min;nextRunAt = 1789709640000)。
序㊶ 执行棒(P2 · S6:peer 档接线 + D7 块 id 复算)· 2026-09-18 13:35–14:0x
判定 = ✅ D7 绿(先红后绿两腿齐)· ✅ 零回归三件套全绿 · 🔴 D8 云安全组仍未放行(既存唯一红,本棒只读核对)· ➡️ 已登记唯一下一棒 = 序㊷(P2 · S7 规模回归)。
开工门 = 锁 --claim-exec "序㊶ 执行棒(P2·S6)" 抢到(13:35)|§8 前前缀开工前现算 = 8925c2460810c6dc5cdbc075b6cdaed2 ✅ 逐字一致(回填 §8.8 后仍逐字不变)。范围 = 只做 §6 的 S6(⛔ 未做 S7)。
交付(2 源文件 + 1 观测面) = src/net/relay/content/runtime.ts(fetchFromPeers() + 双通道 PEER_CHANNEL_ORDER=['direct','wss'] + 🔴 D7 复算闸门(blockIdOf(gotBytes)!==id ⇒ 丢弃且不算命中、idMismatches 计数)+ peerWireSnapshot() + noteDirectCandidate()/withdrawDirectCandidate() + 注入式 peerChannels)|src/net/relay/content/source.ts(仅注释:复算闸门刻意落在装配层、⛔ 不放进"五档通用链"以免分层退化)|scripts/overlay-direct-probe.cjs 新增 peer-wire 子命令(13 条具名判据 + 块 id 不变性读数)。
D7 读数(原文) = 主判据 idsDigest = ec70e7166ae24b1367c7c251ead8ad2979f66463ae3e6380eeda84fabb985c3a(四处同值:本机接线前/本机接线后/47 生产接线前/47 生产接线后;plain putPlan[0]=3374319c90813e8f7911654132f34a0c、cipher putPlan[0]=8dd3ea58093df7130ba07722cd28bf81);先红 ① 扰动 blockIdOf ⇒ digest → fbb80585c86a4c492f6d71a7af9212121f35c2c43f2cc7018d08149e2cff5ac3,还原后 md5 逐字回 a69b3379c719562c46d3e63832bdf25d、diff 空;先红 ② 拆闸门 ⇒ peer-wire 判据 ⑦ 转 FAIL(原文 {"tier":"peer","bytesMatch":false,"hits":{"wss":1},"idChecks":1,"idMismatches":0,"peerHitsTotal":1} = 篡改块被记成"命中成功"的假绿本形),还原后 ✅ + idMismatches=1、tier=null。真机 content.peerWire 新键在线(wired={direct:true,wss:false}、idChecks=0、last=null)。
E1 回归 = 接线腿 amp=1.0000(A originFetches=6 / 5,255,225 B;B servedFromPeer=18、hits=[6,6,6]、idChecks=[6,6,6]、idMismatches=[0,0,0])/对照腿 amp=4.0000(originFetches=24 / 21,020,900 B)⇒ 与序㉔/㉛ 的 4.00× → 1.00× 逐项对齐;idGate={idChecks:18,idMismatches:0}。
三件套 = npm.cmd test 201/200/0/1|--scene all --table 12P/0S/0F(rc=0,6m27s,幕4-C 18990 ms/30000;未套外层超时 ⇒ restore() 正常、两台 relay 均 active)|overlay-probe --table 28P/0S/0F(部署后+演练后两次同值)|test/overlay-content.test.mjs 44/44。
部署 = 4 处(47 /opt/dshs/lib + /opt/dsh-relay/lib;106 /opt/dshs-cluster/lib + /opt/dsh-relay/lib),runtime.js md5 四处全同 c9a8b01a78524d31cd77fde32895839a、source.js 43cb1b7ab5387ff9745e8dab7726b68b(接线前 runtime.js = 7fe548c42b71b9e4785f139561fe8925);重启 47 dshs-relay+dshs、106 dshs-relay;回滚点 = 两机 /opt/dsh/backups/seq41-20260918-135146/。改动面 = 6 文件(content/runtime.{js,d.ts,js.map} + content/source.{js,d.ts,js.map})。
D8(只读核对,红) = 双向并发 UDP:47 发 29 收 0 / 106 发 28 收 0(reason=deadline);两机 nft 72 行未动 ⇒ 挡在云侧;⛔ 未改任何云侧规则、⛔ 无任何 0.0.0.0/0、⛔ 未索取/未硬编码任何云 AK/SK。
🔴 三条经验(可复用):① D7 这类"接线不改语义"的判据,红腿必须做两条 —— 只做"扰动实现"会漏掉"闸门被拆"这一路(后者才是"零回源"变假绿的真实入口);② 夹具对照腿必须用全新冷 store —— 复用已填充的 store ⇒ 假对照(本棒实测踩过,amp 得到天文数字);③ 跨模块键口径要对齐 —— 直连候选入册键必须与 peer.ts#candidates() 同口径(逻辑名 network/hostId),用载荷 hostId ⇒ 判据假红。
⚠️ 三条如实留档(已写进单 §8.8-⑦) = ① 真机双向直连不可达属已知 ⇒ peer 档正确形态 = 回落 wss 且块 id 不变(⛔ 未把"直连建立了"写成成功);② S6 的数据面刻意未建成(直连通道以 data-plane-pending 具名降级、fetch() 抛错,⛔ 不静默回"没有");③ 106 /opt/dshs-cluster/lib 无 registry.js ⇒ overlay-direct-probe.cjs 在 106 跑不起来(D8 核对改用独立最小脚本 d8_punch_106.cjs;探针留存在 106 的副本不可跑,属独立后续项)+ 106 bwrap = 0.11.0(47 = 0.4.0)。
收尾四件套 = ✅ 交接单 §8.8(⛔ 未改 §1–§7、⛔ 未改 §8.1–§8.7 小节点名;§8 前前缀写入后现算仍 = 8925c2460810c6dc5cdbc075b6cdaed2)|✅ 参数表 §11.9(§10 指纹现算未变 = 6b37bfd506758d882d9f803678f85d23 —— §11 在 §10 口径之外;⛔ 零键零值变更)|✅ 入口 §0(新增一行)+ §2(下一棒)|✅ 本日志|✅ --release-exec 释锁。证据落点 = _tmp_seq41/(ids.mjs / ids_before.txt / ids_after.txt / e1.mjs / lib_before/ / d8_47.json / d8_106.json / d8_punch_106.cjs),⛔ 未清理("先红后绿"的可复现证据)。
边界自证 = ⛔ 未 commit / 未 push(HEAD 仍 09ce76f;git status --short 19 处 = 开工 17 + 本棒 2)· ⛔ 未改 server.ts(DIAL/白名单语义零字节)· ⛔ 未改块 id 计算路径(扰动临时且已逐字还原)· ⛔ 未改 nft(72 行)/ nginx / bwrap · 🔴 RELAY_FAILOVER_COOLDOWN_MS=0 命中 0 · 🔴 密钥本体不经网络 / relay(两机 600)· ⛔ 零个新增/改动生产 env(DSHS_OVERLAY_DIRECT 两机命中 0 ⇒ 缺省即开)。
➡️ 下一棒(唯一一个)= 序㊷ 执行棒(P2 · S7:规模回归 —— 候选数 / 直连成功率 / 切换耗时 / 回源字节 四项复测),automation 690f44e9-b6f7-4517-ae2b-ca0b05b8dfe9(一次性 · 2026-09-18 14:14 = 收口 +~6 min;nextRunAt = 1789712040000)。
14:14–14:5x · 序㊷ 执行棒(覆盖网络线 · P2/S7 规模回归 四项复测)—— ✅ 四项全绿 · ✅ 三件套全绿 · 🔴 D8 仍为唯一红
一句话 = 四项规模读数各自拿到原始读数并与基线逐项对齐 —— 候选数不退化、回源字节"按组线性增长"被机器断言、切换耗时 20.9 s / 限 30 s、而直连成功率只有模拟器是 1.0000,真机仍是 0。
① 候选数 = dshs@47 与 dshs-worker@106 均 count=3 hosts=3(≥ CAND_MIN=2,逐字同序㉙ 基线;⚠️ hosts=3 ≠ 独立路径数 —— 前两条候选摘名不同同落 47 ⇒ 机器级只有 2)|直连候选准入 accepted=3 / rejected=9(每条具名)/ silentRejections=0 / bucketsPerNetwork=true / matcher=network.ts#isAllowedDialer|🔬 规模夹具(_tmp_seq42/s7_candidate_scale.mjs,2 张网 × {4,16,64} 节点)⇒ accepted 10/34/130(线性)、rejected 32/128/512(8 类原因各 perNet 条、全部具名)、silentRejections=0、按网分桶 true(同名 hostId 跨网互不可见 ⇒ 跨网窥探得 cross-network)。
② 直连成功率(🔴 "判据成立"与"冗余建成"已彻底分开)= 本系统(离线 NAT 模拟器,同一份 runPunchAttempt)正腿 24/24 = 1.0000 双向、p50 建连 155 ms;负腿 one-way(a)=12 / one-way(b)=12 全 0、both=12 全 deadline(⛔ 有收包一律不算成功)|真机 47→106.54.21.172:21100 发 21 收 0、106→47.77.182.89:21100 发 28 收 0(reason=deadline)⇒ 不可达(D8 未放行) ⇒ ⛔ 未把"直连建立了"写成成功;真机形态 = 回落 wss 且块 id 不变。📌 对照 §3.2:HOLE_PUNCH_RATE_LOCAL = 分层可行性 2/2 —— 它是"能不能打洞",⛔ 不是"本系统成功率"(两者必须分开报)。
③ 切换耗时 = 幕4-C 20871 ms / 30000(PASS)|幕1-A 20605 ms|幕4-A 18815 ms(n=3,均在 deadline 内侧;对照序⑨ 修后基线 20.9–23.9 s 同量级)|收口后 jitter.p95AbsDeltaMs=6 ms / overThreshold=false(⚠️ 演练窗口内曾读到 920 ms —— 同源 = 心跳 RTT,含应用层与验签 ⇒ ⛔ 按 §3.5 口径不得当链路 RTT 用)。🔴 阈值权威落点 = 参数表 §4 RELAY_FAILOVER_DEADLINE_MS —— ⛔ 不是 prompt 写的 §3.2(§3.2 是打洞率) ⇒ 按权威落点对照 + 如实留档(⛔ 未为迁就指针改 §3.2 / §4 任一格)。
④ 回源字节(夹具 = 同一份 5,255,225 B / 6 块,逐次计 origin fetcher 字节)= 1组×4节点 1.0000(5,255,225 B)|1组×16节点 1.0000|4组×4节点 4.0000(21,020,900 B)|8组×4节点 8.0000(42,041,800 B)|对照腿(peer 关)= 4 / 16 / 16 / 32 × ⇒ 🔴 每组合计恒 1.0000(= 规模不变量:回源字节 ∝ 组数、⛔ 不随组内节点数增长)。✅ 与序㉔ 1.0000 ⇄ 4.0000、序㊛ 4 组 = 21,021,572 B = 4.0001× 逐项对齐。运行时接线腿(8 组×4 节点,真 ContentRuntime)= wss-回落腿 hits.wss=144 / downReasons={direct:no-address:144}|direct-优先腿 hits.direct=144 / hits.wss=0 ⇒ 优先直连且 ⛔ 不碰 wss;两腿均 idChecks=144 / idMismatches=0(每次命中都过 D7 复算闸门)。📌 §10-2 内容面节省 = 1 − 组数/节点数 ⇒ 组内 4 人 75.00% / 组内 16 人 93.75%(真机直连节省仍 = 0,因 D8)。
零回归三件套 = npm.cmd test 201/200/0/1(duration_ms=53333;逐字同基线)|--scene all --table 12 PASS / 0 SKIP / 0 FAIL(rc=0;6m20s;未套外层超时 ⇒ 末尾 restore() 正常执行、两台 dshs-relay 均 active)|overlay-probe.cjs --table 28 PASS / 0 SKIP / 0 FAIL(开工前 + 收口后两次同值)。
收尾四件套 = ✅ 交接单 §8.9(新增;⛔ 未改 §1–§7、⛔ 未改 §8.1–§8.8 小节点名;§8 前前缀写入后现算仍 = 8925c2460810c6dc5cdbc075b6cdaed2 ✅)|✅ 参数表 §11.10(§10 指纹现算未变 = 6b37bfd506758d882d9f803678f85d23 —— §11 在 §10 口径之外;⛔ 本表零键值改动)|✅ 入口 §0 新增一行 + §2 更新下一棒|✅ 今日日志(本节)|✅ --release-exec 释锁。
边界自证 = ⛔ 未 commit / 未 push(HEAD 仍 09ce76f;git status --short 19 处 = 与序㊶ 收口逐数相同 ⇒ 零新增条目)· ⛔ 本棒零仓内改动(三项夹具 + 读数全在工作区 _tmp_seq42/,⛔ 仓外)· ⛔ 未改 server.ts / content/** 块 id 口径(本棒未做任何扰动实验)· ⛔ 未改 nft(72 行)/ nginx / bwrap(47=0.4.0、106=0.11.0)· 🔴 RELAY_FAILOVER_COOLDOWN_MS=0 命中 0 · 🔴 密钥本体不经网络 / relay(content-group-key.json 两机仍 600)· ⛔ 零个新增 / 改动生产 env(DSHS_OVERLAY_DIRECT 两机命中 0 ⇒ 走缺省即开)· ⛔ 零新增监听口(收口后 ss -lunp 在 21100–21115 段 0 行;OBS-11 多出 0 缺失 0)。
🔴 三条如实留档(已写进单 §8.9-⑥) = ① 探针 / 演练必须从「工作区根」跑(按 cwd 找参数表;从代码仓根跑 ⇒ ❌ 参数表装载失败 … 找到 0 个参数表 rc=2;⛔ 该失败不发生任何生产动作)|② 演练后的复原程序要"停够久" —— "停 2 s 即启"不触发回落(worker 在 RELAY_GRACEFUL_BURST_MS=15000 的快速重试窗内重连回同一条 url;该窗内 attempts 恒 0 ⇒ 切流条件不成立),改"停 26 s 后启"成功(used=2、端点 2 条全在线)⇒ ⛔ 未重启 worker、⛔ 未换实例|③ 一处过程测错并当场修正 = 首次 selfcheck --ss 与 punch 腿并发 ⇒ punch 先绑住 21100 ⇒ 正对照 EADDRINUSE ⇒ ssDuringOnCase 读成 null、ssBefore 读成 1("UDP 口被占"的假红);单跑后 = ssBefore 0 / offCase 0 / onCase 1(与序㊵ 逐字同值)⇒ 测量错,⛔ 非产品缺陷。
🔴 一条口径纪律(本棒再次执行) = "判据成立" ≠ "冗余建成" —— 候选数 count=3 ✅ 但机器级独立路径只有 2 台;打洞模拟器 1.0000 ✅ 但真机 0。两者分开报,⛔ 不许用前者的绿掩盖后者的红。
➡️ 下一棒(唯一一个)= 序㊸ 执行棒(观测面缺口收口:① overlay-direct-probe.cjs 在 106 上可跑〔⛔ 不靠再铺 registry.js,改惰性/可选加载 + 具名降级〕② 参数表定位与 cwd 解耦〔⚠️ 保留"恰好 1 个才合法"防错〕③ 106 上不可跑残留副本处置),automation 8dbee90b-7d49-4c97-a25e-fdc302f9ca32(一次性 · 2026-09-18 14:47 = 收口 +~6 min;nextRunAt = 1789714020000)。⚠️ 同一时刻只挂这一个棒;📌 在册待你拍板项 = D8(云安全组乙-1,需控制台访问方式 / 审批)—— 已在册,⛔ 不因它阻塞排棒。⚠️ D8 仍待用户拍板(已在册、非本轮新发现):要不要现在开通云安全组 乙-1(需用户给控制台访问方式 / 审批;⛔ 不索取、不硬编码任何云 AK/SK)。
2026-09-18 15:2x · 覆盖网络线 序㊸ 执行棒(观测面缺口收口)收官 —— 判定 =「线内可停 · 🔴 D8 待拍板」,⛔ 未登记下一棒
做了什么(3 个脚本,⛔ 零 TS / 零 src / 零 build)
scripts/overlay-direct-probe.cjs:顶层对../lib/net/relay/registry.js(控制面注册表模块)与同样 import 它的../lib/net/relay/join.js的硬require改成惰性 / 可选加载 ⇒ 只有join 回读(判据 D3)这条腿依赖它们,缺则具名降级{available:false, reason:'module-missing', missing:[{spec,code,message}]};读数加机器可读degraded/degradedLegs;文本行join 回读:⛔ 不可用(module-missing)—— 缺 …|⚠️ 这是「没装」不是「没采到」。⛔ 不静默返"没有"(缺块不填direct/readback);只吞MODULE_NOT_FOUND/ERR_MODULE_NOT_FOUND且原文 message 原样带出,其它异常照抛。scripts/overlay-probe.cjs+scripts/overlay-failover-drill.cjs:参数表定位与cwd解耦 ⇒ 候选目录链--table(显式文件,最高优先)>--dir>DSHS_OVERLAY_TABLE_DIR> 机器本地注册文件(DSHS_OVERLAY_TABLE_REGISTRY,缺省~/.dshs/overlay-table-dir,一行一个目录)>cwd> 脚本目录及上两级。🔴 "恰好 1 个才合法"保留且更严:任一候选目录 ≥2 ⇒ 立即报错;跨目录合计 ≥2 ⇒ 也报错;一份都没有 ⇒ 报错并列出所有搜过的目录(⛔ 不放宽成"找不到就用缺省")。- ⚠️ 范围新增 1 处(已声明):
overlay-probe.cjs的OBS-26子判据 +3 行 —— 生产方显式给joinConf.available === false时,该子判据取 SKIP + 留痕(⛔ 不判红、detail 点名缺哪个模块)。理由 = 上面改了读数形状,不改这里会让一份合法的 106 读数假红;零回归佐证 = 老形状(无available键)走原路径、判定与文本逐字不变。
关键读数(⛔ 无编数)
- ① 先红后绿:106 上改前副本(md5
8d1ea60a01fc09fb5f56e492afb76fc9)⇒status/selfcheck --json两条都原文Error: Cannot find module '../lib/net/relay/registry.js';修后同一规范路径 ⇒statusrc=0(直连(打洞):开|来源 default|缺省 true)+selfcheck --jsonrc=0({"degraded":true,"degradedLegs":["joinConf"],"joinConfAvailable":false,"joinConfReason":"module-missing","candAcc":3,"candRej":9,"silent":0,"bi":true,"ok":2,"cooldown":300000,"zero":"throws","deps":true})+punch --peer 47.77.182.89:21100rc=0(窗内零收包(deadline 3000 ms,实耗 3000 ms,发 21 包)⇒ 判死 + 进冷却 300000 ms)。本地等效夹具:临时改名本机lib/net/relay/{registry,join}.js⇒ 同一降级形状、其余腿全在;还原后 md5 逐字回位(951a2526789b897aa58e3abbb5dea332/6946e1d802494ccb7f522ef7b937614a)。 - ② 两腿对照:旧逻辑副本(与
git show HEAD:scripts/overlay-probe.cjs的resolveTablePath逐字一致)从代码仓根 ⇒ rc=2❌ 参数表装载失败:在 D:\github\dsh_shenxian 下按 /^参数表_覆盖网络_.+\.md$/ 找到 0 个参数表(要求恰好 1 个);修后从代码仓根、不给--table⇒ 探针 28P/0S/0F + 演练 12P/0S/0F(原文# 参数表=E:\ProgramData\AI技能\aliyun-dsh-server\参数表_覆盖网络_20260917.md)。防错腿:同目录 2 份 ⇒ rc=2;跨目录 2 份 ⇒ rc=2(探针与演练各测一次)。 - ③ 处置 = 使其可跑(⛔ 未删):探针 scp 三处 md5 全同
4734686b5270059697ccbcf966c34ade(仓 / 47/opt/dshs/scripts/ 106/opt/dshs-cluster/scripts);回滚点 = 两机/opt/dsh/backups/seq43-20260918-150549/。 - ④ 三件套:
npm.cmd test201/200/0/1(53.3 s)|--scene all12P/0S/0F(6m23s;幕4-C17240 ms / 30000)|探针 28P/0S/0F(两次同值)。 - 恢复形态:47 三单元
active、relay 200、门户 200;106 两单元active;演练后 47 视角endpoints=[]⇒ 停 106dshs-relay26 s 再启 + 等 ~20 s ⇒w-106回挂、端点 2 条全在线、OBS-01 used=2。 - 边界:⛔ 未 commit / 未 push(HEAD
09ce76f;git status --short19 处 = 与序㊷ 逐数相同)|⛔ 未改server.ts/content/**/nft(72 行)/ nginx / bwrap(0.4.0–0.11.0)|🔴COOLDOWN_MS=0命中 0|密钥两机仍600|⛔ 零新增 env / 监听口(21100–21115= 0 行)|🔴 D8 零动作(⛔ 无0.0.0.0/0、⛔ 未索取 AK/SK)。
两条须知(会传给后续会话)
- 🔑 参数表定位链新增"机器本地注册文件"
~/.dshs/overlay-table-dir(本机已写一行 = 工作区根)⇒ 换机器 / 换工作区路径需补这一行(或改用--table/--dir/DSHS_OVERLAY_TABLE_DIR/DSHS_OVERLAY_TABLE_REGISTRY)。⛔ 仓内零机器路径(该文件不入库、不进git status)。 - ⚠️ 参数表 §6
OBS-26行本棒 ⛔ 未改(为保 §10 指纹6b37bfd506758d882d9f803678f85d23不变 —— §6 在 §10 口径之内)⇒ "具名降级 ⇒ SKIP + 留痕"登记在 §11.11;下次键值变更时顺带并入。
产物 / 落点:交接单 交接单_覆盖网络直连与P2P_20260918.md §8.10(§8 前前缀 8925c2460810c6dc5cdbc075b6cdaed2 写后现算逐字不变 ✅)|参数表 §11.11(§10 指纹现算 = 6b37bfd506758d882d9f803678f85d23 不变)|夹具与读数全在工作区 _tmp_seq43/(临时产物,待用户确认后清理)。
➡️ 本线可停:三项全绿、无遗留 ⇒ ⛔ 本棒未登记下一棒;唯一在册大项 = D8(云安全组,需你拍板:要不要现在开通 乙-1,需你给控制台访问方式 / 审批)。
2026-09-18 15:3x–16:0x · 覆盖网络线 序㊹ 执行棒(D8 云安全组乙-1) —— ⏸ 未收官 · 阻塞上报(用户已批准,执行侧无凭据)+ 本机角色判定结清
起因(用户原话,15:4x):「1 开通,需要我操作还是你可以自己操作,所有的测试是否包含本机,当做结点或终端」= 对 序㊸ 收官报告末节「待你拍板第 1 项 = D8」的批准 + 追加两问。
本棒性质:--claim-exec "序㊹ 执行棒(D8 云安全组乙-1)" 抢锁成功(15:37)⇒ 只读取证后停下(⛔ 零 scp / 零 build / 零重启任何单元)。
一、D8 执行侧阻塞(原文级证据 ⇒ 只能用户侧控制台落地)
| 位置 | 证据 | 结论 |
|---|---|---|
| 本机(WorkBuddy 开发机) | 无 cloud CLI、无 ~/.aliyun / ~/.tccli / ~/.aws |
无法调云 API |
| 47(阿里云) | aliyun CLI 存在(/usr/local/bin/aliyun)但 ~/.aliyun/config.json 不存在;aliyun configure list = default * | (空) | Invalid | (空) | en |
凭据未配置 |
| 47 metadata | http://100.100.100.200/latest/meta-data/ram/security-credentials/ ⇒ 404 - Not Found |
无 RAM 角色(拿不到 STS) |
| 106(腾讯云) | 无 tccli;http://metadata.tencentyun.com/latest/meta-data/cam/security-credentials/ ⇒ 404 |
无 CAM 角色 |
⇒ 🔴 依本线纪律 ⛔ 不索取、⛔ 不硬编码任何云 AK/SK ⇒ 只能用户侧操作(或由用户主动给一次性凭据 —— 本棒 ⛔ 不索要)。
二、待落地规则(乙-1 · 原文级 · ⛔ 执行侧不得改形)
- 47 阿里云安全组 · 入方向 · 协议
UDP· 端口21100/21115· 授权对象106.54.21.172/32 - 106 腾讯云安全组 · 入方向 · 协议
UDP· 端口21100/21115· 授权对象47.77.182.89/32 - 🔴 硬门:⛔ 零个
0.0.0.0/0(含拆分 / 等价写法);⛔ 不放行 TCP 段;⛔ 不改nft/nginx/bwrap。
三、前置取证(只读 · 证明 D8 是"唯一缺口")
| # | 项 | 实测 |
|---|---|---|
| a | 固定公网 IP | 47 = 47.77.182.89(i-rj99af19cibck1ge93tq)/ 106 = 106.54.21.172(ins-3q6k1p8t) |
| b | 网卡形态 | 47 eth0 172.18.16.212/18;106 eth0 10.0.0.8/22 ⇒ 两侧公网 IP 均为云网关 NAT 映射(⛔ 非直挂网卡) |
| c | UDP 区间 | [21100, 21116)(punch.ts#PUNCH_PORT_BASE=21100 + SPAN=16)。⚠️ 两机 ss -lunp 该段无监听 = 正常(打洞 socket 只在实打时才开),⛔ 不是"没装" |
| d | 直连总开关 | DSHS_OVERLAY_DIRECT 两机 /etc/dshs*.env 命中 0 ⇒ 走缺省 = 开,⛔ 无需改 drop-in |
| e | 47 本地防火墙 | nft 72 行;hook input … policy accept ⇒ 不拦入站 UDP。⚠️ 那条 udp … reject 是沙箱 uid 100000-199999 的出站限制(daddr 含 47.77.182.89),⛔ 与本腿无关 |
| f | 106 本地防火墙 | nft 0 行;iptables -P INPUT ACCEPT + YJ-FIREWALL-INPUT 仅 4 条 /32 REJECT(不含 47)+ ipset test YJ-GLOBAL-INBLOCK 47.77.182.89 ⇒ NOT in set ⇒ 不拦入站 UDP |
| g | 47 节点注册表 | /var/lib/dshs/overlay/nodes.json = {"version":1,"nodes":{}}(空);directory.json relays = alotbuy.com / relay-direct.alotbuy.com / 106.54.21.172(3 条) |
四、本机(开发机)在测试中的角色判定 —— 回答用户第二问
- 判定:本机 = 测试发起端 / 观测台 + 开发机。⛔ 不是覆盖网节点,⛔ 也不是覆盖网终端(本线节点形态只有
worker一种)。 - 五条可分证据:
- 四条测试命令均从本机发起(
npm.cmd test/overlay-probe.cjs/overlay-failover-drill.cjs/overlay-direct-probe.cjs)⇒ 本机是发起端、不是被测对象。 - 本机 零
dshs*/dsh-*进程、零20080/19100/20000/21000–21001/21100–21115监听 ⇒ 结构上不在/status.endpoints[]/sessions[]里。 - 47 权威注册表
nodes.json={}(空)⇒ 本机未注册为节点。 - 🔴 本机
curl -4 ifconfig.me回落到 IPv6(240e:332:cd0:a710:…)⇒ 无固定公网 IPv4 ⇒ ⛔ 给不出稳定/32⇒ D8 式对端放行对本机结构上不成立。 - 本机
~/.dshs/仅两项:overlay-table-dir(序㊸ 自建的参数表定位注册,⛔ 非节点注册)+secret.key(64 B · 09-13 15:40 · 系src/config.ts#ensureSecretKey的数据根密钥,⛔ 非节点密钥;密钥本体 ⛔ 未读取)。
- 四条测试命令均从本机发起(
- 若要纳入:只能作「只拨出」从节点(本线铁律:worker 永远只拨出),需装运行时 + profile + 注册为 Worker;⚠️ 因无固定公网 IPv4 ⇒ 天然只能用 relay / 443 兜底腿,直连腿结构上不可用。
五、边界自证
⛔ 只读取证(零 scp / 零 build / 零重启)|⛔ 未 commit / 未 push(HEAD 仍 09ce76f)|⛔ 未改 nft(47 仍 72 行)/ nginx / bwrap / server.ts / content/**|🔴 零个 0.0.0.0/0、⛔ 未索取 / 未硬编码任何云 AK/SK|🔴 密钥本体 ⛔ 未读取、两机仍 600。
产物 / 落点:交接单 交接单_覆盖网络直连与P2P_20260918.md 新增 §8.11(⏸ 未收官 · 阻塞上报;§8 前前缀写后现算仍 8925c2460810c6dc5cdbc075b6cdaed2 ✅,666 行、CR=0)|接续入口 §0 新增 15:5x 行 + §2 首行改为 ⏸ 未收官(432 行、CR=0)|⚠️ 参数表本棒零改动(§10 指纹仍 6b37bfd506758d882d9f803678f85d23)。
➡️ 下一棒 ⛔ 未登记(阻塞项需人操作,⛔ 无人值守重试无意义);落地后第一动作 = 双向实测复测(基线 47→106 发 21 收 0 / 106→47 发 28 收 0)+ 探针 OBS-27/28 复跑 + 参数表 §11 补记。锁已 --release-exec 释放。
16:0x 追加(用户追问「需要什么哪台服务器什么凭据,人工操作需要做什么」)—— 交付「控制台定位 + 人工步骤」
- 🔴 新取证(会传给后续会话):47 在阿里云「美国(硅谷)
us-west-1·us-west-1a」(实例i-rj99af19cibck1ge93tq,私网172.18.16.212,VPCvpc-rj900gd84ra3taamu6tbr)|106 在腾讯云「上海ap-shanghai·ap-shanghai-2」(实例ins-3q6k1p8t,私网10.0.0.8)⇒ 两机跨洋(打洞建连时延天然偏高,解读 S5/D5 耗时读数时要带上这一条)。 - 🔴 两机的安全组 ID 都取不到:阿里云 metadata
security-group-ids⇒ 404;腾讯云 metadatasecurity-groups⇒ 404 ⇒ 只能从控制台实例详情页点进去。 - 🔴 106 实例 ID 前缀
ins-(CVM)⛔ 不是lhins-(轻量) ⇒ 走 CVM 安全组口径,⛔ 不是轻量「防火墙」口径。 - 🔴 已核连接器市场:不存在阿里云 / 腾讯云 CVM·ECS 安全组相关的 Connector ⇒ 没有"装个连接器就自动获得授权"这条路(腾讯云侧只有 CloudBase / DLC / ES / TCHouse-C 等产品连接器,均不碰安全组)。
- 人工步骤已落档(交接单 §8.11-④-补):阿里云(47)= ECS 控制台 → 地域切 美国(硅谷) → 实例 → 安全组 → 访问规则 → 入方向 → 手动添加(允许 /
自定义 UDP/21100/21115/106.54.21.172/32);腾讯云(106)= CVM 控制台 → 地域 上海 → 实例 → 安全组 → 入站规则 → 添加(UDP:21100-21115/ 来源47.77.182.89/32/ 允许)。两侧保存即生效,⛔ 无需重启实例。 - 代做时的最小权限口径(备查,⛔ 本棒不索取):阿里云 RAM 子账号仅
ecs:DescribeSecurityGroups+ecs:AuthorizeSecurityGroup(地域限us-west-1);腾讯云 CAM 子账号仅cvm:DescribeSecurityGroupPolicies+cvm:ModifySecurityGroupPolicies(地域限ap-shanghai)。 - 边界自证:仍 零写入生产(⛔ 未点任何云控制台 / 未改 nft / 未改任何规则);⛔ 未 commit / 未 push(HEAD 仍
09ce76f)。
16:1x 本轮收官盘点(用户:「这个测试先记下来后续在处理,本轮开发所有任务都完成了吗」)
① D8 已按用户指示「挂起登记」 ⇒ 落点 = 接续入口 §4(标题由「待拍板」改为「待你处理」,首条即 D8;含精确操作 / 定位信息 / 为什么不能代做 / 落地后第一动作 / 🔴 ⛔ 不要为它登记接续棒)。已在册 = 四处(入口 §4 + 单 132 §8.11-④-补 + MEMORY.md 状态层 + 自动化记忆)。
② 盘点结论(如实):覆盖网络线 序①–㊸ 全部完成并验收;唯一未完成 = 序㊹(D8),现转为挂起。
③ 🔴 发现三类「账面未平」事项(均非"没做完",而是"没记账 / 没提交")—— 按纪律先报告、⛔ 本轮未动手:
- 🔴 19 处未提交改动(
git status --short;远端master=09ce76f3af…与本地 HEAD 同 sha ⇒ 未分叉,即本地也无未推送 commit):7 条M(scripts/overlay-{probe,failover-drill}.cjs、src/net/relay/content/{runtime,source}.ts、src/net/relay/{index,network}.ts、src/web/server.ts)+ 12 条??(P2 单的核心新源码全部仍 untracked:src/net/relay/direct/、src/net/relay/{join,registry}.ts、src/web/routes/overlay-nodes.ts、test/overlay-{direct,join}.test.mjs、scripts/overlay-{direct-probe,node-admit,node-join}.cjs,以及_tmp_seq24/、_tmp_seq40/、_中间产物_待清理/)。⚠️ 这些代码已 scp 到 47/106 生产并在跑,但源码未进 git ⇒ 工作区丢失 = 生产代码无源码来源。 - ⚠️
交接单/README.md §一(自称"唯一来源 = 本表")已过期:覆盖网络-序24/25/26三行仍写「⏳ 待执行」(实际均已收官并另处回报);且 129 / 130 / 131 / 132 四份单完全未登记。 - ⚠️ 三份覆盖网络单文件的 §8 回报从未回填(
覆盖网络-序24/25/26*.md里### 8.x 序 ㉔/㉕/㉖ 执行棒回报(YYYY-MM-DD HH:MM–HH:MM)仍是模板占位,文件头状态仍写「待执行」)。
线外(供参考):集群化线 D6(生产拓扑最终落点) 仍在册待拍板。
④ 边界自证:本回合只改 1 个文件(接续入口 §4)+ 本日志;⛔ 未 commit / 未 push;⛔ 未动代码 / 未动服务器;HEAD 仍 09ce76f。
16:4x–16:5x · 用户令「其余部分全部通过测试就,提交到双仓库」—— 已提交+主仓已推,CNB 卡凭据
① 用户指令原话:「其余部分全部通过测试就,提交到双仓库」。
② 提交前零回归三件套复跑(全绿,实测留在 _tmp_seq44 类的证据已清):
| 项 | 结果 |
|---|---|
npm.cmd test |
201 tests / pass 200 / fail 0 / skipped 1(Node v22.22.2 / npm 10.9.7 / 53.6 s) |
overlay-probe.cjs --table |
OBS-01…OBS-28 全 PASS(0 SKIP / 0 FAIL) |
overlay-failover-drill.cjs --scene all --table |
12 PASS / 0 SKIP / 0 FAIL(6 m 47 s) |
③ 提交:git add 18 项(16 个交付物路径),🔴 排除 _tmp_seq24/、_tmp_seq40/、_中间产物_待清理/ 三个临时目录。
新 HEAD = c452013129c810944a7b4996076b9304976ce04e
(message:feat(overlay): 覆盖网络线 序㉔–㊸ 补提交 —— 源码与已部署产物对齐)。
行尾核查:core.autocrlf=true,但暂存新文件 blob CR=0 ⇒ 不污染仓库。
④ 双推结果:
- ✅ 主仓
[email protected]:maogeigei/dsh_shenxian.git——09ce76f..c452013 master -> master成功;git ls-remote复核远端裸 sha =c452013…一致。推前已确认远端裸 sha 是本地新 HEAD 的父 ⇒ FF,无分叉。 - 🔴 CNB 失败:
remote: Repository Not Found. / 仓库不存在。
⑤ CNB 失败根因(本轮新增取证):
~/.cnb/token的expires_at = 1789712902= 2026-09-18 14:28:22,测试时刻 16:45 ⇒ 登录态已过期;~/.cnb/git-token(长期令牌)不存在。- 对照实验:对真实仓与不存在的仓
zzz-not-exist-xyz-0918跑ls-remote --heads,报错逐字相同(连token: cn***…回显都有)⇒ 证明「仓库不存在」是鉴权失败的泛化报错,⛔ 不是 URL 写错(URL 今晨 08:1x 双推成功过)。 - 无自刷新通道(新增结论):CNB 连接器
cnb-api在connector-states.json里 bound=true / enabled=true,但其 CLI 通道要求全局安装@cnbcool/cnb-cli+cnb login设备流(见 marketplacecli.json);本机which cnb= 无、binaries/node/cli-connector-packages不存在 ⇒ CLI 未装;本会话也未暴露任何mcp__cnb__*工具(连接器状态栏仅agent-mailconnected)。⇒ 本地无法自助刷新,必须用户侧动作。 - ⛔ 未改动
~/.cnb/token(无.bak、mtime 仍 06:28)—— 遵守「不碰用户凭据文件」。
⑥ 收尾:工作区仅剩 3 个有意不提交的临时目录(_tmp_seq24/、_tmp_seq40/、_中间产物_待清理/);
全局执行锁已 --release-exec 释放(释放后复核 = 无全局锁)。
本回合未动代码 / 未动服务器 / 未改线上。
16:5x · 跨线事项:授权归档找回(用户令「从 dsh-ai1net-github 空间中找一下授权文件双模式的,也同步到仓库中」)
- 用户指令原话:「从dsh-ai1net-github 空间中找一下 授权文件双模式的也同步到仓库中」。
- ✅ 找到了:09-13 记为「已不存在 · 恢复路径全部失效」的授权归档,实测在
E:\ProgramData\_已移出项目_授权归档\_授权归档_发布时再放回\(误判原因 = 当时搜索深度不足)。 含:LICENSE(5931 B,自拟「双模式」:第一层上游 MIT + 第二层 §二 免费/§三 商业)·LICENSE-UPSTREAM-MIT.txt(1107 B)·THIRD-PARTY-NOTICES.md(4430 B)·README.md.orig-带授权章节·package.json.orig-带SEE-LICENSE·代码仓/与服务器工作树/(各 LICENSE + README.md + package.json,源码仓 09-13 删前原版)。 - 🔴 但「放回」≠「照原样拷回」:导出仓
LICENSE已是 AGPL-3.0 官方全文(B 方案)⇒ 放回自拟「个人免费/商用收费」版 = AGPL §10 追加限制(09-17 定案明确要避开);两份声明文件按现行口径无需单独放回(上游 DSH 为 MIT 且不分发其代码,第三方声明由 README 承载);源码仓那三处删除是用户明令,未经重申不得自行恢复。 - 本回合落点:只改导出空间的台账 3 处失效引用(§F 正文 + §十 A 表项 2 + §十六 快照行)→ 补真实路径 + 「放回判定」;另更新本工作区
MEMORY.md授权行(补路径与「非照原样拷回」)。⛔ 三个仓库零改动、未 commit / push。⛔ 没有自行选一个「最像」的方案写进仓库 —— 三处各踩一条硬线,须用户逐项点名。 - 详见
E:\ProgramData\AI技能\dsh-ai1net-github\.workbuddy\memory\2026-09-18.md的 16:5x 节。
⑤ 补记(17:4x 实测):CNB 连接器恢复 connected 后 补推成功 —— 源码仓 09ce76f..c452013 master -> master ✅(ls-remote 复核两端裸 sha 一致)⇒ 源码仓双仓库已同步。⛔ 全程未改动 ~/.cnb/token 等任何凭据文件。
17:3x–17:5x · 用户选「B 模式」——双模式授权落地为「两条轨各自成文件」(已双推)
- 用户指令原话:「b 模式,那个案子讲的是什么再说说」(B = 把归档里的「双模式」授权文件同步进仓库;并要求复述支撑判定的判例)。
- 🔴 关键判断(自决修正,非照字面执行):归档那份自拟
LICENSE的 §三写「商业使用必须事先取得书面授权」—— 放在已发布 AGPL 项目里 = AGPL §10 追加限制 + OSD 第 6 条 ⇒ ①丢开源名号 ②罗盒案明确否定 ③推翻用户 09-17 的双轨定案。 ⇒ 落地为正向等价:轨 1(AGPL)零改动,轨 2(商业轨)从"README 一段散文"升格为独立文件。 - ✅ 落地(导出仓
dsh-users-platform,提交25f930f· 4 files / +66 / −2 · 双推 GitHub + CNB 均成功): 新建COMMERCIAL-LICENSE.md+.zh-CN.md(各 32 行、CR=0、EN 汉字数 4);_build_export.py的 OVERLAY 28→30、REQUIRED_EXPORT 58→60;四份 README 授权节尾各 +1 句链接;_check_parity.mjs的PAIRS+1 对。 🔴 三条措辞铁律:① 全文写成「平行的许可选择」⛔ 不写成"对 AGPL 的限制";② 文件名刻意不以LICENSE开头;③ 正文不含项目名(改名窗口期两版通用)。 - 验收:
_check_links.mjs26 份 / 0 问题|_check_parity.mjsCOMMERCIAL 5/5、README 19/19 · 75/75 · 11/11、CJKinEN 4|新名 grep 0|AGPLLICENSEmd54ae09d45eac4aa08d013b5f2e01c67f6未动|overlay ↔ 仓 md5 SAME。 - 锁定论据(用户追问的「那个案子」):罗盒 v. 玩友 —— 广州知识产权法院 (2019)粤73知民初207号,入选最高法 2021 年中国法院十大知识产权案件;同构案情,四项认定(GPL = 附解除条件的许可合同;收会员费不违反 GPL;不提供源码 ⇒ 授权自动终止 ⇒ 侵权,判停运 + 赔 50 万;🔴 「在开源项目里加商业使用限制条款」明确不支持)。同类:网经 v. 亿邦 50 万|南京中院 2022 年 300 万。
- 🔴 锁:本会话
--claim-exec抢到 → 收官已--release-exec并复核(无全局锁)。 - ⏸ 仍未动:源码仓
dsh_shenxian授权三处(09-13 用户明令删除,需重申)|归档中LICENSE-UPSTREAM-MIT.txt与THIRD-PARTY-NOTICES.md判为冗余不放回。
17:5x · 技能 dsh-opensource-release 升 1.7.8 并两副本对齐(清结一笔 09-17 起挂的欠同步)
- 背景:MEMORY §15 记的欠同步 —— 用户级副本 1.7.7 vs 文档库副本 1.6.0(差 7 个小版本)。
- ✅ 本轮
.workbuddy/skills/侧改动(4 处):① §0 事实表 ——OVERLAY28 → 30、REQUIRED_EXPORT58 → 60、LEAK_PROBES72 → 75、远端mainc39758d → 25f930f;② §5 补 09-18 落地(轨 2 独立成文件 + 三条措辞铁律 + 🔴 归档自拟LICENSE不得放回);③ 修正_授权归档_发布时再放回/的失效路径引用(改为真实绝对路径 + 注明 09-13 曾误判"已不存在");④ §8 新增坑 20(新增中英文件对必须登记_check_parity.mjs的PAIRS,否则静默跳过对等检查 —— 同类静默跳过已第 3 次出现)+ 坑 21(COMMERCIAL-LICENSE.*落位规矩)。 - ✅ 两副本同步:
cp到D:\github\dsh_shenxian\dsh-server-docs\skills\dsh-opensource-release\SKILL.md⇒ md5 双端一致 =2f4bb3e2714da3b1716ee4469fc18d3a(85,224 B / CR=0 两边同)。 - ✅
INDEX.md两处过期登记同步修(第 19 行能力索引 + 第 182 行变更记录):原文仍写「五条硬规则 R-O1–R-O5 / 验证六件套 / 8 条实测坑 / 产物在本机_开源导出_20260913/」⇒ 改记 R-O1–R-O14 / 验证七件套 / 21 条坑 / v1.7.8 / 真实工作根。🔴 走字节级单行替换(INDEX.md是混合行尾文件)⇒ 改后 CR 5 → 5、LF 255 → 255 逐字节不变,仅目标文本变化。 - 🔒 锁:本回合
--claim-exec "技能同步 dsh-opensource-release 1.7.8(两副本对齐)"抢到 → 收官--release-exec。 - ⛔ 未 commit / push(用户未要求)⇒ 文档库这两处改动现为未提交状态。
20:0x–20:1x · 用户令「开发仓库都要上传 双授权文件」—— ✅ 开发仓补齐并双推(45b4999)
- 用户指令原话:「开发仓库都要上传 双授权文件」。
- 🔴 这是对 09-13「把仓库中的这类授权信息也都删除」的正式重申(反向) ⇒ 之前挂在 MEMORY 里的「源码仓授权三处需重申才动」已结清。
- ✅ 落地(
D:\github\dsh_shenxian,2 个提交):73645ac—— 新增LICENSE(AGPL-3.0 官方全文 34,523 B,md54ae09d45eac4aa08d013b5f2e01c67f6与导出层同一份)+COMMERCIAL-LICENSE.md/.zh-CN.md(与_overlay/同 md5:9a69f164…/abe34bab…)+ README 新增「## 许可证」节(三轨对照表 + 源码披露义务 + 商业轨取得方式)。45b4999——.gitattributes给三份授权文本加-text(本仓core.autocrlf=true,不加则下次 checkout 会把LICENSE改成 CRLF、不再逐字节一致);git check-attr已核text: unset生效。
- ⛔ 未改
package.json—— 其license字段由导出层规则 插入(_build_export.py:266'"version": "0.1.0"' → '"version": "1.2.0",\n "license": "AGPL-3.0-only"')⇒ 源仓若也写,导出产物的 package.json 会出现重复license键(回归)。 - 验收:三份文件工作区与仓库 blob CR 均为 0(纯 LF)|新名/中文新名 grep 0|推前
merge-base --is-ancestor判 FF|双推 work + CNB 均成功(c452013..45b4999,两端ls-remote裸 sha = 本地 HEAD45b4999)。 - 🔴 README.md 是全 CRLF 文件(CR=160/LF=160)⇒ 追加走二进制
\r\n,改后 CR 160→173 = LF 173(全 CRLF 保持)。 - 仍留在工作树未提交(另一话题,等指令):
dsh-server-docs/INDEX.md+dsh-server-docs/skills/dsh-opensource-release/SKILL.md(技能 1.7.8 登记同步)|3 个有意不提交的临时目录。
20:2x 术语纠错(用户追问「你知道我说的双授权是什么吗」后核实):🔴 「双授权」≠「双模式」 —— 前者 = AGPL-3.0 官方全文 + 商业授权(台账 §C 路线 B,09-14 定案;README 自称 dual-licensed)=现行口径,两仓已落;后者 = 归档那份 5,931 B 自拟条款(个人免费/商用收费 + 上游 MIT 分层),09-14 已被 B 取代、不得放回。我此前把两者当同一件,拿 5,931 B 当靶子论证了一轮 —— 结论没错、论证路径错。⇒ 教训:用户提的术语先到本工作区台账/决策证据里查既有定义,别用字面近义替换。详见导出空间当日日志 20:2x 节。
20:1x · 用户问「集群化 D6 待拍板:是什么」—— 口径已核实(⛔ 零改动)
- D6 = 生产拓扑最终落点。三选一:47 扩容 / 106 扩容 / 同云新购(出处:
交接单/archive/交接单-已完成/T08-集群化落地-兼容单例模式.md§4 决策点表;BRIEF.md §3 与 INDEX04-119均指向它)。不阻塞 S0–S5(已在 106 测试环境完成)。 - 两条已定约束把选项压得很窄:① D4 = 跨云实测 150–183 ms ⇒ 生产拓扑须同云,跨云只当故障注入测试床;② 备案坑 —— 阿里云公网 SLB 对未备案域名回 403 Non-compliance ICP Filing(
04-119 §2.4/ §822 / §863)⇒ 入口留在腾讯云 nginx,不要在阿里云侧直接对公网提供域名入口。 - 🔴 现状提醒:47 = 阿里云硅谷 us-west-1、106 = 腾讯云上海 ap-shanghai ⇒ 现行「47 Manager + 106 Worker」本身就是跨云 ⇒ D6 的实质就是「这个跨云形态是否为最终态;若不是,买在哪朵云」。
- ✅ D6 已在上方 20:1x 一并答复用户(含三个候选的优缺点与我的倾向:B(106/腾讯云扩容) 与 C(同云新购) 才是真取舍,A(47/阿里云扩容) 受备案约束基本出局);⛔ 未登记接续棒(属花钱决策,等你拍板后才排下一棒)。
20:2x–20:4x · 用户「把这个双规的授权相关文件都同步到 双开发仓库中」—— 两开发仓已补齐(四仓对齐闭环)
- 执行:抢全局执行锁(
双开发仓同步双轨授权文件,20:32)→ 两仓各克隆临时副本操作 → 完成 → 锁已 20:4x 释放(✓ 已释放全局执行锁,复核.exec-lock不存在);临时副本_tmp_docrepo/_tmp_ai1net已 rm -rf 并复核不存在。 - ✅ 文档仓
dsh_shenxian_doc([email protected]:maogeigei/dsh_shenxian_doc.git,分支main):原无任何授权文件 ⇒ 新增LICENSE+COMMERCIAL-LICENSE.{md,zh-CN.md}(三份均从_overlay/直拷、md5 SAME、CR=0)⇒ 提交74e2654⇒ 推前merge-base --is-ancestor判 FF ⇒ 推送成功9b57578..74e2654。远端 main 裸 sha =74e2654a7c52cdfb6f306bf978951ce2686886da= 本地 HEAD ✅。⚠️ 该仓无本地user.*、全局也空 ⇒ 首次 commit 报Author identity unknown,设maogeigei/[email protected](与代码仓一致)后成功。 - ✅ 新仓
dsh_ai1net([email protected]:maogeigei/dsh_ai1net.git,分支main):原仓只有 1 个文件LICENSE(CRLF,35,184 B —— 归一化后 md5 同为4ae09d45…,即同一份 AGPL 但被autocrlf改写成 CRLF)⇒ 替换为纯 LF 34,523 B(CR 661→0)+ 新增两个 COMMERCIAL 文件 + 新建.gitattributes(三条-text)⇒ 提交8dd8071⇒ 远端裸 sha =8dd80712674c1e0c8ec08513c0f30f7dbf39ac11= 本地 HEAD ✅。 - 🔴 新事实(后续推该仓必须知道):
dsh_ai1net仓只认专用键~/.ssh/id_ed25519_ai1net—— 默认推送报fatal: Could not read from remote repository.;换id_ed25519_github2报ERROR: Permission to maogeigei/dsh_ai1net.git denied to deploy key(该键在此仓只有 deploy key 读权限)。解法:GIT_SSH_COMMAND="ssh -i ~/.ssh/id_ed25519_ai1net -o IdentitiesOnly=yes" git push。⚠️github.com段的默认候选序 =id_ed25519_github2→id_ed25519_github→id_ed25519_ai1net(前两个对上dsh_ai1net都会失败)。 - ✅ 四仓对齐闭环(同一份三文件,md5
4ae09d45eac4aa08d013b5f2e01c67f6/9a69f164d14ec8807ca2c7b76a6491f3/abe34babb0e0a0e14ee5b49ddfa26c6f):- 开发/代码仓
D:\github\dsh_shenxian→45b4999(09-18 早先完成,双推 work + CNB) - 开源导出仓
E:\ProgramData\AI技能\dsh-ai1net-github\dsh-users-platform→25f930f(GitHub + CNB) - 文档仓
dsh_shenxian_doc→74e2654(本轮新增) - 新仓
dsh_ai1net→8dd8071(本轮新增)
- 开发/代码仓
- 🔒 行尾保护分层(已实测):代码仓
core.autocrlf=true⇒ 靠新增的.gitattributes三条-text;文档仓靠既有.gitattributes=* -text/* -crlf(全仓免转换);新仓靠本轮新建的.gitattributes。三仓授权文本工作区 CR 均 = 0。 - ⛔ 未改
package.json(延续铁律):代码仓version必须保持"0.1.0",license由导出层规则插入(_build_export.py:266),源仓再写 ⇒ 导出产物重复license键。 - 仍留在工作树未提交(等指令,本轮未顺手动):
dsh-server-docs/INDEX.md+dsh-server-docs/skills/dsh-opensource-release/SKILL.md(技能 1.7.8 登记同步)|3 个有意不提交的临时目录|本地_中间产物_待清理/等(非本线产物)。
附:MEMORY.md 超限瘦身(系统提示强制项,本轮一并做完)
- 🔴 触发:会话注入时判定本工作区
MEMORY.md超出注入上限被截断(原 14,935 B / 8,719 字符;上限 ≈ 7,800 字符)⇒ 系统在上下文里标ACTION REQUIRED。超出部分 = 等于不存在,会静默丢规则 ⇒ 属事故级。 - 瘦身动作(严格按本文件自身判据「不看它会否导致违规/事故」执行):方法论 → 技能指针(§三 整节压到 4 条,详版指向
会话接续规范 §3.2.1/§6+ 技能dsh-auto-handoff-chain)|一次性事实 / 已过期值 → 现查(删「提交基线 =c452013」写死值,改为「⛔ 不写死 ⇒ 现查state.py」;这正是 09-18 被打穿的同一个坑)|历史枚举 → 删(覆盖网络「已落」清单里 relay 切流/presence/块级寻址/组密钥/jitter 逐项列举合并缩写;表格「形态」行与「判据」行合并为一行)|重复指针 → 删(DEPLOY-本部署.md/覆盖网络_补遗与参考方案两条在 §2 指针表已有同项)。 - 瘦身结果:13,232 B / 7,760 字符 —— 进入上限(余量 40),
CR=0/LF=47(纯 LF 保持)。⚠️ 余量只剩 40 字符 ⇒ 已在文件头写明「只减不增,新增前先删等量」。 - ⛔ 未删任何事故性内容:R10 属主/EACCES、bwrap 版本差异、hook buffer 写入、四条取数坑、
--scene all超时、ssh 引号、单机自用≠不需要互联、异构设计、方案不含合规、接手前先取证、技能加载闸门、本机执行环境 3 条 —— 全数保留;新增的「双授权术语消歧」「四仓 sha」「dsh_ai1net专用 SSH 键」一并纳入。 - ⚠️ 另一处同类欠账(未动,仅记录):导出空间
E:\ProgramData\AI技能\dsh-ai1net-github\.workbuddy\memory\MEMORY.md现为 22,278 B / 13,009 字符 ⇒ 同样远超 7,800,若该空间也按此上限注入,则其超限部分已被截断。⇒ 下次进该空间时先做同样的瘦身(本轮用户未要求,⛔ 未顺手改)。
20:46 · 🔴 D4 重定(用户澄清)——「生产须同云」作废,跨云即目标生产形态
用户原话:「所以 D6 的实质是:现行「47 Manager(阿里云·硅谷)+ 106 Worker(腾讯云·上海)」本身就是跨云:我要求做覆盖网络测的就是复杂网络情况下的网络连接,在一个云一个机房里我开发这些东西做什么」
一、我错在哪
- 09-16 报 D6 时我写「D4 跨云实测 150–183 ms ⇒ 生产须同云,跨云只当故障注入测试床」,并据此把「同云新购」当成真候选之一。这是把"用户要解决的场景"当成了"要消除的偏差"。
- 文档里的原始出处(现已定位):
交接单/archive/交接单-已完成/T08-集群化落地-兼容单例模式.md行 67(D4 表项)/行 69(D6)/行 130(S6 末尾「生产拓扑须同云」)04-调整方案/119-集群化改造方案-Manager-Worker.md§17.5 行 964–965(「这两台机器不能组成一个集群」⇒「必须选一个云内扩容」)交接单/README.md行 24(T08 行括注「跨云只当测试床」)
二、重定后的口径(现行)
- 🔴 跨云 = 目标生产形态本身,⛔ 不是待消除的偏差。理由:覆盖网络的全部机制(relay 切流 · 打洞 · presence · jitter 选路 · 块级寻址)只有在复杂网络下才有意义;同云 <1 ms 会让它们全部退化为无用(= 用户原话「在一个云一个机房里我开发这些东西做什么」)。
- ⚠️ 但要保留一条区分(⛔ 别一起删):跨云 ≠ 性能/容量基线环境 —— 性能与容量结论仍应在同云同 VPC 取数(否则被 150 ms 误导)。这是方法论,与"能不能跨云运行"是两件事(
119 §1054原文就是这个意思,只需补限定)。 - 🔴 §17.5「这两台机器不能组成一个集群」已被实践推翻:47=Manager、106=Worker 已经组成集群并跑起来了(09-15 17:4x 生产整体切换;覆盖网络线序①–㊹ 全部是在这条跨云 47↔106 链路上完成的)。该结论是早期只看 150 ms 数字的推断。
- D6 重排:⛔ 「同云新购」排除(与重定冲突 = 自己拆掉目标场景)⇒ 候选 = 47 侧扩容(阿里云)/ 106 侧扩容(腾讯云)/ 双侧;⚠️ 不变约束 = 入口须留腾讯云 nginx(阿里云 SLB 对未备案域名回
403 Non-compliance ICP Filing)。 - 🔑 给后续会话的判据:凡见到「跨云 = 测试床 / 生产须同云」的表述,一律按本条重定理解 —— 跨云是目的,性能基线才是要同云取数的东西。
三、本轮未完成项(⛔ 因锁被占而跳过,非遗忘)
- 抢锁失败:
handoff-guard.sh --claim-exec "D4/D6 跨云口径重定"⇒ ✗ 占用者 = 「日志可观测面-实现-20260918」(09-18 20:47 起)。按 R9 ⛔ 不接管、⛔ 不删锁 ⇒ 文档改写整体跳过。 - ⏳ 待改清单(3 个文件,共 5 处) —— 上述「一、」里点名的行号,逐处把「生产须同云 / 跨云只当测试床」改为「跨云=目标生产形态;性能基线另在同云取数」,并把 D6 候选里的「同云新购」标注为已排除。改前重跑取号/对账,改后
README/INDEX登记跟随(同属交接单/README.md行 24)。 - ✅ 本轮已完成:口径落记忆(本文件 +
MEMORY.md);⛔ 未动任何受锁保护的文件。
20:5x · memory 优化(用户:「知道 memory 的优化策略吗,知道的话就优化 memory」)
- 策略四条(已确认并按此执行):① 分层判据 —— 不看它会不会导致「违规/事故」?会 ⇒ 写实体;只"更慢更绕" ⇒ 只给指针。② 注入上限 ≈7,800 字符(超出即截断 ⇒ 排序即重要性)。③ 🔴 落点分流 —— 常驻规则 → 根
CODEBUDDY.md(⛔ 不重复)|会变状态 →MEMORY.md|方法论 → 技能 / PLAYBOOK|一次性事实 →PLAYBOOK/04/<NN>。④ 体积只减不增、按重要性插入对应小节(⛔ 不追加末尾)。 - ✅ 工作区
MEMORY.md:8,719(超限被截断)→ 7,738 字符(余量 62)。本轮二次优化走第 ③ 条去重:查得CODEBUDDY.md §7已承载「bash PATH 被 shim 重置」「Node 22 跑npm test」「git ls-remote核验推送」三条,而MEMORY.md的 §二 / §一 里又各自展开了一遍 ⇒ 三处降级为带§号的指针(信息不丢,省约 100 字符)。 - ✅ 导出空间
MEMORY.md:13,009(超限 5,209 = 约 40% 内容失效)→ 7,217 字符(余量 583)。手法 = 第 ③ 条落点分流:把 §3「铁律」17 条的机制细节 + §6 本机环境坑 + §6b_overlay未来版陷阱 全部下沉到新建的PLAYBOOK-导出脚本与铁律.md(5,168 字符,不受 7,800 约束),MEMORY.md只留最高危 5 条实体 + 索引。 - 🔑 判据(可复用):
MEMORY.md的定位 = 索引 + 事故级实体;「改脚本前必读」的机制细节 ≠ 「每轮必读」 ⇒ 它该进 PLAYBOOK / 技能。⛔ 只删字会丢信息,下沉才是正解。 - ⚠️ 两个文件均
CR=0(纯 LF)保持。
21:1x · 用户问「§10-3 定稿口径的影响 / 有无绝对安全方案 / 阻碍」—— 分析结论(⛔ 零改动)
问:「中继看不到明文成立、内容不可推断不成立」会造成什么影响?是否有方案确保数据绝对安全、性能不受影响?有什么阻碍?
🔑 核心结论 = 三者互斥:绝对安全 · 性能不受影响 · 内容可跨节点共享去重 —— 数学上不可能同时满足,必须砍一个。理由:当前 1.0× 回源(而非 N×)完全来自「相同明文 ⇒ 相同密文 ⇒ 相同块 id」这一可判定性,而这个可判定性就是相等性泄露的来源 ⇒ 去掉泄露必然去掉可判定性 ⇒ 必然去掉共享 ⇒ 性能退化到 N×。这是收敛加密 / MLE(Message-Locked Encryption)的定理级结论,⛔ 不是实现缺陷。
三层影响(按严重度):① 相等性 / 重复率可观测 —— 中继无密钥也能看"哪些块是同一块" ⇒ 可推"两用户共享同一份内容"、内容增减、低熵语义(实测 10,000 块 / 100 值域 ⇒ 仅 100 种密文)。② 持组密钥者可枚举 —— 85,878 条/秒,域 2³² ⇒ 全量 14.7 h ⇒ 同组任一节点被攻破 = 该组低熵内容实质暴露。③ 🔴 但"读明文"底线守住 —— 中继自造字典命中 0/1000、持 1 对明文-密文也预测不出别的(0/999)⇒ 定性 = 元数据 / 相等性泄露级,⛔ 不是"数据泄露级"。
三选项:A 保持现状 + 明确披露(性能最优、零改动;泄露永久存在)|B 按熵分层(低熵块加随机盐 ⇒ 真正破坏相等性;高熵块保持确定性共享;⚠️ 低熵块彻底失去共享 ⇒ 该部分 1×→N×;块 id 须换口径 ⇒ 触 §9-5)|C per-node 子密钥(唯一真正的"绝对安全",连相等性都不泄露;代价 = 回源与存储 ×N、中继节省 93.75%→0 ⇒ 等于放弃序㉔/㉜/㉝ 的全部成果)。倾向 = A + B 组合(按内容分级),但 B 的成本须先量「低熵块在首屏包里占多少字节」。
阻碍(5 条):① 理论层 —— MLE 对低熵「可去重且不泄露相等性」不可能;OPRF 去重只是把"判定相同"的能力从中继收窄到 OPRF 服务端,相等性本身仍可见 ⇒ 收窄 ≠ 消除。② 块 id 口径必须换(β′ = 密文哈希正是共享的前提)。③ 超出在册文件集 ⇒ 直接触发组密钥单 §9-5 回头条件。④ E1 判据体系须重写 + 需新建「低熵块识别」判据 —— 而"什么算低熵"本身无可靠判据(开放问题,做错 ⇒ 要么无效要么白付代价)。⑤ 存储已在告急(轮换实测已让 storeBytes 翻倍 5,255,393 → 10,510,786)⇒ 再叠 ×N 容量账要重算。
成本硬数据(已有,⛔ 非估算):加密 CPU 开销 = p50 22.636 → 42.782 ms(1.890×,含 切块/加密/put/get/解密全链;⚠️ 口径界 = 单核、页缓存全热、两臂零回源 ⇒ "加密层自身成本",⛔ 不是线上 E1 读数)—— 🔑 与是否加盐无关|共享的收益 = 1 组×16 节点 = 1.0000×(对照 16×)、中继带宽节省 75%(4 人)/ 93.75%(16 人)。
⚠️ 若立项 ⇒ 属方案类文档(须落 04-调整方案/<NN> + 交接单),⛔ 本轮未动任何受锁保护文件(锁仍被「日志可观测面-实现-20260918」占用)。
21:5x · 用户令「全网查相关文献和 GITHUB 找最佳解决方案」(§10-3 加密去重)—— 检索收官 · 结论 = 文献印证「三不兼得」,⛔ 未推翻
检索范围:学术 2 轮(收敛加密攻击 / DupLESS·SA-MLE)+ 工程 3 轮(RFC 9497 OPRF 实现 / MLE 去重代码 / 备份工具对照)。⛔ 零代码、零服务器改动(锁仍被占)。
一、文献侧 = 印证上节结论(三者互斥),⛔ 不是推翻
| 结论 | 出处 | 关键原文 / 数据 |
|---|---|---|
| 收敛加密对可预测内容必被暴力攻破 | Bellare, Keelveedhi, Ristenpart, Eurocrypt 2013(MLE 原论文) | brute-force attacks exist for all message-locked encryption schemes;MLE 仅对 unpredictable messages 安全 |
| 暴力速度量级 | DupLESS 官方页 | up to 12,000 attempts/sec(单核、短文件)+ 完全可并行 ⇒ 与本项目实测 85,878 条/秒 同量级(我们更快是因为实现更粗 / 值域更小) |
| 🔴 相等性泄露是"必要代价"、不可消除 | DupLESS 官方页原文 | Effectively, semantic security, except that ciphertexts leak equality of the underlying plaintexts. The latter is necessary for deduplication. |
| KS 被攻破 ⇒ 回落收敛加密级 | 同上 | compromise resilience = "不更差",⛔ 不是"更强" |
| 还有一类我们未覆盖的攻击 | Hack Tahoe-LAFS!(Perttula & Warner, 2008) | 除 confirmation-of-a-file 外另有 learn-the-remaining-information (LRI) |
| 加盐 / 域分离能抗上述攻击,但去重域随之收窄 | xn--2-umb.com「Convergent Encryption」 | HA 改 keyed hash ⇒ 去重仅限同 KA 域内;Tahoe-LAFS 方案 = 共享秘密 K = H(S‖M) ⇒ 秘密泄露即全崩 |
⇒ 判定:DupLESS / SA-MLE 抗的是「离线暴力恢复明文」,⛔ 不消除「相等性泄露」(它必须保留相等性才能去重)。故上节「绝对安全 · 性能不受影响 · 共享去重 —— 三者互斥」成立且已被文献确证;能争取的只是把攻击成本从离线抬到在线限速。
二、工程侧:现成实现已存在 ⇒ ⛔ 无需自研密码学
- 🔴 RFC 9497(2023)已标准化 OPRF / VOPRF / POPRF ⇒ DupLESS 用的 OPRF 不再是"论文原语"而是正式标准。可用实现:
·
facebook/voprf—— Rust,MIT / Apache-2.0 双许可,76★,v0.6.0-pre.0,MSRV 1.83,2025-11 仍在更新(生产级,首选) ·bytemare/voprf—— Go,MIT,另含 TOPRF(阈值 OPRF)+ DKG(对应下面「去单点」) ·oprf—— Python(pip install oprf,Ristretto255,可纯 Python 跑 ⇒ 适合本机原型验证) - DupLESS 官方代码可下载(UCSD 页 → Download Code);原型 KS 官称"20 行 Python + Apache on EC2"。
- 性能对照(DupLESS 实测,1 MB put):总时间开销 ≈17%、带宽开销 <1%;分解 = KS 交互
371 ms(9.1%)/TLS243 ms/加密49 ms/上传3676 ms(89.7%),合计4099 ms|存储开销3L+120 bytes|🔑 仅 store 需 KS 交互,KS 不可用 ⇒ fail-safe 回落常规加密。 ⚠️ 口径界:2013 年 Dropbox/EC2 单机实验,⛔ 不可外推到本平台;但「加密/KS 开销占比远小于 I/O」这一结构与本项目实测(加密全链1.890×但绝对值仅~20 ms)方向一致。 - 可选后续读:
BL-MLE(块级双重加密)|UMLE(块二叉树,更新O(logM))|FuzzyMLE(相似性哈希 ⇒ 相似但不相同也能重删)|RekeyDedup(MLE 密钥不可撤销 ⇒ 引入 rekeying,正对应我们"块 id 须换口径")|MetaDedup(CUHK,降元数据开销)。
三、对本项目的结构性发现(本轮新增 · ⛔ 尚无任何文档记录)
- 🔑 DupLESS 的 KS 可直接落成我们的 Manager(47) —— 本项目已有「权威状态单点 Manager」「归属/租约只有 Manager 能写」的既有判据 ⇒ 架构天然吻合,不需要新增组件。⚠️ 但须先定 KS 的域边界(全局一个 / 每 network 一个)—— 它直接决定去重域。
- 🔑 文献已给出 DupLESS「KS 单点故障 / 效率瓶颈」的解法 ⇒
eprint 2013/807Distributed Key Generation for Secure Encrypted Deduplication:给出 DupLESS 在 ROM 下的严格安全证明,并用分布式密钥生成消除 KS 单点,使 P2P 系统同样可达该安全级。⚠️ 与本项目 P2P/覆盖网络形态高度契合 ⇒ 若走 B 路线应直接上阈值/分布式 OPRF(TOPRF),⛔ 不做单点 KS(bytemare/voprf已含 TOPRF + DKG)。 - ✅ 一个"代价≈0"的真发现:把块 id 的
HA从裸哈希改成带每个-network 密钥的 keyed hash(域分离) ⇒ 可抗 COF / LRI / 离线枚举;而跨 network 本来就不该去重(不同租户 / 不同覆盖网络)⇒ 对本项目代价≈0。⚠️ 但它只切断跨域攻击,同一 network 内部持钥者枚举(85,878 条/秒)依然存在 ⇒ 是低成本加分项,⛔ 不是 §10-3 的解。 - ⚠️ 第三条路(Borg / Restic 做法)值得单列:两者均为「加密前分块 + 明文哈希索引 + 随机 nonce 加密」⇒ 明确放弃"相同明文 ⇒ 相同密文",换取不泄露相等性;原文一句 client-side deduplication and strong encryption are mathematically incompatible unless you separate the two。⇒ 对本项目 =
1.0×回源直接失效(即上节选项 C)。 🔴 关键推论:1.0×回源不是"白拿的性能",它的价格就是 §10-3 这条泄露。⇒ 「既绝对安全、性能又不受影响」的方案,在文献层面不存在。
四、结论与边界
- 可答复用户:文献 + GitHub 均未给出「绝对安全 / 性能不受影响 / 保持共享去重」三者兼得的方案;可行性被定理级排除。可得最优 = 把离线枚举抬成在线限速查询(DupLESS / OPRF 路线,RFC 9497 已有成熟实现),且仍保留相等性泄露。
- ⛔ 本轮零改动 ⇒ 上述第 3 条「域分离」与第 4 条「Borg 路线」均为候选、未立项;第 1/2 条为架构判据补充,未动任何受锁文件。
- 📄 本轮检索已整理为独立报告:
调研_MLE加密去重最优方案_20260918.md(工作区根,⛔ 非文档库 —— 待锁释放后再定是否并入04-调整方案/)。
21:2x · 用户问「B 方案改造复杂吗 / 能提升多少安全性 / 举例」(⛔ 零改动 · 只读取证 2 次)
取证:src/net/relay/content/chunker.ts#blockIdOf = sha256(字节) 前 32 hex(只由字节决定)|src/net/relay/content/crypto.ts = 组密钥实现|package.json 依赖极简(fastify / better-sqlite3 / pg)⇒ 🔴 零第三方密码学库,全走 node:crypto;✅ 但 @fastify/rate-limit ^10 已在依赖里 ⇒ KS 限速中间件现成。
一、改造复杂度 = 中等偏低(6 项 · 唯一真难点是 OPRF 原语)
| # | 改动 | 量级 | 说明 |
|---|---|---|---|
| 1 | Manager 侧新增 KS 端点 | 小 | 复用 fastify + 现成 @fastify/rate-limit;一条路由 + 一把密钥 |
| 2 | 客户端密钥派生改造 | 中 | content/crypto.ts:k = HMAC(key,…) ⇒ mleKey = OPRF_KS(H(明文)) |
| 3 | 🔴 OPRF 原语实现 | 难(唯一) | 无现成依赖 ⇒ 引 @noble/curves(纯 JS 零 native)须走 dsh 依赖披露(package.json#disclosure);或降级为非盲化 HMAC 派生(零依赖,但 Manager 会知道块指纹 ⇒ 信任模型变化) |
| 4 | fail-safe 降级 | 小 | KS 不可达 ⇒ 回落常规收敛加密 |
| 5 | E1 判据扩展 |
小 | 加 KS 交互 / 降级项 |
| 6 | ✅ 块 id / 存储 / 去重率 | 零 | 🔑 OPRF 对同输入同输出 ⇒ 确定性保持 ⇒ blockIdOf 不用改、storeBytes 不翻倍 |
🔑 关键:B 比"按熵分层加盐"更简单 —— 因为它不动块 id 口径、不动去重率(加盐方案两样都要动)。
二、安全性提升(分场景量化 · 本项目实测 85,878 条/秒 vs DupLESS 限速 ≈3.3 条/秒)
| 攻击者 | 现状 | B 后 | 提升 |
|---|---|---|---|
| 中继(无密钥) | 可判相等性(10,000 块/100 值域 ⇒ 100 种密文) |
🔴 完全一样 | 1×(零改善) |
| 外部攻击者(无 KS 认证) | 离线 85,878/秒 ⇒ 域 2³² 13.9 h |
无法离线派生 + 查不了 KS | 不可行 |
| 组内持钥者(能认证) | 85,878/秒 ⇒ 域 2³² 13.9 h |
3.3/秒 ⇒ 域 2³² 41.3 年 |
≈ 26,000× |
| 组内持钥者 · 极低熵(域 100) | 1.16 ms |
30.3 s |
26,000× —— 🔴 但两边都是"秒破" |
| Manager 被攻破 | —— | 回落收敛加密(= 现状) | 不更差 |
🔴 核心洞察:B 的收益 ≈ 2.6 万倍,但只对「高熵且可枚举」有效;对低熵块(本项目最担心)绝对值两边都是"可破" ⇒ B 治不了 §10-3 的主症状,只治"离职成员带密钥枚举 ID/口令"这类。
三、四例(用户要求举例)
- B 有效 —— 配置块 = 32 位设备 ID(域
2³²):现状组内成员一台笔记本 14 小时枚举全组;B 后须逐条问 KS ⇒ 41 年 ⇒ 从"一个下午"变"不可行"。 - B 无效 —— 首屏包里的布尔状态块(域 2):中继不需要密钥就能数出统计,B 后一样数得出;持钥者
0.02 ms⇒0.6 s,两边都是立刻破。 - B 无效 —— 跨 network 相关性:中继仍能从"同一块 id 同时出现在 A / B 两个 network"推出"两租户共享同一份内容";B 后照样推得出(确定性保持 = 去重保持)。
- B 的兜底价值 —— Manager 的 OPRF 秘密若泄露 ⇒ 回落收敛加密级 ⇒ 回到今天的水平,不会更糟(这是敢上 B 的理由)。
⇒ 一句话:B = 把"离线暴破"变成"在线限速查询" ⇒ 对高熵可枚举资产 2.6 万倍(14 h → 41 年);对低熵块与中继侧泄露近乎无用。改造中等偏低,最大成本在 OPRF 原语 + 依赖披露,最大利好是确定性保持 ⇒ 不动块 id、不动存储。
21:2x · 用户追问「低熵(域 100)有什么互补方案 / B 是不是当前最合适的方案」(⛔ 零改动 · 零工具取证)
一、先厘清威胁模型(本轮补正 · 决定解法方向)
收敛加密下 持组密钥 ≠ 能解密 —— 块密钥含明文成分(iv = HMAC(key,"iv"‖明文) ⇒ k = HMAC(key,"k"‖iv))⇒ 持钥者只能"猜明文 + 验证"(85,878/秒)。
🔴 推论:低熵块的唯一有效解 = 把"明文成分"从块密钥里彻底拿掉(非确定性加密),⛔ 不是去限速 —— 限速挡不住"域只有 100"。
二、低熵互补方案族(5 类 · 按性价比)
| 方案 | 治低熵 | 治中继相等性 | 代价 |
|---|---|---|---|
| A 现状 + 披露 | ❌ | ❌ | 0 |
| B OPRF / SA-MLE | ⚠️ 仅到 30 秒(仍可破) | ❌ 零改善 | 中(OPRF + 披露 + 在线依赖) |
| C 域分离(per-network keyed hash) | ❌ | ⚠️ 只治跨 network | ≈ 0 |
| D 低熵块非确定性 / 合并加密 | ✅ 唯一有效 | ⚠️ 该块失去去重 ⇒ 中继也失去抓手 | 小(低熵块体积小、种类 ≤ 100) |
| E 低熵字段移出块存储(放实例 home / 元数据层) | ✅ | ✅ 该字段根本不进网络 | 小-中 |
🔴 D 的两种实现(推荐 D-1):
- D-1「稀释域」合并加密 —— 把低熵小字段与高熵内容(用户 ID / 时间戳 / 会话号)拼在一起再加密 ⇒ 域
100 ⇒ 100×2³²⇒ 不可枚举。🔑 代价 ≈ 0,不动密码学、不动块 id 口径,只牺牲这个合并块的去重(低熵块去重本无价值)。 - D-2 随机密钥(每块随机 key + key 随内容封装)—— 彻底非确定性;代价 = 该块不去重,且需新增密钥封装配送。
三、判定:B 不是"最合适"的,它是"最贵且收益最窄"的那个
- 性价比排序:C + D > E > B > A(C/D 治的正好是主症状,代价小得多)。
- B 的独特价值只在「大域暴破」这一格(设备 ID / 口令类),而这恰是本项目优先级最低的风险(域大本来就难猜)。
- ✅ 公平说:B 有一个别人没有的性质 —— 不破坏去重。而 D 牺牲低熵块去重(价值低)、C 牺牲跨 network 去重(本不该去重)⇒ C/D 的"代价"都踩在不值得保留的地方。
- ⚠️ 真正有效的低熵组合 = B(限速)+ D(非确定性);B 单独不够(30 秒仍可破)。
四、结论与待测
- 自决判断(技术项):最合适 = C + D;B 降级为可选加强,仅在"确实存在大域可枚举资产"时才值。
- 前置待测:低熵块的种类数 / 体积 / 占首屏包比例(决定 D 的边界;⛔ 本轮仍未测)。
- ⛔ 本轮零代码、零服务器改动;⛔ 未动任何受锁文件(锁仍被「日志可观测面-实现-20260918」占用)。
21:3x · 用户令「按照你的建议优化,可以建立接续会话处理」—— 已登记一棒规划棒(⛔ 零改动)
用户拍板(2026-09-18 21:28):采纳 C + D 方向;B(OPRF / SA-MLE)降级为可选加强、⛔ 不立项。
已登记(唯一一棒 · 一次性):
- 名称 =
覆盖网络线 §10-3 低熵块治理 · 规划棒 - 🔑 id =
b188a495-033b-4da4-87d4-f23ced466ccb(来自工具返回值,⛔ 非占位) scheduledAt = 2026-09-18T21:35(nextRunAt = 1789738500000⇒ 🧾 已用date -d @…复核 = 2026-09-18 21:35:00 ✅)cwds = E:\ProgramData\AI技能\aliyun-dsh-server- 判据:收口时刻(21:29)+ 6 分钟 ⇒ 符合「首个接续 5–8 分钟」铁律;⛔ 同时只挂这一个,下一棒由当棒收官时再排。
该棒任务(写入 prompt 的要点):跑 state.py ⇒ 先抢全局执行锁(抢不到只报告、⛔ 不删别人锁) ⇒ 为 §10-3 低熵块治理立方案类文档(04-调整方案/<NN> 复跑取号 + .lock-<NN> 原子占号 + 交接单/)⇒ 第一个动作为补测「低熵块种类数 / 体积 / 占首屏包比例」(从未测过,决定 D 的边界)。边界:⛔ 不改生产 / ⛔ 不重启在线服务 / ⛔ 不引依赖 / ⛔ 不动 package.json / >10 文件先出清单。
⛔ 本轮零代码、零服务器改动;⛔ 未动任何受锁文件(锁仍被「日志可观测面-实现-20260918」占用)。
21:35–21:5x · 覆盖网络线 序㊺ 规划棒(§10-3 低熵块治理 · 立方案 + 派执行棒) —— ✅ 收官 · ⛔ 零代码 / ⛔ 零服务器改动
用户拍板(2026-09-18 21:28):采纳 C + D;B(OPRF / SA-MLE)降级为可选加强、⛔ 本轮不立项。
产出(4 处落盘)
- 方案 =
04-调整方案/133-覆盖网络-低熵块治理方案-C域分离与D非确定性.md(原子占号 133;⚠️ 130 空号未补占 —— 记忆里 130 已言明归「单 B」,131/132 已被锁占) - 交接单 =
交接单/覆盖网络-序45-低熵块治理-测熵与实现.md(8 段模板;§8 前前缀be548afc3340583b2b63ca254bcf550f;全文件 md50169b900a6ea50608c0d50a3a0514e68· 210 行) 交接单/README.md §一新增一行 +INDEX.md §二新增04-133行(⚠️ 机器生成的状态摘要用docs-index-stats.py --write刷新 ⇒ 档案 115 → 117 份,差额 = 129(他棒遗留未计数)+ 133)docs-manifest.json已刷新
🔑 本轮新增的源码级结构发现(⛔ 尚无任何文档记录 · 待实测确认 · 决定方案形状)
| 事实 | 出处 | 推论 |
|---|---|---|
切分是定长 1 MiB(offset += blockSize,块大小是常量非配置) |
chunker.ts:60 + :137 |
首屏包 10.8 MB ≈ 11 块、每块混高熵内容 ⇒ 首屏包内几乎不可能有纯低熵块 |
块 id = 裸 sha256(字节) 前 32 hex(blockIdOf);内容 id 同理(contentIdOf) |
chunker.ts:108-115 |
⇒ C 必须同时改两个函数,⛔ 只改一个会留"内容指纹仍裸哈希"缺口 |
块密钥含明文成分:iv = HMAC(key,"iv"‖plain) ⇒ k = HMAC(key,"k"‖iv) |
crypto.ts:405-413 |
⇒ 🔑 持组密钥 ≠ 能解密(本题前提);低熵可枚举 = "猜明文+复算",⛔ 不是"直接解密" |
| 块存储纯内存 + 可选 dir,装配处没给 dir | server.ts:909-911、runtime.ts:347-350 |
⇒ 生产盘上无块样本可捞 ⇒ 测熵只能对真实内容离线做 |
⇒ 两条方向相反的结论:① D-1「稀释域」对首屏包几乎免费也无收益(低熵已被同块 1 MiB 高熵内容稀释);② 🔴 D 的真实战场 = 「整体小于 1 MiB 的独立内容」(只切 1 块;本身低熵 ⇒ 纯低熵块)。
⇒ 🔴 因此测熵只测首屏包会得出"没有低熵块"的假绿 ⇒ 必须加子窗口熵腿(滑窗找块内低熵片段)—— 这是本方案 M1-d 的由来。
M1(= 本轮定义的"第一个动作")四项指标:种类数/重复率 | 低熵块数 + 体积 + H 直方图 | 占首屏包比例 | 子窗口熵尺寸分布。
⚠️ 为什么必须先测:D 的边界(什么算低熵 / 稀释单元多大 / 要不要合并)全是它的函数;且历史所有"低熵"读数都是合成字节 —— _tmp_seq32/p01-perf.mjs:42 用 makeBytes()、_tmp_seq32/p03-lowentropy.txt 用 8 B 合成块 ⇒ 从未对真实内容测过。
🔴 发现一条既有漂移(⚠️ 只报不改):参数表 §10 头值记 d408d640246a980f702fe7b0a2895219(序㊴ 12:2x 记录),现算 = 6b37bfd506758d882d9f803678f85d23(830 行 · mtime 09-18 15:18)⇒ 记录值未随 §10 之前的内容更新。⚠️ 与序㊹ 自报值一致(两次独立计算同值)⇒ 不是算错、是漏更新。⇒ 已登记为交接单 §10 未验证项 1(执行棒取基线一律用现算)。
边界自证 = ⛔ 零代码(未改 src/** / scripts/** / test/**)· ⛔ 零服务器触碰(未 ssh / 未 scp / 未 build / 未重启任何单元)· ⛔ 不 commit / 不 push(CODEBUDDY §4:未明确要求不提交 ⇒ 本棒未提交;未提交改动 = 本棒 4 处)· ⛔ 未动 参数表(指纹现算仍 6b37bfd5…)· ⛔ 未动 package.json / DEFAULT_BLOCK_SIZE。
⚠️ 两条如实留档:① docs-sync-check.sh 报 无法读取服务器目录 bt-server:/opt/dsh/docs(ssh 失败或目录不存在) ⇒ 未能双端对账(规划棒不 scp、未推送 ⇒ 不阻塞;⚠️ 执行棒推送前必须复跑成功)② docs-audit.py 退出码 0(无 P0)。
➡️ 下一棒(唯一一棒 · 已登记) = 序㊺ 执行棒,automation f94f2973-4ead-471a-a020-df6dc0b144a4(一次性 · 2026-09-18 21:56 · nextRunAt = 1789739760000 ⇒ date -d @… 复核 = 21:56:00 ✅ · 收口 +6 min,落在 58 分钟窗口内)。已同步推进入口 接续入口_覆盖网络线_20260916.md §0 + §2(含真 id)。
📌 在册待你拍板项仍 = D8(云安全组乙-1;⛔ 不进排棒队列、⛔ 不阻塞排棒)。
2026-09-18 21:56–22:2x · 覆盖网络线 序㊺ 执行棒(低熵块治理 · 测熵先行)收官
判定 = 「M1 首次实测完成 · 🔴 D 的作用面为空 ⇒ D 本轮不实现」。一句话 = 「低熵块」第一次被真实内容量了 —— 首屏包 0 个低熵块、低熵物质只以 ≤ 80 KiB 块内片段存在(1.0225%)、60 份真实独立小内容 0 份低熵 ⇒ D(非确定性)当前没有对象可治,而 C(域分离)仍值得做。
① M1 四项读数(真实内容 · ⛔ 零合成字节):S1 = GET https://admin.alotbuy.com/ 壳页 → 按页面顺序取全部 60 条 /plugins/??…&rev=… 拼接(23,629,336 B;🔴 口径纠正:历史 11,363,655 B = 最大单条 combo(本棒实测 11,794,471 B),⛔ 非全部之和)⇒ M1-a 块 23 / 唯一 23 / 重复率 0.00%|M1-b 低熵块 0 块 / 0 B,逐块 H ∈ [5.1807, 5.8444],直方图 {5.0-5.5: 8, 5.5-6.0: 15}|M1-c 0.000000%|M1-d 4 KiB 窗 5,768 ⇒ 低熵段 15 段 / 241,664 B = 1.0225%(max 段 81,920 B)|S2 60 份中单块 56、低熵 0 份。
② 判定与处置:D 的目标已由「定长 1 MiB 切分」结构性达成(低熵物质只以 ≤ 80 KiB 块内片段存在 ⇒ 对块级去重 / 枚举不可见;且无低熵内容单元)⇒ D-1 无对象可稀释、D-2 前提不成立(04-133 决策点 4 两分支都不命中)⇒ D 本轮不实现(⚠️ 非降级 —— 实测已证目标达成;🔑 回头条件 = 出现「低熵内容单元」)。⇒ 步骤 4–5 的前提被证伪(OBS-29 原负腿「稀释源换确定性派生量 ⇒ 必红」失去对象)⇒ 若继续落 C 而沿用原判据面 = 交付没有判据的代码 = 本线明令禁止的"静默放行" ⇒ C + 判据重裁一并交序㊻。
③ 产物 = scripts/overlay-entropy.cjs(只读探针 · 零第三方依赖 · 切分调用仓库那份 chunkify = lib/net/relay/content/chunker.js ⇒ ⛔ 无双源;OVERLAY_CHUNKER 可覆盖)+ 参数表 §11.12 补记(行 829 起;⛔ 未新增键 / ⛔ 未改值 / ⛔ 未改阈值 ⇒ §10 指纹现算仍 6b37bfd506758d882d9f803678f85d23,写入前后两次同值 ✅)+ 本单 §12 回填 + 交接单/README.md + INDEX.md(docs-manifest.json 已刷新)。
④ 边界自证:⛔ 未改 src/** 一行(C 未开工)· ⛔ 未动 DEFAULT_BLOCK_SIZE / package.json · ⛔ 未改生产实例 / ⛔ 未重启在线服务 · ⛔ 不 commit / 不 push(HEAD 45b4999;git status --short 13 处,本棒唯一新增 = scripts/overlay-entropy.cjs)· 🔴 临时物已清(47 /tmp/s45;PG 临时会话 user_agent='seq45-entropy' ⇒ remaining=0)· docs-audit.py rc=0(无 P0)。
⑤ 三条如实留档:① 🔴 仓里 mksess.cjs 已失效 —— 它写 SQLite /var/lib/dshs/dshs.db,而 47 控制面权威库 = PG(dshs.service.d/cluster.conf 的 DSHS_DB_URL=postgres://[email protected]:15432/dshs)⇒ 插进去的会话 Manager 查不到 ⇒ 一插就 401;正确做法(本棒实测可用) = 往 PG sessions 表插(cookie 名 sid;token_hash = sha256hex(token))+ 用完即删(待收口小项);② /plugins/??… 有鉴权(无会话 = 401 / 24 B)且盘上无"首屏包单文件产物"(combo 由宿主运行时拼装)⇒ 测熵取数只能 HTTP + 临时会话;③ ⚠️ "低熵"阈值 H ≤ 4.0 判别力有限(JS 文本字节熵天然落在 5.0–6.0 ⇒ 单用恒 0)⇒ 后续任何低熵结论必须同时给 M1-d 子窗口腿。⚠️ docs-sync-check.sh rc=2(与规划棒逐字同:无法读取服务器目录 bt-server:/opt/dsh/docs)⇒ 既有条件、本棒未 scp / 未推送 ⇒ 不阻塞,🔴 执行棒推送前必须复跑成功。
➡️ 下一棒(唯一一棒 · 已登记) = 序㊻ 执行棒(C 域分离 + 判据重裁),automation aab9e357-8101-4011-b829-bf9f4a459bf7(一次性 · 2026-09-18 22:33 · nextRunAt = 1789741980000 ⇒ 收口(22:2x)+7 min,落在 58 分钟窗口内)。已同步推进入口 §0 + §2(含真 id)。
📌 在册待你拍板项仍 = D8(云安全组乙-1;⛔ 不进排棒队列、⛔ 不阻塞排棒)。🔴 新增在册项 = mksess.cjs 失效(见 ⑤①,待收口小项,⛔ 不阻塞)。
序㊻ 执行棒 · C(块 id per-network 域分离)+ OBS-29 判据重裁(2026-09-18 22:33–23:4x)
判定 = C 全绿 · 零回归三件套全绿 · ⏳ 唯一未办 = 真机腿(须部署)
① 交付(8 文件 · 代码仓 D:/github/dsh_shenxian) = src/net/relay/content/{chunker,crypto,store,runtime}.ts + src/net/relay/{main,index}.ts + test/overlay-content.test.mjs + scripts/overlay-probe.cjs。块 id 口径换代:blockIdOf / contentIdOf 由裸 sha256 ⇒ HMAC-SHA256(netKey, bytes) 取前 32 hex;per-network 密钥复用 crypto.ts 既有组密钥链派生(deriveBlockIdKey() + BLOCK_ID_DOMAIN_TAG = 'dshs-overlay-block-id/v1')⇒ 🔑 零新密钥文件 / 零新 env;🔴 缺省或空 netKey ⇒ 回落裸 sha256(= 回滚路径 + 保住既有单测语义);encode 与 netKey 由新增的 writeTransforms() / readTransforms() 同生同灭(⛔ 不许半开)。观测面 snapshot() 新增 blockIdKeyed? / blockIdKeyId?(未启用时整体缺席,⛔ 不写 false、⛔ 不写空串)。
② 判据重裁(本棒存在的主因) = 序㊺ 实测判 D 无作用面 ⇒ 原 OBS-29 那条"稀释源换成确定性派生量 ⇒ 必红"的负腿失去对象 ⇒ 重裁为 C 的判据:正腿 3(P1 跨网必不同且两侧都 ≠ 裸哈希 / P2 同网必相同=去重不得丢 / P3 装配面无漏改)+ 具名负腿 2(flat-key-collapses / empty-key-falls-back-to-bare-hash)。🔴 两条负腿都真跑过(先红后绿,⛔ 非纸面声明):红腿 A(派生丢掉 network 维度)⇒ 单测 48/54、6 红(G1/G1-b/G3/G5/G7/G8)、探针 腿数 4/5 ❌ 缺 P1;红腿 B(writeTransforms() 漏传 netKey = 漏掉一个调用点)⇒ 单测 45/54、9 红、原文 content-store: 块校验失败(丢弃)expected=9aef9126… actual=e1311d71…。两条均已复原(md5 回位、REDLEG 计数 0)。
③ 读数 = npm.cmd test 200 pass / 0 fail / 1 skipped|overlay-content.test.mjs 55/55(新增组 G 共 10 例,含 G10 的 E1 重取)|npm.cmd run check:layering 无新增违规|探针 29 PASS / 0 FAIL / 0 SKIP(基线 28 ⇒ +1 = OBS-29)|--scene all 12 PASS / 0 SKIP / 0 FAIL(rc=0;8m25s)。E1 基线已重取(定义不变 = 回源字节 ≈ 1 份 × 组数;旧读数作废):同网 4 轮 × 4 块全 local 命中、origin = 0、putRejected = 0、puts = dedupIds;跨网各 1 份(起点 local = 0)。
④ 本棒发现的四条既有缺陷(⛔ 均只报不动手 ⇒ 另立小项):
(a) 🔴 演练脚本 currentChannelHint() 用 journalctl -u dshs --since -6h 捞每 2 s 一条的 [overlay-dir] 取址(6 h ≈ 1 万行 / ≈1.3 MB)⇒ 单次 ssh 实测 ~47 s > SSH_TIMEOUT_MS 20 s ⇒ 整轮 spawnSync ssh ETIMEDOUT 中止。⚠️ 该函数源码自述「仅供人读,不参与判定」 ⇒ 装饰性线索不该是主流程的硬依赖(处置方向:加长超时 / 缩小 --since / 失败降级为空串)。
(b) 🔴 演练 lastManagerAuthOn() 的 6 h 上限 ⇒ Manager 隧道稳定超过 6 h 就不再重注册 ⇒ 两台 relay 都读 -1 ⇒ killTarget = null ⇒ 幕1-A 降级 SKIP + 幕1-B / 幕1-C 结构上位于 else 分支(脚本 863–866 行)⇒ 一行都不打印(12 腿里 3 腿未判)。已取证 + 已先红后绿:开工前两侧最后一条 AUTH = 1789720529(47) / 1789720501(106),开工 = 1789744400(23:13:20)⇒ 间隔 ≈6.63 h > 6 h;首跑 9P/1S/0F ⇒ 按脚本自述办法重启一次 47 dshs 刷新 AUTH(1789745060 = 23:24:20)⇒ 复跑 12P/0S/0F。⇒ 🔴 是判据口径缺陷,⛔ 不是产品回归、⛔ 与本棒 C 改动无关(演练脚本本棒零改动)。
(c) ⚠️ mksess.cjs 已失效(写 SQLite,而 47 控制面权威库 = PG ⇒ 一插就 401)。
(d) 🔴 docs-sync-check.sh rc=2 的真因 = ssh 别名 bt-server 端口陈旧**(~/.ssh/config 里 Port 32022 ⇒ Connection refused;脚本第 88 行不带 -p 22)。⚠️ 不是"目录不存在" —— ssh -p 22 bt-server 'ls -d /opt/dsh/docs' ⇒ 存在、EXIT=0。
⑤ 边界自证 = ⛔ 未 commit / 未 push(HEAD 45b4999;git status --short 21 = 序㊺ 遗留 13 + 本棒 8)|⛔ 未 scp / 未部署|⛔ 未动任何配置值 / nft·nginx·bwrap|⛔ 未改 DEFAULT_BLOCK_SIZE / package.json / 零新依赖。⚠️ 对生产的唯一动作 = 重启 47 dshs 一次(R8;为满足演练的 6 h AUTH 窗口;无不可逆项)。演练后生产态核对 = 47 dshs/dshs-relay/dshs-worker 全 active;106 dshs-relay/dshs-worker active(dshs inactive = 正常);门户 200。
⑥ 产物落点 = 交接单 dsh-server-docs/交接单/覆盖网络-序45-低熵块治理-测熵与实现.md §13 全节(§13.1 如实留档 + §13.2 零回归三件套;⛔ §8 前前缀 be548afc3340583b2b63ca254bcf550f 逐字不变,已复算)+ 参数表 参数表_覆盖网络_20260917.md §11.13 补记 + OBS-29 行(§6 判据表 · 行 430)+ §10 指纹 d408d640… → ac6bbbbb8c92bd57ff0dc4cd8f4983ba(现算并已同步;⚠️ §11.13 在 §10 口径之外 ⇒ 追加后指纹不变,已复算)。docs-audit.py rc 0(无 P0)|docs-manifest.py rc 0(已重生成 docs-manifest.json)。
➡️ 下一棒(唯一一个 · 已登记) = 序㊼ 部署棒(C 落地两机 + OBS-29 真机腿),automation 92f8a1b9-5e38-4a7b-bd1b-7d7695e73d09(一次性 · 2026-09-18 23:43 = 本棒收口 +~6 min)。🔴 要点 = 两机必须同一窗口内一起换(C 改了块 id 口径 ⇒ 一台新一台旧 ⇒ 跨机取块全部判校验失败)。📌 在册待你拍板项仍 = D8(云安全组乙-1)。
🆕 用户新需求登记 · 覆盖网络「密钥轮换 + 多路分发」(2026-09-18 23:42 提出 / 23:46 定「记录下来后续实现」)
用户原话 = 「能否增加一个随机时间更换加密密钥的方式增加破解难度,甚至可以通过不同节点或打洞设备更新加密密钥,还可以多设备同时分发多个只有一个是真实的」→ 「可以记录下来后续实现」。
状态 = ⏸ 待实现(⛔ 零实现)。落点 = 工作区根 需求登记_覆盖网络_密钥轮换与多路分发_20260918.md(新建独立文件;⚠️ 因 序㊼ 部署棒持有全局执行锁,未写入口 §4 / 交接单 ⇒ 待其放锁后折进 §4)。
评估要点(详细版见该文件):
- 🔴 先纠正前提:用户以为"C + D 已采纳",实际 C 已落地(序㊻)/D 未实现(序㊺ 实测判 D 作用面为空:23 块 0 低熵、60 份小内容 0 低熵)。
- 🔴 本需求三条全是"抗密钥失窃(乙)",都不解决已实测证伪的"相等性泄露/低熵枚举(甲)";不能替代,只能叠加。
- 第 1 层(随机换钥)建议采纳,形态收窄为「随机间隔(6–24 h)而非随机时刻」;🔴 关键代价 = 轮换 ⇒ 块 id 全换 ⇒ 去重归零、首轮回源回到 1 份 × 组数(序㉛ 实测 24/24)⇒ 轮换每秒都在花带宽。🔑 洞察:轮换 = 按时间窗做的 D(D 逐次随机化 ⇒ 去重全死;轮换保留 epoch 内去重)。
- 第 2 层拆两半:凭据多路分发(不含密钥本体)可立即做、零暴露面;密钥本体经网络须 R5 权限影响评估(且它不提升对已失陷节点的抗性,只提抗关联/可用性/时延)。
- 第 3 层(诱饵密钥)建议暂不采纳:不解决「甲」+ 有自毁条件(真伪一落可见面即失效;否则 N× 试解)。
- 实现前须用户拍板的一条 = 轮换周期口径(安全窗口 vs 回源放大),候选 A 不轮换 / B 随机 6–24 h / C 随机 1–6 h,优缺点已列在该文件 §4 —— ⛔ 留到规划棒开工前再问,本轮不问。
序㊼ 部署棒(2026-09-18 23:43 – 2026-09-19 00:1x)· C 落地两机 + OBS-29 真机腿
做了什么:把代码仓 D:/github/dsh_shenxian 的 build 产物 lib(270 文件)全量部署到两机 4 处 —— 47 /opt/dshs/lib + /opt/dsh-relay/lib、106 /opt/dshs-cluster/lib + /opt/dsh-relay/lib;两机同一窗口内换包 + 重启(47 dshs-relay/dshs/dshs-worker;106 dshs-relay/dshs-worker)。
四条关键判定:
- 🔴 部署口径 = 全量,不是"只传改动文件" —— 实测两机 4 处
lib是历次增量 scp 的叠加(47net/relay/index.jsmtime 12:55:27 vs 同目录content/chunker.js06:52:16),与本机产物同名 md5 不同 38–41 个。⇒ 今后部署一律全量替换 + 两机同窗口。 - ✅
OBS-29真机腿 PASS:两机/status.content的blockIdKeyed=true+blockIdKeyId逐字相同(d6e62322e5166938);第二来源 = 两机 relay 启动判别器日志原文[content] 块 id 口径 = HMAC-SHA256(域密钥) blockIdKeyId=…。⇒ §6 该判据的"⏳ 真机腿"结清。 - 🔴
OBS-09由 PASS 退化 SKIP = 既有缺陷被"重启 106dshs-worker"触发(⛔ 非本单引入、⛔ 非业务中断):实例286172健在且未被 teardown(OBS-22 scanned=1 adopted=1 stopped=0+[rehydrate] probe OK dsh-100002-7d1c8cbf.scope :21001),但 47 端点表缺w-106:21001;机理 =relay-tunnel.ts#cancel()只撤销当前进程forwarded集里的端口 ⇒ 遗留条目无人撤销、新进程不重注册已认领实例的端口;恢复须"实例重新拉起" ⇒ 本棒不修、不凑绿(另立小项 → 下一棒)。 - 备份/回滚点 = 两机
/opt/dsh/backups/seq47-20260918-2347/(47 = 262/263 文件,106 = 260/262);核对 = 1080 对 md5 全同、不一致 0(270 × 4)。
读数:探针 28 PASS / 0 FAIL / 1 SKIP(⚠️ 基线 29P/0S/0F)|--scene all 12 PASS / 0 SKIP / 0 FAIL(rc=0;6m28s)✅ 同基线|npm test ⛔ 未跑(本棒零代码改动)。
边界:⛔ 未 commit / 未 push(HEAD 45b4999;git status 仍 21 处)|⛔ 未改 DEFAULT_BLOCK_SIZE / package.json / 零新依赖|⛔ 未改 nft·nginx·bwrap|⛔ 值格未动(§10 现算 ac6bbbbb8c92bd57ff0dc4cd8f4983ba = 与 §13 记录同值)|🔴 密钥本体不经网络 / relay。
产物 = 交接单 覆盖网络-序45-低熵块治理-测熵与实现.md §14 + 参数表 §11.14 + 本入口 §0 / §2。
下一棒 = 序㊽(OBS-09 孤儿端点条目修复:让 worker 重启后能重注册已认领实例的端口)。