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

15 KiB
Raw Permalink Blame History

S3「数据面」落地与三轮回执(第 41 棒 · 执行棒)

线:插件投放与分库线 | 棒次:第 41 棒(执行棒)| 日期:2026-09-26 会话:插件投放与分库线-41(锁目录实际名 ________________________-41-1377504050,开始 14:35) 执行依据:规格书 05-交接单/交接单_包规格书_20260926.md §〇/§五 A/§五 C | 方案 交付物/功能打包到基础插件-分步实施方案-20260926.md §3.10.5 结论:🟢 本棒判据全绿(建库 → 迁移 → 对账 三轮 + 库名正则 + 负控 + 包内门禁);⚠️ 浏览器级 v-ui.sh 未取到(与第 40 棒同因,需客户端线起真壳)。


一、只读前置(命令 + 原始输出)

# 项 命令 原始输出
1 锁空闲 "$PY" state.py [锁] 空闲 ✅(+ 入口/收口段;5 条工作线,本条只走插件投放线)
2 方案件在位 ls -la 交付物/功能打包到基础插件-分步实施方案-20260926.md 51364 B · mtime 2026-09-26 13:29
3 库名形状三处硬编码 grep -nE "PLUGIN_DB_PREFIX|PLUGIN_DB_RE|PLUGIN_DB_MAX_IDENT" src/db/plugin-data/schema.ts 90: PLUGIN_DB_PREFIX='dshs_pl_'|100: /^dshs_pl_[a-z][a-z0-9_]{0,40}$/|103: PLUGIN_DB_MAX_IDENT=41
4 平台侧建库能力 ssh 47:select rolname,rolcreatedb from pg_roles dshs createdb=true|postgres createdb=true
5 既有插件库(开工对照) ssh 47:select datname from pg_database where datname like 'dshs_pl_%' dshs_pl_dsh_plugin_mcn_suite|dshs_pl_storyforge(dshs_pl_ai1net 不存在 ⇒ 本棒要建)
6 台账两表在位 ssh 47:to_regclass(...) plugin_datastores ✅ plugin_data_audit ✅(列:plugin_id,db_name,state,schema_version,plan_hash,last_error,created_at,updated_at)
7 平台 lib 产物 ssh 47:ls /opt/dshs/lib/db/plugin-data datastore.js / diff.js / registry.js / runtime.js / schema.js(可直接 import 复用)
8 门禁与尺子 ls 交付物/验证脚本/ v-baseline.sh v-neg.sh v-plugin.sh v-ui.sh(S0 四把,⛔ 本棒未改一行)

二、四件事 · 逐条原始输出

① 声明数据面(包内)

载体(🔴 关键口径):package.json 的 dsh.data.schema 显式指向 ./dsh.data.yaml —— 平台端 parseDeclFromDir 不自动探测(schema.ts:695 原文:⛔ 不自动探测 <dir>/dsh.data.yaml)。 新增/改动文件(全在新包内):

文件 动作 说明
dsh.data.yaml 新增 8 张表 / 29 列 / 5 个模块段;格式照 DB-03 §三
lib/data-limits.js 新增 插件侧唯一把关人 COLUMN_MAX_BYTES=16384 + 按类型上限 + 两个纯函数(零 DB 动作)
package.json 改 dsh.data.schema + exports["./data-limits"] + 🔴 files 补 dsh.data.yaml
scripts/build.mjs 改 新增门禁 ①d(数据面声明);组装清单补 dsh.data.yaml
README.md 改 新增「数据面(S3)」章 + 红线自查命令

🔴 files 与 build.mjs 的组装清单是两处,漏任一处都是"分发出去少了声明件"的静默故障 ⇒ 已两处同改。

平台解析器裁决(ssh 47 · /tmp/p41/decl):

  ✅ 声明解析:level=ok origin=yaml-file 库名=dshs_pl_ai1net schemaVersion=1 表=8
