release: wiki 目錄頁專用存取庫、HASH 完整 40 碼、閘門依 CLI 分流 #74
2 Participants
Notifications
Due Date
No due date set.
Depends on
#73 feat(wiki): 異常目錄頁改走專用存取庫,並修正目錄列連結恆空
plugins/hooks
Reference: plugins/hooks#74
Reference in New Issue
Block a user
把 develop 上累積的變更釋出到 master。合併之後,這些變更才會透過 marketplace 到達每一台機器。
這一版帶了什麼
一、wiki 目錄頁進專用存取庫
CONTENTS成為第 15 種頁面類型,解析鏈是JSC_WIKI_REPO_CONTENTS到JSC_WIKI_REPO,刻意不退回型別變數。14 個目錄頁從此同住一庫,內容頁仍各走自己的型別。兩者不再同庫,跨庫沒有 wiki 連結語法,所以目錄頁指向內容頁的連結一律改成gitea.sh wiki-url的絕對網址。目錄頁的整列 upsert 收成一支
jsc-gitea/tools/wiki-contents.sh,取代原本 14 處只有 1 處寫成程式的手工流程。二、wiki 頁 HASH 去除截短與 H 前綴
hash-id只保留大寫轉換,輸出完整 40 碼。原本的H前綴會命中 16 個十六進位首碼裡的 13 個,還丟掉第 8 碼,把有效熵壓到 28 位元,而且全庫查不到任何理由紀錄。頁名樣式仍收H加 7 碼的舊頁,遷移期間讀得到舊頁。三、SDLC 能力閘門依 CLI 分流
閘門的模型來源改成只讀屬於當前 CLI 的那一份,政策改為 fail-closed:判不出 CLI、判不出模型、模型不在能力標籤表上,三種一律擋下,每一則擋下的訊息都帶兩條逃生門。階段鎖狀態檔改成
$JSC_HOME/sessions/{CLI 代號}-{sid}.stage,舊路徑仍讀得到。四、skill-check 加入優化與建議流程
Group 3 先讀上一輪決議,不重複掃、不重複問;建議表加上「決議」與「決議日期」兩欄;新增步驟 8 把稽核結果寫進 SKILLSET 頁。Group 1 補進三支現成但沒人呼叫過的檢查腳本。
五、順手修掉的既有缺陷
H開頭舊頁編號漏偵測。JSC_WIKI_REPO_MONITOR,體檢看不到它而孤兒掃描還會誤報;另有指向不存在頁面的殘留項目。升級後的一次性代價
階段鎖狀態檔改名,所以每台機器第一次啟動會清一次重啟閘門——起始檔不存在,看起來像新的工作階段。只發生一次,已實測連跑三次不會再清。升級當下正好有閘門升著的話,那一次會被放下。
部署後要做的事
wiki 既有頁要用
jsc-gitea/tools/migrate-wiki.sh搬。先部署再搬:舊版技能算的是 8 碼頁名,先搬會讓舊版找不到頁、照範本另外開一份新的。那支預設只印對照表,--apply才真的動,而且是先寫新頁、確認寫成、才刪舊頁。What: - current_model_report() 的偵測鏈依 CLI 分流,一支只讀自己的紀錄。claude 讀 transcript 與 hook stdin,codex 讀 hook stdin 與自己的 session 記錄,copilot、antigravity、kiro 本機沒有可讀的模型紀錄,判不出是哪一支 CLI 時不採用任何自動來源。JSC_MODEL 人工覆寫五支都保留,而且一律排在最後。 - session_id() 的退路鏈補上 CLAUDE_CODE_SESSION_ID,cli_name() 補上 CLAUDECODE 與 CLAUDE_CODE_SESSION_ID。 - 階段鎖狀態檔改成 sessions/{CLI 代號}-{sid}.stage。舊路徑仍讀得到,unlock 不帶參數時新舊兩份一起清,也收一個狀態檔路徑當參數。 - check 改成 fail-closed:判不出 CLI、判不出模型、模型不在能力標籤表上,三種一律以 exit 2 擋下該輪提示。每一則擋下的訊息都印出兩條逃生門。 - write-guard.sh 的 stage 模式改讀 lib.sh 的路徑函式,擋人訊息把實際讀到的狀態檔路徑寫進解除指令。 - codex_session_file() 取「全樹最新一支」的做法改掉。 - wire-cli.sh 的冒煙夾具跟著補:模型來源四條各自指定 CLI 代號,另加三種擋下情形、check 的 fail-closed、階段鎖的 CLI 區隔與舊格式相容,這一組的判定條數由四條增為十二條。 - README 的 hooks 表、狀態檔分界表與環境變數表跟著改。 Why: - 使用者回報兩件事:在 claude 底下被 codex 的模型判定,而且這道閘門應該只鎖能力標籤、不鎖模型。查下來根因是同一個——閘門完全不分辨自己跑在哪一支 CLI 上。 - 偵測鏈不分流,claude 拿不到 transcript 就一路掉進 codex 的 session 記錄,拿別支的模型判這一支。順帶每一輪都對一個上千個檔、兩百多 MB 的目錄樹跑一次 find,宿主 CLI 跟著卡。 - session_id() 讀的變數名在目前的 claude 上並不存在,sid 一路退回 default。cli_name() 犯同一類錯:只認 plugin 接線才有的變數,技能以 Bash 工具呼叫腳本時取不到,一律判成 unknown。 - 前三項合起來的後果是:技能呼叫 lock 算出的檔名,跟 hook 算出的檔名永遠不同。階段鎖上了也對不上,所以這道閘門在 claude 上一直沒有真正生效。 - 狀態檔不分 CLI,各支就共用同一支 default.stage,一支上的鎖擋到另一支。那不只擋提示,write-guard.sh 的 stage 模式連 Write、Edit、MultiEdit 一起擋。 How: - 政策改成 fail-closed:不知道能力就擋下,知道才比對標籤。原本判不出模型只提醒不擋,那等於「換一支讀不到紀錄的 CLI 就能繞過去」,閘門形同虛設。代價是把人鎖在送不出提示的狀態,所以每一則擋下的訊息都要帶兩條逃生門,照抄就脫困。 - 逃生門的路徑照抄進指令裡。擋人的是 hook,解鎖的是人在殼層手動執行,兩邊算出來的檔名未必相同,不點名就解不到真正擋人的那一支。 - unlock 的參數只收 sessions 目錄底下的 .stage 檔,逃生門不該順便變成任意刪檔的工具。判準刻意不綁這支行程算出的 JSC_HOME:擋人的一側跟解鎖的一側未必相同,綁上去就會把照抄訊息的人擋掉,那正是這個逃生門要避免的事。 - 狀態檔用檔名前綴不用子目錄。外部工具以單層的 sessions/*.stage 盤點階段鎖,改成子目錄會讓每一支鎖從那些盤點裡整批消失。 - 舊路徑只讀不搬也不刪,unlock 一併清掉。只清新的那一份,舊格式的鎖就永遠解不開,被它擋住的人沒有逃生門。 - 變數名只補實測看得到的那幾個,而且只補 claude 這一支。其他 CLI 的變數名與環境特徵沒有實測過,猜一個填進來只會多一個錯誤來源,那幾支本來就由接線設定明確帶 JSC_CLI。 - codex_session_file() 原本寫成 xargs ls -t 再 head -n 1,那是錯的:xargs 依參數長度分批,ls -t 只在自己那一批裡排序,取到的是第一批裡最新的,不是全域最新。改成讓 find 一併印出修改時間再全域排序;沒有 -printf 就退回路徑排序,那些檔名以 ISO 時間開頭,字典序等同時間序。 - 冒煙的擋人案例連訊息一起驗,不只比結束碼。訊息漏掉逃生門一樣是綠燈,而那才是這道 fail-closed 真正的風險。 - 四支腳本併成一筆。write-guard.sh 讀 lib.sh 的路徑函式,wire-cli.sh 是驗這些行為的冒煙夾具,拆開會留下跑不過的中間版本:路徑函式與呼叫端分兩筆,中間那一筆狀態檔的讀寫兩側就對不上。 - 一次性代價:升級後每台機器第一次 SessionStart 會清一次重啟閘門。sid 換了名字,看起來像新的工作階段。只發生這一次。 - 三份 manifest 這一筆不動,版本號另外提升。 Who: SDLC 階段能力閘門。修的是它一直沒有生效的那條路徑,順帶把 codex session 記錄的取檔方式一起修掉。What:ERROR_CONTENTS 改由 wiki-repo CONTENTS 解析,ERROR_{HASH} 仍走 wiki-repo ERROR,兩者是兩個不同的存取庫。目錄列的連結改用 wiki-url 的絕對網址。 註解掃描的頁面編號樣式補上 40 碼與 H 加 7 碼兩種形狀。 Why:目錄列的網址原本在異常頁寫入之前就取,而頁名的雜湊帶時間戳、每次都是全新頁, 那時查一定是 404,又被吞掉,所以那一格一直都是空的。註解掃描原本只收 8 碼純十六進位, 舊演算法有十三個首碼會改寫成 H 開頭,等於對絕大多數舊頁編號漏偵測。 How:降級語意分兩層——異常頁的存取庫解不出來就整支安靜降級,只有目錄頁解不出來就 只寫異常頁、跳過索引,兩種都維持 exit 0。「只有 exit 4 才准建新頁、7 與 8 一律中止」 那段原樣保留,那是防止把金鑰失效讀成頁面不存在、拿範本蓋掉整頁既有列。 Who:jsc-hooks