Files
dsh_ai1net_server/交付物/MCN数据面接入-阶段二-B案落地与shadow读数-20260925.md
admin 318430c9e9 chore(工作区): 插件投放与分库线收口入库(第 35 棒 + 22:44 拍板落盘)
范围 = 本线(插件投放与分库线)产物 + 记忆类,共 27 件:
- 接续入口_插件投放与分库线(1 件):§0 新增 22:44 拍板行;§2 第 36 棒范围改 5 步、条件步转无条件
- 交付物(22 件):MCN 数据面接入阶段一/阶段二系列(含 B 案落地与 shadow 读数)、
  P0 修通与移动端真机验收、pnpm-EPERM、两机 lib 差异、共享层台账语义、
  基础插件身份与回滚、插件接入验收、插件数据面取数口、移动端迁包与字号扩面、跨机错误消息
- 记忆(4 件):2026-09-24 / 2026-09-25 日志、MEMORY.md、本棒 automation 执行记录

⛔ 未含他线在途改动(只报告、不代提交):机制层 CODEBUDDY.md / state.py /
.codebuddy/rules/server-ops.md、接续入口_IM线、接续入口_StoryForge验收线、
其余 29 个 automation 目录、docs/规则与载体/、归档/、接续包_*。
2026-09-25 23:06:29 +08:00

30 KiB
Raw Permalink Blame History

MCN 数据面接入 · 阶段二 · B 案落地与 shadow 读数(第 35 棒 · 执行棒)

会话:p35-exec-plugin-dataline(2026-09-25 21:47 开工 → 22:5x 收口) 工作区:E:/ProgramData/AIProject/aliyun-dsh-server(本件落 交付物/) 上游:入口 接续入口_插件投放与分库线_20260922.md §0 最新行 + §2「⏭️ 本轮动作(第 35 棒)」 唯一执行单:$DOC/05-交接单/插件投放与分库线-04MCN数据面接入改造-阶段二第三批.md(§五 S0–S8 / §六 A1–A9) 依据件:$WS/交付物/MCN数据面接入-阶段二-第三批接线完成-20260925.md(第 34 棒) 变量:PKG=D:/dshworkspace/plugin_package/dsh-plugin-mcn-suite|WS=E:/ProgramData/AIProject/aliyun-dsh-server|DOC=D:/github/dsh_shenxian/dsh-server-docs


〇 结论(3 行)

  1. ① – ⑤ 全部达成(处方 (a) 落码 → 出包 0.5.0 → 上池 → 加列迁移 2 条 → 回填),A2(取数口面)达成、A1 两表达成、A3/A4/A6/A7/A9 达成。
  2. 🔴 ⑥ 未全绿 ⇒ 按执行单 §五 S6/S7 与任务书铁律,停住不切档(⛔ 不带病切换),⑦ 整条留给下一棒;A5 未达成、A1 的 account_video_source 一支具名未达成、A8 如实记「两机不一致」。
  3. 🔴 根因两条已钉死(均非数据丢失,均非本棒引入):甲=本地 5 组重复 aweme_id ⇒ 计数 39 ≠ 34(平台主键唯一 ⇒ 必然折叠);乙=平台 jsonb 重排对象键序 × 插件 canonicalJsonText() 保留序 ⇒ 逐键比对假阴性(换成「与序无关」比对 ⇒ 34/34 全等)。

归属:本棒已动生产(47 共享层投放 + 平台库 2 条 ADD COLUMN + 存量回填),未动实例本地库、未重启任何服务、未切任何档。 🔴 本棒不 commit / 不 push —— 用户 2026-09-25 22:44 已拍板「不纳入版本管理」(§5-②)⇒ 本条由"待定"转为长期有效;源码保底改为定期打包到 E:/dsh-backups/plugin-src/(见 §5-②、§六)。 ✅ 两条待拍板已于 22:44 全部到手(① ⇒ A 案删本地 5 条旧副本;② ⇒ B 案不纳管 + 定期打包备份,机制已落地)⇒ 第 36 棒 ⑥ 可闭环、⑦ 可执行。


一 本棒动作逐条状态(按序 · 与任务书 ①②③④⑤⑥⑦ 一一对应)

