lens pack 外部化:三層疊加(built-in → lens pack → user) - #31
Open
kiki830621 wants to merge 7 commits into
Open
Conversation
三層 lens 疊加(built-in → lens pack → user)的核心語意落在 harness: 撞名時後來者只有標了 override 才勝出,未標記維持 first-wins。 - customs 保留 override 欄(原先被 map 掉) - 折疊改為逐層走訪並原位取代 —— devil's-advocate 依 lens 順序讀 reviewer 完稿,移位會讓它看到的東西因與 override 無關的理由改變 - stats.lensProvenance 記錄每個進來的 lens 的處置(added / overridden / ignored + overrodeFrom),空集合的 early-return 也帶上, 那正是解釋「為何一個 lens 都不剩」的資訊 向後相容:override 預設 falsy,未標記的行為與本 commit 前逐位元相同。 測試 4 條(含向後相容鎖),mutation 驗證:忽略 override 旗標 → 相容鎖 轉紅;改成移除+追加 → 順序測試轉紅。
lens pack 的 CSV 用 override 欄向 harness 宣告「取代同 key 的既有 lens」。 沿用 needsSrt 的 truthy 慣例(1/true/yes,不分大小寫),兩欄抽出共用的 _truthy —— 兩套判準會逼寫 lens pack 的人記兩組規則。 無 override 欄的舊 CSV 輸出不變(向後相容測試鎖住)。 突變驗證:移掉 override 寫入 → 2 條轉紅。
skill 端唯一的 lens 蒐集點:定位 lens pack cache(跨 marketplace semver glob,取最高版)、讀 lenses/<profile>.csv 與 ~/.claude/pai-lenses/<profile>.csv, 依序串接後交給 skill 併進 args.customLenses。 刻意不做的事: - 不碰層 ① built-in —— 那活在 harness 的 PROFILES,workflow runtime 無 FS - 不去重 —— 撞名判定全在 harness,單一去重點才不會兩邊語意漂移 - 不自己解析 CSV —— 委派 bin/pai-parse-lens-csv(既有紀律) D5 的「缺席 vs 損壞」拆成四種 status,其中兩種是刻意加的防安靜失敗: - empty:檔案在卻解析出 0 條(header 打錯)—— 不警告的話它會安靜地 什麼都不貢獻,正是最難察覺的失敗模式 - unversioned:裝了 pai-lenses 卻無 semver 目錄(plugin.json 缺 version) —— 「裝了但不可用」不是「沒裝」,不可比照靜默處理 兩個根路徑經 PAI_LENS_CACHE_ROOT / PAI_USER_LENS_DIR 注入,否則測試會讀到 開發機真實的 lens pack、結果隨機器而異。 bats 10 條全綠;突變驗證三處:semver→字典序、unversioned→absent、 移除 empty 警告,各自讓對應測試轉紅。CI py_compile 一併涵蓋新檔。
契約集中在新的 references/lens-layers.md(沿用 codex-governance.md 的 引用模式)—— 三個 profile skill 各寫一份 Phase 0 說明必然漂移,那是 diagnosis 記下的 F3 風險。skill 只留「呼叫 helper + 引用契約」兩行。 四個 skill 的改動: - code / academic / lecture:Phase 2 新增蒐集步驟,args 加 customLenses, 報表階段加 provenance 行 - compose:--base 帶入時自動疊層;CSV 欄位表新增 override; 更正三處「first-wins」敘述為「first-wins,除非標 override」 刻意寫進文件的兩個「不要」: - profile 維持原值不可改 custom(profile.title 無 args 覆寫路徑,改了 會讓每次審閱對所有 agent 自稱「自訂 ensemble」) - 沒裝 lens pack 時 provenance 行仍要印 —— 量測儀器換了刻度卻不說, 是 eval 數字不可比的根源 academic 多輪模式每輪重新蒐集(使用者可能在輪次之間改 user 層)。
catalog 的註解列放在 header **之後** —— 放前面會被 csv.DictReader 當成 header,整份檔案解析成空(實測確認)。放後面則落在第一欄、key/focus 為空, 被 pai-parse-lens-csv 跳過,所以檔案仍可安全餵給 --lens-file。 CI 加 drift 檢查:跑 regen 後 git diff --exit-code。在 #29 的方案下 catalog 已退回純 reference(層 ① baseline 由 harness 的 PROFILES 供給), 所以過期是文件缺陷而非正確性缺陷 —— 但這個 repo 的賣點是「來貢獻一條 lens」,catalog 與程式不一致會把貢獻者指向錯的地方。 順手修掉 regen script 的一個既有陷阱:heredoc 是 unquoted,JS 註解裡的 反引號會被 shell 當命令替換執行(加註解時實際踩到,log 出現 `profile: command not found`)。已在該處留下警語。
plugin.json 與 marketplace.json 同步(root CLAUDE.md 的 CRITICAL 規則)。 CHANGELOG 的 Changed 段特別記錄 harness 去重語意的改變 —— 那是使用者 可見的行為改變,即使未標記 override 的路徑逐位元不變。Known limitations 記下 profile.title 不可覆寫(這正是 profile 必須維持原值的理由)與兩項 spec §11 明確排除的範圍。
lens pack 用官方 schema 的 github source 註冊為第二個 plugin:
{"source": "github", "repo": "PsychQuant/pai-lenses"}(已對 code.claude.com
的 plugin-marketplaces 文件查證,非憑記憶)。repo 已建立、CI 綠。
順帶修正 collector 的警告文字:缺 version 時 cache 目錄名的 fallback 是
git commit SHA(官方文件),unknown 是實測見過的另一種情況 —— 兩者都不是
semver,結論不變但敘述要準。
marketplace description 一併更新到 v2.21.0(先前只 bump 了 version 欄,
description 仍以 v2.20.1 開頭)。
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #29
Summary
把 lens 從 harness 的
PROFILES抽成可外部疊加的三層結構(built-in → lens pack → user),讓新增一條 lens 的成本從「改 JS + bump plugin + 同步 marketplace」降為「改 CSV + bump lens pack」。實作了設計 spec
98dcaf0的 D1–D8。與 diagnosis 的差異:diagnosis 把 harness 的 first-wins 去重當成不可動的約束,設計了「skill 端全折疊 + 改傳profile: "custom"」繞過它;起草 plan 時實查PROFILES.custom發現profile.title被寫進 reviewer/DA/Codex 三種 prompt 的四個位置且無 args 覆寫路徑,繞道會讓每次審閱都對所有 agent 自稱「自訂 ensemble」。改採 harness 原生支援 override,profile 維持原值。改了什麼
workflows/ensemble-workflow.jsstats.lensProvenancebin/pai-parse-lens-csvoverride欄輸出(沿用needsSrt的 truthy 慣例,抽出共用_truthy)bin/pai-collect-lens-layersreferences/lens-layers.mdreferences/builtin-lenses.csv.github/workflows/test.ymlpy_compile涵蓋新檔.claude-plugin/marketplace.jsonpai-lenses(github source);bump 2.21.0新 repo:PsychQuant/pai-lenses v0.1.0(CI 綠)。
向後相容
override預設 falsy → 未標記的行為與 2.20.1 逐位元相同。有專屬的向後相容鎖測試,且 mutation 驗證過(忽略 override 旗標 → 該測試轉紅)。沒裝 lens pack 時報表與今日相同(D5 靜默)。
驗證
override旗標 → 向後相容鎖轉紅unversioned併成absent→ 該測試轉紅empty警告 → 該測試轉紅PROFILES不 regen →git diff非零(抓到);還原 → 乾淨version→ exit 1;header 打錯 → exit 1;還原 → exit 0刻意排除
builtin-lenses.csv的廢除 —— 保留為唯讀 catalogChecklist
Generated by /idd-implement on PR path. Do NOT add a GitHub close trailer (Closes/Fixes/Resolves) — IDD discipline requires manual /idd-close after merge to enforce checklist gate + closing summary.