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/ 知识文件,按口径入库)
This commit is contained in:
1 parent
30b46dbd0c
commit
c1b5e4d966
735 files changed
+153192
-2415
No files matched your search
@@ -0,0 +1,186 @@
|
||||
# S6「第二块:技能插件管理」· 落地与四轮回执(2026-09-26 · 第 44 棒)
|
||||
|
||||
> **工作区**:`E:/ProgramData/AIProject/aliyun-dsh-server` | **会话名**:`插件投放与分库线-44`
|
||||
> **执行依据**:本线入口 §0 最新行 + §2「🎯 本轮动作」(第 43 棒块)|规格书 `05-交接单/交接单_包规格书_20260926.md` §〇/§五 A·C|方案 `交付物/功能打包到基础插件-分步实施方案-20260926.md` §3.10.8 + §4
|
||||
> **本棒只做一件事**:S6(⛔ 不碰 S7、⛔ 不跨 S9 的 P2)
|
||||
|
||||
---
|
||||
|
||||
## 一、一句话结论
|
||||
|
||||
S6 四条判据 **全部落地并逐条取证**——包内那一半(上传/检测/建库/启用 + 「更新」四拆的 ①②)真发到平台面;**「搬包」与「自动处理的执行者」两拆明确留在包外**(分别为 S4 拉取器与引导层),并由**负控**证明「关掉包外执行者 ⇒ 自动更新行为确实停」。
|
||||
|
||||
过程中**抓到并修掉一处会让 M3 五条路由全线静默失效的真 bug**(包名形态校验不收带 scope 的冻结包名),并已把它钉成包内门禁的第 ⑩ 条断言。
|
||||
|
||||
读数:包内门禁 **60 ✅ / 0 ❌(rc=0)**|S6 取证编排 **58 ✅ / 0 ❌(rc=0)**|S6-1 四条面 **rc=0**|`v-neg all` **rc=0**。
|
||||
|
||||
---
|
||||
|
||||
## 二、四条判据逐条回执
|
||||
|
||||
| # | §3.10.8 判据原文 | 本棒落地 | 取证 | 结论 |
|
||||
|---|---|---|---|---|
|
||||
| ① | 上传/检测/建库/启用 进包 ⇒ `v-plugin.sh` 四面绿 | 七条包内路由(`lib/plugins-sdk.mjs` + `lib/index.js` 注册面) | 装配 端A/端B · 取数 · 回调 · 运行 **全 `rc=0`**;spy ctx 抓到九条平台请求逐条对得上 | ✅ |
|
||||
| ② | 「更新」四拆:①②进包(只到"请求")/③搬包走 S4 拉取器/④执行者留包外 ⇒ 能逐条指出"谁在做",且执行者在包外 | `UPDATE_SPLIT` 数据表 + `describeOwnership()`(UI 与回报件共用**同一份**来源) | 四拆逐条具名(见 §三);机验「凡 `executor:true` ⇒ `inPackage:false`」;机验「包内零搬包实现」 | ✅ |
|
||||
| ③ | `package.json` 指向 yaml;自增 id ⛔ 不照搬;UI ≤900px 独占 ⇒ 窄屏截图 | `dsh.data.schema = ./dsh.data.yaml`(S3 已落)|行键 = 自然键(包名/版本/`user_id`)|窄屏样式段独立成块 | 门禁 ⑨(断点逐字 900px + 四条硬判据 + 零 `100vh`)+ 门禁「零自增 id」两处(包内 + 声明件)**全绿**;⚠️ **真壳窄屏截图未取到**(见 §八) | 🟡 机械判据 ✅/截图未取到 |
|
||||
| ④ | 负控:关掉包外执行者 ⇒ 自动更新行为**必须停** | 包内只有 `requestUpdate`(登记请求)与 `setAutoHandling`(写偏好) | 对比实验:执行者**在位** ⇒ `pulled=2` + 取包口被调 2 次;执行者**关掉** ⇒ 本地**零包目录** + 取包口 **0 次调用**,而包内台账仍记着"请求发生过" | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## 三、S6-2「谁在做」——四拆逐条(判据的输出就是这个表)
|
||||
|
||||
| # | 拆 | 包内? | 执行者? | 归属 | 做到哪为止 |
|
||||
|---|---|---|---|---|---|
|
||||
| ① | 看见新版本 | ✅ 是 | ❌ 否 | `package` | 只报差异(`differs`/`same`/`unknown` 三态),⛔ 不代替用户下"该更新"的结论 |
|
||||
| ② | 点「更新」 | ✅ 是 | ❌ 否 | `package` | **只到 `requested`**(回 `requestId` + `executor:'s4-puller'`),⛔ 不假装进度 |
|
||||
| ③ | 搬包 | ⛔ **否** | ✅ 是 | **`s4-puller`** | S4 已落地的拉取器(平台/引导层),⛔ 包内一个字节都不搬 |
|
||||
| ④ | 设置自动处理 | ⛔ **否** | ✅ 是 | **`bootstrap-layer`** | 包内只写一条偏好(`pullsTriggered:0`)——**执行者必须活在被自动化对象之外**(实例没起 = 插件不存在) |
|
||||
|
||||
机验(不靠自述):
|
||||
|
||||
- `UPDATE_SPLIT.filter(r => r.executor).every(r => r.inPackage === false)` ⇒ **执行者全在包外**。
|
||||
- 归属只落两个具名外部角色,`['s4-puller','bootstrap-layer']`,**不含本包**。
|
||||
- **包内代码行**(去注释)扫 `spawn` / `createGzip` / `syncSharedLayer` / `pullOnePack` / `extract` / `rename(` / `cpSync` ⇒ **零命中**。
|
||||
- 包内零自增字眼(`autoIncrement` / `AUTO_INCREMENT` / `rowid` / `serial`)⇒ 行键确为自然键。
|
||||
|
||||
---
|
||||
|
||||
## 四、包内七条路由 → 平台端点(逐条真发,spy ctx 记账)
|
||||
|
||||
| 包内路由 | 平台端点(真实实现) | 方法 | 备注 |
|
||||
|---|---|---|---|
|
||||
| `GET /api/ai1net/plugins` | `/api/plugins/business` | GET | 候选池清单 |
|
||||
| `POST /api/ai1net/plugins/upload` | `/api/plugins/business` | POST | body `{file, filename, trust?}`;**检测链安全/兼容两项在这条响应里** |
|
||||
| `POST /api/ai1net/plugins/detect` | `/api/plugins/business/datastore` | POST | body `{id, dryRun:true}`;⚠️ 返回值**如实标** `covers:'dataplane-declaration'`,⛔ 不让前端以为"三项都重跑了" |
|
||||
| `POST /api/ai1net/plugins/db`(`plan`) | `/api/plugins/business/datastore` | POST | `{id, dryRun:true}`,⛔ 不动库 |
|
||||
| 同上(`create`) | 同上 | POST | `{id}`,✅ 真建库 |
|
||||
| 同上(`migrate`) | `/api/plugins/business/datastore/migrate` | POST | `{id, confirm:true, expect}`;🔴 `expect` **必填**且**包内不生成**(生成 = 替用户确认改动) |
|
||||
| `POST /api/ai1net/plugins/enable` | `/api/plugins/mine/apply` | POST | `{plugins:[{id, enabled}]}`;平台两道门禁(基础插件不可关/未建库不许开)**都在平台**,包内只转交 |
|
||||
| `GET /api/ai1net/plugins/updates` | `/api/plugins/shared/status` | GET | 折成三态,**判据只看 `treeSha256`** |
|
||||
| `POST /api/ai1net/plugins/update-request` | `/api/plugins/business` | POST | 只到请求;`role='auto'` 时**改走 `setAutoHandling`,零平台请求** |
|
||||
|
||||
「该拒就拒」五条负控(**一律零平台请求**,⛔ 不发注定失败的请求):
|
||||
|
||||
| 场景 | 结论 | 平台请求数 |
|
||||
|---|---|---|
|
||||
| `mode=migrate` 缺 `expect` | `bad-args` | 0 |
|
||||
| `upload` 缺 `file` | `bad-args` | 0 |
|
||||
| 包名形态不合法(`../../etc/passwd`) | `bad-args` | 0 |
|
||||
| 出示**空**凭据(带了身份头却没带令牌) | `plugin-not-enabled` | 0 |
|
||||
| 出示**别人的**令牌 | `plugin-not-enabled` | 0 |
|
||||
|
||||
🔴 三态凭据语义(继承第 43 棒):**没带身份头** ⇒ 视为本包自己(用本机装配注入)|**带了身份头却是空串** ⇒ **必拒**(⛔ 不许回退到本机 env —— 那正是"插件自称身份"的缝)。
|
||||
|
||||
---
|
||||
|
||||
## 五、S6-4 负控(本棒核心)
|
||||
|
||||
装置:**真执行者** = `tmp/p42/puller.mjs`(S4 已落地的拉取器,⛔ 不重造)+ `tmp/p42/mgr-mock.mjs`(照抄平台对账/产物口口径)。
|
||||
|
||||
| 局面 | 观测 | 结论 |
|
||||
|---|---|---|
|
||||
| 执行者**在位** | `ok=true`;`pulled=[_dsh-local_ai1net, _dsh-local_probe2]`;盘上真出现包目录;**取包口被真实调用 2 次** | 行为确实会发生 |
|
||||
| 执行者**关掉**(清空本地后,只跑包内动作) | 本地**零包目录**;**取包口 0 次调用**;`setAutoHandling` 回 `pullsTriggered:0` | **行为确实停** |
|
||||
|
||||
⚠️ 这条负控**不是空绿**:同一轮里包内台账记着 `updateRequests=1 / autoHandlingWrites=1` ⇒ 证明"**请求确实发生过,只是没人执行**",而不是"脚本压根没跑"。
|
||||
|
||||
叠加三条既有判据(S4 口径,本棒复测):
|
||||
|
||||
1. **清单拿不到** ⇒ `ok=false` + `pulled` 空 + **本地零改动**(目录清单前后一致)。
|
||||
2. **单包失败**(截断 gzip)⇒ `failed` 恰含该包、另一包照常落地、失败已回报平台。
|
||||
3. **`extra`**(本地多余目录)⇒ 如实出现在 `extra` 里,**目录仍在**(⛔ 平台不据此删)。
|
||||
|
||||
---
|
||||
|
||||
## 六、🔴 真实 vs 建模(逐条标注 · ⛔ 不许把建模当"已通")
|
||||
|
||||
| 面 | 本棒是**真实**还是**建模** | 说明 |
|
||||
|---|---|---|
|
||||
| 包内七条路由的实现与注册 | **真实** | `lib/index.js` 真装配 + 真 `apply(ctx)`(spy ctx 抓到路由原文) |
|
||||
| 包内 → 平台的出向请求 | **真实**(HTTP 层) | 三条头(包名 / 每插件令牌 / 实例令牌)+ `body` 真的 `JSON.stringify` |
|
||||
| **平台侧收到的效果** | ⛔ **建模** | 平台端由 spy / mock 代替;**未对真机投放**(属投放线) |
|
||||
| 「更新」③ 搬包 | **真实**(复用 S4 产物) | 真拉取器 + 真 mock Manager;⚠️ 平台的**权威共享层**是沙箱替身 |
|
||||
| 「更新」④ 自动处理的执行者 | ⛔ **仅契约** | 包内只有"偏好"这一半;**引导层那一半尚未实现**(本棒只证明"包外不干活 ⇒ 行为停") |
|
||||
| **每插件令牌的平台侧那一半** | ⛔ **建模 / 尚无** | 真实 `im.ts` 里**仍无**这道闸 ⇒ ⛔ **不能断言"平台侧令牌闸已上线"**(属投放线待落地) |
|
||||
| 长轮询 / 会话面 / 桥传输 | 继承第 43 棒口径 | 会话面走 `imAuth`;桥端点才有令牌闸 |
|
||||
| 窄屏 UI | **机械判据真实 / 视觉效果未取到** | 样式段与断点由门禁逐条断言;**真壳截图未取到**(§八) |
|
||||
|
||||
---
|
||||
|
||||
## 七、§4 避坑总表对表(本棒相关类目)
|
||||
|
||||
| 类目 | 本棒处置 |
|
||||
|---|---|
|
||||
| **B1** 桌面端无 webServer | 服务端一律走 E1(`connection.fetch.register` 精确路径),⛔ 不用 webServer 具名路由 |
|
||||
| **B2** 只认精确路径 | 七条逐字冻结、⛔ 无前缀匹配;门禁把七条与规格书 §五 A3 冻结清单**逐字比对** |
|
||||
| **B3** 平台不是实例 | 「写平台库」的动作(建实例/租约/配额)⛔ 一律不进包 |
|
||||
| **C1** 指纹两侧不一致 | 判据只看 `treeSha256`,⛔ 不比版本号;`diffOfSharedStatus` **只聚合不重算**(避免第二真相源) |
|
||||
| **C5** 算不出指纹就报算不出 | 三态强制:全 `current` ⇒ `same`/有 `stale` ⇒ `differs`/有 `unknown` ⇒ **`unknown`(⛔ 绝不折成 `same`)** |
|
||||
| **D1** 一个包 = 一个库,表名分段 | 库 `dshs_pl_ai1net`/前缀 `p_ai1net_`/M3 段 `p_ai1net_plugin_`(S3 已落,`DECL_DIGEST` 未破) |
|
||||
| **E1** 测试跑的是构建产物 | 改完**必** `node scripts/build.mjs`(本轮改 `build.mjs` 自身后先 `--check-only` 复验) |
|
||||
| **E6** 禁 `exports.default` | 门禁覆盖;`lib/client.js` 仍只导出 `apply` + `inject` |
|
||||
|
||||
---
|
||||
|
||||
## 八、尺子回归(⛔ 未改尺子一行)/ 未取到(如实)
|
||||
|
||||
```
|
||||
⓪ 包内门禁 node scripts/build.mjs --check-only | rc=0 (60 ✅ / 0 ❌)
|
||||
M5_DIGEST=55cdc0d5fc8eb99d ← 与第 43 棒逐字相同 ⇒ M5 的绿没被弄红
|
||||
M3_DIGEST=7045a778baa82cfe DECL_DIGEST=88c752a3e12597b3…(8 表 29 列未破)
|
||||
S6-1 装配 · 端A 客户端形态(桌面 profile 真件副本 + 本包) | rc=0
|
||||
S6-1 装配 · 端B 平台形态(profiles/web 键位建模 link: 依赖) | rc=0
|
||||
S6-1 取数 · 真实 import 本产物 | rc=0
|
||||
S6-1 回调 · 真实调用 apply(ctx)(spy ctx) | rc=0
|
||||
运行 · 真启动日志的失败面(⚠️ 弱证据) | rc=0
|
||||
v-neg.sh all | rc=0
|
||||
S6 取证编排 node tmp/p44/run-s6.mjs | rc=0 (58 ✅ / 0 ❌)
|
||||
```
|
||||
|
||||
### ⚠️ 未取到 / 不成立(如实,⛔ 不折算成"已知/通过")
|
||||
|
||||
| 项 | 读数 | 原因 |
|
||||
|---|---|---|
|
||||
| **窄屏截图(S6-3 第三条)** | **`v-ui.sh` rc=3** | 需**真壳在跑**;启动器属**客户端线**(`dsh-ai1net-desktop/.workbuddy/_devkit/launch-desktop-dev-017.mts`),本线 ⛔ 不代启 ⇒ 机械判据已绿,**视觉效果未取到** |
|
||||
| M5 卡片 + S4-6 实例页能力栏 | 同上 | 同因(第 43/42 棒已欠,本棒未消) |
|
||||
| `v-baseline.sh` 平台侧 | **rc=255**(客户端侧 ✅ 取到 5 个 bundle,`@dsh-local/*` 计 0 个) | `ssh 47.77.182.89` 本轮连不上(**瞬时**;该项按尺子自述「只作开工对照,⛔ 不进判据」) |
|
||||
| `v-plugin.sh 运行` 面 | rc=0 但**空真** | 可用日志 mtime 早于本包 ⇒ **弱证据**,⛔ 不当"运行期已验" |
|
||||
|
||||
---
|
||||
|
||||
## 九、本棒唯一一处真 bug(如实记录)
|
||||
|
||||
🔴 **包名形态校验不收带 scope 的包名** —— `lib/plugins-sdk.mjs` 首版 `PKG_RE = /^[a-z0-9][a-z0-9._-]*$/i`,而规格书 §五 A4 **冻结**:包名 = **`@dsh-local/ai1net`**(带 scope),`pluginId` 只是它的末段。
|
||||
|
||||
- **后果**:`upload` 之外的五条走 `pkgOf()` 的路由(`detect`/`db`/`enable`/`update-request`)**全线 `bad-args` 就地拒**,**一个平台请求都不发**;且这是**静默失败**(看着像"平台不认",其实是包内先拒的)。
|
||||
- **发现方式**:`tmp/p44/run-s6.mjs` B 段的真发取证(九条里 5 条报"零请求")。
|
||||
- **修复**:`PKG_RE = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/i` —— ⛔ 仍拒 `'../'` 穿越(scope 后那段与无 scope 时用**同一把尺子**)。
|
||||
- **防复发**:把「带 scope 的冻结包名必须过 + `../` 必须拒」钉成包内门禁 **①f-⑩**(读 `package.json` 的 `name` + 从源码取 `PKG_RE` 字面量真跑:4 个合法名全过 / 7 个非法名全拒),并把包名与正则字面量一起喂进 `M3_DIGEST`。
|
||||
|
||||
另一处**自家脚本的坑**(不是包的问题,如实记):编排脚本首版把「记账窗口」取在 promise 创建之后,而 `guarded()` 是**同步**走到 `callPlatform` 的 ⇒ 九条全报"零请求"(假红)。改成传 thunk 后即正确。
|
||||
|
||||
---
|
||||
|
||||
## 十、硬边界自查 / 遗留 / 回滚
|
||||
|
||||
- ⛔ **未 commit / 未 push**(未明确要求)。
|
||||
- ⛔ **未触碰官方 dsh 主程序与缓存**(R2);未把包装进任何 profile(装配用 `tmp/p44/` **沙箱 profile 副本**)。
|
||||
- ⛔ **未重造分发与更新机制**:「搬包」直接复用 S4 已落地的拉取器(`tmp/p42/puller.mjs`)。
|
||||
- ⛔ **未代用户起实例**;⛔ **未动客户端工作区**(`dsh-ai1net-desktop` / `dsh-desktop-0.1.7rc2` 只读引用)。
|
||||
- 包内**零直连平台库路径**(红线扫描绿)。
|
||||
- **S9 的 P2 未跨过**;本棒**未发现新停点**。
|
||||
- **回滚**:本棒包内改动集中在 `lib/plugins-sdk.mjs`(新建)/`lib/index.js`(M3 装配块 + `statusOfReason`)/`lib/client.js`(M3 卡片 + 窄屏段)/`scripts/build.mjs`(①f + ⑩)/`package.json`(`exports` 加一条)。回滚 = 删 `lib/plugins-sdk.mjs` + 撤 M3 装配块与卡片即可(M5 与 S2–S5 的绿不受影响,`M5_DIGEST` 可作前后一致的锚点)。
|
||||
|
||||
---
|
||||
|
||||
## 十一、出处
|
||||
|
||||
| 项 | 出处 |
|
||||
|---|---|
|
||||
| 七条包内路由冻结清单 | `D:/github/dsh_shenxian/dsh-server-docs/05-交接单/交接单_包规格书_20260926.md` §五 A3 |
|
||||
| 包名/库名/表前缀冻结值 | 同上 §五 A4 / §五 A5 |
|
||||
| 四拆判据原文 | 本线入口 §2 第 43 棒块 → 方案 §3.10.8 |
|
||||
| 避坑类目 | `交付物/功能打包到基础插件-分步实施方案-20260926.md` §4 |
|
||||
| 编排脚本 | `tmp/p44/run-s6.mjs`(58 ✅ / 0 ❌)|`tmp/p44/run-scales.sh` |
|
||||
| 读数 | `tmp/p44/读数-S6-20260926.txt`|`tmp/p44/尺读数-S6-20260926.txt` |
|
||||
| 真执行者 | `tmp/p42/puller.mjs` + `tmp/p42/mgr-mock.mjs`(S4 产物,本棒⛔ 未改一行) |
|
||||
Reference in new issue
Block a user