Skip to content
dsh.fish
Bundle

dsh-selfharness

Harness 层递归自我改进:把 Harness 物化成可版本化的 Harness Pack,从真实会话轨迹里挖缺陷、提议改进、在留出集上配对评测,只有过门控的候选才会生效。

Source
shuiiiiimu
License
MIT
Updated
Updated 15 days ago

Readme

# dsh-selfharness — DSH 上的 Harness 层自我改进插件

把 Harness 物化成**可版本化的 Harness Pack**:从真实会话轨迹里挖反复出现的缺陷,据此改进,
在留出集上配对评测;只有增益超过噪声底的候选才会生效。基础模型全程冻结,
整个演化过程落盘成可 `git diff`、可 `git revert` 的产物。

---

## 1. 自进化的逻辑

**Harness 也是模型能力的一部分。** 同一个模型,换一份 system prompt、换几个 skill、
收紧几条工具边界,表现会不一样。所以「自我改进」在这里不是改权重,而是改这些外置的东西,
并且把它们从散落的配置收拢成一个**对象**(Pack),才能版本化、评测、回滚。

**改进必须可测,因为增益小、噪声大。** 每一次改动都在留出集上做 task 级配对比较,
只有超过噪声底、且不牺牲能力的候选才算数 —— 这一条把「听起来有道理」和「真的更好」分开。

**判据是泛化,不是适应。** 记住训练任务不算自我改进。所以留出集分三类:
提议者可见的 public 只看诊断,private / transfer / regression 只给门控看。

```
[1] 真实会话轨迹 ──▶ 经验库(SQLite)
                          │  同一个失败签名反复出现
                          ▼
[2] 缺陷簇 ──▶ 机会筛选 ──▶ 值不值得花这一轮预算?
                          │  估不出来就直接砍掉,不花预算
                          ▼
[3] 提议(改 Pack)──▶ 审查(静态 + 行为契约)
                          │
                          ▼
[4] 门控(配对统计 + 风险分级)──▶ 不通过:写进否决台账后结束
                          │  通过
                          ▼
[5] 激活(指针移动)──▶ 新 Pack 生效 ──▶ 挂上观察窗
                                             │  同一缺陷签名回升
                                             ▼
                                       自动回滚(只回滚、不推进)
```

**五个面**(候选能改的东西):

| 面 | 是什么 | 生效方式 |
|---|---|---|
| `doctrine` | system prompt 的一段文本 | 热切换:下一个会话立刻生效 |
| `skills` | `skills/*.md` | 热切换 |
| `tool-policy` | 工具 **deny** 列表,沿版本链单调不减 | 热切换 |
| `context-policy` | 别的插件的 Config | 只产出**建议值**,粘进 `cordis.patch.yml` 后重启 |
| `observation-policy` | 同上 | 同上(这两个面不参与自动门控) |

**三道防线**,任何一道不通都不激活:

1. **静态** —— schema 校验 + deny 单调 + 全 Pack 字面量扫描(把留出集特征写进 Harness 直接拒);
2. **统计** —— 能力下限 + 两条并列通道之一:
   `Δ_private ≥ δ_noise` 且区间下界 > 0(能力增益),或至少一项效率指标显著改善且其余不倒退(约束效率)。
   `δ_noise` 由历史 baseline 池的成对差异 95 分位标定,不是两次基线自比。
   配对单位是 **task 不是 rollout**:k 次重复先聚合成任务通过率,再做 McNemar + bootstrap 区间。
3. **风险** —— `doctrine` / `skills` / `tool-policy` 一律 `defer` 到人工;只有两个"建议值"面能自动通过。

**激活之后仍然有安全阀**:Pack 指针移动、新会话生效,同时按该候选针对的缺陷签名叫醒一个观察窗;
证据显示该签名回升就**自动回滚**(只回滚、不推进),并写台账。回滚是一等公民操作,不需要评测。

**留出集不落盘**:private / transfer / regression 只以数据库行存在,评测时才物化进那个 rollout 的
工作目录,跑完随目录一起删。提议阶段磁盘上不存在这些文件,这是泄漏防火墙的主防线。

```
    缺陷签名 ~ 机制假设(并行)
    ├── lineage L1 ──▶ 候选 A ──┐
    └── lineage L2 ──▶ 候选 B ──┴──▶ 各自独立评测 ──▶ 门控 ──▶ 至多一个被激活
```

---

## 2. 安装与上手

作为普通 bundle 装进 profile(`<checkout>` 是本仓库路径):

```bash
dsh plugin --profile web add <checkout>
```

装完**必须重启一次 `dsh`**:bundle 列表在启动时读取,profile 的 `patchReload: live`
只能热重载已挂载的 row,装不进来一个全新的 bundle。

开发时 Host 侧改动不必重启:

```bash
npm run build:js && npm run reload   # 禁用原 row + 插入 selfharness-dev 指向新的内容寻址副本
```

`reload` 不能直接把原 row 的 `name` 改指向新副本:非 `insert` 补丁里的 `name` 只是**断言**,
与 row 不符时整条补丁会被 Loader 跳过(`patch: name mismatch … skipping`),这正是它早期版本
静默失效的原因。所以它写两条补丁——按 id 禁用 bundle 自己的 row,再插入 `selfharness-dev`
row(`insert` 的 name 才可解析,相对路径由 DSH 锚定到 patch 文件所在目录)。落盘前它用
DSH checkout 自己的 `applyEntryPatches` 复算一遍,patch 不生效就拒绝写入。

全部操作都在**面板**上(侧边栏「自进化」→ 收益 / 轮次 / 谱系 / 设置四个视图):

| 要做什么 | 在哪里 |
|---|---|
| 看**这次进化的收益**:已生效的改进各改了什么、门控实测到多少、覆盖之前哪些历史任务 | 「收益」页(默认首屏)。模型侧对应 `selfharness_value` 工具 |
| 看某一条候选的判决依据、逐行 diff | 轮次 → 展开该轮 → 候选卡片 |
| 回填历史会话、挖缺陷、装内置示例套件 | 设置 → 「登记评测套件」下方的 bootstrap 入口(面板 `bootstrap` 动作) |
| 试算一轮值不值得跑 / 真跑一轮 | 页头「运行一轮」;设置页的预算与熔断 |
| 采纳 / 拒绝 / 推后一个候选 | 轮次 → 展开该轮 → 候选卡片上的三个按钮(二次确认 + 填理由) |
| 回滚到任一历史版本 | 谱系 → 每个非 active rev 上的「回滚到此版本」 |
| 熔断 / 恢复 | 设置 → 「熔断(pause)」/「恢复(resume)」 |
| 导出两个"建议值"面 | 设置 → 「导出 context / observation 建议值」 |
| 问它现在什么状态 | 设置 → 「循环状态」,或让模型调 `selfharness_status` 工具 |
| 在模型里看「尺子」够不够大(不花钱) | `selfharness_preview` 工具:套件题数、MDE、δ_noise 来源 |
| 让模型/脚本做维护动作(bootstrap / harvest / 扩产 / 自检 / 复检 / 清理 / 清空历史) | `selfharness_maintain` 工具(面板上都有对应按钮) |
| 清空全部历史、从零重跑(调试/验收用) | 设置 → 「清空历史(重新开始)」:要输入 `reset-history` 才可点;也可用 `selfharness_maintain`。默认**保留已装套件**(尺子不是历史;留出集正文只存在数据库里),要连套件一起删就传 `includeSuites=true` |

所有写操作都要二次确认并填理由。

### 无界面(headless)跑一轮

面板不是唯一的入口:模型工具与脚本都能跑完整流程。DSH 自带 headless profile,把插件装进去即可:

```sh
# 1. 建一个 headless profile(只含 base + headless,没有任何 HTTP 端口)
dsh --profile headless --dump-config >/dev/null

# 2. 把插件挂进这个 profile(本地 link,不联网)
ln -s ../../../codespaces/dsh-selfharness ~/.dsh/profiles/headless/node_modules/dsh-selfharness
#    并在 ~/.dsh/profiles/headless/package.json 里加 "dsh-selfharness" 到 dsh.profile.bundles

# 3. 跑一轮
dsh --profile headless "用 selfharness_maintain 做 bootstrap,再用 selfharness_run 跑一轮并把报告原样打印出来"
```

headless profile 里没有交互式批准,所以要么给 `selfharness` 行配 `config.toolApproval: never`,
要么自己接一个 answerer —— 默认的 `mutating` 在无人应答时会**失败关闭**(`ask` 被拒),
这不是 bug,是设计。

> **注意**:内置示例任务(一段真有 bug 的小 JS)只够跑通链路,不够支撑显著性结论 ——
> 在它们上面门控通常会正确地拒绝所有候选。要看到真正的增益,需要把你自己的历史失败
> 会话沉淀成套件。改进幅度本身也不大(同量级工作报告在 Terminal-Bench 上是 +4.9pt),
> 这是**受约束的有限自我修改**。

---

## 3. 配置

所有字段可选,写在 profile 的 `cordis.patch.yml` 里:

```yaml
- id: selfharness
  config:
    enabled: true
    toolApproval: mutating          # always | mutating | never
    pinnedRev: 0003-a1b2c3          # 钉住一个已知可用的版本
    agentModel: { provider: deepseek-official, model: deepseek-flash, reasoningEffort: high }
    budgets:
      maxRoundsPerDay: 4
      maxRolloutsPerRound: 400
      autoPauseAfterConsecutiveNoImprovement: 3
      phaseShares: { screen: 0.1, confirm: 0.8, recheck: 0.1 }   # 轮内预算按阶段硬闸
      noiseCalibrationTarget: 4           # 同一 rev 的基线样本数,够了才允许能力通道
      noiseCalibrationRepeatsPerRound: 2  # 每轮最多花几次基线重复来标定 δ
    gates:
      screenK: 1
      confirmK: 3
      noiseFloor: auto                    # auto = 由 (rev,model,suite,split,k) 池标定
      capabilityFloorTolerance: 0.03      # τ_cap:非劣边界(≠ δ_noise)
      capabilityAlpha: 0.05               # 单侧显著性水平
      minDiscordantPairs: 5               # 达不到就只能说「证据不足」
      targetMde: 0.05                     # 面板上的 MDE 目标
    risk: { requireHumanApprovalFor: [tool-policy, doctrine, skills, permissions, self-modification, request-policy, proposer-policy] }
    crossModel: { enabled: false, arm: { provider: xiaomi, model: mimo-v2.6-pro },
                  critic: { provider: xiaomi, model: mimo-v2.6-pro }, required: false }
    taskFactory: { enabled: true, stabilityRuns: 3, mainTaskTarget: 30 }
    population: { archiveLimit: 200, routingEnabled: false }
    requestPolicy: { enabled: false, audit: true }   # 审计始终开;策略默认关
    selfModification: { enabled: false, minStableRounds: 5 }
```

