HarryKong824/fde-copilot

fde-copilot

给 AI 助手装上工程护栏的 DSH 插件套件 —— AI 改业务规则、推进阶段时没通过校验就动不了,所有动作记在一本改不掉的哈希链账上。零运行时依赖,41 套离线回归。

待分类ai-safetyaudit-trailfail-closed

FDE Copilot

把 Palantir 式 FDE(前向部署工程师)的交付动作,固化成一套 AI 能照着走的插件。
它以本体(Ontology)当业务规则的唯一权威,用 15 个交付阶段驱动 AI 从「接入客户」一路走到「移交 / 退出」:
每走到一个阶段,就按那个阶段该有的条件校验业务规则;改本体只能走唯一入口,改完还要过「规则可信度」校验。
门禁与审计是保证 AI 不跑偏的实现机制,不是产品本身。

这是什么

一句话:它让 AI 扮演一名 FDE —— 按「干系人对齐 → Bootcamp → Demo → 本体定义 → AIP 叠加 → 部署 → 变更管理 → 评估飞轮 → 产品化 → 移交」的节奏做交付, 而不是拿到一句需求就直接去改代码。

15 个交付阶段(4 个区)

区 · 阶段 A 切入 · 0.1 Connect | 0.2 Site Survey | 0.3 Stakeholder Map | 0.4 Success Criteria B 共建 · 1 Bootcamp + 场景发现 | 2 Demo 深化 + 数据接入 | 3 Ontology 完整定义 | 4 AIP 叠加 C 落地 · 5 交付与移交准备 | 6 Deploy | 7 Change Management | 8 Eval Flywheel | 9 Productize D 收尾 · 10 Handoff | 11 Disengage

三条硬规则(由插件强制,不靠嘱咐):

  1. 阶段只能一格一格推进(current → next)—— 跳过「Ontology 完整定义」就等于跳过 D1 门禁;
  2. 每次改本体都要定级:L0 / L1 / L2,看语义载荷而不是看 diff 形状;
  3. 本体节点有成熟度:draft → verified → locked,只能升不能降。

靠什么实现:四个互相协作的插件

跑在 DeepSeek Harness(DSH) 上:

插件 · 管什么 `dsh-fde-ontology-gate` · 谁能在什么条件下改本体(业务规则)+ 变更定级 `dsh-fde-dsl` · 改出来的规则能不能信(D1 护栏 + D3 反例) `dsh-fde-phase` · 现在处在哪个阶段、能不能推进 `dsh-fde-memory` · 决策、清单、干系人、实验沙箱、本体成熟度,以及审计采集

共注册 20 个工具,全部通过 ctx.tools.guard 挂在宿主的工具调用链上。

为什么「门禁」必须做在机制层,而不是写在提示词里

「在提示词里提醒 AI 注意安全」是没用的——AI 可以不听。

方式 · 能拦住吗 提示词提醒 AI · ❌ AI 可以不听 守卫(`ctx.tools.guard`) · ✅ 同步、单调、只能否决——返回拒绝后无人能翻盘

这套系统提供的是机制,不是建议:

  • fail-closed:判定不了「安全」时,一律判「不放行」;
  • 哈希链审计:改任何一条记录都会导致后续全部哈希不符;
  • 结论绑定内容哈希:改了文件 ⇒ 旧结论自动失效,杜绝「拿改动之前的结论蒙混过关」。

快速开始

环境要求

项 · 要求 操作系统 · Windows(本项目在 Windows 11 上开发与验证) Node.js · 插件运行:与 DSH 宿主一致(四个插件的 lib/ 不用 node:zlib,没有额外版本要求)跑回归:Node ≥ 22.15(package.json 的 engines;实测依据见下节) DeepSeek Harness · 桌面应用形态(DeepSeek Harness.exe)已安装

⚠️ DSH 不是命令行服务,是 Electron 桌面应用 ⇒ 「启动/停止」= 打开/关闭应用,没有 systemd 概念。

跑一遍回归(不需要 DSH)

bash tests/_run_all_tests.sh
#   期望最后两行(本机**没有**部署 DSH 时):
#   共 41 个套件;已跑 37;跳过 4(白名单内,需本机部署的 DSH);失败 0;疑似空程序 0
#   ALL-TESTS-GREEN
#   ⚠️ 「跳过 4」= 这 4 套要读你**本机已部署**的插件副本,没有那份部署就跑不了 —— 见下节。
#      本机**有**那份部署时是「已跑 41;跳过 0」。
#   退出码:0 = 通过;1 = 有失败(判定行与退出码同源,不会一个说绿一个说红)

部署插件

# 1. 复制 4 个插件目录到 DSH 的插件位置
cp -r dsh-fde-*  <DSH_HOME>/profiles/web/node_modules/

