Skip to content

feat: 補上 authoritative_source 第二層的 producer,並釘死 exists 判準 (#290) - #291

Merged
kiki830621 merged 4 commits into
mainfrom
idd/290-authoritative-source-priority2-producer
Aug 5, 2026
Merged

feat: 補上 authoritative_source 第二層的 producer,並釘死 exists 判準 (#290)#291
kiki830621 merged 4 commits into
mainfrom
idd/290-authoritative-source-priority2-producer

Conversation

@kiki830621

Copy link
Copy Markdown
Member

Refs #290

Summary

authoritative_source 的三層優先序被 consumer 讀,但第二層沒有任何 producer——idd-update 的 Current Status 模板只 emit Key Decisions / Scope Changes / Blocking / Commits,全 repo 搜 ### Tasks 只剩讀取端那一行。

於是 chain 實務上退化成「只有第一層」,而它只有 idd-implement 產生 → 任何繞過 idd-implement 的路徑都沒有 authoritative source,fallback 去掃 diagnosis 當初寫的 pre-implementation checkbox——而那些在 SDD 流程裡沒有任何一步會勾

下游實證:一個走完 19/19 tasks、跨模型驗證 0 blocking、PR 已開的 issue,被 7 個 - [ ] 擋在 close 門外,唯一解法是人工 PATCH diagnosis comment。

Changes

內容
producer idd-update--tasks-file <path>,據以 emit 第二層
路徑來源 由呼叫端查詢外部工具取得,不由任何一方從「名稱+目錄慣例」組出。新增的 skills/rules/ 敘述中外部目錄名 0 命中
圍籬 路徑必須落在當前 git toplevel 內,三道檢查(fail-closed / 一般檔案 / 整路徑 realpath)
exists 升為 canonical:heading 在 ≥1 個可解析項目,三個 consumer 一致
角色 「4 個 gate site」→ 按角色的矩陣(idd-update 同時是 producer 與 consumer)
不變式 優先序每層必須具名 producer 或明示無自動 producer——不得留白(留白正是本 bug 的成因)

為什麼圍籬是必要而非防禦性過度

實測:某工作目錄下查詢,回傳路徑指向同一 repo 的另一個 git worktree(registry 不是 cwd-scoped)。若原樣採用,gate 會讀另一工作樹的完成狀態——那份若全 [x]一個沒做完的 issue 會通過 close gate

修一個假陰性卻引入假陽性,後者嚴重得多:前者會被人擋下並抱怨,後者沒人會發現。

Verification

跨模型盲驗(Codex gpt-5.6-sol / xhigh)一輪,六項成立、兩項嚴重、全部修完

  1. 修法在自己的 pipeline 裡活不過一步——managed zone 是整段替換,「未給 flag = 不輸出」使 Phase 4 的 Auto-Update 會抹掉 Phase 3b.5 剛寫入的 ### Tasks。改為未給 flag 時逐字保留我測了「寫得進去」,沒測「留得住」。
  2. 圍籬 fail-open——TOP="" 時 pattern 變 /*,任何絕對路徑都通過。
  3. 最後一段的 symlink 可繞過(我的探測只測了 symlink 目錄,漏了 symlink 檔案)。
  4. Step 4 模板無條件列出 ### Tasks + 可解析 placeholder → 會製造假的 authoritative source。
  5. 「1 producer + 3 consumer」與底下列兩個 producer 的表自相矛盾
  6. 不變式「每層都必須指名 producer」與 priority 3「無」自相矛盾

24 個斷言(12 機制 + 12 drift-lock),全套件 43 suite / 0 失敗idd-implement/SKILL.md diff 0 行

誠實邊界:drift-lock 只證明文字在檔案裡,不證明行為;fixture 驗的是測試檔內重實作的邏輯。這是本 repo markdown-skill 測試的固有形狀(doc-sync-sweep 同構),非本 change 引入。exists 變更也不是零 backward-compat 影響——詳見 issue 的 Verify comment。

Checklist

  • Diagnose ✓(Spectra tier)
  • Clarify ✓(3 rows,全數 resolved/dismissed)
  • Spectra:discuss → propose → apply,14/14 tasks
  • Verify ✓ — 0 blocking
  • Verify-gated:ready to merge → merge 後請跑 /idd-close

Related

  • 由 PsychQuant/Akashic-Library#87 移轉而來(消費端觀察到的上游缺口)
  • 下游實例:PsychQuant/Akashic-Library#67

🤖 Generated by /idd-all. 不要加 GitHub close trailer——IDD 紀律要求 merge 後手動跑 /idd-close

`.gitignore` 已明寫本 repo 的政策:

    # Sibling .claude/.idd/attachments/ deliberately STAYS tracked
    # (its manifest is committed), so ignore state/ specifically, not the parent.

但 29 個已追蹤、21 個未追蹤——同一種檔案、同一個用途,那是歷次 diagnose
產生後沒人 commit,不是另一種選擇。本 commit 把已宣告的政策執行完。

內容已逐項確認:21 個全是 `_manifest.json` 且 `"files": []`(「查過 issue N,
它沒有附件」的記帳),整個 attachments 樹裡**零個**非 manifest 檔案。無任何
第三方內容,總量 200K 純文字。

副作用:clean-tree gate 不再被這 21 個擋住。那對本 repo 特別有價值——它就是
IDD 自己的 repo,idd-* 在這裡跑得最頻繁,代價原本會一直付下去。

(附帶觀察,不在本 commit 處理:`process-attachments.sh` 對每個 diagnose 過的
issue 都寫 manifest 即使零附件,而 plugin 沒說該不該追蹤。Akashic-Library 選了
忽略、本 repo 選了追蹤,兩種都站得住——真正的缺口是沒有指引。)
兩者都是 per-machine ephemera(前者 0-byte 同步標記、後者 hook cache),
與 repo 已忽略的 .claude/.idd/tree-lock 與 .claude/.idd/state/ 同類:
可重新產生、不是 durable artifact。

與前一個 commit 一起讓工作樹回到乾淨,clean-tree gate 不再被無關檔案擋住。
`authoritative_source` 的三層優先序被三個 consumer 讀,但**第二層沒有任何
producer**——`idd-update` 的 Current Status 模板只 emit Key Decisions /
Scope Changes / Blocking / Commits,全 repo 搜 `### Tasks` 只剩讀取端那一行。

於是 chain 實務上退化成「只有第一層」,而它只有 `idd-implement` 產生 →
**任何繞過 idd-implement 的路徑都沒有 authoritative source**,fallback 去掃
diagnosis 當初寫的 pre-implementation checkbox,而那些在 SDD 流程裡沒有任何
一步會勾。下游實證:一個走完 19/19 tasks、跨模型驗證 0 blocking、PR 已開的
issue 被 7 個 `- [ ]` 擋在門外。

四項改動:

1. **`idd-update` 收 `--tasks-file <path>`**,據以 emit `### Tasks`。路徑由
   呼叫端**查詢**外部工具取得,不由任何一方從「名稱+目錄慣例」組出——組路徑
   只是把佈局知識換個位置,對方改佈局會靜默失效。樹內零個外部目錄名(已驗證)。

2. **toplevel 圍籬(實測逼出來的,非防禦性過度)**:外部工具的 registry 不一定
   cwd-scoped,實測回傳過**同一 repo 另一個 git worktree** 的路徑。若原樣採用,
   gate 會讀另一工作樹的完成狀態——那份若全 `[x]`,一個沒做完的 issue 就會通過
   close gate。修一個假陰性卻引入假陽性,後者嚴重得多:前者會被人擋下並抱怨,
   後者沒人會發現。測試用**真的**第二個 worktree 重現,不是換字串的假 fixture。

3. **`exists` 判準升為 canonical**:heading 在**且**至少一個可解析項目。原本只有
   idd-close 寫出 `len > 0` 且只對第一層,另兩個 consumer 無條件。三者現已一致,
   且 consumer 不得自訂 emptiness 規則。

4. **角色描述修正**:「4 個 gate site」→「1 producer + 3 consumer」。
   `idd-implement` 是 producer 不執行 resolution,原本被誤列為 gate。
   另加不變式:**優先序的每一層都必須指名 producer**(無 producer 的層會讓
   優先序靜默塌縮);並註明該不變式無法被測試強制,靠 review 維持。

第一層行為逐字未變(`idd-implement/SKILL.md` diff 為 0 行)。

測試:新增 19 個斷言(12 機制 + 7 drift-lock),全套件 43 個 suite 0 失敗。

過程中自己踩到一次「測試抓不到東西」:`assert_grep "name" -- "--tasks-file"` 的
`--` 讓 needle 變成 `--`,兩條 drift-lock 假通過。assert_grep 是 shell function
不是有 getopt 的指令。只有真的讀輸出才看得見——這正是本 change 要修的那類缺陷。
Codex(gpt-5.6-sol / xhigh)六項成立,兩項嚴重:

**1. 修法在自己的 pipeline 裡活不過一步。** `idd-update` 的 managed zone 是
「`## Current Status` 到結尾整段替換」。原本寫「未給 flag = 不輸出」,於是:

    Phase 3b.5  idd-update --tasks-file   → 寫入 ### Tasks           ✓
    Phase 4     idd-verify 的 Auto-Update → idd-update(無 flag)→ 抹掉  ✗

authoritative source 在下一個 phase 就被自己刪掉,chain 又塌回去。我測了
「寫得進去」,沒測「留得住」。改為:未給 flag 時**逐字保留**既有 `### Tasks`;
路徑壞掉時**視同未給 flag**——拒絕一個壞路徑不得順帶刪掉一份好的既有 checklist。

**2. 圍籬 fail-open。** `TOP=$(git ... rev-parse --show-toplevel)` 沒檢查失敗,
`TOP=""` 時 pattern 變成 `/*`,**任何絕對路徑都通過**——圍籬看起來在,實際
形同虛設。改為三道各有失敗模式的檢查:toplevel 解析失敗 fail-closed、必須是
可讀的一般檔案、**整條路徑**用 realpath 解析(只解析 dirname 會被
`ln -s /別處/tasks.md "$TOP/link.md"` 繞過——ABS 看起來在樹內、讀取落在樹外;
我先前的探測只測了 symlink 目錄,漏了 symlink 檔案)。

其餘四項:

3. **自相矛盾**:標題寫「1 producer + 3 consumer」,底下的表卻列兩個 producer,
   且 `idd-update` 同時是兩者。改為按角色的矩陣,明說角色非互斥。
4. **不變式自相矛盾**:「每一層都必須指名 producer」與 priority 3「無(僅人手寫)」
   直接衝突。改為「具名 **或** 明示無自動 producer」——要求的是不留白,不是必須有。
5. **Step 4 模板無條件列出 `### Tasks` 與可解析的 placeholder checkbox**,與
   「未給 flag 不 emit」衝突;照模板輸出會製造**假的 authoritative source**。改為
   條件註記。
6. query 未在 `$CWD` 下執行(registry 選擇已知與 cwd 有關)、路徑未加引號
   (含空白會被拆參數)。兩者已修。

測試:兩條 drift-lock 鎖的是被推翻的錯誤措辭,已更新;另補 5 條鎖住本輪的兩個
嚴重修正(保留語意、fail-closed、整路徑解析、原始值訊息)。過程中又自己寫錯
兩條 needle——一條被 markdown 粗體切斷,一條用了 `\|` 但 assert_grep 是字面比對。

24 個斷言全綠;全套件 43 個 suite 0 失敗。
@kiki830621
kiki830621 merged commit dc2601f into main Aug 5, 2026
1 check passed
@kiki830621
kiki830621 deleted the idd/290-authoritative-source-priority2-producer branch August 5, 2026 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant