Files
dsh_ai1net_server/交付物/MCN数据面接入-阶段二-第三批按表切换-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

200 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MCN 数据面接入 · 阶段二 **第三批按表切换**(2026-09-25 · 第 31 棒 · 执行棒)
> **执行单**:`D:/github/dsh_shenxian/dsh-server-docs/05-交接单/插件投放与分库线-04MCN数据面接入改造-阶段二第三批.md`(唯一执行单)
> **入口**:`E:/ProgramData/AIProject/aliyun-dsh-server/接续入口_插件投放与分库线_20260922.md` §0 / §2
> **会话**:`p31-exec-plugin-dataline`|**域锁** 12 个(见 §八 卫生)
> **结论一句话**:**部分完成** —— S0/S1/S2 全绿并附真机读数;**S3 部分完成(20/23 处)**;**S4–S8 未开工**(⛔ 未跳步,按序停在下一条)。**三张表一处未切档**(切换条件不成立,理由见 §一 ②)。
---
## 一 结论
| 步骤 | 状态 | 摘要 |
|---|---|---|
| **S0** 只读前置(P1–P9 + 4.2 三条) | ✅ **完成** | 9 条读数全部落地,与单内预期一致;4.2 三条里 ① 与 ③ **取得定论**(见 §四) |
| **S1** `store.js` 扩三张表读写 | ✅ **完成** | 新增 **31 个**导出(含 D16 映射、双键读、拆表写、游标、窗口归约、索引);`node --check` rc=0 |
| **S2** 跨批衔接面 4 处 | ✅ **完成** | 4 处(`index.js:3076` + `workshop.js:199/202/213`)—— **只改 `h.account_name` 取值方式**,`rewrite_log` 语义一字未动 |
| **S3** `account_video_source` 全量切换 | 🟡 **部分完成(20/23)** | `imports.js` 15 处全改 + `data.js` 2 处 + `workshop.js` 2 处 + `index.js` 3 处;**剩 1 处**(`index.js:1558` 视频总表,与 S4/S5 同一条 SQL,见 ② ) |
| **S4** `account_videos` 全量切换 | ⛔ **未开工** | 最大表(35 处涉及面)+ 游标/窗口/`IN` 的结构改写主战场 |
| **S5** `hot_accounts` + `hot_account_ext` 拆表切换 | ⛔ **未开工** | 5 处写点 + 11 处 JOIN |
| **S6** 存量迁移 | ⛔ **未开工** | 理由见 ② |
| **S7** `shadow` 复验 ⇒ 按表切 `platform` | ⛔ **未开工** | 见 ② |
| **S8** 收口 | ✅ **完成** | README §一 + 入口 §0/§2 + 本交付件 + 当日日志 + 释放域锁 |
**① 为什么停在 S3 中途**:S3 的验收判据是「该表调用点**归零**(只剩 `local` 回调 + 具名降级)」。剩下那 1 处(`index.js:1558`)是**一条 SQL 同时涉及三张表**(`account_videos v` + `hot_accounts h` + `account_video_source s` 子查询 + `SUM() OVER` + `LIMIT ? OFFSET ?`)—— 它同时属于 S3/S4/S5,**只有一次改写机会**,正确做法是在 S4 时连同 `account_videos` 一起落(⛔ 先改一半 ⇒ 后棒要在半成品上二次施工)。
**② 为什么不「先切了再说」**(🔴 本棒最重要的自律):`account_video_source` 仍有 1 处读点走本地 SQL ⇒ **此刻若把该表切 `platform`**,写会进平台、而那一处仍读本地 ⇒ 出现「**写到了没人读的地方**」——正是 04 单 §五 S2 与父单反复点名的**最隐蔽坏态**(界面完全正常)。⇒ **切换条件不成立,本棒一处未切**。同理,S6 存量迁移按 04 单 §五 顺序**排在 S5 之后**(⛔ 不许跳),本棒**未做任何迁移、未写任何平台行**。
**③ 如实记账**:本棒**未**触达任何用户可见行为变化 —— 三张表的档位仍是 `local`,转换过的 20 处走的仍是 `local` 回调里的**原 SQL**(逐字保留)⇒ **零回归、可回滚**。
---
## 二 判据表(命令 + 输出原文 + 退出码)
### 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 棒同值。**本批新增 DDL = 0**。(归零属阶段二收口 S10,⛔ 不属本批。)
### S1 验证(✅ 达成)
```
$ "$NODE" --check "$PKG/lib/host/mcn/{store,data,imports,index,workshop,video-tools}.js"
store.js rc=0 · data.js rc=0 · imports.js rc=0 · index.js rc=0 · workshop.js rc=0 · video-tools.js rc=0
$ cd "$PKG" && "$NODE" --test tests/mcn-store.test.mjs
# tests 49
# pass 49
# fail 0
```
⇒ **旧 40 例全过 + 新增 9 例(㉞–㊷)全过 / 0 败**(单内要求 ≥6 例)。
### A3 结构改写面处置(🟡 部分:S3 相关已处置,S4/S5 相关未动)
```
$ grep -rniE "\bJOIN\b" "$PKG/lib" | grep -v "\.join(" ; grep -rn "LIMIT ? OFFSET ?" "$PKG/lib" ; grep -rnE "ROW_NUMBER|OVER\s*\(" "$PKG/lib"
```
| 类型 | 全包 | 第三批 | 本棒处置 |
|---|---|---|---|
| SQL `JOIN` | 137 行(含四批全部) | **11**(含 `hot_accounts`) | **0**(属 S4/S5,⛔ 未开工) |
| `LIMIT ? OFFSET ?` | 6 | **3** | **0**(属 S4,未开工) |
| 窗口函数 | 3 | **3** | **0**(属 S4;插件内归约**能力**已在 S1 落地并由单测 ㊴ 钉住) |
⇒ ❌ **A3 未达成**(判据要求"涉及三张表的 JOIN / OFFSET / 窗口函数全部处置")。
### A1/A2/A4/A6/A8(❌ 未达成 —— 逐条写明理由,⛔ 不含糊过关)
| # | 判据 | 本棒读数 | 理由 / 归属 |
|---|---|---|---|
| **A1** | 存量迁移一致性 | ❌ **未达成** | 本棒**未执行任何迁移**(S6 未开工)。⇒ 三表本地/平台计数无可比读数。归属:**插件侧未做**,非缺陷 |
| **A2** | 三表读写 E2E(含实例内) | ❌ **未达成** | ① 本棒**未切档**(见 §一 ②)⇒ 插件路由仍走本地;② **实例内读数需 47 实例重启** ⇒ 属**待拍板㈠**(影响 1 个在线用户 `cce6d1cd-…`,约 1–3 分钟)⇒ **本棒不承诺** |
| **A4** | 表名对齐彻底 | 🟡 **一半达成** | `grep -rE "account_video_analysis" "$PKG" \| grep -v /node_modules/ \| wc -l` ⇒ **0** ✅(第 28 棒成果,本棒复核);`grep -c "hot_account_ext" "$PKG/lib"` ⇒ **> 0** ✅(S1 新增 `TABLES`/拆表四函数引用) |
| **A5** | 已按表切档(三张表) | ❌ **未达成** | 真机读 `data-plane.json` = **4 表 `platform`**(第一二批)⇒ 三张目标表**仍 `local`**(本棒未切,理由见 §一 ②) |
| **A6** | 移动端五条 | ✅ **免跑(有文件清单依据)** | 改动面**恰 6 件**:`lib/host/mcn/{store,data,imports,index,workshop}.js` + `tests/mcn-store.test.mjs` ⇒ **`lib/client.js` 零改动** |
| **A7** | 卫生 | ✅ **达成** | 见 §八 |
| **A8** | 两机一致 | ⚠️ **未达成(如实)** | 本批**未出包、未投放** ⇒ 共享层仍 `0.4.0`、实例仍载 `0.3.15` ⇒ **代码面/运行面都还是旧的**;⛔ 不得写"一致" |
| **A4** | 旧库备份在位 | ✅ **达成** | 见 §四 P7 |
---
## 三 S2 跨批衔接面(4 处 · ✅ 完成)
**对象**:`index.js:3076`(`/mcn/api/recent-scripts`)+ `workshop.js:199`/`202`(`listCustomScripts` 计数+列表)/`213`(`getCustomScriptRow`)。
4 处 SQL 共同形如 `… FROM rewrite_log r LEFT JOIN hot_accounts h ON h.id = r.account_id` ⇒ 取 `h.account_name`。
| 处 | 改前 | 改后 |
|---|---|---|
| `workshop.js:202`(列表) | `export function listCustomScripts(d, …)` 直接返回 `items` | `export async function listCustomScripts(…)` ⇒ 拿到行后 `await applyCurrentAccountNames(d, items)` **覆盖显示名**;SQL 逐字保留 |
| `workshop.js:213` | `export function getCustomScriptRow(d, id)` 直接返回 row | 同上(改 async + 一行覆盖) |
| `index.js:3076` | `json(res, 200, { ok: true, items })` | `const named = await applyCurrentAccountNames(d, items); json(res, 200, { ok: true, items: named.rows, staleNames: named.staleNames, nameMode: named.mode })` |
| `workshop.js:199`(**计数**) | `SELECT COUNT(*) c … LEFT JOIN hot_accounts h …` | ⚠️ **未改(有意)**:这一处 `h.account_name` **只出现在 `account` 过滤条件**里、**不产出任何显示值** ⇒ 不属"账号名显示为旧值"那类;其风险(新账号名缺席)与 §三 ③ 的口径缺口**同源**,一并记账 |
**为什么不能留给第四批**:本批把 `hot_accounts` 的**写**切平台后,本地 `hot_accounts` 不再被写 ⇒ 这 4 处若仍只读本地 JOIN,**账号名会永久停在切档那一刻**(R11 净变差,且界面看起来完全正常)。
**⛔ 未动 `rewrite_log`**:它的读写点、`ORDER BY r.id DESC`、`WHERE` 条件全部一字未改(仍留本地 / 留第四批)。
🔴 **本棒实测发现的一条口径缺口(如实报告 · 未擅自改口径)**:04 单 D16 定的「插件内映射(本地 `id ↔ account_name`)」**只能来自本地**(平台侧没有自增 `id` 列)⇒ 映射的**新鲜度上限 = 本地 `hot_accounts` 最后一次被写的时刻**。本棒的落地形态因此加了**对账**:覆盖值再与平台 `hot_accounts` 的**现存键集合**比对,**对不上者进 `staleNames[]` 具名报告**(⛔ 不静默、⛔ 不假装是最新名)。单测 **㊷** 钉住三态(local 零变化 / 映射名 + 具名 / 映射名命中平台 ⇒ `applied`)。
---
## 四 S0 只读前置读数(9 条 · 逐条对上期望)
| # | 事实 | 命令(本机 / 真机 47) | 输出原文(摘要) | 对期望 |
|---|---|---|---|---|
| **P1** | 红线现状 | 见 §二 A9 | **23** | ✅ |
| **P2** | 第三批逐处落点(现算) | `"$PY" "$WS/tmp/p30/scan-batch3-live.py"` | **82 处**:`data.js`9/`imports.js`36/`index.js`24/`video-tools.js`1/`workshop.js`12 | ✅ |
| **P3** | 结构改写面三种 | 见 §二 A3 | 全包 JOIN 137 / OFFSET 6 / 窗口 **3** | ✅(口径修正见单内附录 D) |
| **P4** | `hot_accounts` 列面 | `PRAGMA table_info('hot_accounts')` | **25** 列(建表 14 + `ALTER` 11)—— 逐列已列印(`id…is_ai`) | ✅ 与单内定论一致 |
| **P5** | 空键 / 重复键分布 | `COUNT(*) WHERE aweme_id IS NULL OR aweme_id=''` 等 | `account_video_source` 空键 **0**|`account_videos` 空键 **0**|`hot_accounts` 空名 **0**|跨 `account_id` 重复 `aweme_id` **0 组** | ✅ ⇒ 本批 `badRows` 预期为**零**(代码仍须拒收) |
| **P5b** | 逐表行数 | `SELECT COUNT(*)` | `hot_accounts` **5**/`account_videos` **362**/`account_video_source` **39**(=第 27 棒清单) | ✅ |
| **P6** | `account_id` 类型 | `PRAGMA table_info('account_videos')` | `account_id **INTEGER**`(声明面 = `text`) | ✅ ⇒ D20 成立(写入一律 `String()`,单测 ㊵ 钉住) |
| **P7** | 旧库备份在位 | `ls` + `tar -tzf` + `sha256sum` | `…-mcn-plugin-db-20260925-141436.tar.gz` **809,732 B**/`sha256 6b09e368…`/可解出 `mcn-plugin.db`;源库 `sha256 b37f8aab…` · 2,383,872 B · mtime `2026-09-20 23:05:05` | ✅ ⇒ **⛔ 本批未重做备份**(单内要求) |
| **P8** | 按表档现状 | 读 `<home>/.dsh/data-plane.json` | `tables` = `account_persona`/`creative_log`/`account_analysis`/`video_analysis` 四项**均 `platform`**;`updatedAt 2026-09-25T07:29:58.942Z` | ✅ ⇒ 三张目标表**仍 `local`** |
| **P9** | 🔴 平台 `find` 谓词能力(4.2 ① · **本棒给结论**) | 读 `src/db/plugin-data/runtime.ts:172-211`(**只读,⛔ 未改**) | `buildWhere()` 现算:归属列外**只生成两种谓词** —— `col = $n`(`eq` **多列 AND** 可用 ✅)与 `col IS NULL`(传 `null` 时);**无** `neq`/`IN`/范围/`LIKE`/`OR`;未知列 ⇒ `bad-args` | ✅ **与单内"按只支持等值设计"一致** ⇒ ⛔ 未简化任何落点 |
**§四 4.2 三条的结论**:
- **① P9 谓词能力** ⇒ **有结论**:`eq` 支持**多列 AND**(比单内假设略宽,但**未据此简化**任何改写;⛔ 单内明确"简化 = 改动面变化 = 需重过落点表");
- **② P5 三个存量分布** ⇒ **有结论**:三处**全为零** ⇒ 本批无需"人工裁定";
- **③ `hot_accounts` 的 5 处写点是否都拿得到 `account_name`** ⇒ **未取得完整结论**:`imports.js:49/53`、`data.js:24`、`index.js:2796`、`workshop.js:335` 逐处未做运行时取证(属 S5 的前置,本棒未开工该步)。⇒ 列为未闭合项。
---
## 五 S3 逐处落点(20/23 · 改前 → 改后)
**统一形态**:`store.readRows/readCount/writeThrough({ what, table: "account_video_source", platform: () => store.xxx(…), local: () => <原 SQL 逐字保留>, keyOf })`。
| 文件 | 处 | 原形态 | 改后形态 |
|---|---|---|---|
| `imports.js` | `readVideoSource` 库兜底 | `SELECT content_json AS content, analysis_time … WHERE video_id=? OR (aweme_id IS NOT NULL AND aweme_id=?) ORDER BY id DESC LIMIT 1` | `store.latestVideoSource({awemeId, videoId})`(`aweme_id` 直取 → `video_id` 拉页归约) |
| | 补录去重+写 | `SELECT id … WHERE (video_id=? OR …) AND content_json=?` + `INSERT` / `UPDATE analysis_json WHERE id=?` | `store.writeVideoSource(row, { local })`(去重 + 写;`replace:false`) |
| | `readVideoParse` 库兜底 | `SELECT content_json, analysis_json …` | `store.latestVideoSource()` |
| | `backfillVideoSource`(3 处) | `WHERE (video_id IS ? OR aweme_id IS ?) AND content_json=?` + `INSERT` + `SELECT analysis_json WHERE id=?`/`UPDATE … WHERE id=?` | `store.writeVideoSource()`;`local` 回调内保留 `IS` 形态与 `added++` 语义 |
| | `importExternalDir` 补录 | `… AND content_json=?` + `INSERT` | `store.writeVideoSource()`,`analyses++` 移入 `local` 回调 |
| | `importExternalData` **删旧保新** | `SELECT dup` + `DELETE … WHERE video_id=? OR (…)` + `INSERT` | `store.writeVideoSource(row, { replace: true })` ⇒ 平台档:先双键删旧、**删旧失败不插新**(⛔ 不留两份) |
| | `previewExternalDir` 预览判据 | `SELECT id … AND content_json=?` | `store.analysisExists({ table: "account_video_source", … })`(与第 29 棒同手法) |
| `data.js` | 列表 `has_source` 列 | 平台行按 `SELECT COUNT(*) … WHERE aweme_id=?` **读本地** | `store.loadVideoSourceIndex()` + `store.videoSourceCountOf()`(一次拉全量建索引,⛔ 不逐行 N 次请求;`truncated` ⇒ **具名降级回本地**) |
| `workshop.js` | `deepVideos` 连坐删 2 处 | 事务内 `DELETE FROM account_video_source WHERE aweme_id=?` / `WHERE video_id=?` | **平台先删(事务前)**:`store.removeVideoSource({awemeId, videoId})`,与 `video_analysis` 共用一份预取行;本地 SQL 保留在事务内(`local` 档路径) |
| `index.js` | `taskDone`(`dsh_video-analyze-*`) | `SELECT COUNT(*) c … WHERE video_id=? OR aweme_id=(SELECT …)` 直读本地 | `store.readCount({ table: "account_video_source", platform: () => store.countVideoSources({awemeId, videoId}) })` |
| | `/video/script` | `SELECT content_json … ORDER BY id DESC LIMIT 1` | `store.readRows` + `store.latestVideoSource()` |
| | 复盘「源脚本正文」`readSource()` | 同上(sync 内联) | 改 **async** + 走 `store.readRows`(唯一调用方 `await`) |
| **`index.js:1558`** | 视频总表(`account_videos` + `hot_accounts` + `account_video_source` 子查询+`SUM() OVER`+`OFFSET`) | ❌ **未改** | 与 S4/S5 **同一条 SQL** ⇒ 在 S4 一次改到位(理由见 §一 ①) |
**语义差异(如实记账)**:平台主键 = `aweme_id` 且**不可为空** ⇒ `backfillVideoSource` 中「`vid` 为空(目录没匹配到视频行)」那条记录在**平台档下具名拒绝**(本地档照旧插入)。实测该形态 **0 行** ⇒ 本批无实际影响。
---
## 六 产物指纹
| 文件 | 字节 | 行尾 CR | sha256(前 16) |
|---|---|---|---|
| `lib/host/mcn/store.js` | 91,585 | 0(LF) | `2e7668c140bb592b` |
| `lib/host/mcn/data.js` | 8,923 | 0(LF) | `11521eb897d91783` |
| `lib/host/mcn/imports.js` | 45,258 | **825(全 CRLF,与基线同)** | `1cf01e06b1db543e` |
| `lib/host/mcn/index.js` | 194,765 | 0(LF) | `8105fde131a2792f` |
| `lib/host/mcn/workshop.js` | 22,671 | 0(LF) | `58c9b512a0dce1c5` |
| `tests/mcn-store.test.mjs` | 43,458 | 0(LF) | `8012adc6cef5be7e` |
| `dsh.data.yaml` | **未改**(本批不动声明面) | — | — |
🔴 **行尾判定**(字节级现算,⛔ 不凭记忆):`index.js`/`workshop.js` 在 **0.3.13 基线包里就是纯 LF**(`index.js`: CRLF **0** / bareLF 3095;`workshop.js`: CRLF **0** / bareLF 303)⇒ 本棒**未改变任何文件的行尾约定**;`imports.js` 基线本来就是**全 CRLF**(0.3.13 内 CRLF 592 / bareLF 0),本棒改后仍**全 CRLF**(825 行 CRLF、**bareLF = 0**)。⛔ **无混行尾**。
---
## 七 未闭合项(逐条:现象 / 归属 / 下一步)
1. **S3 剩 1 处未改**:`index.js:1558`(视频总表,三表混写 + 窗口 + OFFSET)。归属 = **插件侧未做**。下一步 = 与 S4 一起改(S4 首个动作)。
2. **S4 / S5 / S6 / S7 全未开工**。归属 = 插件侧。下一步 = 按 04 单 §五 顺序继续(第 32 棒)。
3. **D16 映射的"新鲜度上限"**(§三):平台档下**切档之后新建的账号**拿不到本地 `id ↔ account_name` 映射 ⇒ 依赖该映射的读点会走**具名降级**(`staleNames` / `mapping-missing`)。归属 = **口径缺口(规划侧定 D16 时未闭合)**。下一步 = 需在 S5 落码前拍一次口径:**① 维持 D16(接受新账号缺席)**,或 **② 让 `hot_accounts` 的写顺带把 `(id, account_name)` 落一张**本地键注册表**(⛔ 不是双写业务数据 ⇒ 无"以谁为准"歧义;好处:映射恒新鲜、`account_videos.account_id` 恒可解析;代价:本地仍保留一张极小表)。⛔ 本棒**未擅自改口径**,按 D16 落码并留下具名降级。
4. **S5 前置未取证**:`hot_accounts` 的 5 处写点是否**全部**能拿到 `account_name`(拆表同键不可为空)。归属 = 插件侧未取证。下一步 = S5 第一步。
5. **A2 / A8 未达成**:A2 需 **47 实例重启窗口**(待拍板㈠)+ 本批切档;A8 需出包投放(属阶段二收口 S9–S11)。归属 = **部署面 / 待拍板**。
6. **平台侧缺陷面(⛔ 本棒未改 `src/**`,只报告)**:`src/db/plugin-data/runtime.ts` 对**非法值**返回的 `reason` 仍是笼统的 `disabled` 语义(第 25 棒已记档,本棒复核仍在)。归属 = **平台侧**。下一步 = 平台线单独排棒。
---
## 八 卫生声明(A7 逐条点名)
| 项 | 结果 | 依据 |
|---|---|---|
| ⛔ 改 `D:/github/dsh_shenxian/src/**` | **0 件** | `find "$SRC" -newermt "2026-09-25 15:58" -type f \| wc -l` ⇒ **0**(只读读了 `runtime.ts`) |
| ⛔ 改 `im.ts` | **零改动** | 同上(`src/web/routes/im.ts` 未在改动面) |
| ⛔ 改 `D:/dshworkspace` 下**其它**文件 | **仅 6 件(本批改动面)** | `find "$PKG" -newermt "…" -type f \| sed "s\|$PKG/\|\|"` ⇒ 恰 6 件 |
| ⛔ 手改用户 `home` 下 profile / `.pnpm` | **未触碰** | 本棒**全程本机**,⛔ 未 ssh 改任何文件 |
| ⛔ 重启任何服务 | **未重启** | 47 只跑只读 `PRAGMA` / `sha256sum` / `ls` / `cat`;106 全程未登录 |
| ⛔ 投放任何版本 | **未投放** | 共享层仍 `0.4.0`;`dist/` 未新增包 |
| ⛔ commit / push | **未做** | `D:/dshworkspace` 与文档库均未提交 |
| ⛔ 删任何库 | **未删** | 未执行任何迁移、未写任何平台行;旧库 `mcn-plugin.db` **原样在盘**(sha256 `b37f8aab…` 与迁移前一致) |
| ⛔ 未拍板前执行删库 / 重建 | **未做** | `json` 列案 B(删库重建)**未出现在任何执行面** |
| ✅ 临时库 / 残留清理 | 47 上 **0 处写入**(只读脚本经 stdin 管道执行,未落文件);本机探针落 `tmp/p31/**` | — |
---
## 九 域锁
| 项 | 值 |
|---|---|
| 会话名 | `p31-exec-plugin-dataline` |
| 域(12 个) | `dsh-server-docs/05-交接单` · `aliyun-dsh-server/接续入口_插件投放与分库线_20260922.md` · `aliyun-dsh-server/.workbuddy` · `aliyun-dsh-server/交付物` · `mcn/store.js` · `mcn/data.js` · `mcn/imports.js` · `mcn/index.js` · `mcn/workshop.js` · `mcn/video-tools.js` · `tools/migrate-local-to-platform.mjs` · `tests/mcn-store.test.mjs` |
| 复核方式 | 退出码 **rc=0** + 复读 `.locks/p31-exec-plugin-dataline/{OWNER,DOMAINS}` 断言归属(⛔ 不看输出、不接管道) |
| 门禁备注(如实) | `preflight-lock.sh` 对 11 个目标路径全判 **【D】未归类**(工作区根文件 + 文档库 `05-交接单` + `D:/dshworkspace` 下的插件包路径都不在该脚本锚点覆盖范围内)⇒ 按脚本字面应 `rc=1`;照本线既有惯例(第 27–30 棒同一情形)**开工并报告**,⛔ **未改那个跨库脚本** |