# 2. 编辑配置(这是配置的唯一权威)
#    <DSH_HOME>/profiles/web/cordis.patch.yml

# 3. 对拍源 ↔ 副本
node tests/_deploy_diff.mjs      # 期望:ALL_MATCH

# 4. ⚠️ 重启 DSH —— 改了 lib/*.js 不重启等于没改

完整步骤见 → docs/03-usage/deployment.md

零运行时依赖

"dependencies": {}

四个插件的 dependencies 全部为空。

意味着 · ✅ 不向宿主引入任何依赖面 · ✅ 不联网、不上云、数据 100% 留本机 ✅ 不打包任何第三方代码 · ✅ 无第三方许可证义务

peer 依赖(由宿主 DSH 提供,本项目不打包):

@deepseek-ai/dsh-tools    0.1.2-rc.1
@deepseek-ai/schemastery  3.18.2
连 YAML 解析都是自研的受限子集(yamlsubset.js)——代价是行内集合必须写合法 JSON(双引号)。

仓库结构

.
├── README.md                    ← 本文件
├── LICENSE                      ← 规范 MIT 正文(GitHub 可自动识别)
├── DISCLOSURE.md                ← 四项如实披露(AI 生成 / 领域敏感 / 第三方宿主 / 非专业意见)
├── CHANGELOG.md
├── CONTRIBUTING.md
├── SECURITY.md                  ← 报漏洞的私密渠道 + 已知安全边界
├── CODE_OF_CONDUCT.md
├── package.json                 ← `npm test` 入口(= bash tests/_run_all_tests.sh)
├── .gitignore                   ← ⚠️ node_modules 有反常规处理,改前先读
├── .gitattributes               ← ⚠️ 强制 LF;删了会让 .sh 在 Windows 上坏掉
├── .github/
│   ├── workflows/test.yml       ← CI:每次推送自动跑那 41 套
│   ├── ISSUE_TEMPLATE/bug_report.md
│   ├── ISSUE_TEMPLATE/feature_request.md
│   └── PULL_REQUEST_TEMPLATE.md
│
├── docs/                        ← 📚 18 份交付文档(从这里开始读)
│   ├── README.md                  导航中枢
│   ├── 01-overview/               项目说明书 · 功能对照表 · 技术架构
│   ├── 02-development/            开发日志 · 变更台账 · Bug台账 · 版本记录
│   ├── 03-usage/                  用户手册 · 部署运维 · FAQ
│   ├── 04-retrospective/          总结报告 · 成本统计 · 迭代规划
│   └── 05-ai-development/         AI工具清单 · Prompt库 · 代码风险 · 数据版权
│
├── dsh-fde-ontology-gate/       ← 插件 1(20 文件 / 7,042 行)
├── dsh-fde-dsl/                 ← 插件 2(17 文件 / 2,728 行)
├── dsh-fde-phase/               ← 插件 3(25 文件 / 6,625 行)
├── dsh-fde-memory/              ← 插件 4(26 文件 / 5,055 行)
│
├── tests/                       ← 41 套离线回归(+ 7 个它们真正 import/spawn 的脚本,必须同目录)
│   ├── README.md                  这个文件夹里有什么、怎么跑
│   ├── _run_all_tests.sh          全量回归入口(**从任意目录调用都行**,脚本会自定位)
│   ├── _*_test.mjs                41 套套件
│   └── _fixtures/                 回归夹具
├── tools/                       ← 111 个独立工具脚本(活验 / 勘察 / 一次性,**不进回归**)
│   └── README.md
├── evidence/                    ← 历史测试产物归档(⚠️ 已在 .gitignore,不进仓库)
└── node_modules/@deepseek-ai/   ← ⚠️ 测试桩,【必须保留】,见 .gitignore
✅ 本结构已被验证:从本仓库克隆到干净目录后 bash tests/_run_all_tests.sh → ALL-TESTS-GREEN。
这证明 .gitignore 里的 node_modules 例外有效、LF 归一化不破坏夹具、脚本的子目录自定位有效。
(本机有部署时 41/41;干净机器上是 37 跑 + 4 跳过,见下节。)
📌 关于「脚本放进子目录」这件事,之前写在 README 里的理由是错的
(原文:「它们用 ./dsh-fde-phase/lib/state.js 相对导入,移动会直接破坏 41 套回归,是不可移动的硬约束」)。
2026-09-29 实测证伪:移动确实要顺手改两类路径——① 相对导入 ./dsh-fde-* → ../dsh-fde-*;
② 少数按「我所在目录 = 仓库根」拼的运行时路径。改完 41/41 全绿、0 失败。
⇒ 它不是「不可移动」,是「移动时要顺手改路径」。仓库根的条目数从 `182` 降到 `19`
(= 10 个文件 + 9 个目录;用 git ls-tree --name-only HEAD | wc -l 与
git ls-files | awk -F/ 'NF==1' | wc -l + 首层目录数对拍得出)。
(仍在根目录出现的只有 _*_out.txt 这类产物,已 gitignore、不进仓库。)