── 模块段覆盖(⛔ 不建"无模块段"的表)
  ✅ M1 多租户(tenant_)2 张:tenant_orgs → p_ai1net_tenant_orgs | tenant_bills → p_ai1net_tenant_bills
  ✅ M2 模型管理(model_)2 张:model_configs → p_ai1net_model_configs | model_creds → p_ai1net_model_creds
  ✅ M3 技能插件管理(plugin_)1 张:plugin_registry → p_ai1net_plugin_registry
  ✅ M4 覆盖网络界面(net_)1 张:net_zone_refs → p_ai1net_net_zone_refs
  ✅ M5 IM 插件侧(im_)2 张:im_rooms → p_ai1net_im_rooms | im_messages → p_ai1net_im_messages
  ✅ 库名 dshs_pl_ai1net(长度 14 ≤ 48)
  · 库名正则:匹配 ^dshs_pl_[a-z][a-z0-9_]{0,40}$
  · 声明结构摘要 declDigest=b46b4983b8da6fc0efa97051ab29793c23eab5a644c4906a96ad18021ba50892

rc=0

② 先建库(平台侧)

预演(⛔ 不动任何库):

  ✅ 库存在=false | 计划项=17 | 禁止项=0
  · planHash=1e587f9a2f0b06727e17d937fbef6cc3e86dd817618d2bf8b2c73f614238579e
  · 计划:create_database dshs_pl_ai1net / create_table ×8 / add_index ×8

rc=0

建库(🔴 动手前说明:这是生产变更 —— 在 47(开发环境服务器)建插件库 dshs_pl_ai1net + 落台账; 可逆:回滚口径 = 改名冻结,⛔ 不 DROP。未重启控制面、未中断任何用户):

── 建库(先建库再投放 · 单语句非事务 · 幂等)
  ✅ CREATE DATABASE dshs_pl_ai1net OWNER dshs ENCODING UTF8 TEMPLATE template0 ⇒ created
  ✅ 台账已写(state=created)+ 审计一条

rc=0

③ 迁移(单入口 · 按模块分步 · 每模块独立事务)

── 迁移(单入口 · 按模块分步 · 每模块独立事务)
  · 本棒执行模块:M1 → M2 → M3 → M4 → M5
  ── M1 多租户:表 2 | 计划 4 | 执行 4 | 失败 0 | 42ms
  ── M2 模型管理:表 2 | 计划 4 | 执行 4 | 失败 0 | 34ms
  ── M3 技能插件管理:表 1 | 计划 2 | 执行 2 | 失败 0 | 26ms
  ── M4 覆盖网络界面:表 1 | 计划 2 | 执行 2 | 失败 0 | 29ms
  ── M5 IM 插件侧:表 2 | 计划 4 | 执行 4 | 失败 0 | 30ms
  ── 迁移后现状:exists=true schemaVersion=1 表=9/8
  ✅ 台账已写(state=ready,plan_hash 保留)

rc=0(完整逐条输出在 47 的 /tmp/p41/migrate.out)

⚠️ 表=9/8 的解释(⛔ 不是异常):9 = 声明 8 张 + 内核台账表 p_meta_schema 1 张 (executePlan 每次都会建它并写版本号 —— 它是 diff 判 ready 的依据)。

「每模块可单独回滚」的取证(事务内演练 · 零残留):

── 单模块回滚演练(M1 多租户)—— **事务内**,结束后 ROLLBACK,库内零残留
  · 本模块表:p_ai1net_tenant_orgs, p_ai1net_tenant_bills
  · 其他模块表 6 张(演练必须不碰它们)
  ✅ 事务内改名生效:p_ai1net_tenant_orgs ⇒ p_ai1net_tenant_orgs__rbprobe(命中 1 行 pg_tables)
  ✅ ROLLBACK 后表集合与演练前逐字相同(9 张)⇒ 单模块 DDL 可独立回滚且零残留

rc=0

④ 对账(pg_database 的 dshs_pl_* × 控制面台账)

── 对账(pg_database 的 dshs_pl_* × 控制面台账)
  ✅ pg_database=3 台账=3
  · 库侧:dshs_pl_ai1net, dshs_pl_dsh_plugin_mcn_suite, dshs_pl_storyforge
  · 台账:dshs_pl_ai1net, dshs_pl_dsh_plugin_mcn_suite, dshs_pl_storyforge
  ✅ 两集合一致(差集双空)
  ✅ 本棒的库 dshs_pl_ai1net 在 pg_database 里

rc=0


三、负控(🔴 本棒的取证核心)

改一处声明且不回读 —— 选 model_configs.params_json 的 maxBytes: 8192 → 16384 (刻意选"改动仍在常量上限内的值":这样包内门禁不会红,只有回读能查出)。

