雲端工人會分診、會組里程碑,組了就照里程碑做(inkstone/ISEP#159)

leo 09-18:「它看到票時要能夠組成 milestone 提出版本,所以不只是看票,還要組票。」
雲端只會撿(ISEP#130),沒有任何機制分診或組里程碑;open 302 張裡 74 張沒 s/*、257 張沒掛里程碑。

- ticket triage:沒 s/* 的票 → s/backlog/s/triage/s/pending+票上一則說明(--why 必填),一個動作;
  --dup-of:說明+close/duplicate+關+在留下的那張留一則指回來(留下的那張若是 leo 的就不寫)
- ticket compose:把已分診的票組成 InkStoneCo 里程碑(開工規約 1–7 條):既有載體+前置相依、
  s/backlog → s/todo、名字不准是版本號、期限 1–60 天、不開新票;先全部讀過才寫,理由一次列齊
- 不碰:Human/human/*、指派給別人(含 Leo)——判準是標籤與 assignee 登入名
- pick --pool:還沒到期的 InkStoneCo 里程碑的前置排在散票之前;可做的都抓盡時回待分診的票,
  每列帶 next;queue-drain-guard 照 next 印(待分診是 triage,不是 claim)
- 全局票池只有一個讀法 pool_issues(),接口留給 ISEP#154(global_index 寫卡驗完後只換這一個函式)
- InkStoneCo 掛在 open 里程碑的票=載體(容器):不進票池、不算待分診

假設(寫在這裡等總管 review):
- 分診只收「沒有 s/*」的票;s/triage 仍是總管/leo 的判斷,工人只能把拿不準的丟進 s/triage
- 載體撈不到時,工人用 ticket where+ticket new 補一張 InkStoneCo User Story 當載體(開工規約第 2 條的「真缺口」)
- 期限上限 60 天(9999 與過去日期都擋)

實測:test-ticket-triage 80/80、test-ticket-pick 84/84、queue-drain-guard 28/28;
真 Gitea 代跑一趟:分診 4 張、建 InkStoneCo milestone 68(載體 InkStoneCo#136,前置 ISEP#47、arcrun-rag#199),
pick --pool 第一組即為它的前置;一次違規三格的 compose 真的零寫入擋下。
待總管定版。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-18 18:43:07 +08:00
parent 51c668f9c8
commit 2bbcda2ac3
8 changed files with 900 additions and 41 deletions
+53 -2
View File
@@ -429,11 +429,11 @@ bash hooks/tests/gitea-arm-check.test.sh .
- ①③⑤⑥ 任一紅 ⇒ 收手收得太晚,暫存區已經開始長東西(磁碟風險回來了)
- ② 紅 ⇒ 訊息沒給出走得通的那一行(本票整張票在講的就是這件事)
- ⑧⑨⑩ 任一紅 ⇒ **誤攔/複製錯**:正常用法被弄壞,或複本裡混進了 `hooks/` 以外的東西
### A31 — 雲端工人抓票的規則是機械可判的:80
### A31 — 雲端工人抓票的規則是機械可判的:84
```
bash scripts/test-ticket-pick.sh
```
**該看到**`通過 80 條,失敗 0 條`。**全程離線**:假池子(5 個 repo、3 個 open milestone、
**該看到**`通過 84 條,失敗 0 條`。**全程離線**:假池子(5 個 repo、3 個 open milestone、
52 張票、1 條相依邊;`big` 那個 repo 的假伺服器每頁只給 30 張,驗分頁)餵給換掉的 `api()`,時鐘走 `ISEP_COUNTDOWN_NOW``TICKET_HOST` 指到連不上的位址
——任何一條真的走到網路會當場炸,不會靜靜變成假綠。**不開票、不改票、不留任何東西在 Gitea 上。**
@@ -473,6 +473,8 @@ Gitea 主線里程碑抓票(`inkstone/InkStoneCo#118`),但那是一段給
- ②「沒帶 --pool → 票池一通都沒讀」紅 ⇒ **誤攔**:本機總管跑過 `handback` 後每次收工都會被佇列閘點名去抓票池
- ⑤「可抓 0 張時列理由表、不說正常」紅 ⇒ 「0 張」又被說成正常收工(c7797)
- ⑤「分頁」紅 ⇒ 伺服器每頁上限比 50 小時,第二頁之後的票看不到
- ⑤「票池抓盡、還有沒 s/* 的票 → 回待分診那張,下一步是 triage」紅 ⇒ 沒驗傷的票又沉默地消失在「可抓 0 張」後面(`inkstone/ISEP#159`A43 測分診本身)
- ⑤「pick --claim 遇到待分診 → 不認領」紅 ⇒ 會對一張還沒決定要不要做的票寫 s/doing
📌 **真實 Gitea 唯讀實跑**2026-09-07isep-hand,不改任何票):
`ticket pick --mainline InkStoneCo/system-dev/mainline.json --all` 在主線
@@ -483,6 +485,55 @@ Gitea 主線里程碑抓票(`inkstone/InkStoneCo#118`),但那是一段給
assignee`claude-code`、標籤 `s/todo → s/doing`、留言 6325 第一行【身份】——
之後再 `pick` 就不再回 #131(票上驗收第 2 條的 log 在票的留言裡)。
### A43 — 雲端工人會分診、會組里程碑,而且碰不到 leo 的票:80 條
```
bash scripts/test-ticket-triage.sh
bash hooks/tests/queue-drain-guard.test.sh # 28 條:待分診那一列,閘印 triage 不印 claim
```
**該看到**`通過 80 條,失敗 0 條``通過 28 條,失敗 0 條`。**全程離線**(形狀同 A31:假池子 3 個 repo、
3 個 open 里程碑、1 張載體帶 3 條相依;時鐘定在 2026-09-18`TICKET_HOST` 連不上)。
**它在守什麼**`inkstone/ISEP#159`):leo 09-18「我有快 500 個票⋯⋯它看到票時要能夠組成 milestone 提出版本,
所以不只是看票,還要組票」。當天實量 open 302 張、沒 s/* 的 74 張、沒掛里程碑的 257 張;雲端只會撿(A31),不會組。
哪張跟哪張重複、哪幾張該一起出版——是**讀票的人的判斷**;這一支守的是判斷寫回 Gitea 的那一步:
```
triage 沒有 s/* 的票 → s/backlogs/triages/pending 票上一則說明(--why 必填),一個動作
--dup-of <票> → 說明+close/duplicate+關+在留下的那張留一則指回來
compose --title --goal --due --carrier inkstone/InkStoneCo#N <前置…>
建在 InkStoneCo、掛在既有載體、前置掛成相依、s/backlog → s/todo,不開任何新票
先全部讀過才寫第一筆;驗不過一次列出全部理由
pick --pool 時:還沒到期的 InkStoneCo 里程碑的前置 → 排在散票之前(組了就照里程碑做)
可做的都抓盡 → 回一張待分診的(row 帶 next=triage 那一行,佇列閘照它印)
不碰 掛 Humanhuman/*、指派給別人(含 Leo)——判準是標籤與 assignee 登入名,不看文字
```
**失敗**
- ①「掛 Human/指派 Leo → 不碰」任一紅,或 ②③ 裡「驗收 3」那幾條紅 ⇒ **會寫 leo 的票**(驗收 3 破了)
- ②「重複的對象是 Leo 的票 → 不在它上面寫字」紅 ⇒ 關重複票時順手在 leo 的票上留言
- ②「寫入恰好是 [留言, 改標籤]」紅 ⇒ 改了欄位卻沒留說明(驗收 1:每張被動過的票都說得出分到哪、為什麼)
- ②「--to s/todo 擋」紅 ⇒ 沒排進里程碑的票被標成「已排進里程碑」
- ③「好幾格不對時一次列齊」紅 ⇒ 改一格撞一次——閘在懲罰人
- ③「名字是版本號/沒期限/9999/過去」任一紅 ⇒ 開工規約第 5、6 條破了
- ③「載體不在 InkStoneCo」紅 ⇒ 開工規約第 7 條破了(在子 repo 建里程碑)
- ③「前置已是別的里程碑載體的前置」/「載體是別一輪的前置」紅 ⇒ 一張票同時排進兩輪
- ③「不開任何新票」紅 ⇒ 開工規約第 2 條破了
- ④「里程碑那一組排在票池之前」紅 ⇒ 組了里程碑,工人還是照開票時間撿散票
- ④「沒帶 --pool → 不看、不回待分診」紅 ⇒ **誤攔**:本機總管收工時被佇列閘叫去分診
- ④「載體票本身不當成可做的票」紅 ⇒ 工人會去「做」一張容器票
📌 **真實 Gitea 實跑**2026-09-18isep-hand 用本分支代跑一趟,署名 `[isep-hand]`):
- 分診前 `triage --list`:待分診 72 張 → 分診 4 張後 67 張(總數同時受別條線影響;我動的 4 張讀回皆對)
- `Arcrun#188` → 與 `Arcrun#143` 重複:`close/duplicate`、已關,#143 上有指回來的留言
- `Arcrun#131``s/triage`(與 #143 同一件事,兩張留哪張交總管)
- `ISEP#47``arcrun-rag#199``s/backlog`,各有一則說明
- 組里程碑:`ticket where` 撈不到能載這一輪的 InkStoneCo User Story ⇒ 補一張載體 `InkStoneCo#136`
`compose` 建出 InkStoneCo milestone 68「金鑰不再出現在任何畫面與 log 裡」(期限 09-25):
載體掛上、`ISEP#47``arcrun-rag#199` 成為相依並 `s/backlog → s/todo`、三張各一則說明
- `pick --pool --all`(主線 #65):第一組就是這個里程碑的兩張前置,之後票池 101 張、待分診 67 張
- 真的擋:`compose --carrier InkStoneCo#134 ISEP#47 Arcrun#143` → 離開碼 2、一筆都沒寫,三個理由一次列出
#134 已是主線載體 #55 的前置/#47 已排進 milestone 68#143 還沒分診)
### A19 — 下游做完時頂層跟著關:49 條
```
bash scripts/test-ticket-handoff-writeback.sh
+23
View File
@@ -206,6 +206,29 @@ $ curl … https://git.uncle6.me/api/v1/version → 200
其餘(讀票、認領、留言、handback、寫 code、跑測試、開 PR、對 leo21c 唯讀查詢、發 Telegram、**種 secret/直推成品/POST 到 stage 實例**——走 `scripts/stage` 與 Arcrun 的 `stage-deploy-artifacts.py`)雲端全做。
📌 這份清單的家是 `inkstone/InkStoneCo` 的 `cloud-worker.md`(票上驗收第 4 條),ISEP 只放草稿;併進去由總管做。
## 雲端工人不只撿票,還要分診、組里程碑(inkstone/ISEP#159,給 `cloud-worker.md` 的草稿)
leo 09-18:「它看到票時要能夠組成 milestone 提出版本,所以不只是看票,還要組票。」
ISEP 這一半是 `scripts/ticket` 的 `triage``compose` 兩個動詞,與 `pick --pool` 多的兩層(見 `docs/TESTING.md` A43)。
`cloud-worker.md` 現在寫著「🚫 不開里程碑、不改里程碑⋯⋯」——那一條要換成下面這段(**併進 InkStoneCo 由總管做**):
```
1. 分診:`ticket triage --list`(找重複用 `--all`)。每張沒 s/* 的票讀過之後擇一:
ticket triage <票> --to s/backlog --why "…" 決定要做
ticket triage <票> --to s/triage --why "…" 要總管/leo 判斷(方向、品味、要不要做)
ticket triage <票> --to s/pending --why "…" 在等外部
ticket triage <票> --dup-of <留下的那張> --why "…" 重複(關新的、留舊的)
都帶 `--name <ISEP 工人名> --sign cloud-worker`。掛 Human/指派 Leo 的票工具會擋,不必自己判。
2. 組里程碑:已分診、彼此相關、做完能出一個可測版本的幾張 ⇒
ticket compose --title "<這一輪要讓什麼變成真的>" --goal "…" --due <160 天內>
--carrier inkstone/InkStoneCo#N <前置票…> --name … --sign cloud-worker
載體=既有的 InkStoneCo User Story`ticket where` 撈不到能載這一輪的 ⇒ 先 `ticket new InkStoneCo` 補一張 US 當載體
(開工規約第 2 條:撈不到才是真缺口)。一張票同時只排一輪,工具會擋。
3. 取票:`ticket pick`ISEP_DRAIN=1 ⇒ 自帶 --pool)。組好的里程碑的前置排在散票之前;
可做的都抓盡時它回一張待分診的,下一步就是它印的那行 triage。
收工條件不變:`ticket pick` 回離開碼 1。
```
## 這張票沒動、也不會動的東西
- 沒有動 `youlinhsieh/inkstoneco`GitHub 薄殼 repo)——這個新機制**完全不需要
+9 -1
View File
@@ -11,6 +11,14 @@
其中 **3 支檔案存在但沒被掛上**(2 支是待人填的空範本、1 支是刻意留著沒開的止血帶,見下面「未生效」表)。
下面按「你會在什麼時候撞到它」分組,一支一行。
> 📌 **`inkstone/ISEP#159`2026-09-18,待總管定版)+0 支、+0 條、腳本 65→66**:沒加閘。`scripts/ticket` 多兩個動詞
> `triage`(沒 s/* 的票給狀態+留說明,或當重複關掉並指回去)與 `compose`(把已分診的票組成 InkStoneCo 里程碑:載體+前置,
> 先全部驗過才寫);`pick --pool` 多兩層(還沒到期的 InkStoneCo 里程碑的前置、最後是待分診的票),每一列帶 `next`。
> `queue-drain-guard.sh` 改判準不加閘:照 pick 那一列的 `next` 印下一步(待分診的票下一步是 triage,不是 claim)。
> `scripts/` 1`test-ticket-triage.sh`。
> **62 支、88 條、66 支腳本是在這棵樹上當場數出來的**`ls hooks/*.sh | wc -l`62、
> `grep -c '"command":' hooks/hooks.json`88、`ls -p scripts | grep -v / | wc -l`66)。
> 📌 **`inkstone/ISEP#153`2026-09-13,待總管定版)+0 支、+1 條**`baton-handback-guard.sh` 多掛一條 `Stop`。
> 背景派工時 `PostToolUse:Agent` 在工人**剛出發**就觸發,舊版當場念「收工了但棒子沒交回來」(09-13 對 ISEP#150、arcrun-rag#14 各一次,工人其實還要跑 17 分鐘)。
> 現在送出那一刻看到 launch ack 就不查;工人交件(主對話收到 `<task-notification>` completed)時由 Stop 那半用 `tool-use-id` 對回原派工單再查,同一條線只點名一次。
@@ -284,7 +292,7 @@
| `delivery-police.sh` | AI 宣稱「這件事做完了」,卻看不到任何實測證據(畫面截圖、指令輸出、HTTP 狀態碼…)就擋下。 | 🛑 擋 |
| `wiki-first-police.sh` | AI 做完事卻沒有把結論寫回 wiki 就想收工,就擋下——下次(或別的 AI)查 wiki 會查不到這次做過什麼。 | 🛑 擋 |
| `unpushed-police.sh` | AI 改好的東西還留在本機、沒有真的推送出去給別人用,卻想收工,就擋下——「改對了但沒送到」跟沒改是一樣的。 | 🛑 擋 |
| `queue-drain-guard.sh` | **在接票的 session(跑過 `ticket pickclaimhandback`,或環境設了 `ISEP_DRAIN=1`),池子裡還有現在就能抓的票,就不准收工**——它自己跑一次 `ticket pick`,有票就把票號和認領指令交回去。「池子」多大看環境:設了 `ISEP_DRAIN=1`(雲端工人)時 pick 會看到整個 open 票池的 `s/todo``s/backlog`;本機沒設時只看主線與逾期里程碑,所以總管跑過 `handback` 也不會被叫去抓票池(`inkstone/ISEP#130`)。這是 ISEP 唯一一支看「佇列」而不是看「這回合寫了什麼」的收工閘(`inkstone/ISEP#33`:雲端三趟 run 都是做完一件、還有票就停)。做不了的票要把理由寫回票、改欄位,pick 就不再回它。跟 leo 聊天的 session 不會被咬;同一張連續指名 3 次、讀不到佇列 3 次、或一個 session 擋滿 40 次就放行並留痕,不會鎖死。 | 🛑 擋(有上限) |
| `queue-drain-guard.sh` | **在接票的 session(跑過 `ticket pickclaimhandback`,或環境設了 `ISEP_DRAIN=1`),池子裡還有現在就能抓的票,就不准收工**——它自己跑一次 `ticket pick`,有票就把票號和認領指令交回去。「池子」多大看環境:設了 `ISEP_DRAIN=1`(雲端工人)時 pick 會看到整個 open 票池的 `s/todo``s/backlog`;本機沒設時只看主線與逾期里程碑,所以總管跑過 `handback` 也不會被叫去抓票池(`inkstone/ISEP#130`)。雲端環境下可做的都抓盡、還有沒 s/* 的票時,pick 回一張待分診的,本閘照那一列印 `ticket triage …` 而不是 claim`inkstone/ISEP#159`)。這是 ISEP 唯一一支看「佇列」而不是看「這回合寫了什麼」的收工閘(`inkstone/ISEP#33`:雲端三趟 run 都是做完一件、還有票就停)。做不了的票要把理由寫回票、改欄位,pick 就不再回它。跟 leo 聊天的 session 不會被咬;同一張連續指名 3 次、讀不到佇列 3 次、或一個 session 擋滿 40 次就放行並留痕,不會鎖死。 | 🛑 擋(有上限) |
| `baton-handback-guard.sh` | **背景派出去的工人交件時**(主對話收到完工通知),檢查那張工單票有沒有把棒子交回來(指派/標籤/下一步三格),缺就擋一次要 AI 補。工人還在跑的時候一聲都不出(`inkstone/ISEP#153`)。同一條線只點名一次;補完三格就不再出現。前景派工的那一半在下面 H 組。 | 🛑 擋(每條線至多一次) |
> 🔴 **`claim-verify-police.sh` 已於 `inkstone/ISEP#60` 移除**(連同下面原本的 G 組 `subagent-claim-worksheet.sh`)。