| 字段 | 默认 | 说明 |
|---|---|---|
| `rootDir` | `<cwd>/.dsh/selfharness` | Pack 仓库 + 台账;**这个目录本身是一个 git 仓库** |
| `dataDir` | `$DSH_HOME/storages/selfharness` | `selfharness.db` |
| `enabled` | `true` | 全局 kill switch:`false` 时读面照常、写面拒绝 |
| `toolApproval` | `mutating` | 只读工具不申请批准;花钱/改 Harness 的三个(`run` / `maintain` / `decide`)强制申请。headless 部署把它设成 `never`(等于「这个部署自己有闸门」) |
| `pinnedRev` | 无 | 钉住一个版本,忽略 `ledger/active.json` |
| `budgets.maxRoundsPerDay` | `4` | 每日轮次上限;熔断只挡写操作 |
| `gates.confirmK` | `3` | 阶段 2 每任务重复次数 |
| `gates.minEvidenceCount` | `3` | 缺陷成案所需的独立证据条数 |
| `gates.noiseFloor` | `auto` | `auto` = 由 `(packRev, model, suite, split, k)` 基线池标定;给数字可钉死(复现实验用) |
| `gates.capabilityFloorTolerance` | `0.03` | **τ_cap**:非劣边界(2–5pt)。它与 δ_noise 是两个旋钮:δ 回答「有没有变好」,τ_cap 回答「有没有明显变坏」 |
| `gates.capabilityAlpha` / `minDiscordantPairs` | `0.05` / `5` | 预注册的**单侧**能力检验;不一致对数不够时判决是 `insufficient-evidence` 而不是 `reject` |
| `budgets.phaseShares` | `0.1/0.8/0.1` | 轮内 rollout 按阶段硬分配;超限抛 `BudgetExhausted`,候选记 `insufficient-evidence` |
| `budgets.noiseCalibrationTarget` | `4` | 同一 rev 的基线样本少于它时,能力通道被禁用,本轮最多只能 `defer` |
| `crossModel.*` | 关闭 | F1:异族迁移臂 + 异族审查者。**`enabled` 不等于泛化成立**——无数据时门控报 `undetermined` |
| `population.routingEnabled` | `false` | F3:按任务族路由到不同 rev。默认关闭时行为与单 pack 完全一致 |
| `requestPolicy.enabled` | `false` | 面 D:按任务族覆盖 `reasoningEffort`/`maxTokens`。关闭时行为逐字节不变 |
| `evalPreset` / `proposerPreset` | `selfharness-eval` / `selfharness-proposer` | 打在这两类会话上,经验采集据此排除它们 |

预算、门控、路径与预设都是**插件 Config,不是运行时状态**:改它们要编辑 `cordis.patch.yml`
并重启 Harness,面板只做只读投影。

---

## 4. 数据落地

```
<rootDir>/                                  # 本身是一个 git 仓库
├── packs/<rev>/                            # pack.json + doctrine.md + skills/ + tool-policy.json
│                                           #   + context-policy.json + observation-policy.json
│                                           #   + request-policy.json + proposer-policy.json
├── eval/suites|fixtures/                   # 套件与任务工作目录
├── work/                                   # 评测工作区,每 rollout 一个,跑完即删(崩溃残留按保留期清理)
└── ledger/{active.json,round.lock,rounds.jsonl,rejections.jsonl,coverage.json}

$DSH_HOME/storages/selfharness/selfharness.db   # episodes / defects / candidates / evaluations /
                                                # decisions / baselines / feedback / archive
```

审计 = `git log`,回滚 = 指针移动。

---

## 5. 面板

![面板 · 收益页](docs/demo1.png)

首屏是**「收益」页**,它回答使用者真正打开这个页面的那个问题——**这次进化给了我什么**:先是一排计数
(已生效 / 实测增益 / 覆盖历史经验 / 受影响任务族 / 等你决定 / 已回滚),然后是每条已采纳改进的卡片
(针对哪个缺陷签名、命中多少条真实经验、改了哪个面、门控实测的 Δ 与区间、成本的前后对比、观察窗状态),
最后按**任务族**归集「对哪一类历史任务有优化」。

三处诚实性规则把这个页面和一张宣传单分开:**没测过的增益显示「未测量」而不是 `+0.0pt`**(零是测量结果,
未知不是);**不同版本的增益不求和**(它们是在各自轮次的留出集上配对测的,相加会造出一个没有任何门控
产出过的效应量);**影响范围来自真实回合**(按经验里记下的缺陷根因匹配,而不是引用候选自己的说法),
扫描有上限时明说「只覆盖最近 N 条经验」。