⚠️ 哪些脚本你能跑,哪些跑不了

请先读这段,否则会在不该失败的地方失败。

类别 · 能否直接跑 · 说明 _*_test.mjs(41 套) · ✅ 能 —— 限 Windows + Node ≥ 22.15 · 路径从脚本自身位置推导,不含作者本机绝对路径。2026-09-29 实测:换目录也能跑,且改坏插件会让对应套件变红(变异验证过)。 ↳ 其中 4 套 · ⚠️ 要本机已部署 DSH,否则明确跳过 · tests/_fde_e1_wiring_test.mjs、tests/_fde_e2_test.mjs、tests/_fde_e5_test.mjs、tests/_fde_phase_wiring_test.mjs。它们要读你本机已部署的插件副本 / 部署配置 ⇒ 不是纯离线套件。没有那份部署时它们 exit 77(跳过),汇总行会报出「跳过 4」。设 FDE_DSH_HOME= 即可让它们真跑。 tests/_deploy_diff.mjs · ✅ 能(限 Windows,且需本机有部署) · 不传参数 = 对拍全部 4 个插件(就是下面部署步骤里那条命令)。本机没有那份部署时它会明确报 SKIP 并 exit 77,不会报 ALL_MATCH;设 FDE_DSH_HOME= 即可真跑。也支持原用法 node tests/_deploy_diff.mjs 只对拍一对。退出码:0 全一致 / 1 有差异 / 77 无部署可测(不是一致)。 tools/_token_usage_report.mjs · ✅ 能(跨平台) · 纯统计工具,路径由命令行参数给。 | _*_live*.mjs、_cc_*.mjs、_dsh_*.mjs 等(36 个) | ❌ 不能开箱即跑 | 它们是活验仪器:① 需要 DSH 正在运行;② 里面写死了作者本机路径(C:/Users/DELL/...)与 launch-token 文件位置。(口径:grep -rl "Users/DELL" 命中的根目录脚本共 36 个; 另命中 4 份文档,逐一列出以免读者数不出来 —— README.md、CHANGELOG.md、 dsh-fde-ontology-gate/README.md、dsh-fde-ontology-gate/HANDOFF.md。) |

🔴 两条边界 —— 都是 CI 实测出来的,不是猜的
① 平台:这 41 套回归是 Windows 专用的。
| 平台(同一次提交) | 结果 |
|---|---|
| Windows 11(开发机) | ✅ 41 套全绿 |
| windows-latest(GitHub 托管) | ✅ 全绿(修好下面②之后) |
| ubuntu-latest | ❌ 41 套挂 9 套 |
从失败断言能看出两处根因方向:tests/_gate_mode_test.mjs 的断言原文是
「enforce 下路径命中应拒」⇒ 路径语义不同;tests/_shelltok_test.mjs ⇒ shell 分词语义不同;
其余若干在导入期直接崩溃。
② Node 版本:不能低于 22.15。
| Node | 结果 |
|---|---|
| 20.20.2 | ❌ 挂 2 套:zlib 没有 zstdDecompressSync 这个导出 |
| 22.15.0 | ✅ 有该导出(实测 typeof === 'function') |
| 24.15.0 | ✅ 全绿 |
用到 zstd 的是读 DSH 会话记录的那几个脚本(tests/_tool_surface_check.mjs 等)——
插件 `lib/` 本身不用 zstd,所以「跑插件」没有这个版本要求。
下界已写进 package.json 的 engines。
⇒ 所以 CI 固定在 `windows-latest`,Node 取 `22.15.0` 与 `24` 各跑一遍。
没有把它改成"Linux 上失败也算通过"、也没有把 Node 钉在 20 再放宽判据 —— 那都是假绿。
CI 的判定步还额外核一件事:跳过数必须正好是 4(白名单一变就红),
这样「跳过」不会变成一个能吞掉红灯的出口。
🔴 关于那 36 个活验脚本 —— 一个必须说清的事实:
它们含作者本机路径这一点已知未修。原因不是没发现,而是修不了:
它们的行为必须连着运行中的 DSH 才能验证,而合并前无法验证的改动不允许进主干
—— 这正是本项目自己的纪律("判据必须可复算")。
⇒ 要复用它们,请先按你的环境改路径,并自己验一遍。