dsh-culprit:用判據二分 Git 歷史,定位迴歸肇事提交

前言

在 DeepSeek Harness(DSH)裏做智能體或工作流時,模型經常需要回答「這段行爲是從哪次提交開始壞的」。按行或按歷史的 blame 類工具能說明某行是誰寫的,但無法替代「在某個 commit 上真的跑一遍命令」——依賴裝不上、測試超時、只在運行時才暴露的問題,單靠讀歷史猜不到。

dsh-culprit 是社區維護者 ca610 發佈的工作流類插件(SkillHub 分類:工作流)。它接受一條有 bug 時退出非零的判據命令,在倉庫 --first-parent 歷史上做二分,返回肇事提交、diff、逐步探測證據,並在結束後把工作樹切回原狀。本文介紹其定位、安裝、用法與約束;事實以 GitHub 倉庫 README 與 package.json 爲準。

這是什麼

一句話:把「測試變紅」當成可執行、可二分的事實,在歷史提交上反覆運行判據,找出第一個引入失敗的 commit。

項 說明
包名 dsh-culprit
版本 0.1.0(資料來源:package.json)
許可證 MIT
維護者 ca610
目錄頁 https://www.skillhub.cn/plugins/ca610/dsh-culprit
源碼 https://github.com/ca610/dsh-culprit
Node >=22

與生態裏按行/歷史做「這一行誰引進」的 slow-stack/euthyna 不同,本插件必須 checkout 並在各提交上執行判據,代價是會動工作樹;工程上因此強調髒樹拒絕、與進行中的 git bisect 互斥、以及 finally 中還原 HEAD/分支。

核心功能

插件向 DSH 註冊工具 regression_culprit,主要能力包括:

  1. 自動或指定好點/壞點:默認壞點爲 HEAD;可傳 goodRef 跳過自動尋點;也可自動沿歷史找健康基線。
  2. 二分與證據鏈:每步記錄判據退出碼、耗時、語義(good/bad/skip),收斂後給出 result.culprit、改動文件統計與 diff。
  3. 判據語義與 git bisect run 對齊:0 爲健康,非零爲有問題;125 與超時均視爲跳過(超時 deliberately 不算「壞」,避免把「依賴裝不上」誤判爲肇事點)。
  4. HEAD 自檢:默認要求壞點在當前 HEAD 上確實失敗;若判據在 HEAD 爲綠,返回 not-reproduced,不硬湊結論。
  5. 斷點續跑:每探一步落盤狀態(默認 %TEMP%\dsh-culprit);預算用盡時可 resume: true 繼續;mode: "status" 只讀列出未完成狀態。
  6. 安全邊界:髒工作樹拒絕(dirty);已有 bisect 拒絕(bisect-in-progress);無 reset --hard / clean / stash;僅 --first-parent 歷史。

返回狀態包括:found、not-reproduced、no-good-baseline、budget-exhausted、inconclusive、dirty、not-a-repo、bisect-in-progress、invalid-args。僅 found 提供 result.culprit;budget-exhausted 故意不給肇事者,避免把未收斂的「最像」當結論。

安裝與啓用

DSH 社區目錄(SkillHub)與 DeepSeek / 幻方無官方從屬關係;安裝前請自行審閱源碼與 MIT 許可證。插件在當前 DSH 進程權限下執行 git checkout 與子進程判據,等同於你在本機終端跑同類命令。

常規路徑(用戶自管 profile)

README 說明由 agent 調用插件管理器安裝本地 bundle(需先將倉庫放到本機路徑,README 示例爲 clone 後指向該目錄):

plugin_manager(action: "install_bundle", target: "C:\\path\\to\\dsh-culprit")

裝完需重啓 profile / DSH:插件僅在啓動時加載,無熱更新。卸載使用 remove_bundle。

Windows 桌面版

desktop profile 由 Electron 應用獨佔管理,dsh plugin --profile desktop add 會被拒絕。README 記錄的手動接法爲三件:profile node_modules 下 junction 指向倉庫、package.json 中 dependencies 使用 link:<倉庫絕對路徑>、並在 dsh.profile.bundles 追加包名(否則不會讀取 cordis.patch.yml)。修改 package.json 前建議備份。

確認是否裝上

README 提供兩層自檢(缺宿主 runtime 時腳本以退出碼 2 跳過,跳過不算通過):

node test/profile-install.mjs
node test/host-dispatch.mjs

前者只讀 profile 解析 link、bundles、junction 與 patch;後者在真實 cordis 上下文中派發一次工具並校驗輸出 schema 與工作樹還原。

典型用法

最簡調用:只填判據,工具自行尋好點、二分、還原工作樹。

regression_culprit(predicate: "npm test -- src/clamp.test.js")

已知健康版本時指定 goodRef,通常更快也更準:

regression_culprit(predicate: "node --test calc.test.mjs", goodRef: "v2.1.0")

跑之前建議在本機 HEAD 上先執行一遍判據,確認當前確實是紅的。判據寫法與 git bisect run 相同;Windows 上 PowerShell 會壓扁非零退出碼,插件會對判據做包裝以保留 125 等語義(詳見 README「已知限制」)。

常用參數(節選)

參數 說明
predicate 必填,判據命令
goodRef / badRef 好/壞提交或 tag,壞點默認 HEAD
root 倉庫路徑,默認會話工作目錄
mode bisect(默認)或 status
resume 續跑未完成區間
maxSteps 最多探測次數,默認 16(上限 40)
timeoutPerStep 單步超時毫秒,默認 120000
totalBudgetMs 總預算毫秒,默認 600000

倉庫內演示(臨時目錄造 bug 倉庫,跑完刪除):

node examples/demo.mjs

配置(可選)

可在 cordis.patch.yml 的 bundle config 中覆蓋默認值,例如:

- insert:
    - id: culprit
      name: dsh-culprit
      config:
        maxSteps: 24
        timeoutPerStep: 300000

其它項包括 workdir、maxHistoryScan、maxAutoProbes、skipLimit、stateDir、allowDirty、shell、firstParent、requireBadAtStart、keepState 等,含義與默認值見 README 配置表。

適用場景與注意

適合:迴歸問題已有可腳本化判據(測試、構建、單行 repro 命令);需要在智能體工作流裏把「哪次提交改掛」結構化返回(含 diff 與探測軌跡)。

不適合或需知:肇事改動若只在已合併分支內部、結果可能落在 merge commit 上(插件會警告);舊提交環境跑不起來會導致大量 skip 進而 inconclusive,可縮小區間或提供更近的 goodRef;merge commit 的 combined diff 不可用時退回 git diff <sha>^1 <sha>。

本地無宿主時可跑單元測試:

node test/culprit.test.mjs

結尾

dsh-culprit 把「判據在歷史上的通過/失敗」當作唯一事實來源,用二分加逐步證據回答「從哪次提交開始壞」,並儘量在不傷害未提交改動的前提下還原工作樹。需要插件詳情與分類入口見 SkillHub 目錄頁;安裝、參數、安全保證與 Windows 退出碼細節見 GitHub README。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