态 动作 包内门禁 平台侧 readback
改坏 8192 → 16384,⛔ 不回读登记 ✅ 仍绿(maxBytes ≤ 16384 仍成立;只 DECL_DIGEST 变 ccb81776…) ❌ rc=1 红 —— 快照 b46b4983… ≠ 现读 2b28a76b… ⇒ 声明被改过却没回读登记(负控即命中此条)
改回 恢复 8192,回读登记 ✅ 绿 ✅ rc=0 绿 —— 两侧同为 b46b4983…

改坏/改回的字节级证据:dsh.data.yaml sha256 460c27d1…6350(改前)→ e4973b3e…e3b3(改坏)→ 460c27d1…6350(改回,与改前逐字相同)

⇒ 结论:① 回读这一步真的在起作用(不回读就查不出)② 包内门禁不能替代回读(改坏时它全绿) ③ 声明有两处表达(yaml 的 maxBytes 意图 × lib/data-limits.js 的常量),改任一处都必须回读另一处。


四、判据总表(退出码即结论)

# 判据 命令 rc 结论
1 建库 执行器 create 0 ✅ 绿
2 迁移(5 模块分步,0 失败) 执行器 migrate --modules M1,…,M5 0 ✅ 绿
3 对账(差集双空) 执行器 reconcile 0 ✅ 绿
4 库名正则 + 总长 执行器 decl / plan 0 ✅ dshs_pl_ai1net 匹配 ^dshs_pl_[a-z][a-z0-9_]{0,40}$、长度 14 ≤ 48
5 负控(改坏不回读 ⇒ 红;改回 ⇒ 绿) 执行器 readback 1 / 0 ✅ 命中(见 §三)
6 包内门禁 node scripts/build.mjs --check-only 0 ✅ 绿(8 表 / 29 列 / 模块段齐 / maxBytes 合规 / 回读摘要)
7 红线自查(包内零 DB 动作) grep -rEn "CREATE[ ]TABLE|…" lib scripts dsh.data.yaml package.json 1(零命中) ✅ 通过
8 尺子①v-plugin.sh 装配(端A 客户端形态) 沙箱副本 profile + 本包 0 ✅ 绿
9 尺子①v-plugin.sh 装配(端B 平台形态) profiles/web 键位建模 + link: 0 ✅ 绿
10 尺子②v-plugin.sh 取数 真实 import 本产物 0 ✅ 绿
11 尺子②v-plugin.sh 回调 真实调用 apply(ctx) 0 ✅ 绿
12 尺子①v-baseline.sh 平台 4 包 / 客户端 4 bundle 0 ✅ 绿(与 40 棒对照一致)
13 尺子③v-ui.sh 需真壳 3 ⚠️ 未取到(⛔ 不算绿)
— v-plugin.sh 运行 — — ⚠️ 不成立(可用启动日志 mtime 09-25,早于本包存在 ⇒ 空真,⛔ 不当证据,同 40 棒口径)
— v-neg.sh 靶子固定旧插件 — ⚠️ 本棒未跑(它只证明"尺子能变红";本棒已自做针对数据面的负控,见 §三)

五、本棒两处自纠(如实)

包内门禁 ①d 是新写的扫描器(正则逐行扫 yaml 文本),首版有两处缺陷,均已当场修好并复验:

# 缺陷 症状 根因 处置
1 索引行被当列 列数报 34(平台解析实为 29) 6 空格缩进的流式映射有两种:列行(含 name:)与索引行(含 columns:) 加判据:不含 name: 的行不计入列
2 default: "{}" 被截断 列数报 26(少 3 列) 正则用 [^}]* ⇒ 值里含 } 时提前收尾 改为 \{(.*)\}(贪婪到最后那个 })

复验:声明可读:8 张表 / 29 列 —— 与平台解析器(表=8、列 29)逐字一致 ✅。 ⇒ 教训(写进门禁注释):"包内自检"与"平台解析"是两个层次,数字对不上时先怀疑自检扫描器。


六、发现的文档偏差(⛔ 本棒只报告、不擅改)

# 位置 文档写的 实测 影响
1 规格书 §五 A4 · 决策点 D1 库名 dshs_pl_ai1net(15 字符) 14 字符(dshs_pl_=8 + ai1net=6) 纯笔误;换算与正则判据均独立成立,不影响任何判据。⛔ 规格书在文档库、属"冻结规格",本棒持锁域不含它 ⇒ 未改,留给文档棒/收口会话一支笔
2 规格书 §五 A4 表前缀 p_ai1net_ — 实测一致 ✅(p_ai1net_tenant_orgs 等 8 张) 无偏差

