按用户令提交:把此前未纳管的 9 个技能目录一并入库
用户令逐字:「E:/ProgramData/.workbuddy/skills 提交仓库是指的这里」—— 即本目录就是仓库(2026-10-07 已在本目录建仓,见当日日志 §22),本轮把余下未纳管的 9 个技能一并提交。 本次入库(9 个技能,46 个文件): 1、`AI HOT` 2、`draw-ui` 3、`dsh-diagnose` 4、`dsh-knowledge` 5、`dsh-local-env` 6、`dsh-opensource-release` 7、`dsh-workflow` 8、`oil-motion` 9、`skills-security-check` 提交前核对: · **凭据类扫描**(`*.env` / `*token*` / `*.key` / `*secret*` / `*.pem`)⇒ **零命中** ✓; · 体积合计约 20 MB(`draw-ui` 12M + `oil-motion` 6.5M 是大头,形态为配图/素材 —— 仓库 `.gitignore` 里明写「`assets/*.png` 是内容不是产物」⇒ 属刻意入库); · 运行产物仍按既定规则排除(`__pycache__` / `logs/` / `tmp/` / `.venv/` / `*.egg-info` / `uv.lock` / `.workbuddy/`)。
This commit is contained in:
1 parent
d26c844f64
commit
e03465c398
46 files changed
+7558
No files matched your search
@@ -0,0 +1,534 @@
|
||||
---
|
||||
name: dsh-opensource-release
|
||||
description: DSH 多租户托管平台的「开源导出与版本迭代」技能 —— 把私有代码仓导出成可公开的开源副本(脱敏 / 去插件 / 分层授权 / 重写说明文档),并在后续版本里安全地重跑导出、登记版本。当用户说「开源一份」「导出到 GitHub」「发新版本」「改一下开源那份的脱敏/授权/说明」「开源那份同步一下」时触发。核心:**源仓库只读** + **阻断性探针 0 命中**才准放行 + **OVERLAY 手工撰写层**不得被重建抹掉。
|
||||
version: 1.0.0
|
||||
updated_at: 2026-09-20
|
||||
last_change: 【2026-09-22 按要求统一版本号】frontmatter `version` → `1.0.0`(原 v2.10.8);正文与历史中的版本号为当时记录,未改动。此前 2.10.8(2026-09-20):**登记「提交并推送双仓」的写法与一条换行陷阱**(用户指令:「**提交到仓库**」)—— ①✅ 本轮以 commit **`4a870dc`** 推送双仓(8 files · 146+/152−),**推前三方同 hash 复核**:`git ls-remote origin/main` = `git ls-remote cnb/main` = 本地 `HEAD` = `4a870dc27de183486f255e9aaeaf511228f2d540`。②🔑 **推送写法(两仓两套,⛔ 别互换)**:`origin` = GitHub 走 SSH,**必须显式** `GIT_SSH_COMMAND="ssh -i C:/Users/Administrator/.ssh/id_ed25519_ai1net -o IdentitiesOnly=yes"`;`cnb` = `https://cnb.cool/…` 走凭据钩子 `~/.cnb/git-cred.sh`(**⛔ 不给它套 SSH 密钥**)。③✅ 提交信息经 **`-F <文件>`**(⛔ 不用 heredoc — 非 ASCII 会被改写)· 身份**内联** `-c user.name/email`(⛔ 不改全局)· `git add` **显式路径**(⛔ 不用 `-A`)。④🔴🔴 **新增换行陷阱(写进坑 36)**:`dsh_ai1net/.gitattributes` **只钉了 `LICENSE` / `COMMERCIAL-LICENSE.*` 三行 `-text`,`*.md` 不在其内** ⇒ 走 `core.autocrlf=true` ⇒ **导出仓 `*.md` 一旦被 git 重新检出就变 CRLF,而 `_overlay` 恒为 LF ⇒ `_sync_overlay.py --check` 会假报「有差异」**(`git status` 反倒干净)⇒ ⚠️ **此时反向拷贝就是事故 #27 的反向版**;正确处置 = 直接跑 `_sync_overlay.py`(LF 覆盖回去),且 **git blob 一直是 LF**(`git cat-file -p HEAD:README.md` 实测无 `\r`)。2.10.7(2026-09-20):**新增坑 36 —— 「巡检表」是自己的草稿、⛔ 不是事实源;并给出可复用的「精确串替换器」落地法**(用户:「**按照你的方案优化,要确保中文英文内容一致**」)—— ①🔴🔴 **差一步按草稿改错数**:第 9 轮巡检 P1-4 建议「改成**七个**失败模式」,落地前回源文档核对 ⇒ `PLUGIN-PORTING.{md,zh-CN.md}` **早已是 H1~H8 八个失败模式 + 六条规范(R-a~R-f)** ⇒ 按**源文档**对齐成 8 行(补 H7 静默挂死 / H8 原生绑定 glibc),收尾指针的「五条规范」一并去计数。🔑 **判据:README 是二手转述、定义在源文档 —— 凡动「几个 / 几条 / 第几条」必须回定义处核对**,否则修完仍与文档打架(正是 P1-4 要修的毛病)。②✅ **落地法定型:精确串替换器**(`(old, new)` + **先数命中次数要求恰为 1**,任一不中即**整体中止不落盘**;行级删除按行首前缀断言 1 次)—— 比逐次 `Edit` 可靠、比 `sed`/heredoc 安全(非 ASCII 不被改写);跑完 `grep -c` 复核旧串 = 0 再比字节/行数。③🔴 **索引不写死计数**:文档地图 3 处 + 收尾指针 1 处;⚠️ **括号里的枚举保留**(那是指针的坐标不是计数)。④🔴 **搬内容优先于删内容**:版本历史里 5 条讲「文档自己怎么改的」⇒ 选**搬到 `manual/contributing.*`**(判据 = 该文档地图描述本就写着「版本号与发布历史」),README 只留用户可感的行为变更(v1.4.1 只剩 `503` 冷启动 + 整理)。⑤🔴 **历史条目里的旧名 ⛔ 不要改**(`project.*` 3 处「功能管理」是当时改名事件的历史条目名;要改的是 README/FAQ 的现名)。⑥🔴 **地图加一行会动 parity `tableRows`**:75 → **78**(地图 +1、PLUGIN-PORTING +2),**中英须同增**。⑦🔴 **中英同批执行**(6 文件一次脚本写完),彻底修掉 2.10.2 记的「英文滞后一轮」问题。2.10.6(2026-09-20):**确立「两语言各用各的工具」并跑完中文侧实测**(用户:「**中文用中文版本测 给你两个语言各用各的**」)—— ①🔴🔴 **分工定案:中文 → `humanizer-zh`(24 模式 + 5 维 50 分表);英文 → `humanizer`(55 模式 + CLI)**,⛔ 不交叉用;**原待办「给中文侧补分词器」据此作废、不再上抛**。②📌 **15 份 zh-CN 文档实测**:词层面**已干净**(P1/P3/P4/P5/P6/P8/P19–P24 **全 0 命中**;P10 三段式 0;P2 不适用)。③🔴🔴 **唯一大宗项 = P13 破折号 206 处**(`PLUGIN-PORTING` 69 · `highlights` 44 · `project` 26 · …),绝大多数是同一个句式 **`**加粗术语** —— 说明`**(兼中 P15)⇒ 🔑 **判定要拆开:加粗与列表是对的(用户要跳读形态)⛔ 不动结构;该动的只有破折号,最小改法 = `——` 换 `:`**,信息与结构 100% 保留;⚠️ 例外 = `COMMERCIAL-LICENSE` 表内 `轨 1 —— AGPL-3.0` 是分栏分隔。🔴 **与英文侧同源**(英文 66 处 `—` vs 中文 206 处 `——`)⇒ 两侧同批处理。④🔴 **P9 否定式排比 6 真 + 2 假**(假的是「**不只是**」作范围限定)。⑤🔴🔴 **机械扫既虚报也Line truncated
|
||||
agent_created: true
|
||||
---
|
||||
|
||||
# dsh-opensource-release — 开源导出与版本迭代
|
||||
|
||||
## 何时用
|
||||
|
||||
- 要把 `dsh_shenxian`(私有部署版)导出成可公开的仓库副本;
|
||||
- 要**发新版本**(v1.0.1 / v1.1.0 …)→ 重跑导出 + 登记版本表;
|
||||
- 要改开源那份的**脱敏口径 / 保留范围 / 授权结构 / 说明文档**;
|
||||
- 有人问「开源那份怎么维护 / 怎么保证不泄密」。
|
||||
|
||||
**不适用**:日常平台改造(用 `dsh-workflow`)、知识库维护(用 `dsh-knowledge`)。
|
||||
|
||||
---
|
||||
|
||||
## 0.5 🔴 事故清单(真发生过,**开工前 30 秒读完**)
|
||||
|
||||
| # | 事故(真实) | 正确做法 | 详见 |
|
||||
|---|---|---|---|
|
||||
| 1 | **误放别的会话的全局执行锁**:抢锁失败**没看输出** + `claim`/`release` 写在同一条命令 ⇒ 末尾的 `--release-exec` 是 `rm -rf` 语义,删掉了 `R1-注入层-1104` 的锁 | 抢锁**单独一条命令**并**当场看输出**;看到占用者不是自己 ⇒ 停手;放锁前 `cat 05-交接单/.exec-lock/OWNER` 确认首行是自己;**误放**则按 `handoff-guard.sh:43` 格式原样重建**并告知用户** | §8 坑 16 |
|
||||
| 2 | **导出基线在漂**:导出脚本复制的是**工作树**,而多会话在并行改源码仓 ⇒ 导出混入**别人未提交的改动**,还会冒出新的需脱敏标识(`'dsh-plugin-mcn-suite'` 触发探针) | 发布前**按 commit 取**(`git archive <commit>`)=冻结版本;否则**每次重建都必须重跑探针**并复核 README 描述与实际一致 | §10 |
|
||||
| 3 | **盲替 `_build_export.py` 自身**:脚本里同时有「源模式」与「目标值」,批量替换把**源模式**改掉 ⇒ 改名规则**静默失效** | 改脚本只用**精确 `Edit`**;改完**必须重建 + `grep` 复查** | §8 坑 9 |
|
||||
| 4 | **`Dockerfile` / `Dockerfile.dsh` 整份跳过脱敏**:`is_text()` 按扩展名判断 | `is_text()` 已加特判;**新增无扩展名文件**要复核是否进了脱敏 | §8 坑 10 |
|
||||
| 5 | **`package.json` 手改被重建覆盖**:它属「源派生」而不是 OVERLAY | 项目自有字段(version/description/repository/license)必须写成 **GLOBAL 规则** | §8 坑 11 |
|
||||
| 6 | **废弃的中间候选名静默残留**:探针只探最老的名字,`_overlay` 里的中间名(`dsh-hosting`)漏了 72 处 | **所有曾用名**都进 `LEAK_PROBES` | §8 坑 14 |
|
||||
| 7 | **说明文档文案连改 7 轮**(替别人宣传 / 开头讲基线 / 议论式表述 / 授权在最前 / 把未验证的当可用 / 致谢太长) | 严格照 **R-O9–R-O12** 写;**写完自审一遍**再交付 | R-O9–R-O12 |
|
||||
| 8 | **脚本里用键名当标题**(`marks[k][0]` 拿到的是键 `"A"` 不是标题)⇒ 结构改写打歪,误删 `PoC` 的一个字母 | 结构改写用**完整标题字符串**做锚点;改完**读回原文复核**关键块 | 本表 #7 的同一节 |
|
||||
| 9 | **改工作根时漏改脚本常量 ⇒ 旧目录被"重建复活"**(2026-09-13 迁移到 `dsh-laijing-github` 时:先搬目录、后改 `OUT`,中间跑了一次重建 ⇒ 旧位置被重新建出 135 个文件,且**因旧位置没有 `_overlay` 而缺了 6 个手工层文件**;`_overlay` 本身侥幸没被洗掉) | **顺序必须是:① 改脚本常量 → ② 再搬/删目录 → ③ 重建验证**。迁完**必查旧目录没有复活**(`ls`),并核对 `find <repo> -type f \| wc -l` 与手工层文件是否都在。<br>🔴 **改名前先 `grep -rn "<旧路径>" --include="*.py" --include="*.mjs" --include="*.sh"` 把全部引用点扫出来**:2026-09-16 由 `dsh-laijing-github` 改名时实测:要同步的**不是 2 处而是 5 处**(`OUT` · `EX` · `_sop_check.mjs` / `_upload_audit.mjs` / `_verify_all.mjs` 各自的 `W`) | §8 坑 17 |
|
||||
| 10 | **白名单收录静默漏项:`assets/` 没进 `INCLUDE_DIRS`**(2026-09-13 用户问"确认都同步了吗"时查出)—— 导出的仓库缺 `assets/inject/{recovery,assist}.js`:`proxy.ts` 的 `loadInject` 会 **fail-fast 抛错**(平台起不来)、仓库自带 `07-scripts/verify-inject.cjs` 也会**判失败**;`package.json` 的 `files` 同样缺 `assets`(npm/git 安装也会缺) | 已补 `INCLUDE_DIRS`、`package.json` files 规则,并**新增 `REQUIRED_EXPORT` 清单(**23 项**)**:缺任何一项 ⇒ **构建判失败**(`return 1`)。以后新增"运行时要读的文件"必须同步加进该清单 | §3 · §8 坑 18 |
|
||||
| **10** | 🔴 **"顺手清理"的正则把 ASCII 标点也吃进去 ⇒ 直接改坏源码**(2026-09-13 去「档案 NN」时:清理规则写成 `[((]\s*[))]` / `[;;,,]\s*[))]`,**字符类里混了 ASCII `(` `)` `,` `;`** ⇒ 源码里所有 `foo()` 被删成 `foo`,`whitelist.ts` / `security-scan.ts` 当场语法错(tsc 报 *Invalid character* / *Unterminated string literal*)。**而当时 leak 探针全过**) | ⛔ **清理类正则只准碰全角标点(()·、,:;),绝不可把 ASCII 语法符号写进字符类**;<br>✅ **改完必跑 `_verify_tsc.mjs`,`exit 0 + no diagnostics` 是"没改坏代码"的唯一证据**:**探针全过 ≠ 代码还活着**,两者查的是完全不同的东西;<br>另:`(\s*/\s*` 这类"吃掉前导斜杠"的规则会毁掉 `(/api/x)` 路径,一律不要写 | 本表新条目 · 台账 §八 D |
|
||||
| **11** | 🔴 **同一个名字既当"脱敏目标"又当"公开值" ⇒ 自相矛盾**(2026-09-13 填 `PUBLISH_*` 时:`maogeigei` 同时在 `GLOBAL`(替换为占位符)与 `LEAK_PROBES`(判泄露)里 ⇒ ① 刚填好的公开值被规则**改回占位符**,② 探针报 `blocking hits: 4`。**"占位符残留 0"是假象**) | ⛔ **任何进入 `PUBLISH_*` 的值,先 `grep -n "<该值>" _build_export.py` 确认它不在 `GLOBAL`/`LEAK_PROBES`/`INFO_PROBES` 里**;升格为公开身份后要**同时**从 GLOBAL **与** 探针移除(只删一处 = 另一种错);<br>公开联系方式的兜底应靠**更具体的探针**(如私有仓库域名 `work.alotbuy`),不要靠账号名 | 台账 §八 D2 |
|
||||
| **12** | ⚠️ **`--dry-run` 报"假成功"**(2026-09-13 真机预演时:`run()` 会把命令加 `[dry-run]` 前缀跳过执行,**但结果提示语是硬编码的** ⇒ 预演满屏 `✓ 构建完成` / `✓ 服务已启动` / `✓ 部署完成`;更糟的是**打印了一个假的初始管理员密码**:`bootstrap-admin` 根本没跑,用户会照着登录失败。另:未设域名时文案出现空缺「把 与 *. 的 DNS A 记录」) | **dry-run 必须"只读":既不落盘,也不得宣称成功**。所有**结果类提示**(不只是动作)都要有 `DRY_RUN` 分支;**凡是"执行后才产生的值"(密码/ID/路径)在 dry-run 下必须标为"未生成"**;文案里的变量要有 `${VAR:-默认}` 兜底。<br>**验收方式**:`--dry-run` 的输出里**不允许出现任何 `✓`**,只允许 `[dry-run]` | 台账 §八 E |
|
||||
| **13** | 🔴 **`_build_export.py --force` 在本机跑不动**(2026-09-14 实测:`shutil.rmtree(DST)` 被 WorkBuddy 的「安全删除层」shim 拦下 ⇒ `SAFE_DELETE_FAIL_CLOSED`;⚠️ 而且 `--force` 会**连导出物里的本地 `.git` 一起删**:本轮实测提交历史被吃掉后由会话重新 `git init` 建单条提交) | ① 新规则要**抽成具名列表**(如 `K8S_SEMANTIC_RULES`)再 `REGEX_RULES += …`,不要直接内联,具名才能被热应用工具复用;<br>② 本机改规则后用 `<导出根>\_apply_k8s_semantics.py --write` **就地热应用**(不删任何东西,结果与整目录重建**逐字节一致**,且幂等:复跑命中 0);<br>③ 确实要整目录重建:先 `mv dsh-users-platform/.git <导出根>/_keep_git_tmp`,重建完 `mv` 回来 | 台账 §五·补 |
|
||||
| **14** | 🔴 **「K8s 残留」只按 `k8s` 字面量清 ⇒ 清不干净**(2026-09-14:字面量已清零,仍有 **10 处注释**在讲 `Pod` / `file sidecar`,描述的是**已被移除的 K8s 形态**,属悬空描述) | 判据是**「这段描述在单机形态下还成立吗」**,不是「有没有 `k8s` 字样」:`Pod`(K8s Pod ≠ DSH 子进程)· `sidecar`(已移除的 per-user file sidecar)· `a Linux Pod` 都要清;<br>⛔ **噪音不要清**:`--profile headless`(dsh 自己的 profile 名)· `headless-univer`(第三方插件包名)· `manifest`(npm 包清单,不是 K8s manifest)· `egress`(nftables 出网护栏,本项目**保留**能力);<br>复核用 `<导出根>\_k8s_comment_scan.py [--wide]`:它按「**注释 / 代码**」分类输出,可直接核对「只清注释」这件事 | 台账 §五·补 |
|
||||
| **15** | 🔴 **只删「构建步骤」、没删「使用者」⇒ CI 必红**(2026-09-15 实测:撤下 `Dockerfile.dsh` 后,构建 `dsh:ci` 镜像的那条步骤删了,但 **3 条使用者仍在**:`Smoke — dsh resolves runtime plugin` / `Trivy — dsh` / `Push dsh to ACR` ⇒ 首次推送 CI 必红) | 判据 =「**产物不在,引用它的步骤也不该在**」:删任何产物(镜像 / 文件 / 模块 / 脚本)时,**必须把它的「使用者」一并处理**(本次已把 3 条步骤整块删除 + 把 `dsh:ci` 加进 `LEAK_PROBES`);<br>⚠️ 复核**务必用 `os.walk` 脚本**(`_k8s_comment_scan.py`),`bash grep -r` 会漏隐藏目录,见 #16 | 影响说明 §7 |
|
||||
| **16** | 🔴 **`bash grep -r` 不遍历隐藏目录 ⇒ 静默漏掉 `.github/`**(2026-09-15 实测:据此一度误判「CI 没问题」,靠 Read 才看到 `dsh:ci` 仍在) | 全仓复核用**自带脚本**(走 `os.walk`)或给**显式路径**;<br>本机另注:bash 的 `PATH` 会被 shim 重置(`dirname`/`grep`/`awk` 全 `command not found`)⇒ 先 `export PATH=<PortableGit>/usr/bin:<…>/mingw64/bin:/c/Windows/System32:/c/Windows:$PATH`,`python` / `node` 一律用**绝对路径** | 影响说明 §8 |
|
||||
| **17** | 🔴🔴 **只清「新导出物」、从不巡检「已公开仓库」⇒ 泄漏在公网上长期挂着**(2026-09-19 用户当场指出)—— 实测 `dsh-users-platform`(已公开多日)里躺着 **7 个 `verify-cluster-*.mjs` + `start-cluster-manager.sh`**,逐个含**内网主机号 `w-106`(14 处)/ 内部隧道端口 `15432`·`19000`·`19001` / PG 连接串带口令**;另有 7 个 smoke 脚本硬编码 `adminpass123` 之类的**像真口令**的字面量 | **硬规则 R-O15**(见 §1)=「**每次整理/发版,必须对*所有已公开仓库*跑一遍 `_check_public.py`**」;发现命中就**三件一起做**:① 补成 `_build_export.py` 的**规则 + 探针**(否则下版回潮)② **就地清理已公开仓库** ③ 提交推送。<br>判据(正名):**「换一个部署者,这个值会不会一样?」** 会 ⇒ 通用事实、允许(云厂商元数据端点 `100.100.100.200`、docker 网桥 `172.17.0.1`、RFC1918/5737 段);不会 ⇒ **泄漏**(我们的主机号、隧道端口、测试机 IP、口令) | 本表 #17 |
|
||||
| **18** | 🔴 **drop 一个脚本前只查「文档引用」、不查「代码引用」⇒ 误删 12 个被测脚本**(2026-09-19 实测)—— 把 12 个 `overlay-*.cjs` 当「内部工具」drop,结果 `test/overlay-join.test.mjs` 用 **`readFileSync(join(repo,'07-scripts','overlay-node-admit.cjs'))`** 真的去读它、`test/overlay-content.test.mjs` 读 `overlay-probe.cjs` ⇒ 这些测试**必然跑挂**;`jitter.ts` 头注还写着「与 `overlay-jitter.cjs` 逐字同口径」⇒ 变悬空引用 | **判据 ① 必须是「无任何引用」,文档与代码都要查**:`grep` 脚本名 + **搜 `readFileSync` / `join(` / `import` / `require` / `spawn`** 等**代码级**依赖;<br>删除后**必跑悬空引用复查**(对所有 drop 名单逐个在保留文件里搜),并用 `npm run verify` / `npm test` 的入口清单反查 `package.json` | 本表 #18 |
|
||||
| **19** | 🔴 **纯数字的「内部端口」直接全局替换 ⇒ 可能命中 base64 哈希**(2026-09-19 防住)—— `15432` / `19000` / `19001` / `32022` 都是裸数字串,而 `package-lock.json` 的 `integrity` 与**图示内嵌字体的 base64** 里全是 base64 字符 | 加这类规则**前先扫上下文**:① 确认命中处都是 URL/端口语境;② 逐处查 `package-lock.json` 与 `diagrams/*.html`(字体 base64)是否 0 命中;③ 同理,`w106`/`w47` 这种**纯字母数字**串**绝不能裸替**,只替「**带引号 / 对象键 / `network/hostId` 复合键 / 标识符**」等**可区分形态**(或给正则加 base64 安全边界 `(?<![A-Za-z0-9+/\-_=])…(?![…])`)。误伤的典型症状是 **`npm ci` 校验失败**,且与本次改动毫无关联、极难排查 | 本表 #19 |
|
||||
| **20** | 🔴🔴 **drop 文件前只查「文档引用」⇒ 误删 12 个被测脚本**(2026-09-19 实测,同 #18 的第二个实例)—— 把 12 个 `overlay-*.cjs` 当内部工具 drop;实际 `test/overlay-join.test.mjs` 用 **`readFileSync(join(repo,'07-scripts','overlay-node-admit.cjs'))`** 真的去读它,`src/net/relay/jitter.ts` 头注写着「与 `overlay-jitter.cjs` 逐字同口径」 | 判据 =「**无任何引用**」必须**文档与代码双向查**:文件名 `grep` **+** `readFileSync` / `fs.readFile` / `join(` / `import` / `require` / `spawn` / `exec`;删后**必跑悬空引用复查**(对 drop 名单逐个在保留文件里搜)。<br>🔑 **反面对照**:同族的 `verify-*.mjs\|cjs` **不能**按「看着像测试」删,它们被 `src/web/i18n.js` / `src/web/model-landing.ts` / `AGENTS.md` / 安装流程引用,是**产品自带校验** | 本表 #20 |
|
||||
| **21** | 🔴 **删脚本后 `package.json` 留下悬空入口**(2026-09-19 实测)—— ① `"check:layering": "node 07-scripts/check-layering.mjs"`(脚本已 drop)② **同一条命令还内联在 `verify` 里** ⇒ 上一版只删了独立入口、**漏了内联那处**,公开仓 `npm run verify` **必失败**;③ 删完 `test`/`smoke*` 后 `verify` 成了**最后一项** ⇒ **尾逗号让 JSON 非法** | 删任何文件时把它的**每一处引用**都清掉:`package.json`(`scripts` / `files`)· CI `.github/workflows/*.yml` · `Dockerfile` · `.dockerignore` · `tsconfig.json`;改完 **`json.load` 校验 + 打印入口清单**。判据 =「**产物不在,引用它的步骤也不该在**」(= #15 的同一条,本轮在 `package.json` 上第二次踩) | 本表 #21 |
|
||||
| **22** | 🔴 **行级替换的 key 写了「脱敏前」的文本 ⇒ 静默失配**(2026-09-19 再犯)—— `LINE_REWRITE` 改 `07-scripts/ci.sh` 标题,key 带 `(档案 19 §C3)`;而「档案 NN」正则在**行级替换之前**就把那段吃掉了 ⇒ 不报错、不命中、旧标题留在公开文件里 | ① `sanitize()` 的阶段次序是 **GLOBAL → REGEX → 行级(`DELETE_LINES` / `LINE_REWRITE`)** ⇒ 行级 key 必须写**该阶段实际看到的文本**;② 改完**读回原文复核**;③ 整块删除**用 GLOBAL 多行字面量**(纯 `str.replace`,支持跨行),别用「行首前缀」删(删完会留**空壳行**,而 REGEX 抓不到删完后的形态);④ 源文是 **CRLF** 时字面量必须带 `\r\n`(先 `open(p,'rb').read()` 数 `\r\n` 确认) | 本表 #22(同 §8 坑 2) |
|
||||
| **23** | 🔴 **范围收缩时漏改「清单」与「文档宣称」**(2026-09-19 实测三处)—— ① `REQUIRED_EXPORT` 里留着 `test/crash-policy.test.mjs` ⇒ 构建**必然失败**;② 文档仍写「**两层测试**:单测 + 9 个 `smoke:*` 冒烟」⇒ 读者照文档跑 `npm test` / `npm run smoke` **必报错**;③ 忘了同步 `_check_parity.mjs` 的 `PAIRS`(**白名单:没登记就静默跳过对等检查**) | 收缩范围 = **四处一起改**:`INCLUDE_*` / `REQUIRED_EXPORT` / `PAIRS` / **文档的能力宣称**(OVERLAY 手工层 ⇒ 要**手工逐处改**且 `_overlay/` 与导出仓两处同步)。凡「清单式」机制,改完**回读计数**(AST 实读) | 本表 #23 |
|
||||
| **24** | 🔴 **本机 PowerShell 下 CNB 推送「假死」**(2026-09-19:`exit 128` 且**零输出**,`GIT_TRACE` 停在调用凭据助手那一行)—— 而 `git ls-remote cnb`(公开读**不需要认证**)一切正常 ⇒ **极易误判成「令牌失效 / 仓库不存在 / 网络问题」**。真因:CNB 凭据助手是**本地 sh 脚本**(依赖 `tr`/`sed`),git 经 `sh` 调用时 **PATH 被宿主 shim 重置** ⇒ 失败(早期还打印 `tr: command not found`,加过 PATH 后错误反而**静默**) | ✅ **用 Bash 工具 + 显式 PATH 推**(同机同凭据,一次成功):<br>`export PATH="/e/…/PortableGit/versions/1.2.0/usr/bin:/e/…/mingw64/bin:/c/Windows/System32:/c/Windows:$PATH"` 然后 `GIT_TERMINAL_PROMPT=0 git push --force cnb main`。<br>⚠️ 别在 PowerShell 里把 `usr/bin` **前置**(会把 `git` 解析到不完整版本 ⇒ 报 `git: 'remote-https' is not a git command`) | 本表 #24 |
|
||||
| **25** | 🔴 **范围收缩的判据用错 ⇒ 要么白删、要么删坏**(2026-09-19)—— ① 把「没人引用」当判据:`web/i18n.js` 只在**注释**里被提到,但它是**运行时静态资源**,删了页面就坏;`src/web/semver-shim.d.ts` 在「从入口不可达」单子里,但删了 **`tsc` 报 TS7016**;② 漏查「**删完谁还会指向它**」:`install-python-runtime.sh` 等 4 个脚本的名字**出现在管理台 API 返回体**里(`/api/admin/runtime` 的 `installScripts`、`/api/capabilities` 的降级提示)⇒ 只删脚本 = **界面指向不存在的文件**;③ 顺手发现两个「白留」的:`07-scripts/build-web.mjs` 是**空操作占位**(源码自称 *intentionally does nothing yet*)、`.github/workflows/build.yml` **监听 `master` 而导出仓分支是 `main` ⇒ CI 永不触发** | 判据(用户 2026-09-19 定)= **「缺少也不影响项目运行」**,且**四步都要走**:① 真实 import 图 + 从 `package.json` 的 `main`/`bin` 算**可达性**;② 算**移除闭包**(移除后保留文件还有没有边指向它);③ `grep` 文件名在 **`.ts`** 里的位置,看是否出现在**返回给前端的字符串**;④ 查**文档/`package.json`** 引用。<br>✅ 工具:**`_check_unused.py`**(只报告不删) | 本表 #25 · R-O17 |
|
||||
| **26** | 🔴🔴🔴 **把「从代码入口不可达」当成「不影响运行」⇒ 差点删掉生产正在跑的服务端进程入口**(2026-09-19 用户真机验证推翻)—— 我据「从 `package.json` 的 main/bin 出发不可达 + 移除闭包 0」判定 **relay 服务端族 7 文件(214 KB,含 `server.ts` 112 KB)** 可删,并已写进 `EXCLUDE_FILES` + 探针 + 文案改写规则。<br>🔴 **真相**:它们是 **`dshs-relay.service` 的进程入口**,**两台机器上都在跑**(`active running`,监听 `127.0.0.1:20080`)。控制面**从不 import 服务端族**是**设计使然**:**relay 是另一个进程**,入口是 `main.ts`,由 **systemd `ExecStart`** 拉起。<br>🔑 **为什么静态分析必然错**:**systemd 单元文件不在代码仓里**(实测:源仓 + 导出物 **0 个 `.service`**)⇒ **在仓内做可达性,永远看不到这条接线**。<br>🔑 **用户原话(判据正名)**:**「若某份分析以 dshs 控制面为根做可达性,"零引用"是根进程选错了,不是事实。」** | ⛔ **「从代码入口不可达」不再作为任何删除依据**(见 R-O17 修正)。<br>✅ 必须做**接线核实**:问「**这个子系统的进程入口是哪个?由谁拉起?**」:**systemd / cron / docker / 一键安装脚本 / 手动**,并**去真机看状态**(`systemctl status` / `active running`)。<br>✅ **接线线索极可能不在代码仓** ⇒ **仓内查不到接线时,默认「它在别处被接线」,而不是「它没人用」**。<br>⚠️ **连带教训**:我当时还漏查了**源仓内部文档**:`dsh-server-docs/01-规范/02-运维手册.md` 与 `04-调整方案/28-用户数据清理策略.md` 里对这些运维脚本有**成文流程**(我只扫了导出物)。<br>⚠️ 同批被误判的还有「能力已备、门面未接」的两个:`join.ts`(一键入网,只有 barrel + 测试)· `placement.ts`(选点算法,零调用点)—— 用户判定**保留**:**删掉 = 删掉后续自助入网/自动选点的唯一判据来源** | 本表 #26 · R-O17 |
|
||||
| **27** | 🔴🔴🔴 **改手工层时只改 `_overlay/`、没改导出仓 ⇒ 改动在重建时被「静默回滚」**(2026-09-19 实测,白做一整轮)—— 我按规范改完 8 个手工层文件(README ×2 / install ×2 / manual/project ×2 / manual/architecture ×2,全部只是删引用、无新内容),直接 `--force` 重建 ⇒ 回执报 **`blocking hits: 36`**,逐条指向**我刚删掉的那些引用**,改动**全部消失**。 | 🔑 **机制**:`stash_overlay()` 的方向是 **导出仓 → `_overlay/`**(重建前快照、重建后还原)⇒ **导出仓里的旧版会覆盖你刚改好的 `_overlay` 新版**。<br>✅ **纪律**:改手工层 = **两处都要落**(`_overlay/<f>` **与** 导出仓 `<f>`,逐字节一致)。<br>✅ **工具**:改完立刻跑 **`_sync_overlay.py`**(`--check` 只报告,不加参数则同步并报 SHA-256)—— 输出 `两处逐字节一致 —— 可以安全重建` 才准重建。<br>⚠️ 口诀仍然有效但**用途不同**:**「`_overlay` 是未来版、导出仓是当前版」** 说的是 **⛔ 绝不允许整目录 `cp` 导出仓 → `_overlay`**(那会把未来版打回当前版);**不是**「只改 `_overlay` 就够了」。 | 本表 #27 · §12.11 |
|
||||
| **28** | 🔴🔴 **规则用了「跨行锚」⇒ 在按行处理 + 纯 CRLF 的文件上静默空转 ⇒ 关键字段丢失**(2026-09-19)—— 我把版本号规则拆成 `('"version": "0.1.0",\n "description":', …)`,想「先具体后笼统」只在 `package.json` 插入 `license`。重建**成功且全部门禁为绿**,但 `package.json` 的 **`license` 字段整个消失**(此前每一版都有 ⇒ 这是**回退**)。 | 🔑 **两个前提同时不成立**:`sanitize()` **按行处理**(跨行锚永远匹配不上)+ 源仓 `package.json` 是**纯 CRLF**(实测 CRLF=85 / LF=85)⇒ 我的锚里是 `\n`,**必然空转**。<br>✅ **规则里不许出现跨行锚**;要「只对一个文件生效」就用**该文件独有字段的单行锚**(此处改成 `'"description": "面向公网的多租户 DSH 托管平台'`:实测在 `package.json` 命中 1 次、`package-lock.json` **0 次**)。<br>✅ 且必须**核对构建回执里那条规则的 `sanitized` 计数**(空转的话它是 0,一眼可见)。<br>🔴 **根本教训**:**探针只管「有没有不该有的」,不管「该有的还在不在」** ⇒ 凡「由规则生成的关键字段」(`name` / `version` / `license` / `repository`)都要在 `_check_dst.py` 里加**存在性断言**。 | 本表 #28 · §12.12 |
|
||||
| **29** | 🔴🔴 **首推 `--force` 前没和远端比对 ⇒ 差点删掉「只在远端存在」的授权合规件**(2026-09-19)—— 推送前顺手查远端 `main`(`8dd8071`)的文件树,发现它有 **`.gitattributes`**(173 B:`LICENSE -text` / `COMMERCIAL-LICENSE*.md -text`),而**导出物里没有**(它从未进过构建产物)。若不查,`push --force` 会把它一并抹掉 ⇒ **三份法律文本的逐字节保护静默失效**(`LICENSE` = AGPL-3.0 官方全文 34,523 B)。 | ✅ **首推/强推前必做**:`git ls-tree`(或 GitHub API)**列出远端根文件与本地比对**,把「只在远端存在」的**逐个判定**:该留 ⇒ 做成**构建产出**(内容与远端**逐字节一致**,用 `git hash-object` 对 blob sha 核)+ 进 `REQUIRED_EXPORT`;该删 ⇒ 明确记录。<br>✅ 已把 `.gitattributes` 做成 `_build_export.py` 的 `GITATTRIBUTES` 常量并在 `.gitignore` 之后写出。<br>🔑 通用句式:**「远端有、本地没有」的文件,在下一次强推时等价于「主动删除」**。 | 本表 #29 · §12.12 |
|
||||
| **30** | 🔴🔴🔴 **源仓工作树不干净时重建 ⇒ 把「别的会话正在写、尚未提交」的中间状态带进公开仓库**(2026-09-19 实测)—— 我为「覆盖网络架构图」重建导出物,回执 `blocking hits: 0`、`required 52/52`,随后 `_check_dst` / `_check_links` / `_check_parity` / `tsc` / `_check_public` **全部为绿**。`git status` 却显示导出物多了 13 个源派生文件被改(`src/db/*`×6 · `src/web/routes/*`×2 · `src/web/server.ts` · `web/*`×4,**+234 行**)。<br>🔴 **真因**:**源仓是「多会话共用」的工作区**,那一刻另一个会话**正在源仓就地改这些文件(未提交)**;而 `_build_export.py` 是**按文件系统当前状态 copy**(不是 `git archive <commit>`)⇒ **工作树脏 = 导出物脏**。<br>🔑 **时间线取证**(决定「不是我干的」):我 12:32 核验时 `git status` **只有 3 行 `??`**(干净);那 19 个文件的 mtime 是 **12:37–12:49**(连续递增),而我那时正在跑 archify 出图;源仓 `HEAD` 始终 `971ccc3`、`git diff --cached` 为空、`.git` 下 **11:27 之后零写入**、无新 ref ⇒ **我零 commit / 零 add / 零写入**。<br>⚠️ **最危险的一点**:这类污染**任何探针都查不出来**:探针只回答「**有没有不该有的**」,**不回答「内容是否已定稿」**。 | ✅ **新增前置闸门**(`_build_export.py#dirty_src_files()`,事故后立即落地):重建前跑 `git -C <源仓> status --porcelain`,**只要出现已跟踪文件的 `M`/`A`/`D`/`R` 就默认拒跑(return 4)**,列出全部文件名,并提示「等那个会话提交(推荐)/确认过才加 `--allow-dirty-src`」。<br>⚠️ 🔴 **作用域必须收窄到「会进导出物的路径」**(2026-09-19 实测后修):第一版把**任何**已跟踪改动都判脏,立刻在源仓的 `.gitignore` 上**误报**并拦下构建 ⇒ 按案例库 C5「**假阳性过多 = 等于没有工具**」收窄为「路径落在 `INCLUDE_DIRS` 下或与 `INCLUDE_FILES` 同名」才拦,其余只提示。<br>🔴 **且 `??`(未跟踪)必须一起拦**:第一版注释写「白名单取文件,未跟踪天然进不来」,该理由**对 `INCLUDE_DIRS` 内部不成立**:`copy_item()` 是 `os.walk` **整目录复制**,会连未跟踪的新文件一起复制(实测抓到 `src/platform-paths.ts`,它本会被静默发布)。<br>✅ 源仓脏但必须重建时:`--allow-dirty-src` 重建后,**在导出仓**用 `_revert_src_derived.py` 退回(已跟踪用 `git checkout --`,未跟踪直接删)—— ⛔ 绝不碰源仓。<br>⚠️ **⛔ 绝不为了「让闸门通过」去动源仓**(不 stash、不 checkout、不 commit 别人的工作树)—— 那是别人的任务边界。<br>✅ **发现已污染时的处置**:在**导出仓**(不是源仓)用 `git checkout -- <显式路径>` 把这批源派生文件退回上一次干净提交,**保留本次真正要发布的改动**(文档 / 图),然后**暂停推送**并报告。 | 本表 #30 · §14 |
|
||||
| **31** | 🔴🔴 **用 `bash heredoc` 写一次性脚本 ⇒ 反斜杠与非 ASCII 被静默损坏**(2026-09-19 实测两次)—— ① 用 heredoc 传 Python 时,字符串里的 `\n` **被吞掉反斜杠**,写成**字面 `/n`** ⇒ README 里两处该有的空行消失(肉眼极难发现,因为渲染出来只差一个空行);② 同一原因,**em-dash `—` 被改写** ⇒ `old_string` 匹配 **0 次**,脚本报「命中 0 次(应为 1)」而真正原因与「文本不对」无关。<br>🔑 **本机 bash 环境特有**:`heredoc` 会解释/吞掉内容里的反斜杠与部分非 ASCII 序列。 | ✅ **一次性脚本一律用 Write 落盘、再执行**(不要 heredoc、不要内联 `python -c "..."` 传含反斜杠/非 ASCII 的长文本)。<br>✅ 同理:**内联 `-c` 里不要出现反引号**:会被 shell 当命令替换(实测 `<code>overlay-architecture</code>` 被当命令执行报 `command not found`)。<br>✅ 写入后用**探针式自查**收尾:搜 `code:/n` 这类**不该存在的字面串**,比人眼可靠。 | 本表 #31 |
|
||||
| **31** | 🔴🔴 **用 `bash heredoc` 写一次性脚本 ⇒ 反斜杠与非 ASCII 被静默损坏**(2026-09-19 实测两次)—— ① 用 heredoc 传 Python 时,字符串里的 `\n` **被吞掉反斜杠**,写成**字面 `/n`** ⇒ README 里两处该有的空行消失(肉眼极难发现,因为渲染出来只差一个空行);② 同一原因,**em-dash `—` 被改写** ⇒ `old_string` 匹配 **0 次**,脚本报「命中 0 次(应为 1)」而真正原因与「文本不对」无关。<br>🔑 **本机 bash 环境特有**:`heredoc` 会解释/吞掉内容里的反斜杠与部分非 ASCII 序列。 | ✅ **一次性脚本一律用 Write 落盘、再执行**(不要 heredoc、不要内联 `python -c "..."` 传含反斜杠/非 ASCII 的长文本)。<br>✅ 同理:**内联 `-c` 里不要出现反引号**:会被 shell 当命令替换(实测 `<code>overlay-architecture</code>` 被当命令执行报 `command not found`)。<br>✅ 写入后用**探针式自查**收尾:搜 `code:/n` 这类**不该存在的字面串**,比人眼可靠。 | 本表 #31 |
|
||||
|
||||
---
|
||||
|
||||
## 0. 事实(硬编码,勿猜)
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| **中文名 / English name** | **DSH 用户平台** / **DSH Users Platform**(2026-09-14 由 `dsh-web-platform` 定稿改名) |
|
||||
| **文档语言(2026-09-14 定稿,覆盖 R-O13)** | **英文为主**:主文档 `*.md` 为英文 + 顶部中文入口;中文全文在 **`*.zh-CN.md`**;**`manual/` 8 篇 ×2 语言**;架构图也分语言(`diagrams/architecture{,.zh-CN}.svg`) |
|
||||
| **内容来源(🔴 2026-09-17 定稿口径)** | **「人负责规划与关键判断,AI 负责实施」**(英文 `Human planning and key judgment; implementation by AI`)—— 模型 `DeepSeek V4 / V4.1 flash`(**不写工具名**)。⛔ 不要写成「全部由 AI 生成」(法律风险:中国版权保护中心 2026 新规「纯 AI 生成的软件不予登记」⇒ 商业授权缺标的物);⛔ 也不要照 2026-09-13 删掉「人的角色」。落点见下方「本项目定稿顺序」 |
|
||||
| ~~**文档语言**~~ | ⛔ **本行已作废**:2026-09-14 起改为**英文为主**,见上表「文档语言(2026-09-14 定稿)」行;<br>**R-O13 的「中文母本 + `*.en.md`」口径同时作废**,现状是 `*.zh-CN.md` 副本 |
|
||||
| **技术标识(仓库·包·服务·env 前缀)** | **`dsh-users-platform`** | `DSH_USERS_PLATFORM_*` | `/var/lib/dsh-users-platform`(中文名「DSH 用户平台」/ English「DSH Users Platform」) |
|
||||
| 🔴 **新名称(2026-09-17 用户定,🟡 执行中)** | **`dsh_ai1net`**:中文名 **「能力网络」** | 英文名 **`DSH AI1NET`** | 技术标识 `dsh_ai1net` / `DSH_AI1NET_*`。用户原话:「是 `E:\ProgramData\AI技能\aliyun-dsh-server` 对应**开源项目的新名称**」。**旧仓 `maogeigei/dsh-users-platform` 保留不动**(用户 09-16「之前的不动」),新仓 `maogeigei/dsh_ai1net` 已建(空仓),密钥 `id_ed25519_ai1net` 已绑。<br>**口径 = 方案 A(用户 09-17 08:18 选定)**:env 前缀 → `DSH_AI1NET_*` · 数据根 → `/var/lib/dsh-ai1net` · 库文件 → `dsh_ai1net.db`(与源仓在此项上**永久分叉**,映射规则在导出层)。<br>✅ **已完成(09-17 08:3x)**:`_build_export.py` **46 行规则** + 3 条旧名探针 · 6 个工具脚本 · `_overlay/` **13 文件 139 处**:均静态验证通过。<br>⏳ **待做**:源仓提交出冻结基线 → 重建 → `.git` 迁移 → 全量验证 → 推送新仓。<br>📄 作业书:`_改名执行清单_dsh_ai1net_20260917.md`(§零 进度 / §三 规则清单 / §四 步骤) |
|
||||
| **曾用名(全部必须在 `LEAK_PROBES` 里)** | `dshs` · `dsh-multitenant` · `dsh-hosting` · **`dsh-web-platform`** · `DSH_WEB_PLATFORM_*` · `/var/lib/dsh-web-platform`;`taimiao` 未落地也一并加入。**⚠️ 改名 `dsh_ai1net` 执行后,须把 `dsh-users-platform` / `DSH_USERS_PLATFORM_*` / `/var/lib/dsh-users-platform` 补进 `LEAK_PROBES`** |
|
||||
| **前名(已废弃,现为阻断探针项)** | `dsh-multitenant` / `DSH_MULTITENANT_*` / `/var/lib/dsh-multitenant`:2026-09-13 20:2x 由用户定名 `dsh-web-platform` 取代;`LEAK_PROBES` 已收录,**出现即判泄露** |
|
||||
| **源仓库(只读!)** | `D:\github\dsh_shenxian` |
|
||||
| **工作根(GitHub 开源专用文件夹)** | `E:\ProgramData\AIProject\dsh-ai1net-github\`(2026-09-13 由 `aliyun-dsh-server\_开源导出_20260913\` 整体迁入;**2026-09-16 由 `dsh-laijing-github` 改名**;**本项目的独立开源工作区**,不再是 `aliyun-dsh-server` 的子目录) |
|
||||
| **仓库根(可直接 git init)** | ✅ **现行 = `<导出根>\dsh_ai1net\`(255 文件,2026-09-19 重建)**;旧 `<导出根>\dsh-users-platform\`(198 tracked)**已冻结,仅供对照**。⚠️ `_build_export.py` 的 `DST` 已指向 `dsh_ai1net` ⇒ **重建只会写新目录** |
|
||||
| 构建脚本 | `<导出根>\_build_export.py`(**默认拒跑**,须 `--force`) |
|
||||
| 手工撰写层快照 | `<导出根>\_overlay\`(脚本自动维护) |
|
||||
| 类型检查 | `<导出根>\_verify_tsc.mjs`(建 junction → tsc → `rmdirSync` 拆) |
|
||||
| 文档校验 | `<导出根>\_check_links.mjs <repoDir>`(链接/锚点/配图)· `<导出根>\_check_parity.mjs <repoDir>`(中英对等 + 列出英文里的汉字;**英文文档汉字数应恒为 4**) |
|
||||
| 🔴 **已公开仓库巡检**(R-O15) | `<导出根>\_check_public.py [<dir> …]`:**形态级**审计(内网 IP / 主机号 / 内部端口 / 凭据字面量 / 内部绝对路径 / 内部单据名)。默认扫 `dsh_ai1net` + `dsh-users-platform`;**exit≠0 = 有命中**。与构建期的 `LEAK_PROBES`(字符串级)**互补**,缺一不可 |
|
||||
| 🔴 **「不用开源」审计**(R-O17) | `<导出根>\_check_unused.py [<dir>]`:判据「**缺少也不影响项目运行**」。给三张单子:① 死文件(无任何引用)② 从 `package.json` 的 `main`/`bin` 经真实 import 图**不可达**的 src 模块 ③ 名字像运维/辅助且不在 `package.json` 里。**exit≠0 = 有候选**。⚠️ **只报告不删**:范围收缩影响对外可见面 ⇒ 必须人工确认 |
|
||||
| 🔴🔴 **手工层同步器**(2026-09-19 新增) | `<导出根>\_sync_overlay.py [--check]`:把 `_overlay/<f>`(**权威源**)复制到导出仓。**改完任何手工层文件就立刻跑它**:报 `两处逐字节一致 —— 可以安全重建` 才准重建。<br>🔑 起因见事故 **#27**:`stash_overlay()` 方向是 **导出仓 → `_overlay/`** ⇒ 只改 `_overlay` 会在重建时被旧版**静默回滚**(实测 8 个文件的改动全丢、`blocking hits: 36`) |
|
||||
| 给人看的台账 | `<导出根>\_导出说明与脱敏台账.md`(**不随仓库上传**;§七 = 改名记录) |
|
||||
| 手工撰写层(`OVERLAY`:重建时自动快照→恢复,**不得被抹掉**) | **现为 30 份**:`README.md` · `LICENSE`(**AGPL-3.0,2026-09-14 按用户选定 B 方案加回**)· **`COMMERCIAL-LICENSE.md` + `.zh-CN.md`(2026-09-18 新增 · 双轨的轨 2)** · `PLUGIN-PORTING.md` · `install.sh` · `install.md` · `AGENTS.md` + 5 个 `*.zh-CN.md` + `manual/` **9 对 18 份**(2026-09-17 新增 `decisions.{md,zh-CN.md}`) |
|
||||
| 当前版本 | **v1.2.0 / 2026-09-15**,已发布至远端 `main` = **`25f930f`**(普通推送累计;`332afff` 后追加商业轨文件)| 首发 v1.0.0 / 2026-09-13 | v1.1.0 / 2026-09-14 |
|
||||
| 计数现状(2026-09-18 AST 实读) | `OVERLAY` **30** | `REQUIRED_EXPORT` **60** | `INCLUDE_DIRS` **6** | `INCLUDE_FILES` **8** | `EXCLUDE_FILES` **9** | `DROP_SCRIPTS` **28** | `LEAK_PROBES` **75** | `INFO_PROBES` **2** | `REGEX_RULES` **73** | `GLOBAL` **71** | `K8S_SEMANTIC_RULES` **14** | `TEXT_EXT` **16** | `EXTRA_TREES` **3** |
|
||||
| 上游基线(三方) | `上游骨架仓库(已按要求不再具名)` → **MIT**(GitHub 仓库 + DSH 插件目录已收录) |
|
||||
| 运行期上游 | `@deepseek-ai/dsh`(DeepSeek Harness)→ **MIT** |
|
||||
| 本机 Python | `/e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe` |
|
||||
|
||||
> ⚠️ **工作根 = `E:\ProgramData\AIProject\dsh-ai1net-github\`**(独立 GitHub 开源文件夹)。**不要再改名或迁移**:这个名字被 **5 个工具脚本** + 本技能 + 项目 MEMORY 同时引用。真要迁:① 先改**全部 5 处脚本常量**(`_build_export.py:13` `OUT` · `_verify_tsc.mjs:5` `EX` · `_sop_check.mjs:5` / `_upload_audit.mjs:5` / `_verify_all.mjs:5` `W`)→ ② 再搬/删目录 → ③ 复跑重建 + tsc,并检查旧目录**没有被重建脚本重新建出来**(2026-09-13 曾因漏改 `OUT` 而复活一次;**2026-09-16 由 `dsh-laijing-github` 改成现名时,已于 09-17 按此顺序把 5 处全部同步完**)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 硬规则 R-O1–R-O17(含 2026-09-19 真机验证修正)= 用户原始要求 + 实际踩过的坑,任何会话**不得放宽**)
|
||||
> 🔴 **R-O15(已公开仓库巡检与清除)是 2026-09-19 用户点名的「重点」规则**:见 R-O14 之后。
|
||||
> 🚫 **R-O16(测试用例不开源)· R-O17(范围收缩判据「缺少也不影响运行」)** 同上,见 R-O15 之后。
|
||||
|
||||
| # | 规则 | 判据 |
|
||||
|---|---|---|
|
||||
| **R-O1** | **源仓库只读** | 所有改写只落在导出副本。任何 `git`/写操作碰 `D:\github\dsh_shenxian` = 违规 |
|
||||
| **R-O2** | **去掉本机 / 服务器信息** | 域名 / IP / 账号 / 绝对路径 / 私有仓库地址 → **占位符或通用化**;收尾探针 **0 命中** |
|
||||
| **R-O3** | **去掉所有已投放的插件** | 插件包目录 + 插件投放脚本 + 构建产物(`*.tgz`)全部不带;**代码注释里的插件名也要中性化**:⚠️ **唯一例外见下表**:`dsh-univer-office` 经用户 2026-09-13 特许保留 |
|
||||
| **R-O4** | **不带任何项目文档与 skill** | `docs/`、档案类 md、`08-skills/`、`.workbuddy/`、`lib/`、**`.git`** 一律不带;只留 4 个新写文档(见 §6) |
|
||||
| **R-O5** | ~~授权:个人/非商业免费 + 商业收费~~ → **2026-09-13 用户定:授权类内容全部移除、不再处理、不再上抛** | 见 §5;**但「上游 MIT 不得被附加限制」是事实,保留** |
|
||||
|
||||
外加**操作纪律与文档口径(R-O6–R-O12)**,每条都对应 §0.5 里的真实事故:
|
||||
|
||||
- **R-O6** 未经明确要求 **不做 `git init` / commit / push / scp**(同项目 §4)。
|
||||
- **R-O7** 导出的**手工撰写层**(README / LICENSE / NOTICE / PLUGIN-PORTING / install.sh)是资产,**不得被重建抹掉**,由 `_overlay` 自动快照恢复。
|
||||
- **R-O8 · 命名**:**绝不沿用三方项目名**(详下)。
|
||||
- **R-O9 · 能力宣称**:**只写「已验证的」**:有代码 + 有单测 + 有 PoC **都不等于可用**;未验证的标「实验性 · 未验证」(详下)。
|
||||
- **R-O10 · 出处**:只放**文末**,且**只写一行致谢**;不写骨架枚举、不写自我表扬、不写改名理由(详下)。
|
||||
- **R-O11 · README 内容口径**:开头写**重心**不写门槛 · **面向读者**不写议论 · 每条亮点**带机制与数值** · 亮点**先读码再写**(详下)。
|
||||
- **R-O12 · README 结构顺序**:认知漏斗 Hook→Onboarding→Content→Trust→Meta · **授权压轴** · Hero 前 50 行有可视块 · TOC 锚点机检(详下)。
|
||||
- **R-O13 · 双语文档**:**中文是母本**;英文版**在同步 GitHub 之前**才生成(`*.en.md`),两份顶部再加语言切换行;法律文本不翻译(详下)。
|
||||
|
||||
### R-O8 · 命名规则(2026-09-13 立,因踩过)
|
||||
|
||||
> 上游 `dshs` **是 上游作者(已按要求不再具名) 的三方项目**(GitHub 仓库 + **已被 DSH 插件目录收录**,含 L1–L5 验证记录)。
|
||||
> 沿用它当发布名 = **冒名 / 指代混淆**,还会让上游作者的工作被误认作本项目产出。
|
||||
|
||||
**发布前必须做三件事**:
|
||||
|
||||
| # | 动作 | 判据 |
|
||||
|---|---|---|
|
||||
| 1 | **起自己的名**,并**实测未被占用**(npm `registry.npmjs.org/<name>` + 插件目录 `dshbase.com/plugins/<name>`,两处都 404 才可用) | 🔴 **现行命名(用户 2026-09-17 定,🟡 执行中)**:中文 **「能力网络」** | English **`DSH AI1NET`** | 技术标识 **`dsh_ai1net`**(详见 §0 表「新名称」行)。<br>**同口径历史**:中文 **DSH 用户平台** | English **DSH Users Platform** | 技术标识 **`dsh-users-platform`**(2026-09-14 定,线上旧仓仍用此名,**冻结不动**)。<br>⚠️ **已排除的候选**:**`dsh-hive`**(第三方插件 `llluchy/dsh-hive` 已占用);**`dsh-hosting`**(中间候选,已被取代 ⇒ **仓库里不得残留**,已列入阻断性探针);**`taimiao`**(仅候选,未落地)。 |
|
||||
| 2 | **改完全部自指标识**:包名 / bin / cordis plugin id / env 前缀(36 种)/ 数据根 / systemd 单元 / nginx conf / 库文件名 / 镜像与 k8s / 导出目录名 | 全仓 `grep` 旧名,**只剩出处引用**才算干净 |
|
||||
| 3 | **保留出处并正式致敬,但只放在文末**(用户 2026-09-13 明确:"在最后提一下引用了谁就行,不要上来就重点讲用了谁") | ① 上游 = **DeepSeek Harness(MIT)**,**本项目不包含、不分发其代码** ⇒ 无需单独 MIT 声明文件,README 文末保留**一行道义致敬**(`dshs`,MIT,⛔ 不许删);② README **不得在开头单独设「名称与渊源 / 基于 XX」章节**:出处只出现在**文末**的「第三方组件与致谢」里,**一句话带过**;③ 本项目的法律归属由 **`LICENSE`(AGPL-3.0 官方全文)** + README 末节「授权与商业使用」承载 |
|
||||
|
||||
⚠️ **改名时最容易误伤的两处**:① 把「致敬上游」的引用一起改掉(= 抹掉出处,法律与道义双重问题);② 把脚本里作**源模式**的旧名改掉(见 §8 坑 9)。
|
||||
|
||||
### R-O9 · 只写「已验证的」能力
|
||||
|
||||
> 用户原话:「模式 B · Kubernetes **去掉这个,根本没验证**,应该是**待开发验证**」。
|
||||
|
||||
| 规则 | 做法 |
|
||||
|---|---|
|
||||
| **宣称必须可复现** | 只把**真正跑过端到端验收**的路径写成「可用」。**有代码 + 有单元测试 + 有 PoC 记录,都不等于可用** |
|
||||
| **未验证的照实标注,不删代码** | 保留代码与清单,但标注 **「实验性 · 未验证」**,并与可用路径**在同一张表里用状态行对照**,不要让读者自己猜 |
|
||||
| **删掉「已完整落地 / Phase 0–4」式表述** | 这类词最容易把"写完了"说成"验证过了"(2026-09-13 从「部署形态」章节删掉的就是它) |
|
||||
| **配置表 / 脚本文案同步标注** | 未验证路径的 env 变量统一加「(模式 X · 未验证)」前缀;`install.sh` 的报错/提示文案要与 README 口径一致 |
|
||||
| **FAQ 给一句直答** | 加一条「X 现在能用吗?」→ 直接回答「**还不能**」,并说清**缺哪一步**(如「从未做过端到端部署验收」) |
|
||||
| **归属措辞也要改** | 出处/致谢里描述对方贡献时,把「双部署**形态**」降级为「双部署**框架**」,避免暗示未验证的路径是可选项 |
|
||||
| **落点清单(照抄)** | README:部署形态表 + 快速开始 + 配置表 + 功能详解 + 安全模型 + 亮点 + 目录结构 + FAQ;`install.sh` 文案;README **末节「授权与商业使用」**与**文末致敬行**的措辞 |
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
### R-O10 · 出处的位置与措辞
|
||||
|
||||
> 用户原话:「在最后提一下引用了谁就行,**不要上来就重点讲用了谁**,感觉是在宣传别人的项目,已经很多地方深度改造过了。」
|
||||
|
||||
| 规则 | 说明 |
|
||||
|---|---|
|
||||
| **位置** | 只在**文末**(README 的「第三方组件与致谢」+ 末节「授权与商业使用」)。**不得**在开头/前部单设「名称与渊源」「基于 XX」章节 |
|
||||
| **主语** | 正文一律**以本项目为主语**。写「本项目做了…」,**不要**写成「上游提供了骨架,我们在此基础上…」这种自我降格的框架 |
|
||||
| **措辞** | 用「**起步时参考了** X(作者,许可证),**感谢作者开源**」;**不要**用「仅仅接着往前走了一步」「离开它就没有这个项目」这类过度抬举,**也不要**补「我们做了大量深度改造」这类**自我表扬**(见下表「致谢只写一行」) |
|
||||
| **边界** | 「轻描淡写」**只作用于 README 正文**;**`LICENSE`(AGPL-3.0 官方全文,逐字节)与 README 末节的授权说明一处都不能省** |
|
||||
| **JS/注释里的名字** | 代码注释里也**不主动**出现上游名(它们已经被 R-O8 第 2 步改成新名;只剩出处语境才允许) |
|
||||
| **致谢只写一行**(2026-09-13 第七次纠正) | 出处行 = **「起步时参考了 X(作者,许可证),感谢作者开源」**,一行结束。**不要**写:① 骨架范围的枚举(那是 `LICENSE` 与 README 末节授权说明的职责,**重复即冗余**);② 「此后我们做了大量深度改造」(**自我表扬**,致谢不是讲功绩的地方);③ 「项目名从它的 X 换成我们的 Y(避免指代混淆…)」(**内部事务**,读者不关心 ⇒ 不进公开文档)。用户原话:「**有必要讲这么多吗,好好想想**」 |
|
||||
| **别解释我们为什么这么写** | 「—— 这是 MIT 的硬性要求,必须保留」「因此 README 与 install.sh 一律以模式 A 为准」这类**关于文档自身**的话术删掉;正文只陈述事实与规则本体 |
|
||||
| **指针行不重复** | 「机制见亮点」这类导航指针**全文留 1–2 处**(Hero + 功能详解)即可,Content 各节末尾各来一句 = 冗余 |
|
||||
---
|
||||
|
||||
### R-O11 · README 内容口径
|
||||
|
||||
> 🧭 **体例 = 说明书,不是技术文档**(2026-09-13 20:4x 用户定):「readme 是说明不是技术文档 用语需要简明扼要 排版要方便观看」。
|
||||
> ⇒ 只写**怎么用 / 有什么 / 限制**;机制级细节(链名、flag、常量、函数语义)留给代码注释与 `PLUGIN-PORTING.md`;
|
||||
> ⇒ **不写内部变更日志式长表**(如「v1.0.0 的六组改造」);表格单元格要短、可扫读;多用列表少用长段落。
|
||||
|
||||
> 用户原话:「部署到一台服务器,多个用户注册并经管理员审核,各自获得一套相互隔离 —— **这个只是项目的基础不是重点**,重点是多租户各自进程的安全隔离、状态恢复、插件和技能的管理。**多看看项目找出这个项目的亮点**」「对了多想想 **不要弄了半天亮点都体现不出来**」。
|
||||
|
||||
| 规则 | 做法 |
|
||||
|---|---|
|
||||
| **开头 = 亮点,不是门槛** | 开篇**不要**写「部署到一台服务器,多个用户注册…」这类「能跑」描述(那是基线)。改成**一句定位 + 三条主线速览**:① 进程级安全隔离 ② 故障自愈与状态恢复 ③ 插件与技能的受控管理 |
|
||||
| **亮点必须先于功能清单** | README 的第一个正文章节就是**亮点**(`## 亮点`),且**要早于**「快速开始 / 功能详解」。功能清单只做**索引**,并在开头声明「机制见亮点」 |
|
||||
| **每条亮点必须带机制** | 禁止「真隔离」「会自愈」这类空词。每条要写**具体机制 + 关键数值/常量 + 为什么这么设计**(例:端口守卫要在 OUTPUT 链按**客户端 uid** 匹配、且 `-I OUTPUT 1` 插链首,否则 ufw/conntrack 的 ACCEPT 会先吃包;宿主不支持就 fail loud) |
|
||||
| **先读代码再写亮点** | 亮点**必须来自实际读码**(`src/**` 的头注与关键函数就写得很好),不要凭 README 旧文或印象复述。读法:`find src -name '*.ts' \| xargs wc -l \| sort -rn` 找最重的模块 → 读头注 → 再挑 3-5 个「反直觉且踩过坑」的细节 |
|
||||
| **「难在哪」心里有数(但别写进 README)** | 每条主线要能回答「为什么这不容易」(租户之间**真的**隔得住 / 崩溃后**无感**恢复 / 装了**不出事**)—— 用于**决定亮点写什么**;⚠️ 但「多租户演示十分钟就能写出来」这类**对比式议论本身不许出现在 README**(见下表「面向读者」) |
|
||||
| **补一节工程纵深** | 用「双后端同接口 / 关键决策是纯函数 / `npm test` 覆盖 + 注入脚本运行时校验」这类事实回答「凭什么信这些机制」 |
|
||||
| **面向读者,不是面向作者**(2026-09-13 第三次纠正) | README 是给**使用者 / 贡献者**看的。禁止出现「**重点不是 X,而是 Y**」「X **十分钟就能写出来**」这类**议论式 / 对比式**表述,那是在跟作者对话,读者不关心。直接陈述「**项目做什么 + 重心在哪**」即可 |
|
||||
| **小节标题别加议论** | 标题只写名词短语(`### 一、进程级安全隔离`),**不要**写成 `(不是「同机不同目录」)` `(「能装」和「装了不出事」是两件事)` 这种反问/抖机灵。对比与理由放到**表格单元格**里当技术说明 |
|
||||
| **别重复定位句** | 标题下的一句 tagline 与 badges 之后的描述段**不要重复同一个句式**(「把 DSH 变成…」说了两遍)。tagline 一句话,描述段讲**用户视角的事实 + 三条重心** |
|
||||
|
||||
---
|
||||
---
|
||||
|
||||
### R-O12 · README 结构顺序
|
||||
|
||||
**依据**:`readme-craft`(SkillHub 技能,蒸馏 awesome-readme / Standard README / Art of README / Make a README / GitHub Docs / thoughtbot)+ `standard-readme`。核心是**认知漏斗**:**Hook → Onboarding → Content → Trust → Meta**,**不得倒序**。
|
||||
|
||||
**本项目定稿顺序(Hero + 16 节)**
|
||||
|
||||
```
|
||||
标题 → 一行描述 → 徽章(**5 个**:Node · Version · built on DSH · **code & docs-human-planned, AI-implemented** · DeepSeek V4/V4.1 flash;**无 License 徽章**)
|
||||
→ Hero(三条主线 + **一行「人负责规划与关键判断,AI 负责实施」** + 拓扑图)→ 快速开始片段
|
||||
目录 → 亮点 → 快速开始 → 功能详解 → 架构 → 安全模型 → 部署形态 → 配置
|
||||
→ 控制面 API → 插件移植指南 → 开发 → 常见问题 → 目录结构 → 版本与迭代 → 贡献
|
||||
→ 第三方组件与致谢 → 授权与商业使用(必须最后)→ 授权摘要收尾(全文唯一一处摘要)
|
||||
```
|
||||
|
||||
> 🔴 **「本项目由谁建成」= 现行唯一口径(2026-09-17 11:48 用户定):「人负责规划与关键判断,AI 负责实施」**(英文 `Human planning and key judgment; implementation by AI`)。
|
||||
> · **落点**:README Hero 的 `code & docs-human-planned, AI-implemented` 徽章 + 一行声明 · `manual/project.{md,zh-CN.md}` 的 **`## How this project is built` / `## 项目如何建成`**(一行声明 + 2 行「环节 → 由谁负责」表:人 = 方向/范围/架构决策/评审验收;AI = 代码/测试/文档/插件改造示例)。
|
||||
> · **为什么必须这样写**:中国版权保护中心 **2026 新规「纯 AI 生成的软件不予登记」**,判据 = **人类独创性智力投入**。旧口径「全部代码与文档由 AI 生成」= **自认纯 AI** ⇒ 商业授权**缺标的物**;新口径**恰恰确立人类投入** ⇒ 是**法律加固**,⚠️ 不要简化回「AI 生成」(详见 §5 与 `<工作根>\_授权决策与法律依据_20260917.md`)。
|
||||
> ⛔ **不要再写回「全部由 AI 生成」**(用户 09-17 **11:44 曾短暂要求全部删除,11:48 改为本条**);⛔ **也不要照 2026-09-13 的「删掉人的角色」**,两者均已被推翻。
|
||||
> ✅ 一并保留:`DeepSeek V4 / V4.1 flash` 模型标注徽章 · README 的 `**能力网络** · **DSH AI1NET**` 行。
|
||||
|
||||
| # | 硬规则 | 理由 |
|
||||
|---|---|---|
|
||||
| 1 | **授权章节放最后** | 6 个权威来源共识 + readme-craft 的 Trust 评分项就是「License 在最后?」 |
|
||||
| 2 | **授权信息不要出现在前排正文**(2026-09-13 用户纠正):靠**顶部 License 徽章**承载(本项目 = `license-personal free \| commercial paid`,并链接到末节)+ **文末**「授权与商业使用」章节尾的一行摘要。**不要在徽章下方另加一句授权 blockquote**:用户明确「说明文档还是在前面」不接受 |
|
||||
| 3 | **Hero 区(前 50 行)必须有可视块** | 审计项 H3 占 7 分(拓扑图 / 截图 / GIF 任选) |
|
||||
| 4 | 一行描述 **< 120 字符**,且与 `package.json` 的 `description` **开头一致** | 审计项 H2 占 8 分,单项最高 |
|
||||
| 5 | 超 100 行**必须有 TOC**,且**锚点逐条可解析** | 自查法:把标题按 GitHub 规则转锚点(小写 / 去标点 / 空格→`-`)后与 TOC 比对 |
|
||||
| 6 | 功能用**表格/列表**不写散文;**清单型章节要声明「机制见亮点」** | 避免 C1 扣分与 S3 信息重复 |
|
||||
| 7 | **API 概览必须从代码抓真实路由**(`grep -oE "app\.(get\|post\|put\|delete)\("`),别凭印象写 | 审计项 C3;写错路由比不写更糟 |
|
||||
| 8 | 章节重排要用**脚本按标题切分再拼装**,重排后**复跑 TOC 校验** | 手工搬章节极易丢内容 |
|
||||
| 9 | **表格单元格里不要写裸 `\|`**(如 `GET\|POST`)—— 会截断表格,改写「(`POST` 同形)」 | 格式错误扣 P2 |
|
||||
| 10 | 发布后补 **CI 徽章** 与**真实联系方式**;上线前不要加 CI 徽章(占位符 = 死链) | T3 / T4 是唯二「因尚未发布」而扣分的项 |
|
||||
|
||||
**审计口径**(readme-craft 22 项 / 100 分):Hook 25 · Onboarding 25 · Content 20 · Trust 15 · Structure 10 · Polish 5;等级 **S**≥90 / **A**≥80 / **B**≥70 / **C**≥60 / **D**<60。
|
||||
**本项目首轮自审 = 93/100(S)**,扣分仅:CI 徽章 0/3 · 维护者信息 0/3(`<CONTACT_EMAIL>` 未填)· S3 信息重复 2/3。
|
||||
|
||||
---
|
||||
|
||||
### R-O13 · 双语文档(2026-09-13 用户定:**中文优先,英文在同步 GitHub 时生成**)
|
||||
|
||||
> 用户原话:「文档别忘了**中英文双语**,后续**优先写中文**,需要同步到 GitHub 时再更新英语。」
|
||||
|
||||
| 项 | 口径 |
|
||||
|---|---|
|
||||
| **母本** | **中文**(`README.md` / `PLUGIN-PORTING.md`)。**日常只维护中文**;英文文件**不要求随时同步**,避免双份维护成本 |
|
||||
| **英文文件名** | `README.en.md`、`PLUGIN-PORTING.en.md`(与中文同目录,后缀 `.en.md`) |
|
||||
| **生成时机** | **发布 / 推送 GitHub 之前那一步**(SOP 的 5.5)—— 也就是 §7 验证之后、§6 交付之前 |
|
||||
| **语言切换行** | 两份文件**顶部都要有**:中文版写 `[中文](README.md) · [English](README.en.md)`;英文版写 `[English](README.en.md) · [中文](README.md)`。⚠️ **英文文件存在之前不要加**(否则是死链,扣 P1) |
|
||||
| **翻译时严格保持** | 代码块、命令、路径、env 名、包名、URL、图(ASCII/Mermaid)、表格结构与「版本与迭代」表内容,**逐字保留**;占位符(`<YOUR_GITHUB_ACCOUNT>` 等)**同步替换** |
|
||||
| **不翻译(保持原文)** | `LICENSE`:**AGPL-3.0 官方英文全文,逐字节不许翻译或改写** |
|
||||
| **校验** | 英文版同样要跑 **TOC 锚点校验**(按英文标题算锚点)与**相对链接存在性**;两版的「版本与迭代」表**行数与版本号必须一致** |
|
||||
| **别忘** | 这是**发布前唯一会因为"没做"而显得半成品**的项,写进 SOP 与 §10 待办,接手先看 |
|
||||
|
||||
---
|
||||
|
||||
### R-O14 · 🚫 K8s 相关内容:**源仓那侧视为废弃分支**(2026-09-14 定稿;2026-09-15 用户升级为**长期策略**)
|
||||
|
||||
> 用户原话(2026-09-15):「记住这部分和 K8S 相关的代码 **后续获取开发项目代码时 跳过就用当前清除或修改后的版本**」
|
||||
|
||||
| 规则 | 判据 |
|
||||
|---|---|
|
||||
| **① 不回流** | 源仓的 K8s 资源 / 文档 / 注释 / 语义描述 / K8s 专属配置,**不得**因源仓更新而重新进入导出物 |
|
||||
| **② 不重复实现** | 导出层已有的清除与改写就是**唯一口径**,不要每次重新发明 |
|
||||
| **③ 改了源仓也不跟** | 源仓若再改 K8s 那段代码,**以导出层版本为准**(源仓那侧视为**废弃分支**) |
|
||||
| **判定标准** | 构建输出 **`blocking hits: 0`**;不为 0 = 回流了 ⇒ 按台账 §四 处置 |
|
||||
| **权威清单** | **`_K8s排除台账.md`**(本工作根):含「下次取新版本怎么做」的步骤 + 判读表 + 噪音清单 |
|
||||
| **扫描器** | **`_k8s_scan.py`**(`--source` 扫源仓 / 无参数扫导出物;**EXIT=1 = 有未覆盖项**) |
|
||||
|
||||
**三重强制手段**(缺一会静默失效):
|
||||
`INCLUDE_DIRS`/`INCLUDE_FILES` 白名单 → `EXCLUDE_FILES`/`DROP_SCRIPTS` → `REGEX_RULES` ⑦⑧⑨ + **`K8S_SEMANTIC_RULES`** + `LEAK_PROBES`。
|
||||
|
||||
**已清到 0(源码与注释)**:62 → 0;含 K8s 专属配置项(`config.ts` 7 字段 + 3 常量 + `parseCidrs()`)、
|
||||
`DeployMode` 收窄为 `'local'`、全部注释与**语义描述**(`Pod`/`file sidecar`/`ConfigMap`)。
|
||||
⚠️ **连带必做**(否则 `tsc` 报错):`proxy.ts` 的 `deployMode === 'k8s'` 实参改常量 `false`;`web/server.ts` 的 fail-loud 守卫删除。
|
||||
⏳ **唯一剩项**:`@kubernetes/client-node` 依赖 + lock(8 处):导出层删不了(须重生成 lock,⛔ 不手改 lock)。
|
||||
⚠️ **但这不等于「去源仓 `npm uninstall` 就行」**(2026-09-15 更正):**导出物**里它 0 import(3 个 import 它的模块被 `EXCLUDE_FILES` 剔了),可**源仓仍保留 K8s 后端**(`src/supervisor/{k8s-spawner,leader,reconcile}.ts` 都 import 它)⇒ **在源仓直接删会打断源仓 `tsc`**。
|
||||
**正确顺序**:源仓先下线 K8s 后端 → 再 `npm uninstall` 重生成 lock → 最后重跑导出。三条路线见 `_K8s清理影响评估与回归说明_20260915.md §9`。
|
||||
|
||||
---
|
||||
|
||||
### R-O15 · 🔴🔴 **已公开仓库巡检与清除**(2026-09-19 用户点名升级为**重点硬规则**)
|
||||
|
||||
> 用户原话:「**顺带修掉两处既有公开泄漏(不是本轮引入,已随旧仓公开)…!!!严格排查是否还有相同问题!!!,把已经公开的仓库清除相关信息**」,
|
||||
> 随后:「**然后把这个作为重点!!!强化到规则中**」。
|
||||
|
||||
**为什么必须上升到硬规则**:整个流程过去只盯「**新导出物**干不干净」,**从没回头巡检已经躺在公网上的仓库**。
|
||||
实测代价:`dsh-users-platform` 公开多日,里面**逐个含内部主机号 / 内部隧道端口 / PG 口令**的 7 个 `verify-cluster-*.mjs` + `start-cluster-manager.sh` 一直挂着。
|
||||
⇒ **公开发布不是终点;只要仓库在公网上,就必须周期性回头查。**
|
||||
|
||||
| 项 | 规定 |
|
||||
|---|---|
|
||||
| **① 何时查** | **每次整理 / 发版前后各一次**;任何一次「严格排查」都必须**同时覆盖两处**:新导出物 **+ 每一个已公开仓库** |
|
||||
| **② 用什么查** | `<导出根>\_check_public.py [<dir> …]`(**常驻工具**,默认自动扫 `dsh_ai1net` 与 `dsh-users-platform`;**exit≠0 = 有命中**) |
|
||||
| **③ 命中后三件一起做** | ⓐ 补成 `_build_export.py` 的**规则 + 探针**(⛔ 只清新仓 = 下版回潮,见 #17)<br>ⓑ **就地清理已公开仓库**(删危险文件 / 替换敏感字面量)<br>ⓒ 提交 + 推送(**注意**:前向提交**不会**从历史里抹掉,要彻底清除须改写历史,属「不可逆 + 影响面」事项,**必须先问用户**) |
|
||||
| **④ 判据(正名)** | **「换一个部署者,这个值会不会一样?」**:会 ⇒ **通用事实,允许**(云厂商元数据端点 `100.100.100.200`、云内网 DNS、docker 网桥 `172.17.0.1`、RFC1918 `10/172.16–31/192.168`、RFC5737 `192.0.2/198.51.100/203.0.113`、测试夹具 `w-1`/`w-999`/非法 IP);<br>不会 ⇒ **泄漏**(**我们的**主机号、隧道端口、服务器/测试机 IP、口令字面量、内部单据名、内部绝对路径) |
|
||||
| **⑤ 同一把尺子** | ⛔ **不许「新仓严、旧仓松」**。新旧仓用**同一个** `_check_public.py`、同一份 `LEAK_PROBES`。发现新形态 ⇒ 加进工具的 `PATTERNS` **并**补 `_build_export.py` 的规则+探针(**两处都要动**) |
|
||||
| **⑥ 与 `LEAK_PROBES` 的分工** | `LEAK_PROBES` = **已知字符串**(构建时自动跑,防回潮);`_check_public.py` = **形态**(IP / 主机号 / 端口 / 凭据 / 内部路径 / 内部单据,用来发现**规则还没覆盖**的新泄漏)。**两者互补,缺一不可** |
|
||||
|
||||
**本轮(09-19)实际清出的存量**(全部为**既有公开泄漏**,非本轮引入):
|
||||
|
||||
| 类别 | 实例 | 处置 |
|
||||
|---|---|---|
|
||||
| 内部集群脚本(8 个,**逐个含主机号+端口+PG 口令**) | `verify-cluster-{agent,cross,domain,fs,lease,live,migrate}.mjs` · `start-cluster-manager.sh` | 旧仓**删除**;新仓规则层 `DROP_SCRIPTS` 同处置 |
|
||||
| 内部主机号 | `w-106`(14 处)· `w-47` · 无连字符 `w106`/`w47` · 标识符 `w47Secret` | → `<worker-b>` / `<worker-a>` / `node-NN`(**命名体系整体抹掉**,保序号以维持测试区分度) |
|
||||
| 内部端口 | `15432`(PG 隧道)· `19000`/`19001`(隧道监听)· `32022`(sshd) | → `<PG_PORT>` / `<TUNNEL_PORT_1..2>` / `<SSH_PORT>` |
|
||||
| 内网地址 | `10.0.1.11`(注释里写作「agent 的内网地址」)· `10.0.0.5` 等夹具 | → `<HOST_LAN_IP>` |
|
||||
| PG 测试口令 | `dshs_cluster_test` / `dsh-users-platform_cluster_test` | → `_<TEST_DB_PASSWORD>` |
|
||||
| smoke 口令字面量(**读起来像真口令**) | `adminpass123`(配 `username:'admin'`)· `bob/alice/carol/frank/gina/root` + `pass123` | → 统一 `smoke-test-password`(脚本自建用户再用,改值不影响行为) |
|
||||
| 内部单据引用 | `交接单_网抽象与地址规划R6 §待办②` · `交接单 T05` · `` `04-调整方案/133-…md` §2.2 `` | → `设计说明` / `` `the design note` ``(**从 INFO 升格为阻断**:公开仓里它既是内部信息又是**悬空指针**) |
|
||||
|
||||
**配套两条纪律**(本轮新踩,同样进规则):
|
||||
- 🔴 **drop 任何文件前,查「谁读它」必须同时查文档与代码**(`readFileSync` / `join(` / `import` / `require` / `spawn`)—— 只看文档会误删被测脚本(事故 #18)。
|
||||
- 🔴 **纯数字 / 纯字母数字的内部标识(端口 `15432`、主机号 `w106`)不得裸替**:会命中 base64 哈希,症状是 `npm ci` 校验失败且与改动无关(事故 #19)。
|
||||
|
||||
---
|
||||
|
||||
### R-O16 · 🚫 **测试用例相关文件和代码不开源**(2026-09-19 用户定稿)
|
||||
|
||||
> 用户原话:**「测试用例相关文件和代码 不开源」**。
|
||||
|
||||
| 项 | 规定 |
|
||||
|---|---|
|
||||
| **不带** | ① `test/**`(单测套件)② `07-scripts/smoke*.mjs`(端到端冒烟,**也是测试用例**)③ `07-scripts/fake-*.mjs`(只为冒烟存在的**测试替身**) |
|
||||
| **仍要带** | `07-scripts/verify-*.mjs\|cjs` 族:它们**不是**测试用例,而是**产品自带校验**(`verify-inject.cjs` 被 `AGENTS.md` 指引、`verify-static.mjs` 被 `web/i18n.js` 调用、`verify-model-landing.mjs` 被 `src/web/model-landing.ts` 引用、`verify-dsh-install.mjs` 是安装自检)。判据 = **「谁读它」**(见事故 #20) |
|
||||
| **四处连带**(缺一即留断链) | ① `package.json`:删 `test` / `smoke*` 入口、摘掉 `verify` 里内联的 `node --test …`、**并修掉尾逗号**(`verify` 会变成最后一项)② `src/**` 与保留下来的 `07-scripts/**` 里**引用测试文件**的注释(会变悬空引用)→ 中性化 ③ `.github/workflows` 里的测试口令字面量 ④ **文档能力宣称**(OVERLAY 手工层:`README{,.zh-CN}` 能力表 · `AGENTS{,.zh-CN}` · `manual/{architecture,highlights,project}{,.zh-CN}`) |
|
||||
| **兜底探针** | `LEAK_PROBES += [".test.mjs", "node --test", "07-scripts/smoke", "fake-dsh.mjs", "fake-setpriv.mjs", "ci-test-pass-123"]` ⇒ 任何回潮都会让构建**判失败** |
|
||||
| ⚠️ 最易漏 | **文档宣称**(`_check_public.py` / `LEAK_PROBES` **扫不出**「文档说我们有 9 个冒烟」这种语义不一致)⇒ 收缩范围时**必须人肉把 README / AGENTS / manual 过一遍** |
|
||||
|
||||
> 📖 **配套**:本轮所有泄漏实例(含真实值与「为什么没发现」)已整理成 **`<工作根>\_负面案例库_开源前必读.md`**:**每次开源前必读**,且该文件**不得进任何公开仓库**。
|
||||
|
||||
---
|
||||
|
||||
### R-O17 · 🚫 **范围收缩判据:「缺少也不影响项目运行」**(2026-09-19 用户定;同日经真机验证**修正**)
|
||||
|
||||
> 用户原话:**「我说的不用开源 是指缺少也不影响项目运行 比如之前的 测试用例」**。
|
||||
> R-O16(测试用例不开源)与 R-O14(K8s 不带)都是这条判据的**实例**。
|
||||
|
||||
#### 🔴🔴 首要铁律(2026-09-19 真机验证倒逼立,**违反即可能删掉生产在跑的进程入口**)
|
||||
|
||||
> **「从代码入口不可达」≠「不影响运行」。**
|
||||
> 用户原话:**「若某份分析以 dshs 控制面为根做可达性,"零引用"是根进程选错了,不是事实。」**
|
||||
|
||||
| 事实 | 说明 |
|
||||
|---|---|
|
||||
| **多进程系统里,"别人的入口"从本进程看必然不可达** | 本项目实测:`src/net/relay/{server,main,index,join,keys,placement}.ts` + `content/runtime.ts`(**214 KB,`server.ts` 单文件 112 KB**)从控制面 `main`/`bin` **完全不可达**:因为 **relay 是另一个进程**,入口 `main.ts` 由 **systemd `ExecStart`** 拉起,生产上两台中继 **`active running`**、监听 `127.0.0.1:20080`。控制面不 import 服务端族是**设计使然** |
|
||||
| **接线线索常常不在代码仓** | 实测:源仓 + 导出物 **0 个 `.service` / `.timer`** ⇒ **在仓内做可达性,永远看不到 systemd 接线** ⇒ **仓内查不到接线时,默认「它在别处被接线」,而不是「它没人用」** |
|
||||
| ⇒ **所以必须先做「接线核实」** | 问:**这个子系统的进程入口是哪个?由谁拉起?**(`systemd` / `cron` / `docker` / 一键安装脚本 / 手动),**并去真机看状态**(`systemctl status` / `list-units`)。<br>⚠️ **答不上来 ⇒ 不能删**(不是"先删了再说") |
|
||||
| ⚠️ **「能力已备、门面未接」也要保留** | `join.ts`(一键入网:只有 barrel + 测试,它要 POST 的控制面端点尚无路由)· `placement.ts`(节点选点算法:**零调用点、零测试**)—— 用户判定**保留**:**删掉 = 删掉后续自助入网/自动选点的唯一判据来源**。⇒ **「未接线」≠「死代码」** |
|
||||
|
||||
#### 判据与四步
|
||||
|
||||
| 项 | 规定 |
|
||||
|---|---|
|
||||
| **判据** | **缺少这个文件,项目还能照常跑吗?** 不能 ⇒ **必带**;能 ⇒ 进候选,再看它是否属「对外文档」 |
|
||||
| ⛔ **不是**判据 | **「从代码入口不可达」**(首条铁律,最危险)<br>「有没有人引用」(`web/i18n.js` 只在**注释**里被提到,却是**运行时静态资源**)<br>「名字像测试」(`verify-*.mjs` 名字像测试,实为**产品自带校验**,见 R-O16)<br>「在不可达单里」(`semver-shim.d.ts` 不可达,但删了 **`tsc` 报 TS7016**) |
|
||||
| **必须走四步** | ① ~~真实 import 图 + 可达性~~ → **改为「接线核实」**:系统有几个**进程入口**?各自的**拉起方式**是什么?<br>② **移除闭包**:候选集移除后,**保留文件还有没有边指向它们**(0 条只是**必要条件,不是充分条件**,见铁律)<br>③ **查界面牵连**:`grep` 文件名在 **`.ts`** 里的位置:若出现在**返回给前端的字符串**里(API 响应字段 / 报错提示),**必须连文案一起改**<br>④ **查引用**:⚠️ **三个维度都要查**:导出物文档 · **代码** · **源仓内部文档**(`dsh-server-docs/01-规范/02-运维手册.md` / `04-调整方案/` / `05-交接单/`)。<br> 🔴 本轮我**只查了导出物**,于是漏掉「这些运维脚本在运维手册里有成文流程」这一铁证 |
|
||||
| **工具** | **`_check_unused.py`**(只报告不删;给三张单子:死文件 / 入口不可达的 src 模块 / 名字像运维辅助的脚本)<br>🔴 **只报告**:范围收缩属「**影响对外可见面**」⇒ **必须人工确认**;<br>🔴 且**它的「不可达」单必须配合接线核实才能用**:该单里的 **relay 服务端族是生产在跑的**。 |
|
||||
| **固有风险项** | **二进制(图片)不受任何探针覆盖** ⇒ `screenshots/` 是否含真实用户名/域名/IP **只能人工逐张目视**,**每次发版前必看** |
|
||||
|
||||
**本判据下已确认的两类**(2026-09-19 实测):
|
||||
|
||||
1. **内部运维 / CI / 死文件**:`ci.sh` · `session-gc.cjs` · `ws-cleanup.cjs` · `clean-ws-pollution.cjs` · `purge-trash.sh` · `storage-report.cjs` · `instance-mem-sample.cjs` · `mksess.cjs` · `migrate-sqlite-to-pg.mjs` · **`build-web.mjs`(空操作占位)** · **`.github/workflows/build.yml`(监听 `master` 而导出仓是 `main` ⇒ 永不触发)**
|
||||
2. **独立 daemon(最隐蔽)**:`src/net/relay/` 的**服务端族** 7 文件 / **214 KB**:平台**从不 import**(只用 `client` 侧拨出),服务端是**我们自己中继节点**上跑的软件,头注含内部拓扑(「47 无本机防火墙」)。🔑 **靠「可达性 + 移除闭包」两步才看得出来**
|
||||
|
||||
⚠️ **连带纪律**:删 relay 服务端族时,`src/net/relay/jitter.ts` 头注写着「与 `07-scripts/overlay-jitter.cjs` 逐字同口径」⇒ 若同批删那个脚本,**要改成中性说法**(否则是悬空引用)。
|
||||
|
||||
---
|
||||
|
||||
## 1.5 🔴🔴🔴 用户当场纠正过的硬口径(2026-09-14 凌晨:连纠 8 次)!!!
|
||||
|
||||
> **这不是"建议",是硬口径,一条不遵守就要返工。** 全部来自真实纠正,逐条附用户原话。
|
||||
|
||||
| !!! | 规则 | 判据 / 用户原话 |
|
||||
|---|---|---|
|
||||
| **!!! 1 !!!** | **没验证的能力:不写(不是标注「未验证」,是整条删)** | 「**没验证的不要写意思就是不要写 !!!**」,点名删「双部署后端同一接口(K8s 后端未验证)」。⇒ README **不得出现**「未验证 / 实验性 / 模式 B / K8s 后端 / Postgres」等字样,已**全清**(代码可留,**文档不提**)|
|
||||
| **!!! 2 !!!** | **不写废话**:括号里的体贴话、推销话 | 「(想自己掌控每一步)**不要写这种没用的废话**」;「商业授权…联系 xxx **不用写这个废话**」。**判据:括号里若没有机制 / 数值 / 真实行为 / UI 提示 = 废话,一律删**。已删:`手动部署(想自己掌控每一步)`、`(建议先审一遍)`、整段「商业授权」+ 邮箱、章节名「授权与商业使用」→「**授权**」|
|
||||
| **!!! 3 !!!** | **归类必须准:DeepSeek Harness 是「基座」,不是「第三方组件」** | 「**这个不叫三方组件…所有开发都是基于这个来的**」⇒ ① 删掉「第三方组件与致谢」整节;② 在「架构」里讲清 **DSH = DeepSeek AI 开源的 agent harness**(everything-is-a-plugin / Cordis 驱动 / 默认 `npx @deepseek-ai/dsh web` → `127.0.0.1:3080` **本机单用户** Web UI);③ 补上 **developer preview ⇒ 官方明说会破坏性变更**(它才是"为什么要有兼容性预检 + 版本冻结"的钩子)|
|
||||
| **!!! 4 !!!** | **读码找亮点:亮点必须来自实际读码,且区分「已验证」** | 「在分析一遍项目看看还有哪些亮点」⇒ 按 R-O11 逐个读 `src/**` 头注;**没验证过的不写**(本次挖到的"模型管理两层""迁移账本同形"等因**未实测**而**未采纳**)|
|
||||
| **!!! 5 !!!** | **未持锁 ≠ 不能改导出物;但「重建」会删掉本地 `.git`** | ① 本工作根**不在**锁保护范围(钩子只护「文档库 / 代码仓」)—— **别再拿锁当理由拒改导出物**(本次被纠正);② ⚠️ **`_build_export.py --force` 的 `rmtree(DST)` 会连仓库里本地 `.git` 一起删**(本次实测)⇒ 顺序必须 **重建 → 六件套 → `git init`/commit → 推送**,**提交后不得再重建** |
|
||||
| **!!! 6 !!!** | **安装成功才准提交 / 推送(用户定的闸门)** | 「**必须按照说明文档 安装成功才能提交**」⇒ **平台本体跑通**(install 成功 + 登录 200 + 管理台 / 桌面 API 200)是**下限**;`--dry-run` 通过、组件级验证、探针全绿 **都不算通过** |
|
||||
| **!!! 7 !!!** | **敏感信息一律不进仓库**(测试 IP / 账号密码 / 实例 ID / 服务器信息) | 本次把**真实测试 IP** 写进 README 示例被当场抓到 ⇒ 改用 **RFC 5737 文档保留地址**(如 `203.0.113.10.nip.io`);并把 `106.54.21.172` / `ins-3q6k1p8t` / 测试账号密码**四项加进 `LEAK_PROBES`** |
|
||||
| **!!! 8 !!!** | **提「注意事项」前先对齐本技能 §1 的 R-O1–R-O13** | 「感觉都不是我最早说的注意事项,**你看看 skill**」⇒ 用户要的是**他原始定的硬规则**,**不是**实现坑;计划/清单按 R-O 组织 |
|
||||
| **!!! 9 !!!** | **章节顺序服务于读者;参考性章节别放太后;排版要整体看** | 「目录结构 是不是放的太靠后了,**在整体看看你的排版呢**」⇒ ①「**目录结构**」从 Meta 区**上移到「架构」之后**(逻辑结构 → 物理结构,读者顺着一路读);② 排版检查要**整体过**:分隔线用法、标题层级、表格/列表一致性、长句拆分、括号废话(见 !!! 2 !!!)。⚠️ 与 R-O12 的社区标准顺序冲突时,**以用户当场指令为准**并说明理由 |
|
||||
|
||||
### 改文档时的**固定动作**(本次反复用到,照抄)
|
||||
|
||||
1. **两份同步**:`_overlay\<文件>` 与 `dsh-users-platform\<文件>` **必须逐字节一致**(改一份 = 改两份,改完 `md5` 比一次);
|
||||
2. **改完必验**:`md5` 相同 + **TOC 锚点机检无悬空** + **全篇关键词扫描**(`模式 B / K8s / 未验证 / 实验性 / WorkBuddy / 旧名 / 敏感串` 应**全 0**);
|
||||
3. **提交**:`git -c core.autocrlf=false add -A` → `commit --amend --no-edit`(**首发阶段**保持单条发布提交);**提交后不得再重建**;
|
||||
4. **改本技能**:两副本(活跃 + 文档库归档)**md5 必须一致**,同步前**先抢全局执行锁**。
|
||||
|
||||
> 📂 **保留/移除清单 + 脱敏映射表 + 保留未动三节已下沉** → `references/01-保留移除与脱敏口径.md`(**改脱敏口径 / 保留范围前必读,它是唯一口径**)
|
||||
|
||||
## 5. 授权结构(**现状:2026-09-17 定案「双轨」—— AGPL-3.0 原样 + 商业授权**)
|
||||
|
||||
> 🔴 **现状(以本条为准,覆盖本章所有历史描述)**:**双轨授权**:
|
||||
> - **轨 1 · 开源轨 = AGPL-3.0 原样(默认)**:`LICENSE` = AGPL-3.0 官方全文(**34,523 B,逐字节未改**);`package.json` 保持 `"license": "AGPL-3.0-only"`;已在 `OVERLAY` 与 `REQUIRED_EXPORT`(**60 项**)内。
|
||||
> - **轨 2 · 商业轨**:给「**不愿承担 AGPL 开源义务**」(闭源托管 / 嵌入专有产品)的人 ⇒ 联系 `maogeigei@gmail.com` 谈条款与报价。**商业授权是「另开一条平行许可路径」,不是「对 AGPL 加限制」**:这是它不违反 OSD 的关键。**自 2026-09-18 起轨 2 有独立文件**:`COMMERCIAL-LICENSE.md` + `.zh-CN.md`(提交 `25f930f`)。
|
||||
> - 🔴 **三条措辞铁律(2026-09-18 立,⛔ 违反即等于把项目踢出开源)**:① 全文写成「**平行的许可选择**」(parallel choice),⛔ **绝不**写成"对 AGPL 附加的限制";② **文件名刻意不以 `LICENSE` 开头**:免被 licensee 误判为主许可;③ **正文不含项目名**(含新名 / 旧名)⇒ **改名窗口期两版通用**,零泄漏面。
|
||||
> - 🔴 **归档里的自拟 `LICENSE` 不得放回**:`_授权归档_发布时再放回\LICENSE`(5,931 B,自拟「个人免费/商用须书面授权」)的 §三「商业使用必须事先取得书面授权」**放在已发布 AGPL 项目里 = §10 追加限制** ⇒ 正是罗盒案否定、09-17 定案要避开的那一步。**归档 ≠ 照原样拷回**(逐项判定 → `_导出说明与脱敏台账.md` §F)。
|
||||
> - **README 末节** = `## License` / 中文 `## 授权`,承载双轨表述(各 4 段),**授权压轴**符合 R-O12;⚠️ 改后须复核 **英文文档汉字数 = 4**。
|
||||
> - ⛔ **仍有意不带回**:`LICENSE-UPSTREAM-MIT.txt` · `THIRD-PARTY-NOTICES.md`。上游口径:**DeepSeek Harness(MIT,不包含、不分发其代码)**;README 文末保留一行对 `dshs`(MIT)的道义致敬(⛔ 不许删)。
|
||||
> - ✅ **发版前必查**:`LICENSE` 被 OVERLAY 正确恢复 · `package.json` license 由规则生成 · `required present: 60/60` · **README 双轨表述中英同构** · **轨 2 文件存在且中英对等(`_check_parity.mjs` 的 `PAIRS` 已登记)**。
|
||||
|
||||
> 🔴🔴 **两条铁律(2026-09-17 用户连问两轮后确立,不许放宽)**:
|
||||
> 1. **绝不在 AGPL 上加任何限制**:包括「只禁止销售源项目」这种看起来很窄的限制。依据:AGPL **§10** 禁追加 further restriction、**§7** 把非许可性附加条款定义为 "further restriction";且 **OSD 第 6 条「不得歧视任何领域」** ⇒ **判据是「有没有附加限制」,不是「限制多窄」**(Commons Clause 官方对 "Is this Open Source?" 的回答就是 **No.**)。
|
||||
> 2. **也不需要加**:AGPL 的 copyleft **本身就实现了**「防白嫖转售」:想**闭源**改造后销售/托管的人,**§13** 要求其向使用者提供全部修改源码 ⇒ 不愿开源就只能来买商业授权。**这就是双轨的全部机制。**
|
||||
> ⚠️ **两条配套事实**:Commons Clause 原文 "The combined text **replaces** the existing license"(**只能替换、不能叠加**);官方 FAQ "Licenses applied to previous versions are **not revoked**"(**已发布版本收不回** ⇒ 本项目 v1.0.0–v1.2.0 永远是 AGPL)。
|
||||
|
||||
> 📜 **历史(2026-09-13 15:1x – 09-17 的中间状态,仅作留痕,⛔ 不是要求)**:一度把三份授权文件**全部移除**(`LICENSE` / `LICENSE-UPSTREAM-MIT.txt` / `THIRD-PARTY-NOTICES.md`),`package.json` 的 license 回到上游原值 `MIT`;09-14 一度**记录**为「AGPL + 商业授权」,但**当时 README 实际只有 AGPL 单轨**(09-17 核实并改正后真正落地双轨)。原文备份在 **`E:\ProgramData\_已移出项目_授权归档\_授权归档_发布时再放回\`**(⚠️ 09-13 曾误记为"该目录已不存在",**2026-09-18 实测仍在**;恢复步骤见 `_导出说明与脱敏台账.md` §F)。
|
||||
> ⛔ **不要再照那段历史去移除 `LICENSE`**:那会让公开仓库退回「保留所有权利」状态。
|
||||
|
||||
> ⚠️ **硬法律前提(客观事实,任何会话都不许删)**:**上游 DeepSeek Harness 是 MIT,且本项目不包含、不分发其代码** ⇒ 对本项目自有部分采用 AGPL-3.0 **不构成**对上游 MIT 的附加限制。若日后要恢复「个人免费 / 商用收费」的旧思路,仍须**分层**,不得把整个仓库标成「商用需授权」。
|
||||
|
||||
> ⚖️ **中国司法立场(2026-09-17 查证,判例充分,用户问「中国法律是否支持」时直接引这些)**:
|
||||
> · **【支持】协议有效** = 「**附解除条件的著作权许可合同**」(**罗盒案** (2019)粤73知民初207号,**最高法 2021 年十大知产案件**;另有数字天堂案 · 风灵案)。
|
||||
> · **【支持】不开源 = 侵权** ⇒ 授权自动终止 ⇒ 构成侵权:罗盒 **50 万** · 亿邦 (2021)最高法知民终51号 **50 万** · 南京 2022 年案 **300 万**。
|
||||
> · **【支持】收费本身合法**:罗盒案明认「收取会员费仅用于运营维护和技术支持,**不违反 GPL v3**」;**违法的是不提供源码** ⇒ AGPL 防的是「不开源」,**不是**「收钱」。
|
||||
> · **【支持】项目管理人可单独起诉**(最高法知产法庭 2024 年两案)⇒ 维权无需集齐贡献者。
|
||||
> · 🔴 **【不支持】在开源项目里加商业使用限制条款**:罗盒案判决评析原文:「开源软件权利人**不能**在开源项目中添加商业使用限制保留条款来限制用户使用源代码的目的和用户范围,因上述限制保留条款与 GPL V3 协议保证用户自由使用的特性矛盾」。
|
||||
> · ⚠️ **中国暂无 AGPL 直接判例**(判例均为 GPL);实务界将 AGPL 与 GPL 并列为 Copyleft 强传染许可,明确「**AGPL v3 将 SaaS 视为分发**,对云与 SaaS 商业模式构成高风险」⇒ 效力被认可。
|
||||
> · 📌 中国实务界建议:开源作者应选 **OSI 认证许可**,**别用自定义/非 OSI 许可,法律认可度低,难以保障作者知识产权**(反向印证「别用 Commons Clause」)。
|
||||
> ⚠️🔴 **另有一个**不在协议、而在版权基础**的风险(本项目特有)**:中国版权保护中心 **2026 新规「纯 AI 生成的软件不予登记」**,判据 = **人类独创性智力投入**(「春风送来了温柔」案 ✅/「蝴蝶座椅」案 ❌),最高法 2026-09-07 法发〔2026〕10号 已将 AI 生成物权属列重点。✅ **已于 2026-09-17 把口径改为「人负责规划与关键判断,AI 负责实施」**:该口径**恰好确立人类独创性智力投入**,正面对冲这条新规(旧口径「全部代码与文档由 AI 生成」= **自认纯 AI** ⇒ 商业授权缺标的物)。仍有待办:留存人类投入证据 · 考虑软著登记 · 报价前请律师。全部细节 → `<工作根>\_授权决策与法律依据_20260917.md`。
|
||||
|
||||
每次发版要动的地方:`README.md` / `README.zh-CN.md` 的授权节(若条款变)· `LICENSE`(**须保持官方全文逐字节**)· `package.json` 的 `license` 字段。
|
||||
|
||||
---
|
||||
|
||||
## 6. 迭代发布 SOP
|
||||
|
||||
```sh
|
||||
# 0) 先抢全局执行锁(会写文档库/或要动导出物时)
|
||||
cd "/d/github/dsh_shenxian/dsh-server-docs"
|
||||
ME="<会话名>" bash 07-scripts/handoff-guard.sh --claim-exec "<会话名>"
|
||||
|
||||
# 1) 源仓库确认基线(只读)
|
||||
export PATH="/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/usr/bin:/e/ProgramData/.workbuddy/binaries/PortableGit/versions/1.2.0/mingw64/bin:/c/Windows/System32:$PATH"
|
||||
git -C "D:/github/dsh_shenxian" status --short --branch
|
||||
git -C "D:/github/dsh_shenxian" log --oneline -10
|
||||
|
||||
# 2) 若本次要改脱敏/保留口径 → 先改 _build_export.py 的 GLOBAL / INCLUDE_* / DROP_SCRIPTS / OVERLAY
|
||||
|
||||
# 3) 重建(手工撰写层会自动快照→恢复)
|
||||
cd "/e/ProgramData/AIProject/dsh-ai1net-github"
|
||||
"/e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" _build_export.py --force
|
||||
|
||||
# 4) 改版本(三个地方一起改,否则不一致)
|
||||
# package.json 的 version | README.md「版本与迭代」表新增一行 | LICENSE 的版本/日期(条款没变就不用)
|
||||
|
||||
# 5) 六项验证(§7)——**全绿才准交付**
|
||||
|
||||
# 5.5) 【**发布到 GitHub 前必做**】补齐英文版(见 R-O13)——中文是母本,英文此刻才生成
|
||||
# README.en.md + PLUGIN-PORTING.en.md + 两份 README 顶部加语言切换行
|
||||
|
||||
# 6) 交付/推送(**R-O6:未经明确要求不做**)
|
||||
```
|
||||
|
||||
> 📂 **多远端推送细节与坑已下沉** → `references/02-多远端推送.md`(远端表 · 加镜像远端 · CNB 必须后台跑 · 三方同 hash 判据)
|
||||
|
||||
## 7. 验证八件套(缺一不可)
|
||||
|
||||
| # | 验证 | 命令 / 判据 |
|
||||
|---|---|---|
|
||||
| ① | **阻断性探针 0 命中** | 脚本内置 `LEAK_PROBES` 与 `INFO_PROBES` 两档;**`blocking hits: 0`** 才放行。`INFO_PROBES`(`档案` / `交接单`)是**有意保留**的注释引用 |
|
||||
| ② | 未改动文件**逐字节一致** | 抽样 `cmp -s <源> <导出>` → `IDENTICAL` |
|
||||
| ③ | **行尾符不被改写** | `grep -c $'\r'` 两边相等(CRLF 源必须仍是 CRLF) |
|
||||
| ④ | **能编译** | 见下「tsc 验证法」→ `tsc -p tsconfig.json --noEmit` 退出码 **0** |
|
||||
| ⑤ | `install.sh` 语法 | `bash -n install.sh` + `bash install.sh --help` |
|
||||
| ⑥ | **已移除项核对** | 逐一 `[ -e ]` 确认 `docs` / 两个插件目录 / `STANDARD.md` / `lib` / `node_modules` / `.workbuddy` 均不存在 |
|
||||
| ⑦ | 🔴 **发布合规审查**(2026-09-17 补,用户要求) | 对**将要公开的文字**逐字过三关,见下方「合规审查三关」 |
|
||||
| ⑧ | 🔴🔴 **已公开仓库巡检**(2026-09-19 补,用户要求「作为重点」) | **`_check_public.py` 对*所有*已公开仓库 + 新导出物跑一遍,必须 exit 0**(R-O15)。<br>⛔ **本项不可被任何「新仓已经干净了」的说法替代**:存量泄漏只在**已公开仓库**里(事故 #17) |
|
||||
| ⑨ | 🔴 **文案保真门禁**(2026-09-20 补,第九件,表名沿用旧称) | `node "E:\ProgramData\AIProject\_tools\humanizer-metrics\index.js" compare --before <改前> --after <改后> --check-facts`<br>⇒ 判据 = **`All N fact(s) survive` 且 exit 0**。凡改过 README / `manual/` 的文案**必跑**(见坑 35)。<br>⚠️ **它只覆盖硬 token**(数字/日期/版本/URL/路径/标识符),**⛔ 不等于语义等价**:「most」改成「all」这类**它抓不到**,仍须人工读 |
|
||||
|
||||
### 合规审查三关(每次发布前必过)
|
||||
|
||||
| 关 | 扫什么 | 判据 |
|
||||
|---|---|---|
|
||||
| **侵权** | 第三方项目名 / 作者名 / 商标 / 上游仓库的原创文字 | 出现即须处理(按致敬口径写,或删) |
|
||||
| **负面影响** | 事故类词:**事故 · 丢失 · 失败 · 失效 · 忘记 · 混乱 · 崩溃 · 覆盖 · 难以维护**;以及一切**自曝严重问题**的叙述 | ⚠️ **命中不必然要改**:判据是「**这句对外有正面价值吗,还是只在自曝**」。例:「报错而不是静默覆盖」= **设计原则**(fail loud)⇒ 保留;「已两次造成内容丢失」= 自曝事故、且易被误读成**产品可靠性问题** ⇒ 改为只讲**设计动因**,不提已发生的事故 |
|
||||
| **涉政治** | 政治 / 民族 / 宗教 / 地域 / 政府 / 国际关系表述;**国家及地区指称** | 一律避免;涉中国主权与领土的表述必须与中国官方立场一致(港澳台一律写「中国香港 / 中国澳门 / 中国台湾」) |
|
||||
|
||||
**副作用提醒**:收紧措辞后要**同步中英两版**(结构对等、英文汉字数 = 4 的判据不因改词而放宽),并确认 `_overlay` ↔ 仓库**逐字节一致**。
|
||||
|
||||
**tsc 验证法**(导出物没有 `node_modules`,靠**临时联接**;用脚本而不是手敲,**并且绝不能用 recursive 删除**):
|
||||
|
||||
```sh
|
||||
# 脚本已备好:<导出根>\_verify_tsc.mjs(建 junction → 跑 tsc → rmdirSync 拆联接)
|
||||
"/e/ProgramData/.workbuddy/binaries/node/versions/22.22.2-3/node.exe" "<导出根>\_verify_tsc.mjs"
|
||||
# 判据:tsc exit = 0 | junction removed = true
|
||||
# 收尾再确认「导出物无 node_modules 残留」+「源仓库 node_modules 条目数未变」
|
||||
```
|
||||
|
||||
⚠️ **绝不要用 `rm -rf` / `rmSync(…, {recursive:true})` 删这个联接**:在 Windows 上会**顺着联接删掉源仓库的 `node_modules`**。只用 `rmdirSync`(只摘链、不进目标)。
|
||||
|
||||
---
|
||||
|
||||
> 📂 **§8 实测坑整节已下沉** → `references/03-实测坑.md`(**跑重建/脱敏脚本前必读**:文本未落盘 · 行级重写 key · 缩进丢失 · 替换顺序敏感 …)
|
||||
|
||||
> 📂 **§8b 交互式图示整节已下沉** → `references/04-交互式图示-archify.md`(按需抓取 · 流程 · 关键坑 · 双处同步 · 体积)
|
||||
|
||||
## 9. 命令速查
|
||||
|
||||
```sh
|
||||
# 重建
|
||||
cd "/e/ProgramData/AIProject/dsh-ai1net-github"
|
||||
"/e/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" _build_export.py --force
|
||||
|
||||
# 只跑探针/看结构(不重建)
|
||||
grep -rIlF "ai1net" dsh-web-platform/ ; find dsh-web-platform -type f | wc -l
|
||||
|
||||
# 看某文件与源的差异
|
||||
diff -u "D:/github/dsh_shenxian/<f>" "dsh-web-platform/<f>"
|
||||
|
||||
# 行尾对照
|
||||
grep -c $'\r' "<源 f>" ; grep -c $'\r' "dsh-web-platform/<f>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
> 📂 **§10 已知待办 / 漂移整节已下沉** → `references/05-已知待办与漂移.md`(**接手本条线时先读**)
|
||||
|
||||
## 相关
|
||||
|
||||
- 台账(唯一事实源):`_导出说明与脱敏台账.md`(在本工作根下)
|
||||
- 构建脚本:`_build_export.py` | 类型检查:`_verify_tsc.mjs` | 手工层快照:`_overlay\`(三者都在本工作根下)
|
||||
- **插件移植指南**(随仓库发布):`dsh_ai1net\PLUGIN-PORTING.md`:讲「把开源插件改造成多租户平台可用」,含**八个失败模式 H1–H8** 与**六条规范 R-a~R-f**,样本 = `dsh-univer-office`
|
||||
⚠️ **读它的 `## 2.` / `## 3.` 标题取准数**(2026-09-20 修正:此处长期写作「六个失败模式 H1–H6 与五条规范 R-a~R-e」,仓名也还是旧的 `dsh-web-platform`,见坑 36)
|
||||
- 内部权威源(**只读参考,不外带**):`dsh-server-docs/04-调整方案/75-*.md`(托管友好性 + 资源成本两维度)· `76-*.md`(univer 改造全过程)· `71-*.md`(兼容性预检)
|
||||
- 技能:`dsh-workflow`(改动流程与红线)· `dsh-knowledge`(文档库维护)· `dsh-diagnose`(实例故障)
|
||||
- 项目事实:`dsh-server-docs/BRIEF.md`(现行事实)· `dsh-server-docs/CODEBUDDY.md`(动作前规则)
|
||||
|
||||
## 详情索引(references/)
|
||||
|
||||
> 本技能 = **主干(本文件)+ 详情档**。主干只留判据 / 流程主干 / 命令骨架;长表、案例、实测记录、历史细节在下面各档。
|
||||
>
|
||||
> **跨档引用怎么查**:主干与详情档正文里出现的「§N」「见 §8 坑 N」「见下表 / 见上表」等编号,**按本表的「覆盖的原章节」列定位到对应档**(下沉后原编号不再有独立章节标题)。
|
||||
|
||||
| 详情档 | 覆盖的原章节 | 原行段 | 行数 |
|
||||
|---|---|---|---|
|
||||
| `references/01-保留移除与脱敏口径.md` | 保留 / 移除清单 · 保留 · 移除 · 本就不在代码仓(别去找) · 特许保留项 · 待决项 · 脱敏映射表 · 保留未动(刻意) | L382–L480 | 99 |
|
||||
| `references/02-多远端推送.md` | 多远端推送 | L545–L583 | 39 |
|
||||
| `references/03-实测坑.md` | 实测坑(全部踩过,别再踩) | L621–L703 | 83 |
|
||||
| `references/04-交互式图示-archify.md` | 交互式图示:用 Archify 生成并入库 · ⛔ 不要克隆整仓 · 流程(每个图型同一套) · 🔑 关键坑 · 入库 · 体积 | L704–L776 | 73 |
|
||||
| `references/05-已知待办与漂移.md` | 已知待办 / 漂移(接手先看) | L796–L1080 | 285 |
|
||||
@@ -0,0 +1,109 @@
|
||||
# 保留 / 移除清单 · 脱敏映射表 · 保留未动(改口径先改这里)
|
||||
|
||||
> **归属**:技能 `dsh-opensource-release` 的详情档(**按需读**,不是每次都要读)。
|
||||
> **本档覆盖**:保留 / 移除清单 · 保留 · 移除 · 本就不在代码仓(别去找) · 特许保留项 · 待决项 · 脱敏映射表 · 保留未动(刻意)(原行 L382–L480)。
|
||||
> **主文件 / 判据与流程主干** = `../SKILL.md`(§0.5 事故清单 · §0 事实 · §1 硬规则 R-O1–R-O17 · §1.5 用户当场纠正的硬口径 · §5 授权结构 · §6 发布 SOP 主干 · §7 验证八件套 · §相关)。
|
||||
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L382–L480 段**逐行原样**下沉到本文件,未改一字。
|
||||
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
|
||||
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
|
||||
|
||||
---
|
||||
## 2. 保留 / 移除清单(delta · 改口径先改这里)
|
||||
|
||||
### 保留
|
||||
|
||||
```
|
||||
assets/ 注入脚本(2:inject/recovery.js · inject/assist.js)—— ⚠️ **proxy.ts 的 loadInject 按包根解析 ⇒ 缺了平台启动即抛错**,必须随包
|
||||
src/ 控制面 TS 源码(**已剔除 6 个 K8s 后端模块**,见下)
|
||||
web/ 静态页
|
||||
scripts/ 运维与冒烟脚本(**已剔除 5 个 K8s / 已排除插件相关脚本**)
|
||||
test/ 单测(**已剔除 2 个 K8s 模块的测试**)
|
||||
.github/workflows/build.yml
|
||||
package.json package-lock.json tsconfig.json cordis.patch.yml
|
||||
Dockerfile .dockerignore .gitignore(重建)
|
||||
mksess.cjs ensure-role-profile-patch.cjs(临时会话 / profile 补丁)
|
||||
```
|
||||
|
||||
> 🔴 **K8s 相关一律不带**(2026-09-14 用户定稿,2026-09-15 升级为**长期策略**):
|
||||
> ⛔ **不再保留** `deploy/`(11 个 K8s 清单)· `poc/`(4 个 K8s 可行性验证件)· `Dockerfile.dsh`(每用户 Pod 镜像)·
|
||||
> 6 个 K8s 后端模块(`k8s-spawner` `k8s-user-fs` `leader` `reconcile` `tcp-bridge` `web/file-service`)·
|
||||
> 2 个 K8s 测试 · `smoke-file-service.mjs` · CI 里的 dsh 镜像步骤 · `config.ts` 的 K8s 专属配置项 ·
|
||||
> 以及**全部 k8s 注释与语义描述**。
|
||||
> ✅ **保留** `src/db/pg.ts`(Postgres = 共享 HA,**不是** K8s 专属)。
|
||||
> 📌 **权威清单与处置办法**:**`_K8s排除台账.md`**(本工作根下),含「下次取新版本怎么做」的步骤与判读表;
|
||||
> 扫描器 **`_k8s_scan.py`**(`--source` 扫源仓 / 不给参数扫导出物);判定标准 = 构建 **`blocking hits: 0`**。
|
||||
|
||||
### 移除
|
||||
|
||||
| 路径 | 理由 |
|
||||
|---|---|
|
||||
| `poc/business-plugins/` | **已投放插件**(功能管理分区插件,含全部 `.tgz`) |
|
||||
| `poc/workspace-scoped-picker/` | **已投放插件**(目录选择器) |
|
||||
| `scripts/ensure-anysearch-admin.cjs`<br>`scripts/ensure-anysearch-pool.mjs` | 特定插件投放脚本 |
|
||||
| `scripts/ensure-biz-plugins.cjs`<br>`scripts/ensure-portal-entry.cjs`<br>`scripts/install-workspace-picker.sh`<br>`scripts/provision-new-users.sh` | 插件 / 本平台专属投放与开通脚本 |
|
||||
| `docs/`(7 篇) | R-O4:项目文档 |
|
||||
| `STANDARD.md` · `poc/README.md` · `poc/*/README.md` | R-O4:文档 |
|
||||
| `.workbuddy/` · `lib/` · `node_modules/` · `data/` | 本地状态与构建产物 |
|
||||
| **`.git`** | ⛔ 历史里含全部内部信息 ⇒ **必须全新仓库** |
|
||||
| 全部 `*.tgz` | 构建产物 |
|
||||
|
||||
### 本就不在代码仓(别去找)
|
||||
|
||||
**MCN 工作台(`dsh-plugin-mcn-suite`)、douyin-accounts、vision-router、各 skill 本体(含 MCN 相关 skill)** 都不在 `dsh_shenxian` 里,它们在其他仓库 / 实例 profile。收尾探针会复核 `mcn` / `douyin` / `抖音` / `vision-router` **0 命中**。
|
||||
|
||||
### ⚠️ 特许保留项(**不要在脱敏里动它**)
|
||||
|
||||
| 项 | 处置 | 依据 |
|
||||
|---|---|---|
|
||||
| **`dsh-univer-office`**(插件名 + 实例侧 unix-socket 适配) | **保留原名、保留代码**:`src/supervisor/orchestrator.ts` 的 `DSH_INSTANCE_UNIVER_SOCKET` / `UNIVER_DSH_GATEWAY_SOCKET` 段**不得删**;`src/web/routes/whitelist.ts` 注释里点名 `dsh-univer-office`;探针 `LEAK_PROBES` 里**不得**出现 `dsh-univer` / `UNIVER` | 用户 2026-09-13:「univer 可以保留这个插件 专门讲讲如何把开源插件改造为可在多租户平台运行」 |
|
||||
| ↳ 为什么值得保留 | 它是 `PLUGIN-PORTING.md`(插件移植指南)的**唯一实证样本**:一个「静态预检通过但在托管平台完全不可用」的真实案例,含两层根因、3 条设计决策、2 个平台侧机制坑 | 同上 |
|
||||
|
||||
### 待决项(用户没拍板前维持现状)
|
||||
|
||||
- `poc/business-plugins` + `poc/workspace-scoped-picker`:现按**严格口径移除**(「所有已投放的插件」)。若判定它们属「平台自带界面」而非投放插件 → 加回,并同步改本节 + 探针。
|
||||
|
||||
---
|
||||
|
||||
## 3. 脱敏映射表(**唯一口径**,改只改这里 + 脚本里的 `GLOBAL`)
|
||||
|
||||
| 类别 | 原值 | 替换为 | 命中 |
|
||||
|---|---|---|---|
|
||||
| 平台域名 | `dsh.alotbuy.com` / `*.ai1net.com` / `ai1net` | `<baseDomain>` | 3 文件 |
|
||||
| ↳ **特例** | `web/wake.html` 的 `safeNext()` 正则 | 改成**运行时从 `location.hostname` 推导注册域**(`split('.')` 去最左一段),彻底去硬编码 | — |
|
||||
| 服务器公网 IP | `47.77.182.89` | `<SERVER_PUBLIC_IP>` | 1 |
|
||||
| 宿主内网 IP | `172.18.16.212` | `<HOST_LAN_IP>` | 1 |
|
||||
| 服务器代码路径 | `/opt/dshs` | `<INSTALL_DIR>` | 8 |
|
||||
| ↳ **特例** | `require('/opt/dshs/node_modules/better-sqlite3')` | `require('better-sqlite3')`(等价且更规范) | — |
|
||||
| 服务器平台目录 | `/opt/dsh/{state,artifacts,backups}` | `/var/lib/dsh-web-platform/{state,artifacts,backups}`(与上游文档一致的数据根) | 6 |
|
||||
| **内部档案号** | 全角/ASCII 括号里的 `档案 NN`(含 `档案 81 · R1`、`(档案 20)`、`backoff (档案 20)`) | **整块删**(号无对外意义);残渣(空括号 `()` / ` ().`)由后续规则清掉 | 183 |
|
||||
| **悬空文档引用** | `docs/k8s.md §5.2` / `docs/blueprint.md` / `docs/domain-config.md` | 映射到 README 真实小节(`README「部署形态」` / `README「架构」` / `README「配置」`);`§号` 一并去掉 | 42 |
|
||||
| ↳ **实现位置** | 以上两项由 `_build_export.py` 的 **`REGEX_RULES`** 做(不是 `GLOBAL`);⛔ **清理规则只准碰全角标点**,唯一放开的两条 ASCII 规则:① `(档案 NN)`(模式里必须有档案号 ⇒ 不会误伤 `foo()`)② ` ().`+句末标点(`(): void` 后面是 `:` ⇒ 不命中)。**每次改 REGEX_RULES 必须重建 + `tsc` 复核**(第一次踩过:ASCII 括号进字符类把 `foo()` 删了,tsc 报 Invalid character) | — |
|
||||
| ↳ tar 相对写法 | `opt/dsh*`(无前导斜杠) | `var/lib/dsh-web-platform*` | — |
|
||||
| 账号 / 私有仓库 | `maogeigei`、`[email protected]:...dsh_shenxian_doc.git` | `<YOUR_GITHUB_ACCOUNT>`;文档库引用随 README 重写整体移除 | 1 |
|
||||
| 云厂商标识 | 「阿里云内网 DNS」「BT-Panel 58888/8765」「sshd 22/32022」 | 「云厂商内网 DNS」「面板」「sshd」 | 1 |
|
||||
| 插件具体名 | `anysearch` / `@anysearch/anysearch-dsh` / `@liustack/modlens` / `mcn-workstation` | 「该插件」/「某第三方插件」→ 再**整行重写**成中性描述 | 6 |
|
||||
| ↳ **例外(保留原名)** | **`dsh-univer-office`** 与其实例侧适配(`DSH_INSTANCE_UNIVER_SOCKET` / `UNIVER_DSH_GATEWAY_SOCKET`) | **不脱敏、不删代码**(用户 2026-09-13 明确「可以保留这个插件」);它同时是 `PLUGIN-PORTING.md` 的实证样本 ⇒ 其 env 名、注释、`DELETE_LINES` 条目**都不得再动** | 3 |
|
||||
| **项目改名** | `dshs` 全部自指标识 | `dsh-web-platform`(规则顺序:`dshs.db` → `dshs.db` → `/var/lib/dshs` → `DSHS_` → `dshs`) | 149 |
|
||||
| ↳ **必须保留** | `上游骨架仓库(已按要求不再具名)`、`上游 \`dshs\`` | **原样不动**(出处/致谢);`LICENSE`(**AGPL-3.0 官方全文**)逐字节不动 | — |
|
||||
|
||||
**发布前必须替换的占位符**(写在台账里):
|
||||
|
||||
| 占位符 | 出现位置 |
|
||||
|---|---|
|
||||
| `<YOUR_GITHUB_ACCOUNT>` | `README.md`、`package.json` → repository |
|
||||
| ~~`<CONTACT_EMAIL>`~~ | 原为 `README.md` 授权章节 / `LICENSE`,**授权章节与 LICENSE 已于 2026-09-13 移除**,该占位符随之消失(见 §5) |
|
||||
| `<COPYRIGHT_HOLDER>` | `LICENSE` |
|
||||
| `<SERVER_PUBLIC_IP>` / `<HOST_LAN_IP>` | `scripts/install-egress-guard.sh`(部署时按实际服务器填) |
|
||||
| `<INSTALL_DIR>` / `<baseDomain>` | 仅注释,可留 |
|
||||
|
||||
> `install.sh` 里的 `dsh.example.com` / `[email protected]` 是文档示例,符合惯例,**不改**。
|
||||
|
||||
---
|
||||
|
||||
## 4. 保留未动(刻意)
|
||||
|
||||
- **183 处「档案 NN」内部编号引用**(仅代码注释):属内部档案号,**不是**本机/服务器信息。已列入「可选后续」;要清需用户点头(做一次纯注释替换)。
|
||||
- 上游 `docs/` 内容虽为 MIT 可带走,但 R-O4「不带任何文档」⇒ 不带。
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# 多远端推送(GitHub 主仓 + CNB 镜像)
|
||||
|
||||
> **归属**:技能 `dsh-opensource-release` 的详情档(**按需读**,不是每次都要读)。
|
||||
> **本档覆盖**:多远端推送(原行 L545–L583)。
|
||||
> **主文件 / 判据与流程主干** = `../SKILL.md`(§0.5 事故清单 · §0 事实 · §1 硬规则 R-O1–R-O17 · §1.5 用户当场纠正的硬口径 · §5 授权结构 · §6 发布 SOP 主干 · §7 验证八件套 · §相关)。
|
||||
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L545–L583 段**逐行原样**下沉到本文件,未改一字。
|
||||
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
|
||||
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
|
||||
|
||||
---
|
||||
### 6b. 多远端推送(2026-09-18 定型:GitHub 主仓 + CNB 镜像)
|
||||
|
||||
| 远端 | 地址 | 备注 |
|
||||
|---|---|---|
|
||||
| `origin` | `[email protected]:maogeigei/dsh-users-platform.git` | **主仓**(SSH,密钥顺序见 §8 坑) |
|
||||
| `cnb` | `https://cnb.cool/maogeigei/dsh-users-platform.git` | **镜像**(HTTPS + 凭据管理器,凭据已保存 ⇒ 无需配 SSH) |
|
||||
|
||||
```sh
|
||||
cd "/e/ProgramData/AIProject/dsh-ai1net-github/dsh-users-platform"
|
||||
# 加镜像远端(一次即可)
|
||||
git remote add cnb https://cnb.cool/maogeigei/dsh-users-platform.git
|
||||
|
||||
# ⛔ 只推 main —— 本地备份分支(backup-before-orphan-*)含改名泄漏期旧内容,绝不外推
|
||||
GIT_TERMINAL_PROMPT=0 git push origin main # 主仓
|
||||
|
||||
# ⚠️ CNB 首次/大推送**必须后台跑**:实测前台 180s 被 SIGTERM 杀掉
|
||||
# (仓库仅 1.67 MB、207 objects ⇒ 与体积无关,是连接/服务端处理慢),
|
||||
# 后台运行 20s 完成。⇒ 用 run_in_background,别用前台短超时。
|
||||
GIT_TERMINAL_PROMPT=0 git push cnb main # 镜像
|
||||
|
||||
# 核对「三方同 hash」——这是多远端同步的唯一验收判据
|
||||
git ls-remote origin refs/heads/main | cut -c1-12
|
||||
git ls-remote cnb refs/heads/main | cut -c1-12
|
||||
git rev-parse --short=12 HEAD
|
||||
```
|
||||
|
||||
⚠️ **README 里的 clone 地址保持指向主仓(GitHub)**,不改指镜像:这是「多远端同步」的正常形态,CNB 页面自带克隆按钮。若要改指 CNB,属改变对外口径,先问用户。
|
||||
|
||||
|
||||
**版本号约定**:遵循语义化版本。写 README 版本表时**同时写「类型」列**(首个公开发布 / 特性 / 修复 / 内部迭代)。
|
||||
|
||||
**登记格式**(README「版本与迭代」表):
|
||||
|
||||
```
|
||||
| **v1.1.0** | 2026-10-xx | 特性 | 一句话摘要(对外能看懂,不写内部档案号)。 |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# 实测坑(全部踩过,别再踩)
|
||||
|
||||
> **归属**:技能 `dsh-opensource-release` 的详情档(**按需读**,不是每次都要读)。
|
||||
> **本档覆盖**:实测坑(全部踩过,别再踩)(原行 L621–L703)。
|
||||
> **主文件 / 判据与流程主干** = `../SKILL.md`(§0.5 事故清单 · §0 事实 · §1 硬规则 R-O1–R-O17 · §1.5 用户当场纠正的硬口径 · §5 授权结构 · §6 发布 SOP 主干 · §7 验证八件套 · §相关)。
|
||||
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L621–L703 段下沉到本文件;同日按 humanizer 技能做了一轮「人话化」措辞修订,技术标识、判据与条目数未动。
|
||||
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
|
||||
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
|
||||
|
||||
---
|
||||
## 8. 实测坑(全部踩过,别再踩)
|
||||
|
||||
1. **`text` 被重新赋值导致替换未落盘**:脱敏函数里 `text = text.replace(...)` 之后再用 `if text2 != text` 判「是否需要写盘」⇒ 全局替换**永远不落盘**(只落行级改动)。**必须留 `orig = text` 做比较基准。**
|
||||
2. **行级重写的 key 必须写「全局替换之后的文本」**:例:原行 `(档案 70 的 anysearch 事故…)`,key 要写 `(档案 70 的 该插件 事故…)`。用替换前的原文当 key ⇒ 静默不命中,留下半吊子句子。
|
||||
3. **行级重写会丢缩进**:按 `strip()` 匹配就必须把**原行的 indent 补回去**(多行替换值还要给后续行也加 indent),否则 TS 缩进错乱。
|
||||
4. **全局替换顺序敏感**:`wake.html` 的专用规则必须在笼统的 `ai1net → <baseDomain>` **之前**,否则专用规则永远不命中(会被先替换成 `<baseDomain>.com` 这种半成品)。
|
||||
5. **重建会抹掉手写文件**:所以有 `OVERLAY`(先快照 `_overlay/` 后恢复)+ `--force` 安全闸。**验证过一次**:重建后 5/5 个 overlay 文件逐字节一致。
|
||||
6. **`.git` 绝不能带过去**:历史里含全部内部信息;必须是**全新仓库**。
|
||||
7. **Windows 下 `install.sh` 没有执行位**:README 一律写 `sudo bash install.sh`;要执行位就 `chmod +x` 后再提交。
|
||||
8. **别信「探针没命中」的直觉**:探针必须**在重建之后、还原 overlay 之后**跑(overlay 里也可能带泄漏)。
|
||||
9. ⛔ **绝不对 `_build_export.py` 本身做批量替换**:脚本里同时存在「源模式」与「目标值」(例如规则 `("dshs", "dsh-web-platform")`),盲替会把**源模式**一起改掉 ⇒ **改名规则静默失效**(2026-09-13 实际误伤 4 处)。改脚本只用精确 `Edit`,改完**必须重建一次并用 grep 复查**。
|
||||
10. **`Dockerfile` / `Dockerfile.dsh` 曾被整份跳过脱敏**:`is_text()` 按扩展名判断,二者无扩展名(或 `.dsh` 不在白名单)⇒ 漏掉。已在 `is_text()` 里加特判。
|
||||
11. **`package.json` 属「源派生」而非 OVERLAY**:手改 version / description / repository / license 会在下次 `--force` **被覆盖**。这类项目自有字段必须写成 **GLOBAL 规则**。
|
||||
12. **`dshs.db` 是无前缀写法**:`src/config.ts` 里默认库文件名不带 `dsh-` 前缀,只替换 `dshs` 会漏掉它;要单独一条规则。
|
||||
13. **改名要连导出目录名一起改**,并同步两个辅助脚本里的绝对路径(`_build_export.py` 的 `DST`、`_verify_tsc.mjs` 的 `EX`),改完**重跑一次 tsc** 验证路径仍对。
|
||||
14. **废弃的旧候选名要进阻断性探针**:改名改了两轮时(`dshs` → 中间候选 → 终选),如果探针只查最早那个名字,**中间名会静默残留**(`_overlay` 里最容易中招)。做法:把**所有曾用名**都加进 `LEAK_PROBES`。
|
||||
15. **改 overlay 的自指标识可以做批量替换**(overlay 里只有本项目自己的标识,上游出处名是另一个字符串),但**必须先用 grep 确认「旧名出现处全是自指」**再替换;`_build_export.py` 本身**绝不**能这么干(见坑 9)。
|
||||
16. 🔴 **`--claim-exec` 的输出必须当场看;claim 与 release 绝不能写进同一条命令**(2026-09-13 **实际闯祸**):把 claim 结果重定向到文件、只显示 `OWNER` 首行 ⇒ **没发现抢锁失败**;命令末尾的 `--release-exec` 是 `rm -rf` 语义,于是**把另一个会话(`R1-注入层-1104`)的锁删掉了**。正确姿势:
|
||||
- 抢锁**单独一条命令**,且**当场看它的输出**(`✓ 已持全局执行锁` vs `✗ 抢锁失败`);
|
||||
- 看到「占用者」不是自己就**立即停手**,不碰文档库/代码库;
|
||||
- **放锁前再 `cat 05-交接单/.exec-lock/OWNER` 确认首行是自己**;
|
||||
- 万一误放:脚本实现是 `rm -rf "$LOCKEXEC"`、**不留档**,只能按 `handoff-guard.sh` 第 43 行的格式原样重建(`OWNER` / `开始:MM-DD HH:MM` / `在做:…`,值取自抢锁失败时的输出),再用 `bash 07-scripts/handoff-guard.sh` 的信息模式验证「占用者」已回到原会话,并**在回复里明确告知用户**;若该会话其实已结束,请用户自行撤锁(处置权只属于用户)。
|
||||
17. 🔴 **迁移工作根:先改脚本常量,再搬目录**(2026-09-13 实际踩):顺序颠倒(先 `mv` 后改 `OUT`)时,任何一次重建都会**在旧位置把整个仓库重新建出来**(那次建出 135 个文件),而且因为旧位置**没有 `_overlay`**,**6 个手工层文件(README / LICENSE / NOTICE / PLUGIN-PORTING / install.sh / LICENSE-UPSTREAM-MIT)全部缺席**;若此时旧目录被当成交付物,就是一次「文档凭空消失」的事故。
|
||||
**正确顺序**:① 改 `_build_export.py` 的 `OUT` **和** `_verify_tsc.mjs` 的 `EX` → ② 复制/搬运目录 → ③ 在新位置重建 → ④ 核对 `文件数` 与**手工层 6/6** + 跑 `tsc` → ⑤ **`ls` 确认旧位置不存在**(没被重建复活)→ ⑥ 同步本技能与项目 MEMORY 里的路径引用。
|
||||
⚠️ 附带教训:`_build_export.py` 的安全闸与 OVERLAY 机制**都依赖 `OUT` 指向真实工作根**;`OUT` 指错时它**不会报错**,只是**在别处默默新建一套**。
|
||||
18. 🔴 **`INCLUDE_DIRS` / `INCLUDE_FILES` 是白名单:漏了不报错,只是少文件**(2026-09-13 实际踩:`assets/` 漏收录 ⇒ 导出的仓库缺注入脚本,平台会 fail-fast、自带校验脚本也会失败)。**两条防线**:
|
||||
- **`REQUIRED_EXPORT` 清单**(脚本内,26 项):构建时逐个 `os.path.exists`,**缺一即 `return 1`**;新增"运行时要读的文件"必须加进去。
|
||||
- **用被导出仓库自带的校验脚本验收**:`node scripts/verify-inject.cjs`(读 `assets/inject/*.js` + 检查 `proxy.ts` 走 `loadInject`)。这比"我看了一眼目录"可靠得多。
|
||||
⚠️ 同类风险点:`package.json` 的 `files`(npm/git 安装按它过滤,与 `INCLUDE_*` 是**两套名单**,都要补)。
|
||||
19. 🔴🔴 **`cp _overlay/<f> <仓>/` 会把「下一版内容」整份带进当前版**(2026-09-18 血证,已误发上公网):`_overlay/` 在**改名窗口期**是「未来版」,导出仓是「当前版」;为修一处残留引用而 `cp _overlay/README.md` 覆盖旧仓,就把 **新名 + 新中文名 + `git clone …/<新仓>.git` + `cd <新仓>` + `systemctl is-active <新仓>`** 一并推了上去。
|
||||
⛔ **真实危害不是"名字不对"而是功能性缺陷**:README 让用户 clone 的那个仓库当时**是空的**(只有建仓提交)⇒ **照 README 做的人克隆到空仓库,部署直接断**。
|
||||
✅ **规矩**:`_overlay` 处于下一版状态时**绝不整文件 `cp` 到导出仓**,只准**逐处精确 `Edit`**,只落本次要发的那几段。
|
||||
⚠️ **最阴的一点**:这种误覆盖会让「导出仓 vs `_overlay` 的 diff **变空**」。**diff 为空本身就是"新版被覆盖进去"的证据**,不是"一致"的好消息。**看到意外的一致要停下来查原因。**
|
||||
✅ **推前必做两条复核**:① `grep -rn "<新名>\\|<新中文名>" .` ⇒ **须为空**;② **部署命令自洽** —— `git clone` 指向的仓库**真有内容**、`cd` 的目录名、`systemctl` 的服务名三者一致。
|
||||
20. 🔴 **新增「中英文件对」时必须同步登记**(2026-09-18 实证;**2026-09-19 扩充为四处**):
|
||||
这份清单是**白名单**:没登记的对象**不会报错,只是静默跳过检查**。所以新增 `manual/X.md` + `manual/X.zh-CN.md` 时,**四处一起改**:
|
||||
① `_build_export.py` 的 `OVERLAY`:漏了 ⇒ **静默少带**,文件根本不在导出物里;
|
||||
② `_build_export.py` 的 `REQUIRED_EXPORT`:漏了 ⇒ 缺文件**不报错**(它只查"清单里的在不在");
|
||||
③ **`_check_parity.mjs` 的 `MANUAL`/`PAIRS`**:漏了 ⇒ 该对**静默跳过**对等检查(标题数 / 表格行数 / 图数 / 英文汉字数全不检);
|
||||
④ **`_check_links.mjs` 的 `MANUAL`**:漏了 ⇒ 该文档**整份不参与**链接与锚点检查。
|
||||
🔴🔴 **③ 与 ④ 是两份独立实现**(不 import 同一常量)⇒ **必须各改一次**,改一处不算改。
|
||||
✅ **验收判据(别只看 exit code)**:**回读检查器自己报告的文档数有没有 +N**,本轮实测 `links` **24 → 26**、`parity` 输出里多出 `manual/contributing.md` 一行(headings 4/4)。
|
||||
⚠️ **同类静默跳过已出现四次**(坑 18 `INCLUDE_*`/`REQUIRED_EXPORT`、坑 20 的两份 `MANUAL`)⇒ 判据统一为:**凡"清单式"机制,新增对象后必须回读清单计数是否 +N**(AST 实读,别数文件)。
|
||||
21. **`COMMERCIAL-LICENSE.*` 的落位规矩(2026-09-18 立)**:① 只在**四份 README**(仓 + `_overlay/` 各中英)授权节尾加**一句**链接,⛔ 不在正文铺开;② ⛔ **不得**把「商用须授权」的句子写进 `LICENSE` 或 README 的 AGPL 段落(那才是 §10 追加限制);③ 英文版**汉字数仍须恒为 4**(只在顶部入口行出现「中文文档」)。
|
||||
22. 🔴🔴 **`sanitize()` 不作用于 `OVERLAY`,所以「干跑预演通过」≠「构建能过」**(2026-09-19 血证)——
|
||||
`restore_overlay()` 排在 `sanitize()` **之后** ⇒ 手工层(README / manual / LICENSE / install.sh …)**永远不会被脱敏**,上面任何字面量都会原样进公开仓。
|
||||
实测:`manual/decisions.{md,zh-CN.md}` 里一行目录树写着 `poc/`(该目录从未收录)⇒ **重建时被阻断探针抓出 `blocking hits: 2`**。
|
||||
⇒ **纪律**:① 改完手工层**必须重建**(或至少跑整树探针);② 若写了「干跑预演」脚本,**它只覆盖源派生文件,不能当手工层的通行证**;③ 命中后按「**先改仓库同名文件 → 再 `Copy-Item` 进 `_overlay`**」的顺序修(反了会被 `stash_overlay()` 覆盖回去)。
|
||||
23. 🔴 **裸替换「纯字母数字」的内部标识会改坏 `package-lock.json`**(2026-09-19):
|
||||
内部主机号 `w106`/`w47` 全由 base64 字母表字符组成 ⇒ 裸替会命中 `integrity` 哈希,**`npm ci` 校验失败**,且症状与改动毫无关联、极难排查。
|
||||
⇒ 只替**带引号**或**作对象键(后跟冒号)**的形态;**纯数字标识(如 `15432`)也要先扫一遍上下文**再决定(本轮实测 11 处全在 `127.0.0.1:15432` 这类 URL 里,安全)。
|
||||
24. 🔴 **改名之后,新项目名可能与旧脱敏规则「撞名」**(2026-09-19):
|
||||
新名 `dsh_ai1net` 含 `ai1net`,而 `ai1net` 同时是**真实域名**的词根 ⇒ 若照旧写一条笼统的 `ai1net` → `<baseDomain>`,会把新名打成 `dsh_<baseDomain>`。
|
||||
⇒ **只打带 `.com` 的域名形态**(`dsh_ai1net` 永不含 `.com`)。**同理**:任何"新名包含旧敏感词根"的情形,规则都必须**精确到可区分的形态**,并**规则 + 探针同时加**。
|
||||
25. **内部运维 / 演练 / 诊断脚本族的排除判据(2026-09-19 定型)**:新增一整批 `*-probe` / `*-drill` / `*-jitter` / `*-entropy` / `bootstrap-*.sh` / `dshlog.mjs` / `find-ui*` / `check-layering*` 时按四条判:
|
||||
① **README / manual 从不引用它**;② 含内部主机号 / 测试机 IP / 内部隧道端口;③ 引用内部文档(`交接单` / `调整方案` / `poc/`);④ 是「把节点接进本平台自研编排」的一次性手册。
|
||||
⇒ 四条全中 = 与 **K8s 那一族同处置(整批 drop)**,别试图逐条脱敏(脱完也不可用,且留下一堆 `<>` 占位符)。
|
||||
⚠️ **`.py` 这类脚本进来时先看 `TEXT_EXT`**:不在白名单的扩展名**整份跳过脱敏且不被任何探针扫**(本轮 `.py` 就踩了,已补)。
|
||||
26. 🔴🔴 **只改手工层(`OVERLAY`)文字时,不必整树 `--force` 重建**(2026-09-19 定型,**是坑 22 的推论**):
|
||||
坑 22 已证 `restore_overlay()`(纯 `shutil.copy2`)排在 `sanitize()` **之后** ⇒ 手工层**不过脱敏、逐字节直落**。
|
||||
⇒ **「改 `_overlay/<f>` + 跑 `_sync_overlay.py`(方向 `_overlay` → 导出仓)」得到的产物,与整树重建逐字节相同。**
|
||||
✅ **收益**:风险面从**整棵树**缩到**改的那几个文件**,不会顺带把源仓当前状态(别人的未提交改动 / 新提交 / `??` 目录)带进公开仓,
|
||||
也就不必先过 `dirty_src_files()` 那道闸门(省掉一轮「等源仓干净」的阻塞)。
|
||||
⚠️ **前提与边界**:① 改动**必须落在 `OVERLAY` 清单内**;非手工层文件**只能**「改规则 + 重建」;
|
||||
② 仍须 `_sync_overlay.py --check` 报**「逐字节一致」**再提交(方向搞反 = 事故 #27);
|
||||
③ 交付前仍跑**全套门禁**(`_check_dst` 整树探针 / `_check_public` 两仓 / links / parity / tsc),
|
||||
其中 `_verify_tsc.mjs` 与 `_check_public.py` **必须串行**(junction 假阳性)。
|
||||
④ 若这轮**同时**还有规则改动,就必须回到整树重建 —— 捷径只适用于「纯手工层文字」。
|
||||
27. 🔴🔴 **写文档用词之前,先 grep 整个代码库,确认这个词有没有被别的意思占用**(2026-09-19 用户点出):
|
||||
实测:`manual/project*.md` 里用「**水位**」表达「上下文已占用量」⇒ ① 对读者是**类比**(要先自己换算);
|
||||
② **更硬的是术语撞车** —— `水位` 在本项目**已有两个别的含义**:`src/net/relay/client.ts:150` = **WS 出向水位**(字节,默认 256 KiB)、
|
||||
`src/db/schema.ts:301` = **worker 容量水位**。同一个词在文档 + 代码里指**三样**东西,**这是歧义,不是风格**。
|
||||
⇒ **改法:贴回同段前一句已经引入的项目词**(该段前半句是「上下文被当作**有上限的预算**」)⇒
|
||||
ZH `其次是**上下文已经占了多少**` | EN `then **how much of the context is already used**`。⛔ **不另造新比喻**。
|
||||
🔑 **为什么必须单独立一条**:**探针体系对这类问题完全无感**,该文件所在 `manual/` 没有任何探针,
|
||||
`blocking hits: 0`、required 全在、两仓 0 命中 ⇒ **门禁全绿,而词依然是坏的**。
|
||||
判据:**探针只答「有没有不该出现的敏感信息」,不答「这个词会不会产生歧义」。**
|
||||
⛔ **同一段里另有 5 处类比,用户只点了一处 ⇒ 一律不动,列条目报上去等拍板**(`背着这份重量` / `腐坏` / `悄悄搭车` / `淹没` / EN 独有 `blast radius`)。
|
||||
**同段同病也不许自行扩大改动面**:报清单的成本是一个回合,擅改的成本是信任。
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# 交互式图示:用 Archify 生成并入库
|
||||
|
||||
> **归属**:技能 `dsh-opensource-release` 的详情档(**按需读**,不是每次都要读)。
|
||||
> **本档覆盖**:交互式图示:用 Archify 生成并入库 · ⛔ 不要克隆整仓 · 流程(每个图型同一套) · 🔑 关键坑 · 入库 · 体积(原行 L704–L776)。
|
||||
> **主文件 / 判据与流程主干** = `../SKILL.md`(§0.5 事故清单 · §0 事实 · §1 硬规则 R-O1–R-O17 · §1.5 用户当场纠正的硬口径 · §5 授权结构 · §6 发布 SOP 主干 · §7 验证八件套 · §相关)。
|
||||
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L704–L776 段**逐行原样**下沉到本文件,未改一字。
|
||||
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
|
||||
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
|
||||
|
||||
---
|
||||
## 8b. 交互式图示:用 Archify 生成并入库(2026-09-18 定型)
|
||||
|
||||
**工具**:[`tt-a1i/archify`](https://github.com/tt-a1i/archify)(MIT):把带类型的 JSON IR 编译成经校验的自包含 SVG/HTML。落地位置 `E:\github\archify`(含 `archify/bin/archify.mjs`)。
|
||||
|
||||
### ⛔ 不要克隆整仓(8835 objects,实测 ~1KB/s,前台 180s 被 kill)
|
||||
✅ **按需抓取**(快 25 倍,36KB/s):
|
||||
1. `curl https://api.github.com/repos/tt-a1i/archify/git/trees/main?recursive=1` 拿文件树
|
||||
2. 筛 `archify/**`,**排除 `test/` 与 `examples/*.html`**(预渲染样例,4MB)
|
||||
3. 逐个 `raw.githubusercontent.com/tt-a1i/archify/main/<path>` 抓(76 文件 / 2.33MB / 3.5 分钟)
|
||||
4. `node bin/archify.mjs doctor` 自检(应五个渲染器全 `[ok]`)
|
||||
|
||||
### 流程(每个图型同一套)
|
||||
```sh
|
||||
# 1) 先读「一个 schema + common.schema.json + 一个同类示例」---- 只读这三份
|
||||
# 2) 直接写候选 JSON(不要在正文里规划坐标)
|
||||
# 3) 校验:showcase 必须 9/9 + 0 错 0 警
|
||||
node bin/archify.mjs validate <type> <cand.json> --quality showcase --json
|
||||
# 4) 交付:deliver 才是最终验收(会重新渲染、重新检查、原子替换)
|
||||
node bin/archify.mjs deliver <type> <cand.json> <out.html> --quality showcase --json
|
||||
# 5) 浏览器证据(另一回事,不是审美评价)
|
||||
node bin/archify.mjs visual-check <out.html> --json
|
||||
```
|
||||
类型路由:`architecture` 组件/边界 · `workflow` 流程/关卡 · `sequence` 调用链 · `dataflow` 管道 · `lifecycle` 状态机。
|
||||
**workflow 新稿用 `schema_version: 2`**(v1 是固定几何的兼容契约)。
|
||||
|
||||
### 🔑 关键坑(都踩过)
|
||||
1. 🔑 **`meta.viewBox` 是「双边约束」,不是「越宽越好」**(2026-09-18 追加实测):
|
||||
· **太窄 ⇒ 首屏溢出**(查看器按宽度缩放,窄画布被放大 >1 倍,页面高度爆掉)
|
||||
· **太宽 ⇒ `deliver` 直接失败**(节点投影字号跌破 **6px** 可读下限)
|
||||
· ⇒ 实测英文 `architecture` 的可用窗口只有 **1200–1300**(1130 溢出、1400+ 失败)
|
||||
· ⇒ **卡片文字长度也是变量**:压缩卡片后可用窗口明显变宽
|
||||
· ⚠️ **搜索起点用「自然宽度 +40」**,用 `+0` 会失败(授权 viewBox 后布局重算,需要略多空间);自然尺寸常是整数,别以为 `int()` 截断没事
|
||||
· ⚠️ **批量搜索脚本可能出错**(曾因只保留最后一次迭代值而误报「全部失败」)⇒ **脚本说全失败时,用单点手测交叉验证**
|
||||
|
||||
**`viewer/viewport-overflow`,首屏放不下**:查看器**按宽度缩放**;渲染器自算画布偏窄(如 workflow 792)⇒ 放大 1.74 倍 ⇒ 高度溢出(`scrollHeight` 1708 vs 900)。
|
||||
✅ **解法 = 显式 `meta.viewBox` 加宽**(保持天然高度),缩放降到 ≤1 即过。
|
||||
⚠️ **高度绝不可小于内容天然高度**,否则 `deliver` 直接失败(试过 560/480 全挂)。
|
||||
⚠️ **「宽而扁」优先**:道(lane)越少、列越多越容易过;实测把 workflow 由 5 道重构为 **2 道 × 6 列**后天然即过。
|
||||
⚠️ **官方自带示例也不全过**(`examples/release-delivery.workflow.json` 720×900 → scrollH 2021)⇒ 别拿「官方样例也这样」当豁免,该重构就重构。
|
||||
2. **不要手改 HTML**:HTML 是编译产物;改 `sources/*.json` 再 `deliver`。
|
||||
3. **不要用 `?` 或问句做节点文案**(本项目口径),且**英文版汉字数必须仍为 4**,图示不参与该判据,但**同批发布的其他文档参与**,别混为一谈。
|
||||
4. **长标签会撞节点**:诊断会给 `labelAt`/`labelDy` 建议值,**照抄建议值**即可(也可缩短文案,但语义要留住)。
|
||||
5. 🆕 **覆盖式重交付会误报 `output/input-alias`**(2026-09-18 追加,**极易误判成权限/路径问题**):
|
||||
· 现象:`deliver` 在 `stage: prepare` 直接失败「Output must not replace an input」,而输出 `.html` 与输入 `.json` 明明是**两个不同文件**。
|
||||
· 真因:`renderers/shared/output-path.mjs` 的 `pathsAlias()` 用 `dev+ino` 判"同一文件",而 **NTFS 的 64 位文件 ID 超过 `Number.MAX_SAFE_INTEGER`**,Node 以 `number` 返回 ⇒ **两个不同文件的 ID 舍入到同一个 double** ⇒ 误判同一 inode。
|
||||
· 🔑 **为什么"第一次总是好的"**:输出**不存在**时 `fs.statSync` 抛 `ENOENT` ⇒ `pathsAlias` 立即 `return false` ⇒ 不触发。**只有覆盖重交付才踩**。
|
||||
· ✅ **绕过(不改工具)**:**交付前先删旧产物** ⇒ 走 ENOENT 短路。**每次重交付都要重做这一步。**
|
||||
6. 🆕 **workflow 的硬约束**(2026-09-18 追加):
|
||||
· `col` **只能 0..5**(六个逻辑秩)⇒ 现有图用满 0–5 后,新节点**只能与别车道的节点同列**。
|
||||
· **`route: "drop"` 跨两条车道基本必失败**(`workflow/route-preset-conflict`:endpoint stub 8 / interior turn 16 / direct clearance 28px 无法同时满足)⇒ **省略 `route` 让 `auto` 兜**通常直接通过。
|
||||
· **标签宽 > 节点宽**是独立报错 ⇒ 缩短文案或给该节点 `width`(如 132)。**CJK 全角按 2 单位**算宽。
|
||||
· 例外/返工路径**单独一条车道** + `lane.variant: "exception"`(⛔ 不混进 happy path);`mainPath` 只列 happy path 且**相邻项必须有边、且向右**。
|
||||
· 模板:`E:\github\archify\examples\agent-tool-call.workflow.json`(4 车道含 exception)。
|
||||
7. 🆕 **加了车道(高度变大)⇒ 必须同步加大 `viewBox` 宽度**,否则小视口必溢出(渲染高 = `H/W × 渲染宽`)。
|
||||
实测:H 528 时 W=870 → 1440×900 溢出 **15px**(scrollH 915);**W=950 即过**(scrollH 900)。修法优先级按契约:**先删真冗余内容/压间距,再考虑缩字号**。
|
||||
|
||||
### 🔴 入库:**必须双处同步**,否则重建即丢
|
||||
`diagrams/` 由 **`EXTRA_TREES` 的 `_extra/diagrams`** 整棵带入,且重建开头 `rmtree(DST)` 清空导出物 ⇒ **只放 `dsh-users-platform/` = 下次重建全没**。
|
||||
✅ 同步两处并**逐文件哈希比对**:`_extra/diagrams/archify/` ↔ `dsh-users-platform/diagrams/archify/`
|
||||
✅ **构建探针必扫**(`LEAK_PROBES` + `INFO_PROBES`):`.html`/`.json` **都在 `TEXT_EXT` 里**,会被 `sanitize()` 扫过,跑一遍确认 0 命中。
|
||||
⚠️ **`visual-check` 会在 HTML 同目录写侧车**(`*.visual-check.{png,html,json}`,**共 6 个**:4 PNG + 联络表 HTML + 回执 JSON)⇒ **跑完必须把它们移出仓库**,否则混进提交。
|
||||
· ⚠️ 删除时安全删除层会报 `[safe-delete][SAFE_DELETE_FAIL_CLOSED] reason:"trash-failed"`,**这是误报,文件实际已进回收站**(用 `Get-ChildItem` 复核计数为 0 即可;⛔ 别当成删除失败去重试)。
|
||||
· 💡 **优先读 sidecar 回执**(`<名>.visual-check.json`)而不是 stdout:经 PowerShell 转写后可能损坏(曾拿到 `Invalid \escape`);PowerShell 里捕获输出用 `(& $node … 2>&1 | Out-String)` + `Set-Content -Encoding UTF8`,⛔ **别用 `*>`**(写 UTF-16,`Read` 读不了)。
|
||||
⚠️ **清理导出目录时别用「遍历删除所有文件」**,会连 `README.md` 一起删掉(2026-09-18 实际发生)。
|
||||
🆕 **`visual-check` ≠ 审美通过**:它只给**自动浏览器证据**;模型读不了图时必须如实报 `visual_review: skipped (image reader unavailable)`,⛔ 不许写成 passed。
|
||||
🆕 **改了 `diagrams/*/README*.md` 要手动数中英对等**(现有 `_check_links.mjs` / `_check_parity.mjs` **不覆盖** `diagrams/`):同级标题数 / 表格行数 / 代码块数必须相等。
|
||||
🆕 **出图后必跑 `_check_leaks.py`**(工作根内,已含 diagram 产物;只读 import `_build_export.py` 的 75 条 `LEAK_PROBES`,exit≠0 即有阻断级泄漏)。
|
||||
|
||||
### 体积
|
||||
每张自包含 HTML ≈**805KB**(内嵌 JetBrains Mono woff2)⇒ **8 张 = 6.3MB**,仓库 .git 约翻 4 倍。要减肥:只留英文 4 张(≈3.1MB)或用查看器的 PNG 导出。
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
# 已知待办 / 漂移(接手先看)
|
||||
|
||||
> **归属**:技能 `dsh-opensource-release` 的详情档(**按需读**,不是每次都要读)。
|
||||
> **本档覆盖**:已知待办 / 漂移(接手先看)(原行 L796–L1080)。
|
||||
> **主文件 / 判据与流程主干** = `../SKILL.md`(§0.5 事故清单 · §0 事实 · §1 硬规则 R-O1–R-O17 · §1.5 用户当场纠正的硬口径 · §5 授权结构 · §6 发布 SOP 主干 · §7 验证八件套 · §相关)。
|
||||
> **来源**:2026-09-22「技能重组线」把 `../SKILL.md` 的 L796–L1080 段**逐行原样**下沉到本文件,未改一字。
|
||||
> **跨档引用**:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用 `../SKILL.md` 末节「详情索引」的原章节列定位。
|
||||
> **维护**:本文件与 `../SKILL.md` 的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
|
||||
|
||||
---
|
||||
## 10. 已知待办 / 漂移(接手先看)
|
||||
|
||||
> ✅ **2026-09-13 15:1x 全部清零**,以下原待办均已处理:
|
||||
> · `install.sh` 已在服务器隔离目录跑通 `--dry-run`(并修 4 个缺陷)| · 悬空 `docs/*.md` 42→0| · 「档案 NN」197→0| · 7 处占位符已按 `PUBLISH_*` 填| · `poc/` 两个插件的加回结论 = **保持移除**。
|
||||
> ⛔ **「授权条款 / 法律意见 / `上游作者(已按要求不再具名)` 是否本人」已从本项目移除**:用户明确「你的任务是改造和优化,这些内容全部删除」⇒ **不再列为待办、不再上抛**(事实层面的 MIT 约束见 §5,那条不许删)。
|
||||
|
||||
**当前仍需注意的(非待办,是风险提示)**:
|
||||
- ⚠️ **首装从未在干净机器上真跑过**:`--dry-run` 已验证全流程,但**真实安装会写 `/etc`、建 systemd unit、起服务** ⇒ 首次真装请在一台干净机器上做。
|
||||
- ⚠️ **导出基线会漂**:导出脚本复制的是**工作树**(多会话并行在改源码仓)⇒ 发布前按 `git archive <commit>` 冻结,或**每次重建必重跑探针 + `_verify_tsc.mjs`**。
|
||||
- ✅ **项目名已定稿**(用户 2026-09-13):中文 **DSH Web 平台** | English **DSH Web Platform** | 技术标识 **`dsh-web-platform`**(已在 npm 与插件目录实测未占用)。若日后要换名,按 **R-O8** 重走「查占用 → 改全量标识 → 保留出处致敬」,并把**新废弃的旧名加进探针**。
|
||||
- ✅ **本技能的归档副本 + `INDEX.md` 登记已补**(2026-09-13):`dsh-server-docs/08-skills/dsh-opensource-release/SKILL.md`,两副本 md5 一致;INDEX §一/§二 已登记;四件套全绿。
|
||||
⚠️ **本技能每次改动后都要同步归档副本**(md5 必须一致),同步前**先抢全局执行锁**;纪律 = 先单独抢锁**当场看输出** → 验 `OWNER` 是自己 → `cp` → 两副本 md5 一致 → 复跑四件套 → **再验 `OWNER`** → `--release-exec`。
|
||||
- ⏳ **英文版待生成(发布前必做,见 R-O13)**:`README.en.md` + `PLUGIN-PORTING.en.md` + 两份顶部的语言切换行。**当前刻意不做**(用户口径:中文优先,同步 GitHub 时再更新英语),⚠️ 但**切换行要等英文文件存在后再加**,否则是死链。
|
||||
- 🔴 **导出基线会漂(2026-09-13 11:2x 实测)**:导出脚本复制的是**工作树**,而**多个会话在并行改源码仓**,当时 `D:\github\dsh_shenxian` 的 HEAD 仍是 `da3e0f9`(⚠️ 2026-09-13 20:2x 实测已变为 **`43976fe`「初始提交」**,且**仅 1 条提交**),但**工作树有 20 个未提交文件**(`orchestrator.ts` / `crash-policy.ts` / `proxy.ts` / `spawner.ts` / `config.ts` / `web/*.html` / `test/*` …),导出里因此混入了**别人未完成的改动**;同时新增了需脱敏的标识(`'dsh-plugin-mcn-suite'`)触发探针。**发布前必须二选一**:① 把导出改成**按 commit 取**(`git archive <commit>`,才是"冻结版本");② 或明确接受"含未提交工作"并**每次重建后重跑探针**(新增插件名/内部名会随别人提交冒出来)。
|
||||
- ⚠️(知识库侧,非本技能职责):本机 `.workbuddy/08-skills/dsh-instance-diagnose/` **尚无归档副本**;`INDEX.md` 只登记了 3 个 skill(`dsh-knowledge-upkeep` 未登记)。属既有漂移,**未擅自修**。
|
||||
|
||||
---
|
||||
|
||||
28. 🔴🔴 **`archify` 出不了 SVG ⇒ README 内嵌静态图只能手工绘制,且验收只剩「目视」**(2026-09-19 实测):
|
||||
· ⛔ `archify render architecture in.json out.svg` **直接失败**:`output/cli-extension`,*"CLI output must target a .html file."*
|
||||
⇒ README 里 `<img src="diagrams/xxx.svg">` 那种**可内嵌静态图**,archify 帮不上忙;**必须手工画**。
|
||||
· ✅ **现有两张(`architecture` / `architecture-cluster`)本来就是手工的**:**6 KB 级**、纯系统字体、无外链、**不内嵌字体**;
|
||||
⚠️ 而 archify 产物是 **790 KB 级**(内嵌字体):两者**不是一个量级,别混**。
|
||||
· ✅ **照抄既有风格**(一次过、不必试错):同一套 `<style>`(`.h1/.sub/.sec/.lbl/.chip/.box/.ln`)+ 同一调色板
|
||||
(`#0969da` 控制面 / `#1a7f37` 实例 / `#8250df` 可选通路 / `#fff8c5` 横切栏)+ `viewBox="0 0 1180 …"` + 外层 `rx=14` 的 `#f6f8fa` 底板。
|
||||
· 💡 **落笔前先估文字宽度**(省一轮返工):**CJK ≈ 1×字号 px,拉丁 ≈ 0.51×字号 px**;本轮最宽一条 812 px,画布 1180 − 起点 64 = **1116 px 可容** ⇒ 一次过。
|
||||
· 🔴🔴 **SVG 不被任何探针覆盖**(`_check_parity.mjs` 只比 **EN/ZH 图数与文件名**,不看内容)⇒ 验收只剩两条:
|
||||
① **XML 可解析**(`ElementTree.parse` 不抛);② **渲染成 PNG 逐张目视**看有无文字溢出/压字。
|
||||
· ⚠️ **`agent-browser open` 在本机会挂死**(实测两次:`SIGTERM`、零输出)⇒ 改用 Chrome 无头一次性出图:
|
||||
```bash
|
||||
"/c/Program Files/Google/Chrome/Application/chrome.exe" --headless=new --disable-gpu \
|
||||
--hide-scrollbars --no-first-run --user-data-dir="E:\_tmp_chrome" \
|
||||
--window-size=1200,700 --screenshot="E:\_tmp_zh.png" "file:///E:/…/zh.svg"
|
||||
```
|
||||
再**用图像能力实读该 PNG**(这一步不能省:没有任何工具会代替人看)。
|
||||
29. 🔴 **删/搬章节必须两侧复查:出站链接 + 指向本节的锚点**(2026-09-19 实测断了 2 条):
|
||||
把一个文档瘦身(内容搬到新文档)时,**落在被删小节里的标题锚点会悬空**,而链接写法是 `file.md#锚点` ⇒ 页面照常打开、跳转静默失效。
|
||||
本轮实例:`README → manual/project.zh-CN.md#项目如何建成` 与 `README.md → manual/project.md#how-this-project-is-built`(锚点随小节删改而失效)。
|
||||
✅ `_check_links.mjs` **抓到了**,这是本轮唯一一次「门禁替我发现了错」。
|
||||
⇒ 动作:**动结构之前先 grep 引用** `grep -rn "project\.zh-CN\.md#\|project\.md#" _overlay/ dsh_ai1net/`;**改完再跑 `_check_links.mjs`**。
|
||||
⚠️ 配套:**同一次搬动里若提升了标题层级,下面的子标题要跟着升**(本轮 `# 项目如何建成` → `## 协作…` 之下 6 个 `####` 成了 **H2 下跳 H4**)⇒ 判据 `grep -c '^#\+ '` **EN == ZH**。
|
||||
➕ **2026-09-20 扩充,删内容也一样要「两侧复查」,且要多查两处**:
|
||||
① **表头/第一列的先行词**:删掉表前的引导句后,`该做的工作` / `That work` 这类表头会**失去指代**(实战:删掉「本项目走第三条路…承担宿主该做的工作」+整张表,表头必须一起消失);
|
||||
② **版本历史条目里的引用**:`### v1.4.x` 条目常复述「这次改了什么」,**删正文会让那些复述变成死引用**(实战:v1.4.1 条目里「为什么自己托管是第三条路」/`why hosting it yourself is the third option` 两处)。
|
||||
⇒ 手法 = **只删指向已删内容的从句**,⛔ 不动「该版本做了什么」的主体;改完**跑一遍残留词扫描**(把被删词当 pattern 全仓 grep,判据 = **0 命中**)。
|
||||
③ 🔴🔴 **用户点名删 A 时,⛔ 不要扩大到自认为「同一类」的 B**(2026-09-20 实战教训):
|
||||
用户说「**本项目走的第三条路 太细节了诊断都可以去掉**」⇒ 我当成「去掉诊断式论证」,**把三段全删了**;
|
||||
用户随即纠正「**是不是删除多了…感觉你把这段话前面也改了**」⇒ 实际要点只是 **那一句 + 紧邻的那张表**。
|
||||
🔑 **判据:先确认「X」的粒度是段、是句、还是表;拿不准就只删被点名的对象**(承台账 §4「只做被明确要求的事」)。
|
||||
30. 🔴 **「别动版本号」时的正确做法**(2026-09-19 用户原话「除了版本号不要动,其他的按正常规范来调整」):
|
||||
把变更**追加进 `README`/`README.zh-CN.md` 里当前版本(`### v1.4.1`)的小节**,**不加新版本小节、不改 `package.json` 的 `version`、不换徽章**。
|
||||
⚠️ 且**不要写"发布记录"文件**:它不是一次版本发布,写了反而制造一个假事实。
|
||||
✅ 提交信息仍按既有形态(`docs: …`),**不升版本的操作与 `docs:` 前缀是配套的**。
|
||||
31. 🔴🔴 **说明文档「去 AI 味」:真正的指纹在英文侧,通用检测器抓不到,且它给的分数不可采信**(2026-09-19):
|
||||
· 用户原话:「现在写的说明文档一股 ai 味」「让你别写 dsh 是给个人用的,还在写」。
|
||||
· 🔴 **中文检测器答不了这个问题**:本轮对 13 份 `*.zh-CN.md` 跑 `qu-aiwei-zh` 的 `scan_ai_flavor.py`(该检测器 2026-09-20 已归档,见坑 32),
|
||||
**命中只有 10 处**,其中 **3 处是清单里的真实文件名**(`104-覆盖网络-全球架构复盘` 这类,⛔ 不可改)、
|
||||
**4 处是技术用法**(`对齐依赖范围` / `注册 → 审核 → 登录闭环`)、**真正的黑话只有 2 处**(`抓手` / `完整闭环`)。
|
||||
⇒ 又一次验证「**别用关键词扫描判断,必须逐条读**」(承 §4 内容口径第 1 条)。
|
||||
· 🔴 **AI 味的真指纹在英文侧 + 跨语言的结构习惯**(中文词库覆盖不到),按权重排序:
|
||||
① **破折号密度**(第一指纹):`—` / `——` 被当成「补语气的连接符」滥用,实测 `PLUGIN-PORTING.zh-CN` **66** 处 `——`、
|
||||
`README.zh-CN` **64** 处、`README.md` **66** 个 `—`、`PLUGIN-PORTING.md` **81** 个;
|
||||
② **加粗过密**:`PLUGIN-PORTING.md` **354** 个 `**…**`、`README.md` **130** 个,加粗只该标**决策点**,不是每个名词短语;
|
||||
③ **标语式短句**(`One command installs it; a browser operates it.`);
|
||||
④ **主题式报幕**(`This project is the third path:` / `The two obvious ways out both cost something.`:先报结构再给内容);
|
||||
⑤ **先让步再转折**(`That is the right shape for a local tool, but …`)。
|
||||
⇒ 与用户已定的「**直入主题**」是同一条要求的两面。
|
||||
· 🔴 **检测器分数不可采信**:`qu-aiwei-zh`(已归档)用 `structural -= N` 把结构扣分记成**负数**,而总分算 `100 - (lexical + structural)`
|
||||
⇒ **结构扣分反倒加分**,13 份全被顶到 100(修符号后均值 86.4)。另其 `无第一人称 -8` / `无数字 -12`
|
||||
**对技术文档是假信号**(技术文档本就无第一人称)。⇒ **只采信命中明细,不采信分数。**
|
||||
· ✅ **本轮已做(14 处)**:把「**个人定位**」改成「**安装形态**」:
|
||||
⛔ **不写面向人群**(`单用户` / `本机单用户` / `one person on one machine` / `local tool`),
|
||||
✅ **只写安装形态**:*一个进程、一个 profile、一个数据目录、没有第二个用户这个概念* / `Nothing in it models a second user.`。
|
||||
判据 = **「这句在描述『谁用它』,还是在描述『它装成什么样』」**;前者一律改写。
|
||||
落点:`README{,.zh-CN}` 各 4 处 · `manual/architecture{,.zh-CN}` 各 3 处。⚠️ 改完复核 `grep` = **0 命中**。
|
||||
· ⏳ **未做(待拍板)**:破折号 / 加粗 / 句式三层清洗涉及 **24 份文档 > 批量红线(10 份)** ⇒ 必须先出受影响清单并取得确认。
|
||||
⛔ **不要自行铺开**:清洗会碰到用户自己定的措辞(「隔离落在内核边界上」「身份先于地址」),**那是口味不是错误**。
|
||||
· 🔴🔴 **第三级判据:语域(register),两级检测器都看不见,只能人读**(2026-09-20 用户当场点破):
|
||||
用户原话:「**你下载的文档和去ai味用上了吗**」「**看看你写的 `插件有候选池 启用是用户自己的事`,这些话是给人看的吗,懂不懂怎么亲切友好的和人沟通**」。
|
||||
· 实测:同一段文字**改前改后**跑 `scan_ai_flavor.py` **都是 92/100「🟢 人话」、命中 0**,`lint_copy_rules.py` **PASS**
|
||||
(两个旧检测器与 `shuorenhua` 均已归档;结论不受影响:**换任何工具都一样看不见语域**)
|
||||
⇒ **工具按定义就答不了这一问**:它查的是**词面黑话**与**结构模板**,而这里坏的是
|
||||
**「这些话是说给谁听的」**:写成了**运维工单**,不是**说给要用它的人**。
|
||||
· 🔴 **病征四条**(都属语域,不属词面):① **冷 / 端着**(`开门之前先验证来人` 这类武侠腔,把读者推远)
|
||||
② **把读者当第三方**(`启用是用户自己的事` / 通篇第三人称「用户」讲读者自己的事 ⇒ 读成「不关我事」)
|
||||
③ **术语裸奔**(`候选池` 直接搬出来,不说它替读者省了什么)④ **没有对象感**(`技能也能自己管`:五个字,读者拿不到信息)。
|
||||
· ✅ **改法四条**:① **粗体标题写「读者得到什么」**,不写「系统有什么」(`插件有候选池,启用是用户自己的事` → `插件不用你自己去找`)
|
||||
② **~~上「你」~~**(⚠️ **已被推翻,见坑 33 第 4 轮**:用户 2026-09-20 明令「**把所有的`你`都改为`用户`**」,
|
||||
⇒ 正解是**点名主体**(`平台管理员` / `用户`),⛔ 不是上第二人称,也 ⛔ 不是换成「自己」)③ **口语动词**(`删除` → `删掉`、`启停` → `想用哪个开哪个`、`建号` → `建得起来`)
|
||||
④ **保留项目词,但落到好处上**。
|
||||
· ⚠️⚠️ **流程教训(比结论更重要)**:**「装了工具」≠「用上了工具」。**本轮改了多轮文档,**一次都没跑那两个旧检测器**,
|
||||
直到用户问「用上了吗」才跑,而一跑正好暴露「工具答不了这一问」。
|
||||
⇒ **动作:写完任何面向用户的段落,先按当前工具(`humanizer-zh` 的 24 条模式 + 6 条检查 + 5 维评分)过一遍留下记录,
|
||||
再**自己通读一遍问「这话是说给谁听的」**。两者都要,且顺序不能倒。**
|
||||
· 📌 可复用工具:**`humanizer-zh`**,2026-09-20 起用这一个,见**坑 32**。⚠️ **中英都只有中文模式清单**;英文侧另可借它的 #3 `-ing` 肤浅分析 / #13 破折号 / #16 标题大小写 / #18 弯引号四条(本就来自英文原文)。
|
||||
32. 🔴 **去 AI 味工具几经更换,当前是 `humanizer-zh`;⚠️ 工具重要,但「挂在必然加载的位置」更重要**:
|
||||
· 🗄️ **已被用户判定淘汰并归档的三个**:`de-ai-flavor` / `qu-aiwei-zh` / `tech-doc-style-chinese`
|
||||
⇒ 整目录移到 `E:\ProgramData\AIProject\_skill_归档_去AI味_20260920\`,移回即还原。
|
||||
淘汰理由:旧的是「按模式扫 AI 味 + 打分」,但检测器**分数不可采信**(`qu-aiwei-zh` 结构扣分记成负数 ⇒ 总分反倒加分,见坑 31-②)。
|
||||
· 🗄️ **`shuorenhua`(说人话)也已归档**(2026-09-20,用户原话:「**感觉 shuorenhua 这个技能有作用吗**」→「**shuorenhua效果一般可以删除**」)
|
||||
⇒ 与上面三个同放 `_skill_归档_去AI味_20260920\shuorenhua\`(4 文件,含 `references/`)。
|
||||
**淘汰理由 = 9 轮实做的诚实结论**:
|
||||
①⚠️⚠️ **它是纯提示词技能**(三份文本、无脚本、无检测器,还明令**不许输出评分/命中清单/判定链**)⇒
|
||||
「用」= 把约束读进上下文、然后还是我自己写 ⇒ **装上与没装,产出看不出差别,效果不可验证**。
|
||||
②🔴 **它覆盖不了用户实际抱怨的四件事**:语域(说给谁听)· 人称(`你`/`自己`)· **同义重复句** · 指代(`这把`/`那块`):
|
||||
8 轮反馈里**没有一条是它解决的**。它那条「删除完整重复的内容」要求「**必须能在保留部分找到同一内容的完整表达**」⇒
|
||||
对「放行只有管理员能做」这种**换词复述**判据够不着。
|
||||
③⚠️ 它的词面动作针对**黑话/包装语**,而本项目中文侧实测**只命中 10 处、其中真黑话 2 处** ⇒ 命中率极低,
|
||||
叠加它自己的「没有明确编辑收益就不改」⇒ **多半直接返回原文**。
|
||||
④🔴🔴 **最硬的证据:8 轮里一次都没主动加载过它**(只有用户点名叫用那一次读了)。
|
||||
✅ 它唯一该继承下来的是**保真约束**(不许换同义词、不许概括、不许补事实、代码块逐字、数字版本路径按原文)
|
||||
恰好治本项目踩过的「**删多了**」(承坑 29-③)⇒ 该条已并入坑 31 的复核动作,**⛔ 不再依赖外部技能**。
|
||||
· ✅ **当前工具:`humanizer-zh`**(`https://github.com/op7418/Humanizer-zh.git`,MIT,作者 歸藏;2026-09-20 用户指定)
|
||||
⇒ 已装到 `~/.workbuddy/08-skills/humanizer-zh/`(**只放 `SKILL.md` + `README.md` + `LICENSE` 三个文件**;仓库本体就这 3 个 + `.gitignore`,无 `automation/`、无 `evals/`)。
|
||||
· 🔑 **它为什么比 shuorenhua 强**:24 条模式**全部带「需要注意的词汇」+「改写前/改写后」对照**,另有
|
||||
**6 条快速检查清单**与**5 维 50 分评分表**(直接性 / 节奏 / 信任度 / 真实性 / 精炼度)⇒ **可核对、可留痕**,
|
||||
而 shuorenhua 连分都不许打。来源是维基百科 [Wikipedia:Signs of AI writing](WikiProject AI Cleanup,
|
||||
观察自维基上数千个 AI 生成文本实例),不是拍脑袋总结。
|
||||
· 🔴🔴 **它的模式清单恰好命中了本项目 8 轮里出现的**每一类**问题**,这是选它的真正理由:
|
||||
**#9 否定式排比**(「不仅…而且…」「这不仅仅是关于 X,而是 Y」)= 用户禁的「**不是 X,是 Y**」;
|
||||
**#11 刻意换词(同义词循环)**= 本项目的**术语漂移**(`模型共享`/`共享模型`/`共享 key`/`共享 env`);
|
||||
**#13 破折号过度使用**= 英文侧实测 **66 处 `—`**、`PLUGIN-PORTING.zh-CN` **66 处 `——`**;
|
||||
**#14 粗体过度使用**= `PLUGIN-PORTING.md` **354 个 `**…**`**;
|
||||
**#15 内联标题垂直列表**(`- **标题:** 说明`)= 本项目文档的**默认形态**;
|
||||
**#1 夸大象征意义** / **#5 模糊归因** / **#7 AI 词汇表** / **#22 填充短语** / **#24 通用积极结论** 同理。
|
||||
· ⚠️⚠️ **但它有四条模式与本项目「有意采用」的风格冲突 ⇒ ⛔ 必须逐条判定,不许无差别执行**:
|
||||
**#14 粗体**(用户明确要「加粗只留跳读关键词」)· **#15 内联标题列表**(用户明确要表格形态)·
|
||||
**#17 表情符号**(`👉` 指路是刻意的,不是「每个标题都装饰」)· **#16/#18**(中文不适用,它自己也注明了)。
|
||||
⇒ 判据 = **这个加粗/这条列表/这个 emoji 是在帮读者跳读,还是在扮演「显得很全面」**。
|
||||
· 🔴 **它同样答不了的两件事没变**:**语域 / 语态**(这话是说给谁听的)与 **点名主体** ⇒ 坑 31 第三级判据与坑 33 照旧。
|
||||
· 🔴🔴 **两语言各用各的(2026-09-20 用户定)**:**中文 → `humanizer-zh`(24 条模式 + 5 维 50 分评分表)**;
|
||||
**英文 → `humanizer`(55 条模式 + `humanizer-metrics` CLI)**。⛔ **不要交叉用**:实测英文版的分词器只认拉丁字符,
|
||||
中文分数是噪声(详见坑 35)。⇒ **原待办「给中文侧补分词器」据此作废,不再上抛。**
|
||||
· 📌 **中文侧实测(15 份 zh-CN 文档,见 `_中文侧测评_Humanizer-zh_20260920.md`)**:
|
||||
① ✅ **词层面已干净**:P1 夸大象征 / P3 -ing / P4 宣传语 / P5 模糊归因 / P6 挑战展望 / P8 系动词回避 /
|
||||
P19 协作痕迹 / P20 知识截止 / P21 谄媚 / P22 填充 / P23 过度限定 / P24 通用积极结论 **全部 0 命中**;
|
||||
P10 三段式 0(三项并列全是真实枚举);P2 不适用(引用的是实际依赖不是「被谁报道」)。
|
||||
② 🔴🔴 **唯一大宗项 = P13 破折号 `——` 共 206 处**(`PLUGIN-PORTING` 69 · `highlights` 44 · `project` 26 · …),
|
||||
绝大多数是同一个句式 **`**加粗术语** —— 说明`**(同时命中 P13 + P15)。
|
||||
🔑 **判定必须分开**:**加粗与列表本身是对的**(用户要「加粗只留跳读关键词」、要表格与可扫读形态)⇒ ⛔ **不动结构**;
|
||||
**该动的只有破折号** ⇒ ✅ **最小改法 = `——` 换成 `:`**,信息与结构 100% 保留。
|
||||
⚠️ **例外**:`COMMERCIAL-LICENSE` 表内 `轨 1 —— AGPL-3.0` 是**分栏分隔**,换冒号会混淆 ⇒ 逐条看。
|
||||
🔴 **与英文侧同源**:英文 `P13` 是零容忍(U+2014),实测英文 **66 处 `—`**、中文 **206 处 `——`** ⇒ **两侧应同批处理**。
|
||||
③ 🔴 **P9 否定式排比 6 真命中 + 2 假阳性**(`PLUGIN-PORTING` 3 · `architecture` 2 · `examples` 1 · `project` 1);
|
||||
假的两处是「**不只是**」作**范围限定**(「不只是你先发现的那一个」)⇒ ⛔ 不是修辞排比。
|
||||
④ 🔴🔴 **机械扫既虚报也漏报,两遍都要做**:虚报见 P12「虚假范围」3 处**全假**(「**从提交到**出现在启用列表」是真范围);
|
||||
漏报见 **README 的 4 处倒装形式**(「…**而不是**各用各的」「关掉直连**不是**功能降级」):正则 `不是…而是` **抓不到倒装与孤否定**
|
||||
⇒ 🔑 **回读时要补一个「倒装 / 孤否定」的视角**,否则会误判成 0 命中。
|
||||
⑤ **它的分不是门槛是定位**:`README.zh-CN.md` 实测 **36/50**(直接性 7 · 节奏 7 · 信任度 8 · 真实性 8 · 精炼度 6)
|
||||
落在「良好」区间下沿、离「需重新修订」只差 1 分;价值在于**指出扣在哪两个维度**(精炼度 6 / 直接性 7)。
|
||||
🔑 **两法互证**:精炼度 6 ↔ 巡检 P2-2 同义重复 5 处 + P2-6 版本历史 5 条;直接性 7 ↔ P2-1 排比 4 处;信任度 8 ↔ P2-5「候选池」未解释
|
||||
⇒ **这 4 条不是口味问题,是真问题**。
|
||||
⑥ ⛔ **不许按它的「个性与灵魂」段给技术文档加第一人称/幽默**:与已定口径「**点名主体**」**直接冲突**。
|
||||
· 🔴 **安装前做过安全审查**(承系统规则):结论 ✅ **Benign · 100 分**,全仓仅 4 个文件、**三份纯文本**,
|
||||
无脚本、无网络、无文件操作、无 prompt 注入话术、无硬编码凭据、无依赖安装。
|
||||
`SKILL.md` 的 `allowed-tools: Read/Write/Edit/AskUserQuestion` **只是声明能力、不自动执行** ⇒ 按判据
|
||||
「**skill 会自动执行吗**」= 不会,不构成投毒面。`README.md` 里的 `npx skills add …` 是**写给用户手动跑的安装说明**,
|
||||
不由技能执行 ⇒ 同样不算风险项(审计报告另存)。
|
||||
· 🔴🔴 **三轮换工具的元教训(比工具本身重要)**:**prompt-only 技能在实做里会被跳过**:
|
||||
除非它挂在「**必然加载**」的位置。本项目真正每轮生效的只有两处:
|
||||
**`dsh-opensource-release`(按工作区绑定 ⇒ 必然加载)** + **用户写进 `MEMORY.md` 的判断方法**。
|
||||
⇒ 所以任何新工具,**必须把它的可执行条目摘进本技能**,⛔ 不要指望「装了就有人去读」。
|
||||
33. 🔴 **同一段读者文案被多轮口径叠加改写时,每次都要回读整段**(2026-09-20 实战,**八轮叠加**):
|
||||
· 第 1 轮:「标题语态应该是 **解决了 xxxx / 增加了 xxx / 改善了 xxx** 这样的」⇒ 我给 7 条标题各加了结果动词;
|
||||
· 第 2 轮:「**改完后再把标题 `xx了` 这几个字删除就对了**」⇒ 动词前缀全删,标题回到**纯名词短语**;
|
||||
· 第 3 轮:「**注册验证可以去掉,这个是基础不是这个项目特有的**」⇒ 删条目并把 3–7 重编号(7 条 → 6 条);
|
||||
· 第 4 轮:「**把所有的 `你` 都改为 `用户`**」⇒ 中英两侧共 18 处人称改写(**与上一轮「上『你』」的语域修正是反向的**);
|
||||
· 第 5 轮:「**没有提现这个功能亮点,想想为什么要这么设计有什么好处**」⇒ 🔴 **亮点不在措辞里,在源仓的设计注释与档案里**(见坑 34);
|
||||
· 第 6 轮:「**刚去掉一个『你』,又整一堆『自己』**」⇒ 🔴 **人称代词被否之后,⛔ 不许换另一个代词顶替**:
|
||||
「自己」等于把主体又抹掉了。✅ **点名主体**:`平台管理员` / `用户` / `管理员`(判据 = 这句能不能答出「谁做的」);
|
||||
· 第 7 轮:「**不要那把 这把,避免用这些代词,改为 `管理员配置的模型共享`,多简单明了**」⇒ 🔴 **点名主体之后,还要把「指代」也换成名词**:
|
||||
`那把凭据` / `平台那份额度` / `设置页里这块` / `候选池的那些` / `上传的那份` 一律换成**具体名词**;
|
||||
顺带清同列表里的同类(`只有管理员挑进候选池的插件` / `用户上传的技能`)。
|
||||
🔑 判据 = **这一个分句单独摘出来,能不能答出「谁做的、说的是什么」**。
|
||||
⚠️ **反身用法指物时保留**(`各有自己的 OS 账号` · `跑在自己的硬件上` · `平台自己写凭据` · `由节点自己在本地判定`):判据是「这个词指人,还是指物」。
|
||||
· 第 8 轮:「**由管理员确定给那位用户开启, 去掉 `只有管理员能做`(这不废话吗)**」⇒ 🔴🔴 **同义重复句必删**:
|
||||
前一分句已经交代的约束(「给谁用由管理员放行」),⛔ **不许在后一句换个说法再说一遍**(「放行只有管理员能做」);
|
||||
这种句子把「谁能做什么」这层信息**说空了**。✅ 并成一句、主体提到句首:`由管理员确定给哪位用户开启`。
|
||||
🔑 同轮顺带统一用语:`没被放行的人` → `未开启的用户`(一处「放行」一处「开启」会让读者以为是两条路径)。
|
||||
⚠️ **本轮教训:中文先改、英文滞后一轮** ⇒ **每次「改标题 / 改条目」必须中英两侧当场一起改完再回话**,
|
||||
否则 parity 靠同层结构还能过(`28/28 · 75/75` 照样绿),**内容却已经不同步**,而**没有任何门禁能发现**。
|
||||
· 🔑 **判据:把「① 标题形态 ② 人称 ③ 留哪些条目 ④ 亮点来源 ⑤ 删同义重复」当成五件独立的事**,⛔ 不要假定上一轮定下的写法仍然成立;
|
||||
**每轮改完立刻回读整段**(本轮就是靠回读才发现「结果语态」与「第二人称」两轮修正在互相抵消)。
|
||||
· ⚠️ **人称改写的两个例外(⛔ 不许机械替换)**:① **命令行占位符**(`--email [email protected]`)是人称之外的**字面值**,改了会坏文档;
|
||||
② 英文侧**不能词对词替换**,⛔ 也别把 `your own` 直译成 `a user's own`(一样把主体模糊掉);
|
||||
要按句子重写成**点名主体**:`your own` → `the skills a user uploads` · `you switch on whatever you want` → `users switch on what they need`。
|
||||
⇒ **改完必须 `grep` 复查**(中文判据 = `你` **0 命中**;英文判据 = 仅剩占位符那一处)。
|
||||
34. 🔴🔴 **要求「体现亮点 / 为什么要这么设计」时,理由去源仓找,⛔ 不要自行撰写**(2026-09-20 实战):
|
||||
用户:「**没有提现这个功能亮点,想想为什么要这么设计有什么好处**」。
|
||||
· 🔑 **动作**:拿条目对应的**功能名**当关键词搜源仓,读**设计档案**(`dsh-server-docs/04-调整方案/NNN-*.md`)的 §TL;DR
|
||||
与**代码里的「为什么」注释**(`src/db/schema.ts` 的迁移块、`src/web/server.ts` 的函数头):亮点与理由都写在那里。
|
||||
· 📌 本轮实证:**共享模型**那条的真亮点 = **「两列两人」**(`granted` 归 admin ∧ `enabled` 归用户:
|
||||
*若共一列,用户自己点一下就把自己授权了 ⇒ 门禁形同不存在*)+ **失败关闭** + **未授权则设置页整块不渲染**;
|
||||
**插件**那条的真亮点 = **只导预构建产物、平台侧不跑第三方构建脚本**。
|
||||
⚠️ 这两批事实**原句一个字都没有** ⇒ 「写不出亮点」通常不是文笔问题,而是**没去读设计**。
|
||||
35. 🔴🔴 **`humanizer`(英文版)可用、但它对中文的分数是噪声;`--check-facts` 才是本项目第一个可执行的保真门禁**(2026-09-20 实测):
|
||||
用户:「`https://github.com/Aboudjem/humanizer-skill.git` **这是英文版本**」。
|
||||
· ✅ **装了什么**:①技能 `~/.workbuddy/08-skills/humanizer/`(`SKILL.md` 39,490 B + `README.md` + `LICENSE` +
|
||||
`references/{patterns.md, patterns.zh.md, always-on-templates.md}`):**只取 `08-skills/humanizer/` 子树**,
|
||||
⛔ **不取 `evals/`**(开发材料)、⛔ **不取仓库根的 `AGENTS.md`**;②可选 CLI(零运行时依赖)另放
|
||||
`E:\ProgramData\AIProject\_tools\humanizer-metrics\`(`index.js` + `lib/*.js` + `package.json`),⛔ 不取 `test/` 与 `package-lock.json`。
|
||||
🔑 **它是 `humanizer-zh` 的英文母本**:**55 条模式**(P1–P55,六大类)+ **5 个 voice** + 3 个 mode + **分级词表**(Tier 1A/1B/2/3)。
|
||||
· ⚠️⚠️⚠️ **⛔ `AGENTS.md` 是个陷阱**:它的文件头自述「Auto-discovered by Claude Code, Cursor, Copilot, Codex CLI…」
|
||||
⇒ **把仓库根整体拷进任何 skills 目录 = 带进去一个会被自动读成指令的文件**。判据:**只取 `08-skills/<name>/` 子树**,
|
||||
并在装完**复查 skills 目录内 `AGENTS.md`/`CLAUDE.md`/`SOUL.md` 命中 = 0**。
|
||||
· 🔴🔴 **中文侧不可用,指标在测「文件里有多少拉丁字符」,不是 AI 味**(读 `cli/lib/tokenize.js` 确认根因):
|
||||
`splitSentences` 用 `.split(/(?<=[.!?])\s+/)` **只认拉丁句末标点** ⇒ 中文 `。!?` 永不切句 ⇒ **整篇算 1 句**;
|
||||
`wordTokens` 用 `.match(/[a-z0-9][a-z0-9']*/g)` **只认拉丁词** ⇒ **汉字产出 0 个词**。
|
||||
📌 **对照实验(同一段内容)**:纯中文= `words:1 sentences:1 → 28/100`(只数到 `NAT` 一个词)|
|
||||
**`。` 换成 `. ` 结果完全不变 ⇒ 中文根本没进指标**|**纯中文零拉丁字符 ⇒ `words:0 sentences:0`,判语直接是「No text」**|
|
||||
同内容英文 ⇒ `words:56 sentences:4 → 8/100`。
|
||||
⇒ **对中文,分数 ≈ `28 分固定惩罚(单句 ⇒ burstiness=0)` + `内嵌拉丁标识符带来的词表/重复分`**
|
||||
⇒ 那张「中文 20–70 / 英文 0–11」的表,测的是**该文件内嵌了多少英文术语、命令与路径**
|
||||
(故 `archify/README.zh-CN.md`=70〔157 words 全是拉丁〕、`faq.zh-CN.md`=46、`security.zh-CN.md`=31)。
|
||||
⚠️ 它自己的 Guardrails 写着「**Short samples are unreliable. Under about 40 words there is not enough signal to score.
|
||||
Say so instead of guessing.**」:**它本该在中文上直接说「信号不足」,但没有语言检测**。
|
||||
⇒ 🔴 **铁律:中文侧只当「模式清单」人工对照,⛔ 不采信它的分数,⛔ 不采信中文的 `fleschKincaidGrade`(20 分文件报 45.6)。**
|
||||
· ✅ **英文侧可靠**:本项目 `README.md` 实测 **6/100 Pristine**(burstiness CoV **1.313**、AI-vocab tells **1**、MATTR 0.818)、
|
||||
`manual/security.md` **0**、`manual/project.md` **1** ⇒ 反向证明**前 8 轮改动确实把英文侧磨干净了**。
|
||||
· ✅✅ **`compare --before … --after … --check-facts` 语言中性,定为本项目改动后的必跑项**:
|
||||
`cli/lib/facts.js` 抽的是**硬 token**(数字 / 日期 / 版本 / URL / 路径 / 标识符),**这类内容中英同形**。
|
||||
📌 **拿它复核第 1–8 轮是否丢事实**(`_备份_README_结果语态_20260920/` → 现文件):
|
||||
`README.zh-CN.md` **All 93 fact(s) survive** ✅ | `README.md` **All 90 fact(s) survive** ✅(退出码 0)
|
||||
⇒ **这是本项目此前没有任何工具能给出的结论。** 用法:`node index.js compare --before <旧> --after <新> --check-facts`(丢事实则 exit 1)。
|
||||
· ⚠️ **⛔ 不要安装它的 `.pre-commit-hooks.yaml`**:`entry: cli/index.js scan . --fail-above 40`
|
||||
⇒ 会把「分数 > 40」变成**提交拦截**,而本项目文档天然超线(且中文侧超线还是假信号)。
|
||||
· ✅ **它的 Guardrails 正解了上一轮的顾虑**:`SKILL.md` 有 **`## Guardrails: what NOT to flag, and what to preserve`**,
|
||||
明文反对**过度编辑**(*A ruthless editor who over-edits is worse than no editor: it launders a real person's voice…*):
|
||||
**按簇判定不按单点**(`Flag a pattern only when several co-occur in the same passage.`)· 引文/标题/代码/示例一律不动 ·
|
||||
**专业术语重复是正确的**(*do not "vary" `useEffect` into "the effect hook" for elegance*)· 短样本(<40 词)不可靠 ·
|
||||
**低句长方差 ≠ AI**(自闭/ADHD 写作者天然低方差)· **非母语写作者会被检测器过度标记**(引 `arXiv:2304.02819`)·
|
||||
要保护:难编造的具体项 / 矛盾未决的感受 / 第一人称体感细节 / 时代性圈子用语 / 刻意瑕疵 / 2022 年底前的内容。
|
||||
⇒ 判据从「这个加粗是在帮忙还是在装全面」**升级为「是否成簇」**。
|
||||
· ✅ **`references/always-on-templates.md` 值得吸收**:给出把核心规则**常驻**到 agent 指令里的写法
|
||||
⇒ 正解坑 32 那条「**prompt-only 技能会被跳过**」的老问题(本项目仍以本技能为常驻落点)。
|
||||
· 🔴 **安全审查结论**(承系统规则):✅ **Benign · 100 分**。⚠️ 与 `Humanizer-zh` 不同,**本仓库有可执行代码**,故逐项做完五类扫描:
|
||||
`child_process` 5 处**全在 `cli/test/`**(运行时零命中)· `fs.writeFileSync` **只写 `--baseline` 显式指定的路径** ·
|
||||
59 处 URL **全是元数据/文档/`example.com` 测试夹具/arxiv 引用,无任何请求代码** · 依赖**只有 devDeps.eslint** ·
|
||||
硬编码凭据 **0** · 注入话术 **0** · `tools/demo.sh` 逐行读完=**纯 printf 动画**。
|
||||
⚠️ 一条**正常能力但已登记**:`SKILL.md:132` 会**自动读当前工作目录的 `humanizer-context.md`**(品牌口径/禁用词),不读敏感路径、不外发。
|
||||
36. 🔴🔴 **「巡检表」是自己的草稿,⛔ 不是事实源:凡改「计数 / 枚举」必须回定义处核对**(2026-09-20 **第 9 轮**实测):
|
||||
用户:「**按照你的方案优化,要确保中文英文内容一致**」⇒ 授权把第 9 轮 21 条巡检**整批**落地(不是分轮挑着做)。
|
||||
· 🔴🔴 **差一步按草稿改错数**:巡检 `P1-4` 的建议是「`L231` 改**七个**失败模式、把第 7 条并入表」。
|
||||
落地前回源文档核对 ⇒ **`PLUGIN-PORTING.{md,zh-CN.md}` 早已是 `H1~H8` = 八个失败模式 + 六条规范(`R-a~R-f`)**。
|
||||
⇒ 按**源文档**对齐成 **8 行表**(补 `H7` 客户端半边静默挂死 / `H8` 原生绑定要求更新的 glibc),
|
||||
并把收尾指针里的「**五条改造规范**」一并去计数。若照草稿写成「七个」,就**新造了一处与文档打架的错**。
|
||||
🔑 **判据:README 是二手转述,定义在源文档**,凡要动「**几个 / 几条 / 第几条**」,
|
||||
**必须回到定义处核对**(本轮 = `PLUGIN-PORTING.*` 的 `## 2.` 与 `## 3.` 标题)。⛔ **「我上次写的清单」不构成依据。**
|
||||
· ✅✅ **可复用的落地方式:精确串替换器**(本轮 `_中间产物_待清理/_apply_round9.py`):
|
||||
每条规则 = `(old, new)`,**先全局数命中次数、要求恰为 1**,**任一不中就整体中止、不落盘**;
|
||||
行级删除按「**行首前缀**」匹配并同样断言 1 次(长段 bullet 用前缀删,避免逐字重打长串)。
|
||||
⇒ 比逐次 `Edit` 可靠(一次核对全部锚点、不会改到一半)、比 `sed`/`bash heredoc` 安全(**非 ASCII 不会被悄悄改写**,承事故 #31)。
|
||||
跑完**必须 `grep -c` 复核旧串 = 0**,再比**字节数与行数**的预期差(本轮 6 文件:中文 −1562 B / 英文 −1917 B,行数各 −9)。
|
||||
⚠️ 写脚本前先 `diff -u` 备份与现文件的**精简摘要**(只打 `^[+-]` 前 96 字符)核对改动面:全量 diff 会被长表格行淹没。
|
||||
· 🔴 **「索引类章节不写死计数」是已定口径,且要连指针一起清**:本轮清掉文档地图 3 处 + 收尾指针 1 处。
|
||||
⚠️ 但**括号里的枚举保留**(`隔离 · 自愈 · 插件治理 · …`),那是**指针的坐标**,不是计数。
|
||||
· 🔴 **搬内容优先于删内容**:版本历史里 5 条讲的是「**文档自己怎么改的**」(用户无感)⇒
|
||||
我选 **搬到 `manual/contributing.*`** 而非删掉,判据 = **该文档在文档地图里的描述本就写着「版本号与发布历史」**
|
||||
(搬过去名实相符,信息不丢);README 只留用户可感的行为变更(`v1.4.1` 只剩 `503` 冷启动 + 整理两条)。
|
||||
· 🔴 **历史条目里的旧名 ⛔ 不要改**:`manual/project.*` 有 **3 处「功能管理」**,是**当时那次改名事件的历史条目名**
|
||||
(`60-…功能插件改功能管理` / `67-功能管理section按UI规范重做` / `100-…并入功能管理分组`)⇒ 改掉等于**篡改历史**。
|
||||
要改的只有 **README / FAQ 里的现名**(现名 = **能力管理 / Capability management**,源仓条目 `101-能力管理-改名与tab分页与卡片三列`)。
|
||||
判据:**同词两义先看它是不是「历史记录里的引用」**。
|
||||
· 🔴 **在文档地图里加一行会动 parity `tableRows`**:本轮 **75 → 78**(地图 +1、PLUGIN-PORTING 表 +2),
|
||||
**中英必须同增**(`78/78`),否则门禁红。
|
||||
· ⚠️⚠️ **换行口径修正(此前记的「CRLF=0」是只看了 `.md`)**:导出仓**工作树有 52 个文件带 CRLF**
|
||||
(`src/**` · `web/*.html` · `*.json` · `07-scripts/*.sh`),那是 **`core.autocrlf=true` 检出**造成的**既有状态**,
|
||||
与 `_overlay`(Python 以 LF 写入)无关、**不进 git blob**。⇒ **⛔ 别误判成换行污染、⛔ 更不许顺手批量转换**(承「批量换行转换」禁令);
|
||||
验收只报「**本轮改动的 N 个文件 CRLF = 0**」。
|
||||
· 🔴🔴 **换行陷阱(同轮 git blob 实测出来,下次必踩)**:`dsh_ai1net/.gitattributes` **只钉三行**
|
||||
(`LICENSE` / `COMMERCIAL-LICENSE.*` 为 `-text`,法律文本逐字节原样),**`*.md` 不在其内** ⇒ 走 `core.autocrlf=true`。
|
||||
⇒ **`_overlay/*.md` 恒为 LF,而导出仓的 `*.md` 一旦被 git 重新检出(`git checkout` / 切分支 / 全新克隆到同路径)就变 CRLF**
|
||||
⇒ **`_sync_overlay.py --check` 的逐字节比较会假报「有差异」**(内容一致;`git status` 反倒干净,因为 autocrlf 做了归一化)。
|
||||
⚠️ **危险动作**:此时若为「消除差异」把导出仓的 CRLF 文件**反向拷进 `_overlay`** ⇒ **事故 #27 的反向版**(把当前版灌进未来版)。
|
||||
✅ **正确处置**:直接跑 `python _sync_overlay.py`(方向 `_overlay` → 导出仓,LF 覆盖回去);**git blob 里一直是 LF**,公开内容不受影响
|
||||
(2026-09-20 用 `git cat-file -p HEAD:README.md` 实测 blob 无 `\r`)。
|
||||
📌 **判据:「工作树有 CRLF」≠「换行被污染」,先看 `.gitattributes` 与 `core.autocrlf` 再下结论。**
|
||||
· ⏳ **同轮明确「不做」的两件事(都要单独授权,别顺手带上)**:
|
||||
① **破折号批量**(中文 `——` 206 处 / 英文 `—` 66 处,跨 ~15 份文档):触「>10 文件」红线,
|
||||
**且不是机械替换**:`**加粗术语** —— 说明` 这类该改 `:`,而句中插入语式的**真破折号要保留** ⇒ 必须逐处判断。
|
||||
② **代码注释里 4 处旧名**(`src/supervisor/orchestrator.ts:1222` / `:1266` · `spawner.ts:120` · `web/routes/whitelist.ts:482`):
|
||||
⛔ 不许手改非 `OVERLAY` 文件,正解 = **加一条 `LINE_REWRITE` 规则**,而规则变更**必须整树重建**(挪 `.git` · 清 `PYTHONPATH` · 三道闸门)⇒ 高影响面,单独确认。
|
||||
|
||||
---
|
||||
|
||||
Reference in new issue
Block a user