# 动作 状态 一句话读数
① 落 (a) 处方代码(正文列 gzip 编解码落 store.js 的 normalizeRow/rowsOf) ✅ 达成 新增 GZIP_COLUMNS/GZIP_PREFIX="gz1:"/gzipToJsonText/gunzipIfPrefixed/restoreGzipText/restoreGzipColumns/packOversizedRow + jsonbLike() 补正;编解码只在插件侧,调用方零改动。单测 66/66(# pass 66 / # fail 0)、node --check 9 文件全 rc=0
② 出包 0.4.0 → 0.5.0 ✅ 达成 dist/dsh-plugin-mcn-suite-0.5.0.tgz 2,017,667 B/条目 324/md5 5cbccac1348e5dcb8d11bf400a000498
③ 上池 → 发布共享层 ✅ 达成 POST /api/plugins/business →200(compat.level=ok)⇒ 迁移到 state=ready ⇒ POST /api/plugins/business/share →200 action:"replaced" version 0.5.0
④ 加列迁移 2 条 ADD COLUMN(hot_accounts.local_id / account_videos.local_id,可空) ✅ 达成 elapsedMs:16、backup:"taken"(/opt/dsh/backups/plugin-db/dsh-plugin-mcn-suite/v1-2026-09-25T14-06-56-401.sql);库读数 hot_accounts 17 列/5 行、account_videos 20 列/362 行、account_video_source 9 列/18 行;台账 state: ready、对账 clean:true;⛔ 不删库、不重灌
⑤ 重跑迁移回填 local_id ✅ 达成 dry-run DRY_WRITE_CALLS=0;apply:account_video_source ins=16/skip=23、account_videos skip=362/backfill=362、hot_accounts skip=10/backfill=5、失败 0;幂等重跑 ins=0;本地库 sha256 b37f8aab… 前后逐字一致、mtime 未变
⑥ 三表 shadow 读数(全 match=true 才允下一步) 🔴 未全绿 account_videos match=true(362/362)/hot_accounts match=true(5/5)/account_video_source match=false(platform 34 / local 39)⇒ 停住不切档
⑦ 切档 + 重启验收(三表 → platform;47 实例 + 106 合并窗口;A2 E2E + A5 真机读数) ⛔ 未执行(整条留下一棒) 前置 ⑥ 未全绿 ⇒ ⛔ 未切任何表、⛔ 未重启 47、⛔ 未触碰 106;实例 data-plane.json 仍 4 表 platform(account_persona/creative_log/account_analysis/video_analysis),三表仍 local

⚠️ 本棒未按任务书原意走到 ⑦ —— 依据是任务书自己写的判据:「⛔ 若 ⑥ 未全绿 ⇒ 停住不切档(⛔ 不带病切换),如实上抛,⑦ 整条留给下一棒。」


二 判据表 A1–A9(命令 + 输出原文 + 退出码 · 可被第三方复现)

探针环境:ssh [email protected];node = /usr/local/bin/node(--experimental-sqlite);探针包 /tmp/p35/pkg(指纹逐字等于本机与共享层)。 🔴 R10 说明:实例 uid(dsh-cce6d1cdb376430480f0)被平台网络隔离(实测连 127.0.0.1:3080 都 ECONNREFUSED,而 root curl = 200)⇒ 探针只能以 root 跑,故一律 DSH_HOME 重定向到 /tmp/p35/dshhome(实例 home 零写入)+ 本地库 readOnly 打开。

A1 存量迁移一致性

# [真机 47] root + DSH_HOME 重定向;探针 run-p35.mjs §4
node --experimental-sqlite /tmp/p35/run-p35.mjs            # 退出码 0(RUN_RC=0)
A1 [account_video_source] 本地键=39 平台行=34 onlyLocal=[] onlyPlatform=[] truncated=false match=true
A1 [account_videos]       本地键=362 平台行=362 onlyLocal=[] onlyPlatform=[] truncated=false match=true
A1 [hot_accounts]         本地键=5   平台行=5   onlyLocal=[] onlyPlatform=[] truncated=false match=true

☝️ 这是探针自算的「主键集合」判据(onlyLocal/onlyPlatform 皆空 ⇒ 唯一键集合逐字一致)。

# [真机 47] 插件自身的影子读口径(compareRows:计数 + 主键集合)
node --experimental-sqlite /tmp/p35/run-p35.mjs            # 退出码 0
[mcn-store] shadow what=probe35.account_video_source platform=34 local=39 match=false onlyPlatform=[] onlyLocal=[]
[mcn-store] shadow what=probe35.account_videos       platform=362 local=362 match=true
[mcn-store] shadow what=probe35.hot_accounts         platform=5   local=5   match=true

判定:🔴 部分达成 —— 两表 本地 n == 平台 n ✅;account_video_source 本地 39 ≠ 平台 34 ⇒ 未达成(具名:5 组重复 aweme_id,见 §三-甲)。 badRows:三表 全 0(⛔ 无空键、无坏行);空 aweme_id 行数 0(执行单 §附录 C-2 预计"非零" ⇒ 实测为零,具名纠正)。

A2 三表读写 E2E(平台取数口)

# [真机 47] 临时会话(mksess.cjs 直插,TTL 600s)+ Host/Cookie 垫片
bash -s < tmp/p35/remote-09-a2.sh                          # 退出码 0(A2_DONE)
### 0) 取数口就绪态
{"ok":true,"pluginId":"dsh_plugin_mcn_suite","available":true,"reason":null,
 "dbName":"dshs_pl_dsh_plugin_mcn_suite",
 "tables":["hot_accounts","hot_account_ext","account_videos","video_analysis","account_video_source",
           "account_persona","account_analysis","creative_log","rewrite_log","storyboard_log","script_review"]}

=== ① hot_accounts(PK=account_name) ===       7 步 全 HTTP=200(读空→建→读回→改→读回→删→读空)
=== ② account_videos(PK=aweme_id) ===         7 步 全 HTTP=200
=== ③ account_video_source(PK=aweme_id,两个 json 列) ===  7 步 全 HTTP=200
   3 读回 ⇒ {"content_json":"正文 E2E","analysis_json":"分析 E2E", ...}   # jsonb 脱一层引号,存储形态假设成立

=== ④ 负例(应全 bad-args) ===
N1 写他人 user_id    HTTP=200 {"ok":false,"reason":"bad-args","detail":"不得写入他人的 user_id(归属列由内核注入)"}
N2 缺主键列          HTTP=200 {"ok":false,"reason":"bad-args","detail":"缺少主键列「account_name」(它是本表的行标识)"}
N3 带内核审计列      HTTP=200 {"ok":false,"reason":"bad-args","detail":"审计列「created_at」由内核维护,⛔ 不可自写"}
N4 未知表            HTTP=200 {"ok":false,"reason":"bad-args","detail":"未知表「nosuch_table」"}
N5 未知列(过滤)    HTTP=200 {"ok":false,"reason":"bad-args","detail":"未知列「nosuchcol」(表「account_videos」)"}
N6 未知列(写入)    HTTP=200 {"ok":false,"reason":"bad-args","detail":"未知列「nosuchcol」"}

⚠️ 该脚本尾段(PG 残留核查)首轮因内嵌 node -e 的引号/反引号被 bash 吃掉而报语法错误未执行(bash: line 79: syntax error near unexpected token ')')—— 已按「把 node 脚本抽成独立 .mjs 上传执行」重做,本轮补齐(见 A2-附)。

A2-附 PG 侧残留核查(补齐 · 退 0)

node --experimental-sqlite /tmp/p35/diag-src3.mjs          # 退出码 0(DIAG3_RC=0)
### J) A2 收尾:PG 侧残留核查(应全 0)
PG_RESIDUE hot_accounts        (cols=account_name,local_id)          = 0
PG_RESIDUE account_videos      (cols=aweme_id,local_id,account_id)   = 0
PG_RESIDUE account_video_source(cols=aweme_id,video_id)              = 0
PG_TOTALS={"a":"5","b":"362","c":"34"}

判定:✅ 达成(平台取数口面) —— 三表 7 步读写 全 200、6 个负例全 bad-args、0 行返回 {ok:true,value:[]}、写入残留 0。 ⚠️ 「实例内」那一半仍未达成(执行单 A2 原注:「实例内读数需 47 重启 ⇒ 未重启则该条未达成」)⇒ 随 ⑦ 留给下一棒。

A3 结构改写面处置完毕

grep -rniE "\bJOIN\b" lib | grep -v "\.join("        # 残留全落在 local() 回调 / 本地专属分支 / 第四批主表 rewrite_log(具名豁免)
grep -rn "LIMIT ? OFFSET ?" lib
grep -rnE "ROW_NUMBER|OVER\s*\(" lib

判定:✅ 达成(第 34 棒已验并复扫;平台档路径零命中;本棒未改任何调用点 ⇒ 读数逐字不变)。

A4 表名对齐彻底

cd "$PKG"
grep -rE "account_video_analysis" . | grep -v /node_modules/ | wc -l   # → 0
grep -c "hot_account_ext" lib/host/mcn/store.js                        # → 10

判定:✅ 达成(0 / 10 > 0)。

A5 已按表切档(三张表)

# [真机 47] 读该用户 <home>/.dsh/data-plane.json
cat /var/lib/dshs/users/cce6d1cd-b376-4304-80f0-0e1c58c9ffde/home/.dsh/data-plane.json
INSTANCE_DP_UNCHANGED={"tables":{"account_persona":{"writeMode":"platform","mode":"platform"},
  "creative_log":{"writeMode":"platform","mode":"platform"},
  "account_analysis":{"writeMode":"platform","mode":"platform"},
  "video_analysis":{"writeMode":"platform","mode":"platform"}},"updatedAt":"2026-09-25T09:07:28.440Z"}
PLANE={"tables":{"account_video_source":{"mode":"shadow"},"account_videos":{"mode":"shadow"},
       "hot_accounts":{"mode":"shadow"}},"updatedAt":"2026-09-25T14:12:06.586Z"}

☝️ 第一个是实例真档(仍 4 表);第二个是探针档(DSH_HOME 重定向到 /tmp,只用来取 shadow 读数)—— ⛔ 探针档不是实例档,两处别混。

判定:🔴 未达成 —— 三表仍 local(总数仍 4 表 platform,非 A5 要求的 7 表)。原因 = ⑥ 未全绿(依铁律停住)。

A6 旧库备份在位 + 零数据损失可回滚

# [真机 47]
sha256sum "$HOME/.dsh/mcn-plugin.db" | cut -d' ' -f1     # 迁移前后各取一次
tar -tzf /opt/dsh/backups/plugin-data/dsh-plugin-mcn-suite/cce6d1cd-…-mcn-plugin-db-20260925-141436.tar.gz
b37f8aab51a90f7481eb321e50456ca347635bcf2bfce567ea4200d88c18277a    # 迁移前
b37f8aab51a90f7481eb321e50456ca347635bcf2bfce567ea4200d88c18277a    # 迁移后(逐字一致)
DB owner=dsh-cce6d1cdb376430480f0 mtime=2026-09-20 23:05:05.178301565 +0800   # mtime 未变

判定:✅ 达成 —— 备份在位可解出;本地旧库未被删、未被改(sha256 + mtime 双证)。 🔴 本棒新增一处 R10 修复(必须记):<home>/.dsh/data-plane.json 属主为 root:root(第 32 棒 root 探针遗留)⇒ 切档前必须先修,否则实例 uid 写不动档位。已 find "$UHOME" -user root -exec chown "$UOWNER:$UOWNER" {} + ⇒

ROOT_OWNED /var/lib/dshs/users/…/home/.dsh/data-plane.json root:root 644
ROOT_OWNED_AFTER_CHOWN=0
… data-plane.json owner=dsh-cce6d1cdb376430480f0:dsh-cce6d1cdb376430480f0 mode=644
ROOT_OWNED_FINAL=0

A7 移动端五条

判定:✅ 免跑 —— 本棒未改任何 UI 代码(lib/client.js 零改动;改动面恰 6 件:store.js/package.json/tests/mcn-store.test.mjs/(出包物)dist/*.tgz;调用方 0 处)。

A8 两机一致(代码面 / 运行面分开记)

# [47]
grep -m1 '"version"' /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/package.json
md5sum /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/lib/host/mcn/store.js | cut -d' ' -f1
grep -c "gz1:" /var/lib/dshs/bundled-plugins/dsh-plugin-mcn-suite/lib/host/mcn/store.js
"version": "0.5.0",
bc02c23c080eee58d8873508badc1c5b      # 与本地 PKG 逐字一致
4                                      # 处方 (a) 已进共享层
# [47] 节点登记表(查 106 端点)
SELECT * FROM dsh_hosts;
HOST {"id":"w-47","endpoint":"http://127.0.0.1:19100",…,"status":"up","via":"local"}
HOST {"id":"w-106","endpoint":"http://127.0.0.1:19000",…,"status":"up","via":"relay"}

判定:🔴 不一致(如实记,⛔ 不得写「一致」) —— 47 共享层 = 0.5.0(本棒投放,已取证);106 本棒未触碰、未取证(w-106 仅经中继可见、端点是回环隧道,本棒无 106 作业面)⇒ 106 侧同步随重启窗口在下一棒做。

A9 红线零新增

cd "$PKG"
grep -rEn "CREATE TABLE|ALTER TABLE|DROP TABLE|better-sqlite3|from 'pg'|require\('pg'\)" . | grep -v /node_modules/ | wc -l
23

判定:✅ 达成(23,与第 27/28/29/33/34 棒同值;处方 (a) 只加运行时编解码,零新增 DDL / 驱动)。

产物指纹(report §八-6 要求)

件 指纹
lib/host/mcn/store.js md5 bc02c23c080eee58d8873508badc1c5b / 117,808 B / 纯 LF
tests/mcn-store.test.mjs 64,299 B / 纯 LF / # tests 66 / # pass 66 / # fail 0
dist/dsh-plugin-mcn-suite-0.5.0.tgz 2,017,667 B / 324 条目 / md5 5cbccac1348e5dcb8d11bf400a000498 / npm shasum 4e025aba87a4c3edf6cb36e389c6f7ca1bcf873e
package.json "version": "0.5.0"(仅 version + description 两字段与 0.4.0 桶不同)
共享层(47) …/bundled-plugins/dsh-plugin-mcn-suite/ version 0.5.0/store.js md5 同本机

三 🔴 ⑥ 未全绿的根因(两条 · 逐条取证 · 均非数据丢失)

甲|计数 39 ≠ 34 = 本地 5 组重复 aweme_id(平台主键唯一 ⇒ 必然折叠)

node --experimental-sqlite /tmp/p35/diag-src.mjs            # 退出码 2(尾段平台读撞会话过期;甲段已跑完)
LOCAL_TOTAL=39
DUPKEY aweme_id=7658997937279683855 rows=2 ids=[20,40] 正文全同=false 分析全同=true
DUPKEY aweme_id=7648947073131625905 rows=2 ids=[27,28] 正文全同=false 分析全同=true
DUPKEY aweme_id=7667477088350044069 rows=2 ids=[29,44] 正文全同=true  分析全同=true
DUPKEY aweme_id=7631176055600527729 rows=2 ids=[31,42] 正文全同=true  分析全同=true
DUPKEY aweme_id=7629803455813243043 rows=2 ids=[32,46] 正文全同=true  分析全同=true
DUP_SUMMARY 组数=5 冗余行数=5 组内完全一致=3/5 唯一键数=34
  • 本地 account_video_source 39 行 = 34 个唯一 aweme_id + 5 个历史副本;平台主键 (user_id, aweme_id) 唯一 ⇒ 平台只能有 34 行。
  • 5 组里 3 组两个副本逐字全同;2 组(…9683855、…625905)只有正文差 2 字节(分析列全同)。
  • 🔴 本表按 id 累积历史版本、读路径取最新(store.js 注释与本地 SQL 一致:… WHERE video_id=? OR (aweme_id IS NOT NULL AND aweme_id=?) ORDER BY id DESC LIMIT 1;另有两处是 IN 集合索引/COUNT(*)>0 布尔)⇒ 旧副本对读取不可见;平台档下 findVideoSources 亦按主键取单行 ⇒ 行为等价。
  • ⚠️ 但这不等于可以自决删数据:要与 A1 判据(本地 n == 平台 n)对齐,只能删本地 5 行冗余副本(不可逆)或改判据(须回规划棒)⇒ 见 §5-①(待拍板)。

乙|逐键内容 23/34 不等 = jsonb 键序重排 × canonicalJsonText() 保留序(假阴性)

node --experimental-sqlite /tmp/p35/diag-src3.mjs            # 退出码 0(DIAG3_RC=0)
### H) 与序无关的深度相等(本地该键 **最新一行** vs 平台读回)
### H_SUMMARY 唯一键=34 正文+分析 序无关全等(最新一行)=32 序无关全等(任一本地副本)=34 仍有差异=0
### I) 交叉表:`gz1` 形态 vs 与序无关相等
FM aweme_id=7642280101581146850 PG_content[type=string gz1=true ] 序无关相等=true PG_analysis[type=null …]
FM aweme_id=7648968851887115563 PG_content[type=object gz1=false] 序无关相等=true PG_analysis[type=null …]
FM aweme_id=7628138993386034792 PG_content[type=object gz1=false] 序无关相等=true PG_analysis[type=object …]
# [真机 47] PG 地面真值:jsonb 值类型分布
SELECT jsonb_typeof(content_json), jsonb_typeof(analysis_json), count(*) FROM p_…_account_video_source GROUP BY 1,2;
PG_TYPE content=string analysis=string rows=6
PG_TYPE content=object analysis=null   rows=3
PG_TYPE content=string analysis=null   rows=3
PG_TYPE content=object analysis=object rows=20
PG_TYPE content=string analysis=object rows=2
  • gz1=true(落成 jsonb string)的行 ⇒ 逐键 match;gz1=false(落成 jsonb 对象)的行 ⇒ 逐键 match=false,11 / 23 两侧完全对得上(jsonb_typeof=string 的行数恰为 11)。
  • 换成与序无关的深度比对 ⇒ 34/34 全等、仍有差异 = 0 ⇒ 平台侧内容与本地逐字段完全一致,不存在内容丢失。
  • 🔴 机制:PostgreSQL jsonb 会按"键长度+字母序"重排对象键;而插件 canonicalJsonText() 是 JSON.stringify(保留键序)⇒ 只要值以 jsonb 对象形态落库,读回后 canon 必然与本地文本不等。
  • 🔴 这是真缺陷(不是验收口径问题):canonicalJsonText() 还被
    • 迁移幂等 / 稳定键生成、
    • imports.js 的**「同视频+同内容 ⇒ 去重」**判据(… AND content_json=? 的平台档对应实现)、
    • imports.js 的预览判据(sr.ok 分支) 共用 ⇒ 切到 platform 档后,同内容会被判成不同内容(倾向于重复写入,R11 净变差)⇒ 必须在切档前修(修法 = 递归按键排序后再序列化;技术项 ⇒ 自决)。

丙|附带纠正与澄清(防止后棒按错记开工)

项 旧记 实测纠正
account_video_source 空 aweme_id 行数 执行单 §附录 C-2「预计非零」 0(badRows 三表全 0)
CONTENT … 同=12 异=27(第 35 棒中途读数) 疑似内容丢失 假阴性 —— 该读数的 analysis 长度打印串是 String(obj) ⇒ 恒为 "[object Object]"(15 字),是探针自身的量测坑,⛔ 后棒别拿它当结论(已在本件用 PG 地面真值 + 与序无关比对推翻)
会话 TTL — mksess.cjs 的临时会话 TTL = 600 s ⇒ 长探针必须现场新建,否则处处 401(本次撞过一次,报 not-registered / unauthorized)

四 未闭合项(逐条「现象 / 归属 / 下一步」)

# 现象 归属 下一步
1 account_video_source shadow match=false(34 vs 39,5 组重复键) 规划面判据 + 本地数据(⛔ 非平台侧、⛔ 非插件逻辑) 待拍板(§5-①)⇒ 定后由下一棒执行
2 canonicalJsonText() 键序敏感 ⇒ 平台档判据假阴性 插件侧(store.js) 技术项 · 自决 ⇒ 下一棒修 + 出包 0.5.1 + 重投 + 重取影子读数
3 ⑦ 切档 + 重启验收整条未执行(47 实例 + 106 合并窗口) 本棒(有意停住) 下一棒(窗口已获用户批准,见 §0 21:33 行)
4 A2「实例内」那一半未达成 · A5 未达成 同 3 同 3
5 106 共享层仍为旧版(两机不一致) 部署面 下一棒随重启窗口同步
6 hot_accounts / account_videos 的 local_id 回填已到位,但「映射改优先平台」未做 插件侧(第 31/32 棒遗留 ㈦ 的部分缓解) 下一棒(restoreLocalId 已让 row.id 在平台档可用)
7 插件包源码仍未纳入版本管理(?? 未跟踪) 用户拍板项 ㈣ 待拍板(§5-②)
8 共享锁目录曾出现非本线遗留物(.exec-lock/OWNER = __st_other_1879;.locks/修域锁释放缺陷-…) 他人 lane 按 R9 ⛔ 不删锁、不接管;本棒收口时 .exec-lock 已自然消失(本会话已复核)

五 待拍板(自包含 · 一轮一问 · 每条带优缺点 · ⛔ 不在接续棒内自决)

✅ 两条均已于 2026-09-25 22:44 由用户拍板(原提问与优缺点保留在下方,供追溯):

  • ① ⇒ A 案:删掉本地那 5 条旧副本(不可逆 · 已授权)。执行要求(已写入第 36 棒):先原样导出留档(tmp/p36/)+ 打印清单 → 再删 → 删后本地 account_video_source 应 = 34 行;⛔ 只删行、⛔ 绝不删本地库文件 mcn-plugin.db、⛔ 不删 db.js、⛔ 不重建库。
  • ② ⇒ B 案:不纳入版本管理,改为定期打压缩包备份到固定目录。已由第 35 棒会话落地:固定目录 E:/dsh-backups/plugin-src/(backup.sh + 基线包 mcn-suite-src-20260925-2246-v0.5.0.tgz/6,065,179 B/330 文件/md5 247dd1456597e5496a695f4e91d695dc/内容摘要 9c38cdb4…)+ 每周自动备份 automation 1e3c9070-a75d-4ae4-b81e-06e2eb20a5b4(周日 03:30 · 内容摘要去重「未变则跳」· 保留最近 26 份)。⚠️ 该机制只防误删,不防同一块盘损坏(要防盘坏需再复制一份到别的机器/盘)。 ⇒ 第 36 棒起按已定执行,⛔ 不再重问这两条。

① 平台上「一个视频只能存一条来源记录」,本地却存了 5 组重复(同一视频两条)。要不要删掉本地那 5 条旧副本,好让两边数量对齐?

为什么得由你定:这一步要么动实例里的真实数据(删 5 行,不可逆),要么放宽这条验收判据。两条路都对「这台机器上那位用户的资料」有实际影响,且没有客观更优的一方 ⇒ 属边界外。现在不决定也可以 —— 现象已具名,平台侧内容 34/34 与本地逐字段一致(已实测),没有数据丢失;只是「切换开关」这一步卡住不动,第三批就到不了终点。

  • A 案|删本地 5 条旧副本(保留每条视频最新那一份) 优点:一次做完、验收判据如实达成;对读用户无可见影响(读路径本来就只取最新那一份,多出来的旧副本从来读不到)。 缺点:不可逆(只能靠备份回滚);其中 2 组的旧副本正文与最新副本差 2 个字符,删了就没了。
  • B 案|不删数据,改判据为「同一视频只算一次 + 逐条内容比对」 优点:零数据变更,风险最低。 缺点:改的是规划棒定死的判据(本地 n == 平台 n),按规矩要回规划棒再改一次单子;且今后每台机器都得靠这条新口径解释。
  • C 案|保持现状不动(继续停在 local 档) 优点:今天什么风险都不担。 缺点:第三批永远到不了终点,本地库与平台库长期并存、两处结论会越走越远。

我的倾向:A 案(可推翻)—— 5 条旧副本对读取不可见、删除前有备份 + 我会先出逐条清单;⚠️ 但它不可逆,所以必须你点头我才动。

② 这次改的插件源码(近一个月、十几个文件)要不要纳入版本管理?

为什么得由你定:这决定「以后回滚靠什么」—— 是靠 git 记录,还是只能靠备份包。属影响面偏好,不是技术优劣。

  • A 案|现在就纳入(把该目录加进仓库并提交) 优点:改动有版本留痕、可逐笔回滚、后续多会话协作可对账。 缺点:要动仓库与提交动作;该包目前形态(大文件+出包产物)需先定「哪些进、哪些不进」。
  • B 案|暂不纳入(继续只靠 sha256 + 交付件留痕) 优点:不动仓库,零额外动作。 缺点:近一个月改动零版本留痕;一旦误删/误改,只能靠备份整包回退,无法定位到某一笔改动。

我的倾向:A 案(可推翻)—— 本线已连续 8 棒在同一批文件上改,留痕收益已超过成本。

⚠️ 其余存量待拍板项(㈠ 47 实例重启窗口 ✅ 已于 21:33 批准;㈡ 106 重启窗口 ✅ 已批准「可以合并那是 worker」;㈢ json 列是否改声明 —— 本批不需要,留档)本棒一项未新增、未改动。


六 卫生声明

  • ⛔ 未改 D:/github/dsh_shenxian/src/**(平台侧零改动)· ⛔ 未改 im.ts · ⛔ 未改装配协议。
  • ⛔ 未删 本地旧库 mcn-plugin.db(sha256 + mtime 双证未变)· ⛔ 未删 db.js · ⛔ 平台库未删未重建。
  • ⛔ 未重启任何服务(47 实例 / 106 全未触碰)· ⛔ 未逐表切档。
  • ⛔ 未 commit / 未 push(见 §5-②)。
  • ⛔ 未改 D:/dshworkspace/plugin_package/dsh-plugin-mcn-suite/ 以外任何工作区文件(本棒另动的三处均为本线自有文档:本工作区交付物 + 本线入口 + 文档库 05-交接单/README.md)。
  • ✅ R4 卫生:临时会话已清理(DELETE FROM sessions WHERE user_agent='poc-curl2' ⇒ SESSIONS_BEFORE=7 / SESSIONS_DELETED=7 / SESSIONS_AFTER=0)。
  • ✅ 真机产物已清:/tmp/p35*、/tmp/mksess-guest.cjs 全删(TMP_P35_CLEAN);本机证据与探针脚本留在 $WS/tmp/p35/(tmp 保留期 7 天)。
  • ✅ R10 修复:实例 home 下 root:root 属主配置已 chown 回实例 uid(ROOT_OWNED_FINAL=0)。

域锁

  • 抢锁:bash $DOC/07-scripts/handoff-guard.sh --claim-exec "p35-exec-plugin-dataline" --domains <9 键> ⇒ rc=0;复读断言:
OWNER: p35-exec-plugin-dataline / 开始:09-25 21:47 / ME:p35-exec-plugin-dataline
DOMAINS: mcn/store.js, dsh-plugin-mcn-suite/package.json, tests/mcn-store.test.mjs,
         dsh-plugin-mcn-suite/dist, mcn/index.js,
         aliyun-dsh-server/接续入口_插件投放与分库线_20260922.md,
         aliyun-dsh-server/交付物, dsh-server-docs/05-交接单, aliyun-dsh-server/.workbuddy
  • 开工门禁如实记账:preflight-lock.sh 对本棒 8 个目标路径全判【D】未归类 ⇒ 按字面 rc=1;依第 26–34 棒既有惯例开工并报告,⛔ 未改那个跨库脚本。
  • 释放:22:38 已带会话名释放(ME="p35-exec-plugin-dataline" … --release-exec ⇒ RC=0;复核 .locks/p35-exec-plugin-dataline/.exec-lock 均已移除、find -name OWNER 零命中、.locks/ 仅余空容器 .migrations/)。随后为落两条拍板 22:44 二次抢锁(3 域:入口/交付物/.workbuddy,rc=0,OWNER 归属已断言),改完即再次带会话名释放。
  • 备份(拍板②):固定目录 E:/dsh-backups/plugin-src/ 已建(脚本 backup.sh + pkgs/ + backup.log + .last.sha256);基线包 mcn-suite-src-20260925-2246-v0.5.0.tgz 6,065,179 B/330 文件/md5 247dd1456597e5496a695f4e91d695dc;幂等实测:二次运行输出 RESULT=SKIP_UNCHANGED 且包数仍为 1(未新增)。每周日 03:30 自动执行(automation 1e3c9070-a75d-4ae4-b81e-06e2eb20a5b4)。⚠️ 同盘备份只防误删,不防盘坏。

七 下一棒(第 36 棒)范围(已按上表登记)

✅ 本节已于 2026-09-25 22:44 按用户拍板改写(原为条件式;现两条拍板到手 ⇒ 条件步转无条件,范围见入口 §2「⏭️ 本轮动作(第 36 棒)」)。

  1. 🔴 修 canonicalJsonText() 键序敏感性(技术项 · 自决;修法 = 递归按键排序后序列化)+ 补一条单测(jsonb 键序被打乱后仍判相等);node --test tests/mcn-store.test.mjs 必须全过。
  2. 出包 0.5.1 → 上池 →(结构迁移到 state=ready)→ 发布共享层(记条目 / 字节 / md5)。
  3. 删本地 5 条旧副本(执行拍板①):先原样导出留档(tmp/p36/)+ 打印清单(表名/主键值/保留哪份/删哪份)→ 再删 → 删后本地 account_video_source 应 = 34 行。⛔ 只删行、⛔ 绝不删本地库文件 mcn-plugin.db、⛔ 不删 db.js、⛔ 不重建库。
  4. 重取 account_video_source 影子读数 ⇒ 应转 两面对齐 34 = 34 + 内容判据全绿。
  5. 闭环 ⑥ + 执行 ⑦:三表逐表切 platform → 47 实例 + 106 合并同一次窗口重启(窗口已批)→ 三表 E2E(A2 实例内面)+ 真机读数验 A5/A8。
  6. 收口:释放域锁(ME=)· automation 置 PAUSED + 排期(⑤ 完成 ⇒ 不登记下一棒)· 入口 §0/§2 · 05-交接单/README.md §一 · 当日日志 · 交付件(A1–A9 附命令 + 输出 + 退出码)。⛔ 仍不 commit / 不 push。

变更记录:2026-09-25 22:5x 第 35 棒(执行棒 · 会话 p35-exec-plugin-dataline)落盘;纯 LF。