現在的主線是哪一個,有唯一答案(inkstone/ISEP#82) #99

Merged
claude-code merged 2 commits from feat/mainline-milestone into main 2026-08-28 00:43:56 +00:00
Member

交件 inkstone/ISEP#82這不是新開一條線,是接在 #63 剛上線的那個注入點上。

它解什麼

2026-08-27 實查:GET /repos/inkstone/*/milestones?state=open14 個
「Mira 現代化」這個名字同時活在 5 個 repo,5 個已逾期。
⇒ SOP 說的「只做 milestone 的事」在現場沒有指涉對象——
要注入不知道注哪一個,要擋跳線也不知道拿哪一個當基準。規則被讀到了,但機器上不存在。

不動的:跨 repo 同名 milestone 是既有做法(v0.6.0 §4/SOP S7-4),本 PR 一個字都沒改它。
改的:讓「這一刻我在做哪一條」變成一個查得到的事實。

四條驗收,逐條對應

票上驗收 這裡是什麼 測到它的那一格
1 問「現在的主線是哪一個」→ 一個指令,答案唯一 scripts/mainline(主線住在一個檔裡,那個檔放得下一條) A 群 ①–⑤
2 標了之後開新回合 → 目標宣告自己出現 注入點的第二行 🎯;主線的名字同時掛在被查核的 ⏱ 那一行上 B 群 ⑥–⑩
3 派不屬於主線的票 → 攔一次,問補收還是跳線 hooks/mainline-focus-guard.sh(Agent+Task 兩個入口) C 群 ⑫–⑱
4 沒有主線 → 不能整組壞掉 show/注入/閘三處都講得出「現在沒有主線」,閘一律放行 ①②⑪⑲㉔

為什麼沒有為 🎯 再立一道會擋人的閘

那一行已經有 #63 的 Stop 閘在查它有沒有被戴上,而主線的名字就掛在那一行裡
⏱ 已過 …|距收工線 …|主線 SOP 變成閘 剩 …)。
⇒ 主線是跟著一道已經驗過的閘到 leo 眼前的,不是靠新增一道閘。
一個回合最多該被擋一次;多要求一個標記=多一種被擋的方式,而本 repo 心法第 2 條寫死了
「永遠在響的警報等於訓練人忽略警報」。真正會擋人的地方在派工那一端,擋的是一個動作,不是一段文字。

誤攔的出口(誤攔比漏擋更該修)

  • 沒有標主線 ⇒ 一律放行
  • 派工單沒有票號 ⇒ 放行(那是 no-ticket-no-dispatch 的地盤,兩支閘不同時開口)
  • 多張票只要有一張在主線上 ⇒ 放行
  • 查不到那張票掛在哪 ⇒ 放行🔴 讀不到 ≠ 不屬於)
  • 子 session ⇒ 放行(主線是派工者手上的判準)
  • 同一張票只擋一次,重送就過;state 檔壞掉 ⇒ 放行且指令仍答得出來

沒有任何關鍵字黑名單(leo 2026-08-17 已證偽:8 次誤攔 0 次正確攔截)。
判準只有兩個查表:①【工單】欄位是哪張票(結構解析)②那張票所屬里程碑的標題等不等於主線標題(字串相等)。

驗過了

bash hooks/tests/mainline-focus-guard.test.sh   → 通過 24 條,失敗 0 條(全程離線)
bash hooks/tests/countdown-guard.test.sh        → 通過 20 條,失敗 0 條(#63 原有的,沒有回歸)
bash hooks/tests/dispatch-format-guard.test.sh  → 33/33(共用 dispatch_parse,確認沒被我動到)
python3 -c "import json;json.load(open('hooks/hooks.json'))"  → json ok
docs/hooks-inventory.md 的兩組落差偵測指令      → 「有閘沒人話」「列了但檔案不在」皆無輸出

離線是真的離線TICKET_HOST 指到 http://127.0.0.1:9,任何一條真的走到網路會當場失敗,
不會靜靜地變成假綠。「那張票掛在哪」用 ISEP_MAINLINE_FIXTURE 定住,
#63ISEP_COUNTDOWN_NOW(把時鐘定住)同一個性質。

打網路的那半(listsetadopt)不在測試裡,因為只有真的 Gitea 驗得了——
實跑過mainline list 回 15 個 open 里程碑跨 5 個 repo;
mainline set inkstone/ISEP#57 收到同名里程碑的票 13 張;refresh 0.8 秒。
驗法寫進 docs/TESTING.md A17。

盤點數字(當場數的,不是加減推的)

ls hooks/*.sh | wc -l                      → 54
grep -c '"command":' hooks/hooks.json      → 71
find scripts -maxdepth 1 -type f | wc -l   → 37
  • docs/hooks-inventory.md:53→54 支、68→71 條,並補上新閘那一列人話
  • 順手修兩個既有的假綠:①「一句話結論」那一句上一版被貼了兩遍
    ②「指向空氣的閘」那格寫「(無輸出)」,但 #63 之後實跑會吐出
    countdown-milestone-refresh.sh(它在 scripts/ 不在 hooks/)——已標明那是假警報
  • plugin.json:描述數字對齊(39→37 支腳本,是用上面那行指令數的)

🔴 版本號沒有動,待總管定版(今天多線並行)。
本分支已經 rebase 到 dbd7c8c(v0.12.0 定版之後),plugin.jsonversion 就是繼承來的 0.12.0
⚠️ v0.12.0 這個 tag 已經打了,所以這個 PR 併進去之後,
0.12.0 的內容會跟那顆 tag 不一樣 ⇒ 併的時候要一起升版,不然
「ISEP 現在是哪一版」又會變成各說各話(scripts/check-version-consistency.sh 會紅)。

📌 已實測:branch 落在現在的 main 上(HEAD..gitea/main = 0 筆),
Gitea 回 mergeable = true。今天 main 動了三次,這是第三次 rebase 後的狀態。

怎麼用

scripts/mainline list                 # 有哪些可以選
scripts/mainline set inkstone/ISEP#57 # 標成主線(id 是里程碑的 id,不是 issue 號)
scripts/mainline                      # 現在的主線是哪一個(唯一答案)
scripts/mainline adopt <owner/repo#N> # 補收:把一張票掛進主線
scripts/mainline clear                # 現在沒有主線

兩個順手撞到、但不在本票射程內的閘誤攔

只擋錯方向、不會放行不該放的,所以我一個字都沒改,留給總管決定要不要開票:

  1. github-contact-guard.sh 解 remote 時用的是 session 的 cwd,不是指令裡 git -C <dir>
    指的那個 repo。在一個 origin 指向 GitHub 的專案底下 clone 子 repo 時,
    推 Gitea 會被判成推 GitHub 而擋下(繞法:推到一個名字不叫 origin 的 remote)。
  2. milestone-due-guard.sh 的判準是「指令字串裡有 milestones + 有 -X POST」,
    不剝 heredoc。所以開這個 PR 時,光是內文提到 milestones?state=open
    就被當成「在建一個沒有期限的里程碑」而擋下——
    InkStoneCo#23#56 的根因同款(把資料當指令掃),
    github-contact-guard 已經用 lib/strip_heredoc.py 修過同一個病。
交件 `inkstone/ISEP#82`。**這不是新開一條線,是接在 `#63` 剛上線的那個注入點上。** ## 它解什麼 2026-08-27 實查:`GET /repos/inkstone/*/milestones?state=open` 回 **14 個**, 「Mira 現代化」這個名字同時活在 5 個 repo,5 個已逾期。 ⇒ SOP 說的「只做**該** milestone 的事」在現場**沒有指涉對象**—— 要注入不知道注哪一個,要擋跳線也不知道拿哪一個當基準。**規則被讀到了,但機器上不存在。** **不動的**:跨 repo 同名 milestone 是既有做法(v0.6.0 §4/SOP S7-4),本 PR 一個字都沒改它。 **改的**:讓「這一刻我在做哪一條」變成一個查得到的事實。 ## 四條驗收,逐條對應 | 票上驗收 | 這裡是什麼 | 測到它的那一格 | |---|---|---| | 1 問「現在的主線是哪一個」→ 一個指令,答案唯一 | `scripts/mainline`(主線住在一個檔裡,那個檔放得下一條) | A 群 ①–⑤ | | 2 標了之後開新回合 → 目標宣告自己出現 | 注入點的第二行 `🎯`;主線的名字**同時掛在被查核的 ⏱ 那一行上** | B 群 ⑥–⑩ | | 3 派不屬於主線的票 → 攔一次,問補收還是跳線 | `hooks/mainline-focus-guard.sh`(Agent+Task 兩個入口) | C 群 ⑫–⑱ | | 4 沒有主線 → 不能整組壞掉 | `show`/注入/閘三處都講得出「現在沒有主線」,閘一律放行 | ①②⑪⑲㉔ | ## 為什麼沒有為 🎯 再立一道會擋人的閘 `⏱` 那一行**已經有 `#63` 的 Stop 閘在查它有沒有被戴上**,而主線的名字就掛在那一行裡 (`⏱ 已過 …|距收工線 …|主線 SOP 變成閘 剩 …`)。 ⇒ 主線是跟著一道**已經驗過的閘**到 leo 眼前的,不是靠新增一道閘。 一個回合最多該被擋一次;多要求一個標記=多一種被擋的方式,而本 repo 心法第 2 條寫死了 「永遠在響的警報等於訓練人忽略警報」。真正會擋人的地方在派工那一端,擋的是**一個動作**,不是一段文字。 ## 誤攔的出口(誤攔比漏擋更該修) - 沒有標主線 ⇒ 一律放行 - 派工單沒有票號 ⇒ 放行(那是 `no-ticket-no-dispatch` 的地盤,兩支閘不同時開口) - 多張票只要有一張在主線上 ⇒ 放行 - **查不到那張票掛在哪 ⇒ 放行**(🔴 讀不到 ≠ 不屬於) - 子 session ⇒ 放行(主線是派工者手上的判準) - **同一張票只擋一次**,重送就過;state 檔壞掉 ⇒ 放行且指令仍答得出來 沒有任何關鍵字黑名單(leo 2026-08-17 已證偽:8 次誤攔 0 次正確攔截)。 判準只有兩個查表:①【工單】欄位是哪張票(結構解析)②那張票所屬里程碑的標題等不等於主線標題(字串相等)。 ## 驗過了 ``` bash hooks/tests/mainline-focus-guard.test.sh → 通過 24 條,失敗 0 條(全程離線) bash hooks/tests/countdown-guard.test.sh → 通過 20 條,失敗 0 條(#63 原有的,沒有回歸) bash hooks/tests/dispatch-format-guard.test.sh → 33/33(共用 dispatch_parse,確認沒被我動到) python3 -c "import json;json.load(open('hooks/hooks.json'))" → json ok docs/hooks-inventory.md 的兩組落差偵測指令 → 「有閘沒人話」「列了但檔案不在」皆無輸出 ``` 離線是**真的離線**:`TICKET_HOST` 指到 `http://127.0.0.1:9`,任何一條真的走到網路會當場失敗, 不會靜靜地變成假綠。「那張票掛在哪」用 `ISEP_MAINLINE_FIXTURE` 定住, 與 `#63` 的 `ISEP_COUNTDOWN_NOW`(把時鐘定住)同一個性質。 打網路的那半(`list`/`set`/`adopt`)不在測試裡,因為只有真的 Gitea 驗得了—— **實跑過**:`mainline list` 回 15 個 open 里程碑跨 5 個 repo; `mainline set inkstone/ISEP#57` 收到同名里程碑的票 13 張;`refresh` 0.8 秒。 驗法寫進 `docs/TESTING.md` A17。 ## 盤點數字(當場數的,不是加減推的) ``` ls hooks/*.sh | wc -l → 54 grep -c '"command":' hooks/hooks.json → 71 find scripts -maxdepth 1 -type f | wc -l → 37 ``` - `docs/hooks-inventory.md`:53→**54** 支、68→**71** 條,並補上新閘那一列人話 - 順手修兩個既有的假綠:①「一句話結論」那一句上一版被貼了兩遍 ②「指向空氣的閘」那格寫「(無輸出)」,但 `#63` 之後實跑會吐出 `countdown-milestone-refresh.sh`(它在 `scripts/` 不在 `hooks/`)——已標明那是假警報 - `plugin.json`:描述數字對齊(39→**37** 支腳本,是用上面那行指令數的) 🔴 **版本號沒有動,待總管定版**(今天多線並行)。 本分支已經 rebase 到 `dbd7c8c`(v0.12.0 定版之後),`plugin.json` 的 `version` 就是繼承來的 `0.12.0`。 ⚠️ **`v0.12.0` 這個 tag 已經打了**,所以這個 PR 併進去之後, `0.12.0` 的內容會跟那顆 tag 不一樣 ⇒ **併的時候要一起升版**,不然 「ISEP 現在是哪一版」又會變成各說各話(`scripts/check-version-consistency.sh` 會紅)。 📌 **已實測**:branch 落在現在的 main 上(`HEAD..gitea/main` = 0 筆), Gitea 回 `mergeable = true`。今天 main 動了三次,這是第三次 rebase 後的狀態。 ## 怎麼用 ``` scripts/mainline list # 有哪些可以選 scripts/mainline set inkstone/ISEP#57 # 標成主線(id 是里程碑的 id,不是 issue 號) scripts/mainline # 現在的主線是哪一個(唯一答案) scripts/mainline adopt <owner/repo#N> # 補收:把一張票掛進主線 scripts/mainline clear # 現在沒有主線 ``` ## 兩個順手撞到、但不在本票射程內的閘誤攔 都**只擋錯方向、不會放行不該放的**,所以我一個字都沒改,留給總管決定要不要開票: 1. `github-contact-guard.sh` 解 remote 時用的是 **session 的 cwd**,不是指令裡 `git -C <dir>` 指的那個 repo。在一個 origin 指向 GitHub 的專案底下 clone 子 repo 時, **推 Gitea 會被判成推 GitHub 而擋下**(繞法:推到一個名字不叫 origin 的 remote)。 2. `milestone-due-guard.sh` 的判準是「指令字串裡有 `milestones` + 有 `-X POST`」, **不剝 heredoc**。所以開這個 PR 時,光是**內文提到** `milestones?state=open` 就被當成「在建一個沒有期限的里程碑」而擋下—— 與 `InkStoneCo#23`/`#56` 的根因同款(把資料當指令掃), `github-contact-guard` 已經用 `lib/strip_heredoc.py` 修過同一個病。
claude-code force-pushed feat/mainline-milestone from 602500a4c7 to 84f146fbd3 2026-08-28 00:39:20 +00:00 Compare
claude-code added 2 commits 2026-08-28 00:40:24 +00:00
14 個 open milestone 同時亮著,其中「Mira 現代化」同名活在 5 個 repo,
所以 SOP 說的「那個 active milestone」在現場沒有指涉對象。

- hooks/lib/mainline.py        主線的唯一存放處(一個檔放得下一條),從不打網路
- scripts/mainline             show/list/set/clear/refresh/adopt/has
- hooks/mainline-focus-guard.sh 派了不在主線上的票 ⇒ 攔一次,問補收還是跳線
- hooks/lib/countdown.py       ⏱ 那一行的主線改讀「被標定的」,蓋過「期限最近」的猜測
- hooks/countdown-guard.sh     同一個注入點加第二行 🎯(ISEP#63 那半不動)
- 測試 24 條(離線)+ countdown 原有 20 條仍全綠
- 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    描述數字對齊;版本不動,待總管定版
claude-code force-pushed feat/mainline-milestone from 84f146fbd3 to 7871921741 2026-08-28 00:40:24 +00:00 Compare
claude-code merged commit 4014676813 into main 2026-08-28 00:43:56 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: inkstone/ISEP#99