七、未取到 / 不成立 / 刻意不做(⛔ 不折算成"已知")

项 状态 原因 + 取数口
浏览器级 v-ui.sh ⚠️ 未取到 rc=3 需真壳在跑(CDP 9330 不可达);启动器 .workbuddy/_devkit/launch-desktop-dev-017.mts 属客户端线,本线 ⛔ 不代启。取数口:客户端线窗口内起壳后跑 bash 交付物/验证脚本/v-ui.sh
v-plugin.sh 运行 ⚠️ 不成立 可用启动日志 mtime = 09-25,早于本包存在 ⇒ "无失败条目"是空真
真机投放(两端各起一次) ⛔ 刻意不做 硬边界「⛔ 不碰起实例 / 取身份 / 把包装进去」;投放属 S4
包进平台候选池 / 门户点[建库] ⛔ 本棒绕过 门户路径要求包先进候选池(从 tgz 解析声明);本棒 ⛔ 不投放 ⇒ 用同一份解析器从包目录解析(parseDeclFromDir)。⚠️ 差异只在"从目录 vs 从 tgz",解析器与执行器是同一批函数(/opt/dshs/lib/db/plugin-data/*.js)。⛔ 不等于"门户链路已通"
库级回滚 ⛔ 未执行(本棒只做单模块事务内演练) 口径 = 改名冻结、⛔ 不 DROP(方案 §3.10.5);本棒无需动它

八、硬边界自查

边界 状态
⛔ 不改官方 dsh 主程序与缓存(R2) ✅ 未触碰 @deepseek-ai/dsh 与官方缓存
⛔ 不重造分发与更新机制 ✅ 本棒不碰分发;建库/迁移/对账全部复用 datastore.js / diff.js / schema.js
⛔ 不碰「起实例 / 取身份 / 把包装进去」 ✅ 一件未碰(无 ssh 起实例、无凭据取用、无 profile 装配)
⛔ 不改客户端工作区(只读引用) ✅ dsh-ai1net-desktop / dsh-desktop-0.1.7rc2 文件零改动(端A 用的是 tmp/p40/ 里的副本)
⛔ 包内不写直连平台库的路径 ✅ 包内零 DB 动作(判据 §四-7 零命中);要写平台库的动作全在平台侧脚本
⛔ 不 commit / 不 push ✅ 未 commit、未 push
红线门禁(重启控制面 / 中断用户 / >10 文件 / 不可逆) ✅ 未触发:未重启、未中断任何用户、改动 9 个文件(<10)、库可回滚(⛔ 未 DROP)
平台侧口令 ✅ 未落盘、未打印:只在 ssh 会话内由 drop-in 取到 shell 变量并传 env(报道里只给 url_shape=postgres://dshs:***@127.0.0.1:15432/dshs)

九、产物与落点

类别 路径
包内(并入包) E:/ProgramData/AIProject/dsh-plugin-ai1net/:dsh.data.yaml(新) · lib/data-limits.js(新) · package.json · scripts/build.mjs · README.md
平台侧执行器(⛔ 不属于包) E:/ProgramData/AIProject/aliyun-dsh-server/交付物/平台侧-插件数据面执行器-20260926.mjs
远端(47) /tmp/p41/{decl/,p41-exec.mjs,run.sh,migrate.out}(临时件,⛔ 未落代码根 /opt/dshs)
本机读数(⛔ 不入库) tmp/p41/(探针脚本 · run-scales.sh · 尺读数-20260926.txt)
平台侧持久变更 PG:库 dshs_pl_ai1net(8 表+p_meta_schema)|控制面:plugin_datastores 一行(state=ready)+ plugin_data_audit 若干条(plan/create/migrate×5/decl_snapshot)

回滚:① 库 → 改名冻结(⛔ 不 DROP)|② 台账行 → DELETE FROM plugin_datastores WHERE plugin_id='@dsh-local/ai1net'| ③ 包内文件 → git-less 直接还原(⛔ 本棒未 commit,故无历史版本;dsh.data.yaml 改回 sha256 已核)| ④ 远端 /tmp/p41/ → rm -rf(纯临时件)。