首屏常驻一条 **MDE 横幅**:套件太小就显示「不足以支撑任何显著性结论」并给出还差多少题;如果基线上每道题
得分完全一样(方差为 0),它显示「**无法估计 MDE**:这个套件对当前难度没有分辨力」。两种情况下都**不会**
为不可判定的增益画曲线——这是刻意的负向验收。评测表直接读**门控当时存下的那份报告**,面板不复算任何统计量。
候选卡上还有一个「逐行 diff」按钮:按需读出父版本与候选,对每个面给出折叠过的行级差异——这正是
「整面替换文本」和「看得出改了什么」之间的区别。

页头只有**一个**「运行一轮」按钮:一轮要跑几分钟到几小时,所以它总在后台跑,面板显示阶段、进度、rollout
done/total、已用时长与心跳,随时可取消。进度在三处可见,按「离你多远」排:侧边栏「自进化」上的小圆点
(不必先打开面板)、「轮次」页顶部的进度卡片(含当前正在测哪道题)、卡片下方的最近若干次运行记录。
取消的候选记为「证据不足」而不是「否决」;进程崩溃或重载留下的「运行中」记录会被判为**中断(无心跳)**
并允许清理,而不会一直挂着一个停不掉的「取消本轮」。台账仍然逐行留存,上面三处只是手边的状态视图。

页头左侧的指示灯只回答一个问题——插件能不能进化:**已就绪(空闲)**(不会自己开轮,等你点)/
**轮次进行中** / **已熔断**(连续无改进或人工暂停,写操作被拒,可在设置页恢复)/ **已关闭**(插件被配置关掉:读面可用、写面全拒)。轮次结束后横幅不立刻消失,而是显示上一轮的结局与判决摘要,点「知道了」才清掉。

面板文案里不出现仓库内部的计划编号(`§x.y` / `M7` / `F1` 之类)——那是内部说法,不该让使用者猜。

## 6. 已知边界

1. **工具策略只能收紧**:`tool-policy.json` 表达三层——`deny`(工具名)、`families`(能力组:shell / net /
   fs-write / fs-read / process / package)、`argumentRules`(参数级规则),**三层都按集合包含单调**;allow / 白名单语义仍排在 v2。
2. **参数级规则不是沙箱,也不是防火墙**:`tools/pre-execute` 拿到的是**已解析的参数对象**,所以 `bash.command`
   是可读字符串、可以按模式拒绝(`curl|wget|nc|ssh` 等),并留下审计证据。但 `sh -c`、解释器、变量拼接都能绕过它;
   真正的围栏仍只有文件系统 sandbox,而**网络没有围栏**。真正的泄漏防线始终是「留出集在提议阶段不落盘」。
3. **评测 Agent 没有 per-agent 断网 API**:缓解只有 fixture 不依赖网络 + verifier 注入死 proxy + 受限环境跑验证。
4. **只做人工触发**:唯一自动的动作是激活后的观察窗,且只回滚/提示、不推进;后台轮由人点、可随时取消。
5. **跨模型是可立项的实证课题,不是既成事实**:第二个 provider 已装入且凭据已配置,但门控在**没有异族数据时**
   只会报 `undetermined`——「配置了第二个 provider」不等于跨模型泛化(红线 9)。
6. **`context-policy` 仍不能热生效**(属于别的插件 Config,只产出建议值 + 重启);但 **`observation-policy` 一分为二**:
   `inlineTokenBudget` / `preserveOriginal` / `shape` 由本插件自己的 `tools/post-execute` 缩减器**热应用**且 fail-open,
   只有 `maxInlineTokens` 是对 `spill-policy` 的建议值。
