Skip to content

plugin-update: binary-backed detection misses binaryVersion, non-wrapper.sh wrappers, missing marketplace version, and the post-release pin bump; Phase 5 never verifies the binary #22

Description

@kiki830621

Problem

Original text(使用者,2026-09-12,剛用 /harness-devtools:plugin-update che-keychain 把 che-keychain 0.3.0 上架之後):
「這個skill有需要改嗎??」
— Source: Claude Code session, che-keychain 0.3.0 release

實跑紀錄(che-keychain 是 self-hosted marketplace:root .claude-plugin/marketplace.json 的 entry 是 source: "./plugin"plugin/.claude-plugin/plugin.json"binaryVersion";wrapper 是 plugin/bin/che-keychain,變數名 REPO=;session-start hook 不 curl、委派給 wrapper):

Phase 實際發生 原因
0.1 find_plugin_marketplace che-keychain → rc=1 → 照 skill 該 abort「不在任何 marketplace」 佈局假設 — #18
0.3 Step 1 IS_BINARY_BACKED=false (a) PLUGIN_DIR 錯(#18);(b) 就算路徑對,偵測只認 bin/*-wrapper.shGITHUB_REPO= 或 hook 內 api.github.com.*releases — che-keychain 三個信號全 miss(本 issue 第 2 點
0.3 Step 2 BINARY_VERSION='' → Signal 2 永不觸發 binary_version,檔案寫 binaryVersion第 1 點
0.3 Step 2 MP_DRIFT=yes「剛好」 marketplace entry 原本沒有 version 欄位 → ''0.2.0;Phase 2 Step 1 的 p['version'] 對同一份檔案會 KeyError(第 4 點
0.5 clean + 0 unpushed → Case A「Nothing to push」 release 剛 push 完、binaryVersion 還是 0.2.0 而 latest tag 已是 v0.3.0;沒有任何 phase 負責「latest release 比 pin 新 → bump」,Phase 1.5 只有反方向的 Signal 2(main 超前 release)(第 3 點;abort 本身是 #19
5 claude plugin list 顯示 0.3.0 就算完成 沒驗 wrapper 是否真的把新 binary 抓到 ~/bin.che-keychain.version 是否等於 binaryVersion第 5 點)— 我是手動跑 wrapper --version 才確認的

全部都是安靜的:沒有一個 phase 報錯,skill 自己在 Phase 1.5 就寫過「沉默與『檢查過沒問題』不可區分」(#17)。本 issue 只收 #18 / #19 沒有涵蓋的五點;#18(PLUGIN_DIR / resolver 佈局)與 #19(0.3 與 0.5 互斥)各自處理。

Type

bug

Expected

  1. 欄位名binaryVersion(camelCase)與 binary_version(snake_case)二選一為 canonical,另一個在讀取時視同 alias(本機 20 個 binary-backed plugin.json:17 個 binary_version、3 個 binaryVersion;che-keychain / che-transport-mcp 的 wrapper 讀的是 binaryVersion)。Phase 0.3 Step 2 與 Phase 1.5 Signal 2 都改用同一個讀取 helper。
  2. binary-backed 偵測:改成「bin/ 下任何檔案(不限 *-wrapper.sh)含 releases/(download|latest|tags)gh release download」— 與 issue-driven-dev idd-close Step 6.5 的 has_binary_wrapper 同一判準;hook 委派給 wrapper 的佈局不再漏判。GITHUB_REPO= / REPO= / 其他變數名都能抓到 repo(從 URL pattern 抽,不靠變數名)。
  3. Release 之後的正向信號:新增「latest release tag(或 --binary-version 引數)比 binaryVersion pin 新」的偵測 → AskUserQuestion「bump pin 到 vX.Y.Z 並同步?」。這是 common-release-flow「release 完自動跑 plugin-update」鏈唯一需要的動作,目前只能手動改 plugin.json。與 plugin-update: Phase 0.3 與 Phase 0.5 可對同一次執行給出互相矛盾的裁決 #19 的關係:plugin-update: Phase 0.3 與 Phase 0.5 可對同一次執行給出互相矛盾的裁決 #19 讓 0.5 不再對 clean tree abort,本點提供 0.3 判定 sync intent 的正向依據。
  4. marketplace entry 缺 version:視為「缺 → 由 plugin.json 補上」而非 KeyError / 巧合 drift;Phase 2 Step 1 用 .get('version')
  5. Phase 5 驗證 binary:binary-backed plugin 更新後跑 wrapper --version(或讀 ~/bin/.<name>.version),對比 binaryVersion;不一致就報出來(wrapper 下載失敗常見於 release 漏上傳 asset,Phase 1.5 Signal 1 只在 update 前看一次)。

每一點都要有 fixture 級測試(self-hosted 佈局、binaryVersion 拼法、無 version 的 entry),比照 scripts/test-resolve-marketplace.sh 的做法。

Actual

如上表:五個 phase 在 che-keychain 這類佈局上全部沒有作用,且不報錯;使用者靠手動改 plugin.json、手動跑 wrapper 才完成 0.3.0 上架。

Impact

三個 ./plugin 佈局的 marketplace(che-keychain、che-apple-mail-mcp、che-ical-mcp)與所有 binaryVersion 拼法的 plugin,每次 release 後的 plugin-update 都是手動流程;binary 沒換到新版時沒有任何訊號。

Refs #18, #19(同一支 skill 的另外兩個缺陷;三者一起修時共用 plugins/harness-devtools/skills/plugin-update/SKILL.mdscripts/resolve-marketplace.sh,需序列化)。


Current Status

Phase: implemented
Last updated: 2026-09-16 by idd-implement (R8)

Key Decisions

  • R8:E-auto staging 逐檔檢查 + index 一致、最後一次賦值須為字面或 manifest 讀取、partial 讀取不印值、TMPDIR 解析失敗即關座標、Phase 5 PEND 行全狀態、Step 3 checked 只算比對過、Case B no-pin 模板改 wrapper pin 模型、Phase 0.5 abort 提醒
  • R7:writer 改 mkstemp + 保留 mode(修 R6 掉 exec bit 的回歸)、寫入後失敗獨立出口、helper 載入 fail-closed、測試座標限系統 temp 樹、行內覆寫 / jq 讀法 / 移動 ref 都 rc 4、pin rollback 守門、Signal 1 checked 只算查到的
  • R6:repo 逐檔分級再跨檔合併、*_REPO= 賦值須被用進下載行、字面 pin 須為最後一個賦值、寫入階段失敗明說已改檔案、E-auto 寫後失敗印 AUDIT、seam 三條件;plugin-update: #22 verify 遺留 — --binary-version 引數、plugin-health KeyError、Step 3 執行門檻、E-auto 跳幅、sidecar 拼法、_pbm_json_field 非字串值 #26 已開、第 1 點 errata 已貼
  • R5:asset 預檢狀態只升不降、所有 Case E 拒絕走 refuse()(unattended 印 AUDIT 回 75)、同 manifest 多 key 單一 buffer、多 repo 不進 Case E 且 bump 拒絕、Case B 加 no-wrapper、Phase 5 分 PENDING-FETCH / MISMATCH、helper 註解行對稱、BINARY_NAME 只在用於下載時算 asset
  • R4:key regex 認 macdoc 寫法(非註解行 "<key>"[^"]*:)、Signal 1 先查 v<pin> tag、hook-only 有 pin 的佈局用 hooks 列當下載器、共用 pin 的 wrapper 全部同改且寫後重讀 rc、repo 以 bin/ 為準、asset 只認宣告、E-auto 加 asset 預檢、version 來源不做預設
  • R3:pin 逐 wrapper 從三種封閉來源讀(wrapper 字面 DESIRED_VERSION / wrapper grep 的 manifest key / none),不再有 manifest 全域 version 回退;plugin_binary_version_effective 刪除
  • R3:Phase 1.5 Step 2 只算 bin/ 列、hooks 列交 Step 3(有 bin wrapper 的 plugin 跳過);unattended Case E 專用來源 → E-auto(樹乾淨且 0 0 才 commit+push)、version 來源不 bump
  • R3:Phase 5 逐 bin wrapper 對各自 pin,任一 unresolved 即 UNVERIFIED k/N;收尾移到 Step 1.9
  • R2:逐 wrapper 驗證、repo 抽取分級、Case E 不 abort unattended(verify R1 6 HIGH)
  • Plan tier(hard-gate:shared abstraction):新 helper scripts/plugin-binary-meta.sh 收斂 binary metadata 讀取,SKILL.md 各 phase 只消費 helper;Case E 優先於 C
  • 版本 bump 2.5.0 + root marketplace.json 鏡像留到 verify PASS 後最後一個 commit(idd-22-verified 即 2.5.0 的 SHA)
  • Conflict Class C:與 plugin-update: PLUGIN_DIR 寫死 aggregator 佈局,self-hosted marketplace 會讓 binary gate 靜默失效 #18 / plugin-update: Phase 0.3 與 Phase 0.5 可對同一次執行給出互相矛盾的裁決 #19 序列化(同一支 SKILL.md)

Scope Changes

Blocking

  • verify Round 8 進行中(R1 6 HIGH、R2 8 HIGH、R3 8 HIGH、R4 2 HIGH、R5 2 HIGH、R6 3 HIGH、R7 3 HIGH,皆已修)

Commits

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions