Claude Code
|
672439bd95
|
把 main(v0.15.0,派工紀律三件 #105)併進來,逐支點名複驗過 hooks.json
## hooks.json:這次 git 自動合成功了,而那正是最危險的情況
`hooks.json` 是 JSON——**合錯了語法照樣合法、閘卻不見了,不會有任何東西喊一聲。**
所以「沒有衝突」不等於「沒掉東西」,一律再做兩件事:
① 逐支點名(指令已寫進 README「裝什麼」那段)→ 82 條,60 支各自幾條全部列出
② 跟**兩個父節點**做集合對照:
merged 82 = main 79 + 我的 3
從 main 掉了:0 條
從我這邊掉了:0 條
兩邊都沒有卻冒出來的:0 條
`#105` 三支與我的兩支同時在,位置也對:
roster-guard.sh PreToolUse Agent / Task
diagnosis-evidence-guard.sh PreToolUse Bash
investigate-first-stamp.sh PostToolUse Agent|Task / SendMessage
overdue-nag-guard.sh SessionStart
wiki-size-guard.sh SessionStart / PreToolUse Write|Edit|MultiEdit
(總管提醒的 `roster-guard` vs `mainline-focus-guard` 那種「同一陣列位置兩邊各一支」
這次沒有再發生衝突,但兩支都在,各 2 條。)
## 三處文字衝突:兩邊都留,數字重數
- plugin.json 版本吃 main 的 **0.15.0**(總管已定版,**我沒有動它**);
描述欄補上 main 新增的「7 位有名字的工人」,三個數字重數
- README.md 吃 main 的新表格結構(多了 agents/commands/skills/scripts 四列),
數字重數;並把累積成**四列**的 `hooks/` 收成一列
- hooks-inventory 標頭被貼成兩份、「一句話結論」被貼成**三份**(數字還互相打架),
各收成一份;版本註記兩邊都留
## 盤點(全部在合併後的樹上實數,不是加減推的)
ls hooks/*.sh | wc -l 58 → 60
grep -c '"command":' hooks/hooks.json 79 → 82
ls agents/*.md | wc -l 7
ls -p scripts | grep -v / | wc -l 48
未掛進 hooks.json 的 .sh 3(與本頁原本寫的一致,重數過)
📌 抓到的漂移(每次併都有一個,這次三個):
① hooks-inventory 的標頭 ×2、一句話結論 ×3
② README 的 `hooks/` 列 ×4,其中兩列是舊數字
③ plugin.json 描述欄寫「49 支腳本」,而用本頁寫死的那道指令實數是 48
## 測試(合併後全部重跑,帶對參數)
hooks/tests 23 支全綠:ask-user-question 14、countdown 20、diagnosis-evidence 26、
dispatch-format 52、factory-idle 33、gate-ok 17、gitea-arm-check 16、
presence-beacon 14、cross-repo 19、main-and-prod-push 10、mainline-focus 24、
mainline-idle 61、milestone-account 22、**overdue-nag 36**、pr-verdict 52、
prod-write 37、reply-identity 11、roster 24、sdd 8、search-is-not-proof 31、
stage-before-prod 16、unpushed-police 10、**wiki-compress 25**
scripts/test-* 13 支全綠。
claude plugin validate . ✔ passed;check-version-consistency ✅ 0.15.0 = v0.15.0。
兩支新 SessionStart hook 併完實跑過,閘判定探針對 v0.15.0 的 prod-write-guard 回 pass。
🔴 跑之前清 `CLAUDE_CODE_CHILD_SESSION`;四支要帶參數
(三支帶 hook 絕對路徑、cross-repo 帶 hook 絕對路徑、gitea-arm-check 帶 repo 根目錄)
——不帶會紅,而那是假紅。
|
2026-08-28 01:25:49 +00:00 |
|
Claude
|
44f60ba0b8
|
merge main(v0.14.0,五批)into 派工紀律三件
hooks.json 兩處衝突:roster-guard 與 mainline-focus-guard 在同一個陣列位置,
兩支都是真的閘,展開成兩個項目保留(不是二選一)。
盤點在合併後重數:58 支 .sh/79 條註冊/49 支腳本/7 位具名工人。版本 0.15.0。
|
2026-08-28 01:20:00 +00:00 |
|
Claude Code
|
79ee9e62d6
|
把 main(v0.14.0,五批)併進來,解 5 處衝突,盤點數字在合併後的樹上重數
衝突全部**兩邊都留**,沒有丟掉任何一側:
- hooks.json main 的 `scripts/mainline refresh` + 我的兩支,同一個
SessionStart 陣列裡並存
- plugin.json 版本吃 main 的 0.14.0(**沒有自己決定版本**),描述欄的
三個數字在合併後的樹上重數
- README.md main 那格被貼成兩列(54 支/69 條 與 54 支/71 條,互相矛盾),
收成一列並填上實數
- hooks-inventory main 的 `mainline refresh` 那列 + 我的兩列;標頭與
「一句話結論」的數字重數
- TESTING.md 兩邊各自新增的格子都留。**我的兩格改號成 A21/A22**——
併之前兩邊都叫 A16/A17,撞號(這一頁本來就已經有
三組重複的 A14–A18,這次至少沒有再加一組)
盤點(`ls hooks/*.sh | wc -l`、`grep -c '"command":' hooks/hooks.json`、
`ls -p scripts | grep -v / | wc -l`,都在**合併後**的樹上跑):
55 → 57 支 .sh
72 → 75 條註冊
47 支腳本
📌 順手抓到一個漂移:main 的 plugin.json 描述欄寫「48 支腳本」,
而用 hooks-inventory 自己寫死的那道指令實數是 44(main)/47(合併後)。
已記在 hooks-inventory 的版本註記裡——**同一個病,第 N 次,只是換一欄。**
📌 TESTING.md 的「已知斷點」那段補上總管用 MCP 查到的更廣範圍:
不只 notify_leo 不見了,那台實例的工作流定義是**整批失效**;
而且修它要寫 leo 的個人帳號 ⇒ `leo21c-write-guard.sh` 明文禁止
⇒ **那是真人閘,總管也不能解**。
測試(合併後全部重跑,帶對參數):
我的兩套 overdue-nag 36/36、wiki-compress 25/25
hooks/tests/* ask-user-question 14、countdown 20、dispatch-format 33、
factory-idle 33、gate-ok 17、presence-beacon 14、
mainline-focus 24、mainline-idle 61、milestone-account 22、
pr-verdict 52、reply-identity 11、sdd 8、
search-is-not-proof 31、unpushed-police 10、
prod-write 37、stage-before-prod 16、
main-and-prod-push 10、cross-repo 19、gitea-arm-check 16
scripts/test-* 13 支全綠(含 release-manifest 21、milestone-account 23、
debt-worklist 47、ticket-handoff-writeback 49)
claude plugin validate . 通過;check-version-consistency 通過(0.14.0 = v0.14.0)
|
2026-08-28 01:15:54 +00:00 |
|
Leo
|
5ac06abc95
|
工人有名字+回覆也是派工+未經調查不寫診斷(inkstone/ISEP#86/#87/#88)
三張票同一族(誰在派、派給誰、派的內容住哪裡),做在同一條分支:
#86 工人名單:agents/ 七位有名字的工人+scripts/roster+hooks/roster-guard.sh
派工用 Task 的 subagent_type 指名,派工單格式一個字都沒改;
指對名字就把那位的檔案原文注入(你是誰/先讀什麼/你的紅線)。
【身份】欄同時吃得下工人名字(原本三個角色照舊)。
#87 未經調查不寫診斷:hooks/diagnosis-evidence-guard.sh + investigate-first-stamp.sh
三個結構訊號(派過人查沒/有沒有走得過去的出處/有沒有份量),
一個關鍵字比對都沒有;轉述有出處不會被誤擋。
#88 回覆也是派工:不另造閘,把攔截點加掛上去。
hooks/lib/dispatch_parse.py 的 tool_channel() 一次列全所有通往 subagent 的路
(SendMessage/雲端 session・trigger/claude -p);擋下來時把那段內容原文印出來。
subagent 往上回報(to: "main")=交件不是派工,刻意不管。
順手修掉一個真的會咬人的 flake:dispatch-format-guard 原本開四支 python 各讀一個欄位,
機器忙的時候某個欄位會靜靜變空字串(實測連跑 10 次有 1 次「豁免了卻還是被擋」)。
四個欄位改成一次讀完。
版本號待總管定(plugin.json 只更新了描述裡的數字,版本沒動)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
|
2026-08-28 01:15:09 +00:00 |
|
Claude Code
|
156d339308
|
退路留言要帶「為什麼發不出去」,不是只帶閘的判定(inkstone/ISEP#93)
2026-08-28 第一版漏了這一格,而它剛好就在實測時咬到:
閘判定 pass、Telegram 卻 404(實例上找不到 notify_leo 工作流),
退路留言貼上票之後**只看得到 pass**——真正的斷點一個字都沒進票。
⇒ 下一個人會去修閘,而斷點根本不在那裡。
把留言內文抽成 fallback_body()(獨立成一支就是為了測得到),
測試從「看原始碼有沒有那個字串」改成**真的產一份留言出來檢查**:
斷點原因、原文、身份欄三格都要在。36 條全綠。
|
2026-08-28 01:06:52 +00:00 |
|
Claude Code
|
da9bd53cae
|
沒人會叫的事會自己叫+讀不完的必讀檔要被整理(inkstone/ISEP#93、inkstone/ISEP#89)
兩張票放同一條分支:都是「該發生卻不會自己發生的事」,觸發點都在 session 邊界。
## inkstone/ISEP#93 —— 逾期和掛著沒人接的事會主動叫
- scripts/isep-nag 撈三種沒人會叫的事(逾期 milestone/等 leo 的票/掉在地上的棒子)
- scripts/isep-notify 發 Telegram,而且**發不出去的時候不會安靜**
- hooks/overdue-nag-guard.sh SessionStart 跑一次(不輪詢、不 fan-out、不掛 Actions)
- hooks/tests/overdue-nag.test.sh 35 條,全程離線
實跑撈得出票上點名的那五個逾期 milestone(08-24 三個、08-26 兩個)。
沒東西可報時會說「查過了,沒有」——安靜跟壞掉長得一模一樣。
🔴 工單補的那個限制(今天實測出來的)已經處理:
「能不能發得出去」取決於這個 session 載到的 ISEP 是哪一版
(prod-write-guard v0.10.0 才認得出 notify_leo 不是部署,而 hook 註冊路徑
在 session 啟動當下就寫死了)。所以 isep-notify 會**先拿真的要送的那一則
去問這個 session 註冊的那支閘**,把判定寫成檔(誰都查得到),然後:
· 放行 ⇒ 送,並驗內層 data.data.ok(外層 200 不算送到)
· 會擋 ⇒ **不繞路**,改貼回票上並把原文印在眼前
用 git 歷史裡的真跡(c263866 那一版閘)測過「會擋」那條路。
⛔ 實測發現通道本身現在是斷的:實例上找不到 notify_leo 工作流(404)。
不是閘、不是網路、不是金鑰。詳情與修法寫在 docs/TESTING.md 最後一段。
退路兩次都走通了(inkstone/ISEP#93 comment 5182、5184)。
## inkstone/ISEP#89 —— wiki 太長時有人整理
- scripts/wiki-compress audit/plan/apply/verify/bench 五個動詞
- hooks/wiki-size-guard.sh SessionStart 點名太長的檔;寫檔時擋「沒走流程的壓縮」
- hooks/tests/wiki-compress.test.sh 25 條,全程離線、不碰真的 wiki
設計上最重要的一條:**只搬不改**,正文一個字都不動。
「合併同類、濃縮成一行」要重寫正文,而重寫的當下沒有人會發現弄丟了什麼。
所以機器只做「搬 + 目錄 + 標 ×N/↻」,合併留給人。
拿現在的 mistakes.md 複本實壓過(不動真的 wiki):
7,681 行 → 1,199 行
260 條一條都沒少(verify 用內文雜湊逐條對帳)
80 個查詢命中率 80/80,定位成本 2,956 → 131 行,**快 22.5 倍**(bench)
verify 反向測過:真的弄丟一條時它抓得到(抓不到的對帳表比沒有更糟)。
## 盤點數字
在這棵樹上當場數的,不是拿上一版加減推的:
ls hooks/*.sh | wc -l → 55(was 53)
grep -c '"command":' hooks.json → 71(was 68)
plugin.json/README/hooks-inventory 三處同步改。
**版本號沒動**(0.11.0),待總管定版。
|
2026-08-28 01:04:16 +00:00 |
|
claude-code
|
4eed944f68
|
跨 repo 版本清單+結案記帳(inkstone/ISEP#84、#85)(docs/TESTING.md)
|
2026-08-28 01:04:05 +00:00 |
|
claude-code
|
d301810fb6
|
merge main(#98 下游做完時頂層跟著關),我的那節再讓一次編號
衝突只有 docs/TESTING.md 一列:#92 也用了 A19 ⇒ 我改成 A20,並把整節搬到 A19 後面。
(今天 main 上 A16、A17 各被佔兩次、A19 被佔兩次——編號撞是這條線的常態,
讓號的成本比要求別人改小,所以一律我讓。)
plugin.json 的腳本數在合併後的樹上重數 40 → 43:
main v0.13.0 那個「40」= `ls scripts | wc -l`(37 檔+3 目錄),
合併後同一算法 = 43:+2 是本 PR,+1 是 #98 帶進來的 test-ticket-handoff-writeback.sh
(#98 併進 main 時沒有回頭改這個數字)。版本號沒動(0.13.0)。
|
2026-08-28 00:58:49 +00:00 |
|
claude-code
|
45adc10a52
|
併進 main(v0.12.0)並接上「主線唯一答案」(inkstone/ISEP#83)
衝突只有 docs/TESTING.md 一處,兩邊都留:
main 的 A16(gate-ok)/A17(未推警察)/A18(信標)原樣保留,
我那節改編號成 A19——main 上 A16、A17 已經被 #90 與 #99 各佔一次,不動別人的。
接上 inkstone/ISEP#82 帶進來的 hooks/lib/mainline.py(不自己養第二套判斷):
· 有標主線 ⇒ 只排除「屬於主線那一條」的票;掛在**別條** milestone 的仍算債
(那條線現在沒有人在推,正是它躺著的原因)
· 沒標主線 ⇒ 退回保守做法:掛 open milestone 的一律不領,並在清單上照實說沒標
· 別條 milestone 已逾期 ⇒ +15「答應過人家的日期已經過了」
測試 40 → 47 條(+7 條全給主線這段),並把 ISEP_COUNTDOWN_STATE_DIR 也隔離:
不然這支測試的結果會取決於「這台機器現在標了哪條主線」。
盤點數字在合併後的樹上重數:
hooks/*.sh = 54、hooks.json "command": = 71(本 PR 沒新增 hook,兩個都沒變)
scripts 一層檔案 = 39(本 PR +2)⇒ plugin.json description 37→39
版本號沒動(0.12.0,總管統一定版)
|
2026-08-28 00:51:06 +00:00 |
|
claude-code
|
07cb5e4e55
|
併進 main(#96 雲端接線/#100 v0.12.0/#99 主線唯一),解 TESTING.md 撞號(inkstone/ISEP#92)
唯一衝突在 docs/TESTING.md:兩條線各自加了一節、**都叫 A16**。
兩邊內容都留,我這一節改成 A19(main 已用掉 A16/A17/A18),
「目前狀態」表的那一列跟著搬到 A18 後面。
main 側本來就有的 A11/A12/A14/A15 重號**沒有動**——那是它兩條線各自編的,
不是這次造成的,動它會把 diff 炸開。
沒有碰的:.claude-plugin/plugin.json(維持 main 的 v0.12.0,版本由總管統一定)、
hooks/hooks.json、docs/hooks-inventory.md——這三個檔本線一個字都沒改,
自動合併拿到的就是 main 那份。
盤點數字在合併後的樹上重數(不是相加、不是抄別人的):
hooks/*.sh 54 hooks.json 註冊 71 commands 7 skills 2 scripts 頂層 38
docs/hooks-inventory.md 寫的 54/71 **是對的**;README 寫的 48/59/23
**三個都錯**,已改成實數,並把「怎麼重數」的指令寫進去——
這種數字會漂是因為沒人知道它怎麼來的。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
|
2026-08-28 00:48:49 +00:00 |
|
claude-code
|
7871921741
|
把主線接進派工與注入(inkstone/ISEP#82)
- hooks.json mainline-focus-guard 掛 Agent+Task(派工的兩個入口都要守);
SessionStart 多一條 `scripts/mainline refresh`(0.8s,不輪詢)
- hooks-inventory 54 支/71 條(當場數的)+補人話一列;順手修掉上一版重複的那一行,
並把「指向空氣」那格的假警報寫清楚(countdown-milestone-refresh 在 scripts/)
- TESTING A16(24 條離線)+ A17(要網路的那半怎麼驗)
- plugin.json 描述數字對齊;版本不動,待總管定版
|
2026-08-28 00:40:05 +00:00 |
|
claude-code
|
67f5f0fa5e
|
舊票每天有固定管道被撈出來(inkstone/ISEP#83)
leo 2026-08-27:「現在每天都在追新的,所以要用 Routine 去消化舊的,可以有多個條件」
兩條線各用各的判準(他當場訂正的那件事):
緊急線=掛 open milestone 的,用「距離目標的遠近」排
還債線=沒掛的那 188 張,用多條件排(事故/擋人/承諾/票齡/估工)← 本次做的
新增 scripts/debt-worklist(list/claim/forget):
· 撈全 org 15 個 repo 的 open issue + open PR,逐一列出當作「我查了哪些」的證明
· 扣掉掛 open milestone 的(緊急線在管)、等 leo 的(Human/human-exec/s/stage,
那些要催不是要領,催辦是 inkstone/ISEP#93)、已領走的
· 每張票旁邊印出「為什麼排這裡」的分項,排錯可以指著某一項說它給太多
· 成包只認強訊號:互相指著、或 Gitea 原生相依(母子票)。
第一版用單向引用成包,190 張裡 121 張黏成一坨——一包沒有人領得動
· 空清單會明講「查詢跑過了,結果是零」,不默默結束
· claim 之後那些票不再出現在清單上,並在隔天的清單頂端交代它們關了沒
hooks/session-start-recall.sh 加一段(不打網路,只看狀態檔日期):
今天還沒撈過就說一句,並給出要跑的那一行。開 session 自動去撈=輪詢,紅線擋著。
測試 scripts/test-debt-worklist.sh:40 條全離線,票上四條驗收條件各一組。
真實資料唯讀實跑過:229 張 → 可領 188 張/185 包,領走兩張後隔天清單少掉它們。
|
2026-08-28 00:38:02 +00:00 |
|
claude-code
|
f3a41fba0e
|
下游做完時頂層跟著關(inkstone/ISEP#92)
票上的病:「開在頂層的票,下游做完了卻沒人回來關⋯⋯頂層票會永遠掛著,
而 leo 是看頂層的。」缺的三格是 journey 標籤、雙向連結的強制、完工回寫。
不重造既有的(票上明列):`ticket where` 戳記+側門閘(查票防重複)、
`comment-carries-task-guard`(留言藏任務)、Gitea 原生 issue dependency
(跨 repo 關聯的載體)——這一版全部長在它們上面。
四格,判準全部是機械事實(相依邊在不在、state 是什麼),沒有一格在猜文字:
① 雙向連結(驗收 1):`subtask`/新別名 `handoff` 一個動作同時掛原生相依
+ 在頂層票的時間軸貼一則指回下游的留言。相依邊只長在側欄,
時間軸上什麼都沒有,跨 repo 時尤其看不出來。
② 完工回寫(驗收 2,最痛的那格):`ticket close` 關完子票立刻問 `/blocks`
(誰在等我),對每張還開著的頂層票貼回寫留言;下游全關的那一張再
指派回總管+改 s/review。**不自動關母票**——關票要有交付物、要有人看過,
默默關掉跟默默留著是同一個病的兩面。
③ journey 標籤:`--journey <名>` 把 `j/<名>` 同時貼在母子兩端(只貼一端就
聚不起來)。標籤不存在就擋下並指回 labels.yaml——要求標籤在場,
不是猜哪些名字合法。labels.yaml 的 `j/` 段刻意留空:旅程怎麼切、叫什麼
名字是方向題,不由工具代決。
④ 撈得出來(驗收 3、4):新動詞 `ticket loose` 掃 org 的 open 票,撈
「有下游相依、下游全關、自己還開著」的頂層票。這是 ② 的補網——
關票的側門(直接 PATCH state=closed)是刻意放行的,漏掉的由這張網撈回來。
不是輪詢,掛在開場/收工對帳跑一次。
實跑(2026-08-28,唯讀,沒動任何票):245 張 open 票裡 17 張有下游相依,
其中 2 張是「下游都關了、自己還開著」——inkstone/arcrun-rag#136(已 s/review
且指派給 claude-code,正在被處理)與 inkstone/Arcrun#100(沒標籤、沒指派,
就是票上講的那種「永遠掛著」)。
測試:scripts/test-ticket-handoff-writeback.sh,49 條全綠,全程離線
(會打 API 的兩段把 api() 換成錄音機,不開票不關票不留測試票)。
回歸:A13 17/17、A4 24/24、A12 11/11 皆綠。
文件:docs/TESTING.md 新增 A16。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016ZBu4Sa1cGntKFRBYNZ6xs
|
2026-08-28 00:31:35 +00:00 |
|
claude-code
|
45b7b81075
|
Merge remote-tracking branch 'gitea/main' into fix/cloud-wiring-isep90
|
2026-08-28 00:29:10 +00:00 |
|
claude-code
|
4322deb23a
|
補上 stat -f 診斷的最後一層:連離開碼都不可靠(inkstone/ISEP#90 ④)
總管自己驗這一格量到 exit=0,我量到 exit=1。**兩個都是真的**,
而分歧本身就是最後一塊拼圖:
**GNU 的 `-f` 是 `--file-system`,布林旗標、不接格式字串**
⇒ `%m` 不是格式,它被當成**另一個檔名運算元**
⇒ 離開碼取決於「cwd 裡有沒有一個叫 `%m` 的檔」:
A. 沒有(一般情況) → exit 1 ⇒ `||` 會跑 ⇒ 正確的秒數接在垃圾後面
B. 剛好有 → exit 0 ⇒ `||` 不會跑 ⇒ 整包連一個數字都沒有
兩種情況閘的結果一樣:MT 都不是純數字、戳記都作廢。(實測 GNU coreutils 9.4,兩種都重現過)
🔴 教訓比原本寫的更尖銳:舊寫法的 `||` fallback 救不了,
**不是因為它沒跑,而是因為「跑不跑」根本不由這支腳本決定**——
它由「cwd 裡有沒有某個檔名」決定。
一個行為取決於 cwd 有沒有某個檔的判斷式,不管跑不跑都是壞的。
⇒ 所以修法不能只是「把順序反過來」,**每一步都要驗它是不是純數字**
(lib/mtime.sh 本來就是這樣寫的,現在把理由寫進去了)。
gate-ok 測試補第 ⑰ 條守這一層:cwd 裡有一個叫 `%m` 的檔時,file_mtime 仍要回純數字。
16 → 17 條,TESTING.md 的 A16 一併更新。
|
2026-08-28 00:27:51 +00:00 |
|
claude-code
|
be09353330
|
PR 一定要有結論(inkstone/ISEP#81)(docs/TESTING.md)
|
2026-08-28 00:27:32 +00:00 |
|
claude-code
|
3a1c3d4969
|
Merge remote-tracking branch 'origin/main' into fix/cloud-wiring-isep90
# Conflicts:
# docs/TESTING.md
|
2026-08-28 00:25:04 +00:00 |
|
claude-code
|
617315e3dd
|
把四個雲端接線缺陷的診斷寫下來(inkstone/ISEP#90)
docs/governance/cloud-wiring.md:四個缺陷分成兩種病——
①④ 是「閘的判準寫的是地端才成立的假設」,②③ 是「同一個東西有兩份,雲端跑到舊的」。
每一格都附實測證據與修法,並標明還沒關掉的兩格住在哪張票(ISEP#67/真身 repo)。
TESTING.md 補 A14/A15/A16 三格:怎麼跑、該看到什麼、什麼算失敗。
三支閘被擋下的訊息也一併指向 scripts/gate-ok(原本的手打法保留當等價寫法)。
|
2026-08-28 00:14:01 +00:00 |
|
Leo
|
17a74d7d3a
|
每一則回覆都自己說出拖了多久(inkstone/ISEP#63 → comment 5106)
leo 2026-08-27:「前面說過每個回覆要戴上已經花了總時長,這為什麼沒出現?」
「這應該寫在 ISEP,隨時看自己拖了多久」
重點在後面那句:不是要總管記得戴,是要它長在機器上。
總管當時答「我沒做,現在開始戴」——而那正是這條規則第一次失效的方式。
一支閘掛兩個事件,是同一件事的兩半(票上點名的失效模式就在這裡):
UserPromptSubmit → 注入算好的那一行(模型不必自己算,也算不準)
Stop → 查核這一回合的回覆裡到底有沒有那一行,沒有就擋一次
只做前半=又一個會被忽略的提醒;只做後半=罰它做一件拿不到資料的事。
判準不是關鍵字黑名單,是「那個被要求的輸出元素在不在」——
whitelist-of-one:要求一個機器產生的標記在場,不是猜哪些字不該在場。
換講法照樣要帶標記,多寫什麼都不會觸發。
時長從這段對話的第一則訊息算起,理由寫在 hooks/lib/countdown.py 檔頭:
「任務」在機器上沒有起點,而 CLAUDE.md 規則三點七「一段對話=一個 release」
剛好讓對話起點就是這個交付的起點——這個數字沒有人要維護,也不會說謊。
resume 取較早的那個:接關不是重新開始。
連帶修好票上的兩個卡點(prod-write-guard):
卡點一 發一則 Telegram 跟部署工作流在閘眼裡一模一樣 ⇒ 判準改看打的是哪一個
named webhook(路徑形狀+名字),放行範圍只有 notify_leo 一個名字
卡點二 連「把卡點寫進票裡」都被同一支閘擋(同款第八次)⇒ 剝掉內文再判,
起始行保留,所以真的在部署的寫法照樣擋
(修這支的過程又撞了一次同款——那就是這一格最好的證據)
測試:countdown 20/20、prod-write-guard 29→37/37,全程離線
(時鐘定住、狀態走環境變數、不打網路)。
實測:起點 06:28 台北、現在 08:03 ⇒ 期望「已過 1 小時 35 分」,實得同一字串。
plugin.json 0.9.0 → 0.10.0(版本沒動=沒有人吃得到)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-28 00:03:38 +00:00 |
|
Leo
|
ba444d1210
|
戳記要證明「看過」,不是「跑過」(inkstone/ISEP#72 → comment 4873)
2026-08-27 實犯:`ticket where … >/dev/null 2>&1` 之後直接 `ticket new`——
戳記寫成功了,命中的 72 張一眼沒看,於是開出 arcrun-rag#147,
而第一名 arcrun-rag#104 講的是同一件事,已經開了 13 天。
⇒ 舊戳記證明的是「這個程序被執行過」,而「有沒有看」在 stdout 那一端,
閘本來完全碰不到。
做法:把 stdout 那一端變成機械事實,不是文字判斷。
- `fd_is_devnull(fd)`:fstat 問得出來的事實。刻意只認 /dev/null 這一種
(寫進檔案讀得回來、pipe 有下游,只有 /dev/null 物理上找不回來)。
- `where` 把 `shown` 記進戳記;順便替前 3 名補內文摘要——今天的實害正是
「光看標題看不出是同一條線」(#104 的標題完全沒提 ingest)。
- `new` 的閘一之二:命中 >0 且 shown 為假就擋,並把那份被丟掉的清單
交到眼前;只要 stderr 不是 /dev/null,這一次的擋就記成「看過了」,
重下一模一樣的指令就會過——成本落在「看」,不落在「寫」。
- 刻意排在閘二**之前**:否則第一次就帶 `--not-a-comment "理由"` 的人
永遠看不到候選清單,理由是閉著眼睛寫的。
- 舊格式戳記(沒有 shown 欄位)當成沒看過(fail-closed)。
不該擋的(測試覆蓋):沒命中就不吵、看過了就不吵、`--not-a-comment`
既有欄位照舊、不判斷理由寫得好不好(leo 2026-08-17 已證偽文字層判準)。
測試 17/17:scripts/test-ticket-where-seen-guard.sh(離線,不打真實 Gitea、
不留測試票;離開碼 2=擋、1=放行走到網路才炸)。docs/TESTING.md 新增 A13。
plugin.json 升到 0.8.0——版本沒動=沒有人吃得到。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-27 21:17:35 +08:00 |
|
Leo
|
7e1b762cbe
|
merge: 棒子不會掉——子票相依+tag+指派三格全用 Gitea 原生欄位(inkstone/ISEP#58)
衝突只有 docs/hooks-inventory.md 的 A 組表格,解法照 ISEP#59 comment 4763 指定的
「兩列都留」:保留 main 上 #73 更新過的 ticket-api-bypass 敘述與 reply-identity-guard,
再加上本分支新增的 comment-carries-task-guard。標頭數字留到 #62 併完後一次實數。
|
2026-08-27 17:56:11 +08:00 |
|
Leo
|
23e4472715
|
封「新增 Gitea 東西」的每一道側門,不是只有開票(inkstone/ISEP#72)
leo 2026-08-27:「開票不查是否有現成的,這是什麼問題?」「不只開票前,
所有新增 gitea 的東西,都要搜尋」。
v1 的 ticket-api-bypass-guard 只認裸字 `grep -qw POST`(大小寫敏感),
只管 issues 端點。2026-08-27 總管一天開 13 張票,v1 一次都沒攔到——
用的是 `urllib.request.Request(url, data=...)`(靠傳 data= 隱式變 POST,
指令裡從頭到尾沒有 "POST" 三個字)和 `requests.post(...)`(小寫)。
本次改動:
- 寫入訊號從單一裸字換成一組結構性訊號(curl 資料類旗標/`.post(`/
`method=post`/urllib 隱式 POST),且大小寫不敏感,同時保留 v1 的裸字比對
- 端點擴大到 milestones/labels/pulls(含 org 層級的 labels),不再只管 issues
- 用「resource/數字」特徵先放行帶 ID 的既有資源子路徑(貼留言、改標籤、
合併 PR 等),避免貪婪比對把 `/issues/5/labels` 誤判成頂層 `/labels` 端點
- 擋下 issues 新增時,順手用標題猜關鍵字查一次跨 repo 搜尋,把可能撞到的
舊票(例如 Arcrun#100)直接列進擋下的訊息裡
測試:scripts/test-ticket-api-bypass-guard.sh 24/24 通過(v1 的 13 條 + 本次
新增 11 條,含一條打真實 Gitea 網路重演 Arcrun#100 重複主題偵測)。
plugin.json 0.5.0 → 0.5.1;version-consistency 會在合併打 tag 那一刻才對齊
(release-tag-guard.sh 的既定分工:打 tag 是總管驗過整個 milestone 之後的事)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-27 16:19:06 +08:00 |
|
Leo
|
b46bc5e44c
|
dogfood 抓到自己的漏:交棒標記只認第一行,不認「內文提過」
實跑自己那則交件報告時,閘沒有擋——因為報告裡**引用了一段 ticket mine 的輸出**
(那段有 🏃),整則就被豁免掉了,而它裡面真的有「等雲端那半出貨」。
⇒ 同 inkstone/InkStoneCo#23 那個病:複述關鍵字被當成本人。
ticket handback 寫的交棒留言 🏃 一定在第一行,引用別人的輸出則不會 ⇒ 錨在第一行。
回歸測試 +2(20/20 → 22/22)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-27 12:13:27 +08:00 |
|
Leo
|
e474b4cb6f
|
棒子不會掉:子票相依+tag+指派三格,全部用 Gitea 原生欄位
leo 2026-08-27:「子票相依是 gitea 原有機制,改 tag 和指定也是,這些全部都要」
08-26 掉的那一次(arcrun-rag#136 comment 4267「等雲端那半出貨才驗得了」躺了
14 小時)三格全缺:沒有子票、tag 沒動、沒有指派給任何人。根因不是誰忘了,
是那件事沒有落在任何一個「撈一次就看得到」的欄位上。
實測(Gitea 1.26.4):子票還開著時關母票 → HTTP 412
"cannot close this issue or pull request because it still has open dependencies"
⇒ 相依是平台保證的硬擋,不是提醒。跨 repo 也成立(201)。
- scripts/ticket 新增三個動詞:subtask(長子票+掛相依)/
handback(指派+改 tag+寫下一步,一個動作)/mine(撈一次看棒子在誰手上)
- hooks/comment-carries-task-guard.sh:留言帶未完成的未來式卻沒開子票 → 擋一次
- hooks/baton-handback-guard.sh:一條線收工,三格缺哪一格當場說出來(提醒不擋)
- docs/governance §16:三個維度/粒度(傾向多開票)/既有票只從今天起適用/
與 s/* 的關係/實測輸出
- 測試 20+10 全綠,用 fixture 跑不打網路、不在票池留測試票
📌 踩到並記進閘的檔頭:hook 裡比對中文一律用 python3 的 re,不要用 grep 的字元類
(等[^。]{0,20}出貨 在真實 hook 呼叫路徑下對「等雲端那半出貨」不匹配,閘靜默失效)
票:inkstone/ISEP#30(comment 4334/4335/4346/4347)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-27 12:05:53 +08:00 |
|
Leo
|
3bc7f3c5f5
|
派工單只剩票號——閘從驗「有沒有票號」改成驗「是不是只有票號」
leo 2026-08-27(inkstone/ISEP#30 comment 4322/4325/4327):
「這些話票上都沒有,你根本沒照規則做事,你的 hook 讓你這樣搞?」
「你用一個 output parser 把你給 subagent 的指令規範,分作幾點,每一點規定格式,
照這種散文寫法根本無法迭代」「警察也不能抓」
「交件方式不需要寫,定義在原則裡⋯⋯每次都一樣提取出來變成共通規定」
「(那些 session 事實)這些為什麼不寫到票裡?」「subagent 回覆時要表明身份」
病根:no-ticket-no-dispatch.sh 驗的是「有沒有一行【工單】owner/repo#N」,
而規則的原文是「派工單只寫票號」。⇒ 把 40 行任務全寫在 prompt 裡、票號補一行,
閘照樣放行。2026-08-27 一天內這樣做了 5 次,每次票上都沒有那份任務。
規則存在,閘只驗了它的殼——同款第 N 次(history-first/KBDB-first/stage-first)。
新增 hooks/dispatch-format-guard.sh(PreToolUse Task|Agent),兩件事:
- 擋:【工單】以外還有實質內容就 exit 2,並指出那些內容該搬去哪
(每次都一樣 → 共通規定;這次才知道 → 寫進那張票。
判準「這句話換一張票還成立嗎?」)
- 注入:合規的派工自動把共通規定送給收工方(交件方式、不准 push main、
org 是 inkstone…)——這是「派工單只剩票號」能成立的前提,
leo 的驗收條件之一就是「收工方沒讀派工單也知道要貼回原票」
判準是結構不是文字(leo 2026-08-17 那條檢驗):問的是「這一行是不是【工單】欄位」
——在不在,不是寫什麼。hooks/lib/dispatch_parse.py 全檔零個「命中某個詞就違規」的比對。
⇒ 也因此不需要語意判官:免費、瞬間、每次結果一樣。
新增 hooks/reply-identity-guard.sh(PreToolUse Bash)+ scripts/ticket 內建檢查:
票上每一則留言第一行要有【身份】(總管/subagent/leo)。貼留言有兩條路,兩條都封
——ticket-api-bypass-guard 是刻意放行「對既有票留言」的,只封正門等於沒封。
實害:多條線並行時總管寫的診斷被當成 subagent 的結論,而其中一則是錯的。
規約寫成文件:docs/governance/dispatch-and-reply-format.md
(§2 那段就是被注入的那份共通規定本體——只有一份,改那裡等於改所有派工)
實測(離線、不打網路、不花錢):
hooks/tests/dispatch-format-guard.test.sh 19/19
hooks/tests/reply-identity.test.sh 11/11
測資裡的 B⑨ 是真跡:產生 ISEP#30 這條線的那一次派工,一字未改。
另 4 份 leo 點名的違規派工拿不回來了——它們住在 prompt 裡,agent 一停就沒了,
這件事本身就是這條規則的證據(見 hooks/tests/fixtures/README.md,不用想像的例子替補)。
升版 0.4.0 → 0.5.0(產物按版本號分資料夾,不升版新閘不會被載入)。
tag 照慣例打在 merge commit 上,所以這條分支上 check-version-consistency.sh 是紅的。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-27 11:35:03 +08:00 |
|
claude-code
|
e0557334bc
|
閘掛在「收工後」,而 leo 是在「被問到」的當下被打擾——補上那一刻的攔截
leo 2026-08-26:「今天已經好幾次問我,為什麼 hooks 沒有攔下來?」
實查:總管問 leo 走的動作是 AskUserQuestion,而 hooks.json 裡它出現 0 次,
沒有任何 matcher。判準其實早就寫好了——self-drive-police / self-drive-judge
用的就是同一套四題公式——但那兩支只掛在 Stop 與 SubagentStop,
是回合結束後才跑的。問題早就送到他眼前了,事後再反問「你查過了嗎」,
成本已經轉嫁出去。判準對了,時機錯了。
新增 hooks/ask-user-question-guard.sh(PreToolUse / AskUserQuestion):
- 觸發條件是那個動作本身,不是任何句型或關鍵字——全檔零個判擋用的正則,
換句話說閃不過去,講得謹慎也不會被多罰(leo 2026-08-17 文字層封路的檢驗)
- 進來之後用四題公式的 haiku 判官分「該問 / 不該問」,命中任一題一律放行
- 同一個問題只擋一次(雜湊戳記):判官誤判時重送即過,
leo 該收到的問題不會因為一支閘而永遠送不到
- 判官掛掉/沒網路/claude 不在 PATH 一律 fail-open,壞掉等於它不存在
版本 0.3.9 → 0.4.0。這不是儀式,是傳輸機制本身:產物按版本號分資料夾
(~/.claude/plugins/cache/inkstone/isep/<版本>/),版本沒動就不會長出新資料夾,
這支閘一個 session 都載入不到。docs/TESTING.md 開頭那段講的就是這件事,
而第一版我漏了——總管複驗時量出來的。
假設(沒有前例可循,先裁再記):跳 0.4.0 而不是 0.3.10。理由是這一版第一次
掛上 AskUserQuestion 這個事件面,是新能力不是修補;而且 0.3.10 在
plugin 快取目錄的 ls 裡會排到 0.3.1 旁邊,肉眼不好認。錯了打回,改號很便宜。
順手修掉自己寫出來的一個坑:訊息原本用沒加引號的 heredoc,
反引號被當命令執行,wiki 路徑與豁免指令兩行變成空白(閘照擋,只看離開碼看不出來)。
已收成 mistakes.md 一條,並由 ⑩b 這條測試守著。
實測:
- hooks/tests/ask-user-question-guard.test.sh 14/14(離線,不花錢)
- hooks/tests/ask-user-question-guard.live.test.sh 9/9 連跑三次(真的叫 haiku)
A 群 5 條真人閘(花錢/不可逆/跨專案結構/品味方向/物理人閘)全部放行,誤攔 0
B 群 4 條純技術路徑選擇全部擋下
- 既有 7 支測試與改動前逐條對照,結果完全相同(沒有被我弄壞)
順手對帳:plugin.json 與 marketplace.json 的描述寫「43 支機械閘、53 條註冊」,
實際數過是 46/56(含本次新增這支)。docs/hooks-inventory.md 一併更正。
【工單】inkstone/InkStoneCo#55
|
2026-08-26 22:36:08 +08:00 |
|
Leo
|
135637291c
|
B4 的探針我自己沒撞過,實撞後發現它根本不會擋
v0.3.1 我把 B4 從 git tag 換成「寫 __GITEA_TOKEN__ 進 /tmp/x.md」,
說它會被 credential-only-guard 擋下。今天實撞:exit 0,閘完全沒反應。
原因:那支閘刻意豁免 .md/docs//wiki/(文件本來就要能談論這些字串)。
它只管會被執行的產物:*workflow*/.yaml/.yml/installer/worker.js/wrangler。
改成 /tmp/wf.yaml 後三向實測:
違規 workflow.yaml 帶佔位符 → exit 2 credential 鐵律攔截
同檔用 {{credential.gitea_token}} → exit 0(正確放行)
.md 談論同一個字串 → exit 0(正確豁免)
薄殼指標端同樣實測:真身在+違規 → exit 2。
這是同一個病的第四次:修假綠的那一刀,自己又是沒撞過就寫。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-21 00:33:44 +08:00 |
|
Leo
|
291787eaaa
|
TESTING.md B 段整段換掉——舊版在閘全滅時會回綠
2026-08-20 雲端實證:B2/B3/B4 三步在 plugin 完全缺席時**全部通過**。
一個在閘死掉時也會給出正確答案的測試,不是測試。
三處各自為什麼假:
- B2「跑 claude plugin list」→ 要它自己報自己,沒有獨立證據
- B3「Skills (9) / Hooks (5)」→ 那組數字剛好是薄殼自己的 .claude/ 產生的
- B4「git tag -a v9.9.9」→ git tag 在三支閘的白名單裡
新版三步都改成有鑑別力的:
- B2 找 v0.3.0 新增的載入信標(那支腳本住在 plugin 裡,沒載入就不可能發聲)
- B3 看 setup script 的自我驗證輸出(v0.3.0 新增)
- B4 改用金鑰佔位符觸發 credential-only-guard(不在任何白名單上)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
2026-08-20 23:02:47 +08:00 |
|
Leo
|
f855d82573
|
產生雲端 env 設定,不要 leo 自己拼湊(InkStoneCo#14)
leo 2026-08-20:「應該是你會幫我產生正確的 env 我去貼⋯⋯不然就是我要自己拼湊」
「這些值你都有,你可以只寫名字然後 build 一個檔案給我」
總管原本的說法是「你複製設定給我、值遮掉」——那是錯的,兩個理由:
① 把拼湊的工作丟回給 leo ② 讓值經過對話本身就是洩漏面。
scripts/make-cloud-env.sh:
- 腳本裡只寫**變數名字**(NEEDED 陣列,要加變數就加在那裡)
- 值在執行當下才從既有 .env 讀(credentials-map 記的六個位置都找)
- 產物寫到 ~/.claude/cloud-env/<時間>.txt,權限 600,**刻意不在任何 repo 底下**
- 只印路徑不印值;找不到值的變數會標出來而不是靜默留空
- 產物最後一行就是刪除指令
docs/TESTING.md 補 B0 段:先跑產生器,再貼。
實跑過:1 個變數、0 個找不到、產物 45 行、權限 600、不在任何 repo。
|
2026-08-20 20:45:02 +08:00 |
|
Leo
|
1dfc4e373a
|
v0.2.1:43 支閘的白話盤點、測試手冊、補上兩個被抓到的洞
leo 2026-08-20 問「InkStoneCo#40 加入了嗎?如果是這樣我應該可以白話文看到 hooks 的內容?」
答案是不行——43 支閘沒有任何白話清單。這一版補上。
docs/hooks-inventory.md 43 支逐支一行,按「你會在什麼時候撞到它」分 9 組
抽驗 5 支逐行核對源碼;順帶抓到 3 支有檔案沒註冊
docs/TESTING.md A1-A8 + B1-B5,每格都有「怎麼跑/該看到什麼/什麼算失敗」
scripts/test-*.sh 兩支閘的測試,共 21 條,全過
兩個實撞的洞:
- release-tag-guard 的排除清單是前綴比對,x 整條放行
(A8 那個新 session 抓到的,總管複驗屬實)。改用 #23 驗證過的判準:
關鍵字要在指令位置才算執行。補 3 條複合指令測試,8/8。
⇒ 這是 InkStoneCo#36「包一層就繞過去」的同一個病,發生在同一天新寫的閘上。
- scripts/ticket 寫死只認名叫 gitea 的 remote,在 ISEP(remote 叫 origin)整個跑不起來
⇒「開票前先搜」那道閘在新 repo 等於不存在。改成掃所有指向本站的 remote + 環境變數 fallback。
A8 已通過:新 session 裡 plugin 的閘真的觸發(exit 2、tag 未建立、訊息來自 plugin 路徑)。
文件漂移訂正:plugin.json 與 README 寫 42 支/52 條,實際 43 支/53 條。
兩支新閘補上 #40 §1 要求的三行中文檔頭。
🔴 但仍違反 #40 §3「新規則一律先 warn」——兩支都是 block。理由記在 #40 留言,等 leo 裁。
|
2026-08-20 17:08:00 +08:00 |
|