7. **M7(改插件自身代码)默认关闭**,且打开后**没有激活路径**:改动只在 `git worktree` 隔离副本里 apply + build + test,
   验证跑在死 proxy + `ignore-scripts` 的受限环境里,产出可复现构建哈希交人 review;正在运行的 checkout 永远不被写。
   patch 只许动 `src/**` 与 `test/**`;`package.json` / lockfile / 组合文件一律拒绝。
8. **不可削弱条款(F4-b)不进任何可演化面**:doctrine 里的 discipline canary、`preserveOriginal=true`、
   受保护判据键(`capabilityAlpha` / `minDiscordantPairs` / `capabilityFloorTolerance` / `costTolerance` / …)
   由 `applyProposal` 里的硬断言守住,违反者在 schema 阶段就被拒。
9. **F5 的外部任务源不可用**:本版本只交付「本仓库自身历史」这条零成本冷启动路径;
   issue/PR 挖掘需要网络 + 磁盘 + 离线镜像,面板如实显示为不可用,而不是留一个看似接好的 stub。

---

## 7. 测试与预检

```bash
npm test             # 242 个用例,不联网、不花预算、不需要真模型(约 24s)
npm run typecheck
npm run check:compat # 对照 DSH checkout 断言 24 个 seam + 工具归一名单全覆盖
npm run check:config
npm run preview      # 渲染 tmp/preview/*.html 并截图到 tmp/shots/
```

`test/calibration.test.mjs` 是**这个仓库最重要的一条测试**:用确定性 Bernoulli 生成 Δ=0 的成对任务计数,
直接调 `evaluateGates()`,断言**零效应接受率 ≤ 3%**。它锁的不是数学(统计函数本来是诚实的),而是**门控的构造**——
v1 的 `能力 ∨ 效率` 在这里会给出约 40% 的放行率。同一文件还有正向对照(真实 25pt 效应接受率 84%)
与「纯成本改善不得被接受」,所以它同时钉住了特异度、敏感度与通道独立性。

`test/round.harness.test.mjs` 是**零花费端到端**:在 service 边界上注入确定性 fake,驱动生产编排
`buildRoundEngine` 跑完整轮。除了原有的泄漏拒绝 / 高风险 defer / 观察窗回滚 / dry-run 之外,现在还断言:
freeze 行先于任何有判决意义的 rollout、δ 来自同 rev 的池、整段 regression 都被测到、预算耗尽记
`insufficient-evidence` 而不是 `reject`、并发轮次被轮锁拒绝、过期轮锁可回收。

`test/value.test.mjs` 是**收益页的地基**:它把「这次进化收益是什么」最容易说谎的四处钉住——
没测过的增益必须报 `measured: false`(而不是 `+0.0pt`)、影响范围必须来自真实 episode 的 `signals`
(而不是候选自己的说法)、被回滚的改进不得计入「已生效」、`active` 指针不可解析时必须报
「无法判定」而不是「已被取代」。另外两条钉住刻意的特例:效率类缺陷按任务族匹配、扫描上限必须自报。

改面板时的视觉验收:`npm run preview` 把三个视图(外加一个强制展开的轮次)渲染成 `tmp/preview/*.html`,
再用本机无头 Chrome 截图到 `tmp/shots/`,不必重启 `dsh`。

样式表有一条硬规则:**只引用真实存在的 DSH 主题 token**。引用不存在的 token 不会报错,只会静默走 fallback——
于是浅色下「差不多对」、深色下整个错。`test/styles.test.mjs` 断言这条规则(token 白名单 + 无字面颜色 +
类名全覆盖 + focus / reduced-motion),`npm run check:compat` 再断言白名单本身没有脱离 checkout 的主题表。

其余文件覆盖:`stats`(Newcombe / McNemar / 单侧检验 / MDE / 成本规则)、`suite`、`leak`、`value`(收益投影:实测 / 未测量、回滚、取代、指针损坏、扫描上限)、
`pack`(schema / 三层单调 / 内容哈希 / **discipline 六条**)、`gates`(预注册单侧判据、非劣、活跃子集、
`insufficient-evidence`、跨模型三态、budget-stop)、`policy`(工具归一 / 能力组 / 参数规则 / 注入返回值 /
观测缩减 fail-open / 请求路由开关)、`factory`(白名单 / k 稳定性 / 难度带 / blueprint / MDE 环 / Pareto / 路由默认关 / 冷启动)、
`selfmod`(patch 范围 / 稳定增益门槛 / 三方隔离声明)、`diff`、`panel`(含 `GET /value` 与面板 payload 的同形断言)、`client`(jsdom 里真实加载 `lib/client.js`)、`reload`(dev override 的补丁形状过 DSH 自己的 `applyEntryPatches`,脚本对临时 profile 实跑)、`styles`。

---

## 8. 代码地图

```
src/
├── index.ts            apply():装配、注册、注入(含观测面 / 请求路由 / feedback / SSE)
├── value.ts            收益:把「这次进化给了我什么」join 成一份报告(改了什么 / 实测多少 / 覆盖哪类历史任务)
├── config.ts           Config schema、默认值、kill switch、F 层开关
├── service.ts          状态与写入的唯一入口(含 MDE / δ / 档案 / 轮锁投影)
├── pack/               pack schema、discipline(F4-b)、git 版本库、原子落盘、轮锁、激活
├── guard.ts            工具策略求值:NFKC + 别名归一、能力组、参数级规则
├── observation.ts      面 C:证据保全式观测缩减(fail-open)
├── request-routing.ts  面 D:审计 + 按族路由(默认关)
├── experience/         轨迹投影、SQLite(留出集以行存在,v2 迁移)、经验回填、feedback
├── miner/              根因签名聚簇成案(含效率案)、机会估计
├── proposer/           提示与行为契约、全量编辑历史、覆盖图、实现↔审查有界回路
├── evaluator/          套件解析、Pack 注入(agent-scoped pre-execute)、worktree 评测、统计、泄漏扫描
├── selector/gates.ts   预注册单侧判据 + 能力非劣 + 效率非劣 + 风险分级
├── gate-report.ts      从 decision 行里取出「门控当时用的那份报告」(轮次页与收益页共用)
├── round.ts            一轮循环的编排 + 预算硬闸 + freeze 行 + 面板 action 表 + 后台轮
├── observe.ts          观察窗(推导证据量)与自动回滚
├── rsi.ts              RSI 六维自评(按测量而非计数)
├── taskfactory.ts      F2:白名单 / 稳定性 / 难度带 / blueprint / MDE 环
├── population.ts       F3:Pareto 父代采样、固定容量合并、路由表
├── coldstart.ts        F5:把本仓库自己的已知坑变成 public 诊断任务
├── diff.ts             面板用的行级 diff(宿主与浏览器共用同一实现)
├── selfmod.ts          F4-c:默认关闭、范围受限、受限环境验证、可复现构建哈希
├── status.ts tools.ts http.ts     状态文本、模型工具、面板 JSON API
└── client/             浏览器半边(只用主题 token,不 import 任何 Harness Client 包)
```

---

## 9. 许可

MIT

---

## 10. DSH 版本

实测运行的 DSH 版本是 **0.1.7-rc.2**:Host 半边与浏览器半边都正常挂载(`sidebar.panellist`
的 `selfharness` 入口与 `main` 的 `selfharness` key 都 `active`),`npm run check:compat`
对该版本的 24 个 seam 全部命中,`npm test` 242/242。升级 DSH 之后的第一件事仍然是
`node scripts/check-dsh-compat.mjs <新 checkout>`——它把两个最容易在升级里炸的点
(客户端平台模块表、按名字结构调用的宿主 seam)变成会失败的断言,而不是运行时的 throw。

Install

dsh plugin --profile web add github:shuiiiiimu/dsh-selfharness

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source