Files
system-dev-template/docs/3-specs/jdd-dual-profile/design.md
T
Leo 6a49f25aef feat(W2 Phase 0-1): 雙 profile 地基+JDD 兩軸身分+兩支防炸閘
SDD: docs/3-specs/jdd-dual-profile(draft → active,leo 2026-08-05 回「開工」)
範圍:總管指定的「防炸兩件 → Phase 0 → Phase 1」,Phase 2 以後未開工。

■ 防炸(排在所有 task 之前,因為它們炸的是既有的東西)
- check-no-instance-names.sh + instance-names.txt:框架範本不得混入實例專名
  基線實測 22 行命中(非先前誤報的 20)→ 9 行無損泛化改寫、13 行檔級豁免記帳待 W3 搬走
  拒絕假性清理(把專名換成模糊詞=資訊消失、分層問題還在)
- check-legacy-paths.sh:已發佈腳本引用的 35 條遠端路徑只增不移
  舊實例跑的是舊腳本、路徑寫死;搬檔=整排 404 且不會有下一次更新來修它(1.16.0 前科)

■ Phase 0 地基
- template/manifest/{common,repo,orchestrator}.tsv:安裝清單單一真相源
  修好 install/update 兩份硬編清單的既有漂移——install 從不裝 wiki-first-search /
  subagent-wiki-guard / publish-lag-check / decisions-summary,但 update 會
  ⇒ 乾淨安裝反而拿不到 1.16/1.17/1.18 的招牌功能
- .claude/hooks/lib/role-lib.sh:scope×role 兩軸機械判定,零自陳
  身分矩陣六組實測全通過,含「成員 repo × orchestrator」不存在的格子擋下
- .sdt-framework-dev:框架開發標記(官方沒有 --framework-dev 這個參數,實查非記憶)

■ Phase 1 雙 profile
- profiles/{repo,orchestrator}/CLAUDE.md 兩部憲法
- install.sh:--profile + 自動偵測+寫檔前確認、manifest 驅動、
  CLAUDE.md 三段組裝(框架區/本地補充區界標+sha256)、.profile、.template-manifest、
  settings.json 寫入 env.AGENT_ROLE 預設
- update.sh:漂移偵測(不覆蓋手改檔、另存 .new、白話清單)+ 基準快照隨更新前進
- template/CLAUDE.md 原路徑凍結留底(相容)

■ 順手修掉兩個舊 bug(都在本次要動的函式裡)
- add_if_missing 少了 mkdir -p ⇒ 新目錄的檔 curl 失敗但 VERSION 照升(2026-07 記「待回報」至今未修)
- 下載健全性只用 [ -s ]=非空即接受 ⇒ 404 頁面會無聲覆寫好檔
  (SKILL.md 260→1 行的機制;同一支腳本的版本號那條路早就防了,檔案這條沒防)

■ 實測(非推論)
- G4 憲法分流:兩個乾淨環境各裝一次,orchestrator 版含 SDD 三件式關鍵字 0 次、
  repo 版含上游指針 8 次;界標 4/4;sha 宣告與實算相符
- G7 CI 擋實例名:注入違規行 → fail 並指出 sdd-check.md:77,exit 1;還原後 exit 0
- 漂移偵測:手改兩支 hook → 正確報 2 支、手改內容保住、產 .new;
  解掉後歸零;連跑三輪冪等

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-05 23:56:48 +08:00

29 KiB
Raw Blame History

status, superseded_by
status superseded_by
active

jdd-dual-profile — Design

建立:2026-08-05 | 最後更新:2026-08-05 負責人:system-dev-template CC 來源:InkStoneCo 總管交辦 W2 狀態:active2026-08-05 leo 回「開工」升活性)

升活性前實查:全 repo 帶 frontmatter 的只有 TEMPLATE-sdddraft,範本不算數) ⇒ active 數 = 0無衝突、無未完成任務需搬移D35 ④ a 步驟空集合)。

施工順序由總管指定:發現①、發現⑦ 的防炸工程 → Phase 0 → Phase 1 → 停下驗 Gherkin。 Phase 2 以後未經確認不得開工。


一句話說明

把 system-dev-template 從「單一 repo 級框架」改造成 雙 profile 框架(總管級/repo 級) 並在其上裝入 JDD PM 軌root.mdjourneys.md/站號 sprint/角色權限封路), 讓「憲法分流」「角色權限」「實例不改機制」三件事全部由檔案結構與 hook 機械決定, 沒有任何一格靠 agent 自我判斷。


0. 現況實查(動手前先搞清楚現在長什麼樣)

本節是設計的事實基礎,也是「與規格假設不符」的清單來源。每條都是本次實測,不是回憶。

0.1 SDD 現況

  • docs/3-specs/ 下 5 個資料夾,帶 frontmatter 的只有 TEMPLATE-sddstatus: draftcross-repo-signing / install-layout / wiki-architecture / tasks-project-projection 四份都只在正文寫「狀態:已採納/已結案」,沒有 frontmatter ⇒ 機器查得到的 active 數 = 0
  • 本 repo 的 SDD 住 docs/3-specs/,但它發給別人的 sdd-guard.shsdd-active-check.sh 預設路徑是 system-dev/docs/3-specs框架 repo 的 D35 閘從來沒對自己開過火
  • 現有 SDD 的實際慣例是 design.md tasks.md 兩件式TEMPLATE-sdd 也只有這兩支), requirements.md 在本 repo 沒有先例。本案依交辦要求補齊三件式。

0.2 安裝機制現況

事實 影響本設計的地方
install.sh 逐檔 download_if_missing "<dest>" "$REPO_URL/<path>"沒有 manifest,檔案清單硬編在腳本裡 加 profile ⇒ 清單要分四份(commonrepoorchestrator/模組交叉),硬編必然漂移 → 必須先做 manifest
update.sh 另有一份幾乎重複的清單(update_filekeep_fileadd_if_missingkeep_with_template 四類) 同上;manifest 的「類別」欄正好就是這四類
REPO_URL = $TEMPLATE_SOURCE/template,所有安裝產物的遠端路徑都掛在 template/ 底下 分離 §三把 common/profiles/ 畫在 repo 根 ⇒ 會變成第二個 base URL;本設計改掛 template/ 底下(見決策 D2
update.sh自我更新在腳本尾端(先跑完所有下載才更新自己) 若這一版搬動既有檔案路徑,舊實例這一輪會整排 404;1.16.0 已被同型問題咬過(來源改動=自動更新死掉)⇒ 既有檔一律不搬(決策 D3
CLAUDE.md 是整份下載 emit_raw_source_block append沒有任何區段界標 「本地補充區」目前不存在邊界,漂移偵測無從談起 ⇒ 必須先立界標(設計 §2)
build_hooks_json() 依模組(wiki/sdd)條件組裝 settings.json profile 只是加第三個維度,沿用同一支函式,不另造

0.3 hook 現況(template 內共 7 支)

pre-write-guard.sh(空殼,FORBIDDEN_PATTERNS 為空=不攔任何東西)、publish-lag-check.shsdd-guard.shsession-start-recall.shsubagent-wiki-guard.shwiki-first-search.shwiki-secret-scan.sh

  • AGENT_ROLE 在整個 repo 與 InkStoneCo 實例中 0 次出現 ⇒ 角色軸完全從零開始。
  • guard-cross-project.sh 不在 template 裡——它只存在於 InkStoneCo 實例的 .claude/hooks/。 分離 §六.4 標它 [修改],實際動作是「從實例上收進框架」,不是就地改(決策 D6)。
  • 同理,delivery-police.shself-drive-police.shunpushed-police.shhistory-first-guard.sh11 支都是實例自行發明的,框架不知道它們存在。

0.4 漂移基線(機械閘 #3 的今日實測值)

比對 InkStoneCo 實例的 .claude/hooks/ 與本 repo template/.claude/hooks/

狀態 數量
與框架一致 2 session-start-recall.shwiki-secret-scan.sh
已被手改(漂移) 4 pre-write-guard.shsdd-guard.shsubagent-wiki-guard.shwiki-first-search.sh
實例自行發明 11 見 §0.3

今天沒有任何機制知道這 4 支已經漂移。這就是分離 §八 預測②(「漂移數歸零」)的基線值 = 4。

0.5 實例專名基線(機械閘 #2 的今日實測值)

template/ 底下命中 arcrun|mira|leo21c|inkstone|uncle6|polaris8 檔 20 行。分三類:

內容 處置
(a) 註解/舉例(6 行) sdd-guard.sh「誠實限制(抄 arcrun)」、publish-lag-check.sh 的 jsDelivr 例、logseq-markers.md 的 TODO 例句、issue-handle.md 的 repo 名清單 本波清理(改寫成通用敘述)
(b) 政策內容混進框架(3 行) subagent-wiki-guard.sh「有 Arcrun RAG MCP 就用它」、wiki-extract.md「下游 Arcrun ingest」 標逐行豁免,W3 隨 policy pack 搬走
(c) 整支是 L2 產物(13 行) system-dev/workflows/tasks-project-sync.{yaml,local.sh}(本體就是 arcrun workflow 整組標豁免,W3 移入 policy pack

⇒ 閘 #2 不能一上線就全紅。必須配「逐行豁免標記 + 基線報表」,否則為了讓 CI 綠會出現 假性清理(把 arcrun 換成「某工作流引擎」=資訊消失但問題還在)。


範圍

包含(In Scope

  • template 的雙 profile 化(宣告式,非搬檔):manifest、--profile、profile 專屬產物
  • CLAUDE.md 生成、框架區/本地補充區界標、update 漂移偵測
  • JDD 文件範本:root.mdjourneys.md(含站點索引表)、站號 sprint 範本、術語表
  • 兩軸身分(scope × role)的機械判定函式庫
  • JDD §六 8 條封路規則 + 分離 §六 4 條防糾纏閘的實作
  • policy plugin 的插槽:載入順序文件化 profile 憲法 must-read 注入點
  • CHANGELOG VERSION bump 乾淨環境雙 profile 安裝實測

不包含(Out of Scope

  • arcrun-policy plugin 本體W3):plugin.json、marketplace 發行、白名單 hook 內容、 primerdispatch-checklist 搬遷、.mcp.json
  • 實例側落地W4):InkStoneCo 的 root.mdjourneys.md 實填、routine 取任務源改站號、 實例 11 支自製 hook 的退役與上收
  • 雲端側(W5):LLM Wiki 總編輯管線、儀表 job、arch_baselinearch_iteration
  • 記憶階梯改序(KBDB-first:藍圖 §7,屬另一波
  • 既有 SDD 的 frontmatter 補齊(§0.1 撿到的斷層):本波只回報,不順手改—— 那會動到四份別的 SDD 的生命週期狀態,屬規格層,另走 pending-changes

1. 架構總覽

system-dev-template/                     ← 框架 repo(本 repo
├─ scripts/install.sh   --profile=repo|orchestrator   ← 改造:讀 manifest
├─ scripts/update.sh                                   ← 改造:讀 manifest  漂移偵測
├─ scripts/check-no-instance-names.sh                  ← 新增:機械閘 #2CI
├─ scripts/instance-names.txt                          ← 新增:黑名單設定檔
└─ template/                             ← 所有安裝產物的遠端根($REPO_URL
   ├─ manifest/
   │   ├─ common.tsv                     ← 新增:兩 profile 共裝
   │   ├─ repo.tsv                       ← 新增:repo profile 專屬
   │   └─ orchestrator.tsv               ← 新增:orchestrator profile 專屬
   ├─ .claude/hooks/…                    ← 既有 7 支【原地不動】= common 的實體
   │   ├─ lib/role-lib.sh                ← 新增:兩軸判定函式庫(被 source)
   │   ├─ role-guard.sh                  ← 新增:J1+J2+J3
   │   ├─ jdd-format-guard.sh            ← 新增:J4+J5+J8
   │   ├─ station-done-guard.sh          ← 新增:J6
   │   ├─ regression-scope.sh            ← 新增:J7
   │   └─ install-artifact-guard.sh      ← 新增:S1
   ├─ profiles/
   │   ├─ repo/
   │   │   ├─ CLAUDE.md                  ← repo 憲法範本(=現行 template/CLAUDE.md 演進)
   │   │   └─ (SDD 三件式、repo wiki 規範:沿用 common 既有產物,manifest 宣告即可)
   │   └─ orchestrator/
   │       ├─ CLAUDE.md                  ← 總管憲法範本(藍圖 v3 指針+術語表)
   │       ├─ docs/root.md.template
   │       ├─ docs/journeys.md.template
   │       ├─ docs/sprint.md.template     ← 站號 sprint
   │       ├─ docs/triage-map.md.template ← 格式範本,內容留實例
   │       ├─ docs/plugin-load-order.md   ← 載入順序文件(W3 插槽)
   │       └─ hooks/orchestrator-scope-guard.sh  ← 新增:S4(上收 guard-cross-project
   └─ system-dev/…                       ← 既有【原地不動】

實例安裝後:
  CLAUDE.md                    ← 框架區(profile 範本)+ 本地補充區(界標分隔)
  system-dev/.profile          ← 單行:repo | orchestratorscope 軸唯一來源)
  system-dev/.template-manifest ← 每個產物的 path / version / sha256(漂移偵測依據)

2. 設計答案①:雙 profile 的 CLAUDE.md 怎麼生成、本地補充區邊界、漂移怎麼偵測

2.1 生成:組裝而非下載

現行是「整份下載 template/CLAUDE.md append raw source 區塊」。改為三段組裝:

<!-- sdt:framework begin profile=<repo|orchestrator> version=1.19.0 sha256=<前12碼> -->
profiles/<profile>/CLAUDE.md 的完整內容,一字不改)
<!-- sdt:framework end -->

<!-- sdt:local begin — 這一區是你的,update 永遠不會動它 -->
install 產生的 raw source 宣告;之後由使用者/CC 自由追加)
<!-- sdt:local end -->
  • 界標用 HTML 註解:md 渲染看不見、CC 讀得到、grep -n 定位得到。
  • sha256 記的是框架區內容本身(不含界標行),是漂移偵測的比對基準。
  • 兩區順序固定:框架區在上(agent 先讀到憲法),本地區在下。

2.2 兩份 profile 憲法的內容分界(G4 的判準)

profiles/repo/CLAUDE.md profiles/orchestrator/CLAUDE.md
效忠文件 requirements.mdSDD 技術軌) root.md journeys.mdPM 軌)
含 SDD 三件式細節 含(現行內容) 不含(G4 明文:總管版無 SDD 三件式細節)
上游指針 一行(指向總管 repo 的憲法位置,不寫死專案名,由 install 問一次或留空) 無(它自己就是上游)
JDD 術語表 只放「站號怎麼標在 task 上」一段 全表(Journey/Station/通關/點亮/對帳/完備)
sprint 機制 「認領 loop」段(engineer 的動作) 全流程(指定站 → 認領 → 新增必掛站 → 收尾判準)
角色 engineer(可寫 codetasksrequirementsdesign;禁改考卷) orchestrator(可寫 rootjourneyssprint;禁寫 code、禁改 tasks

G4 的機械驗法:grep -c "SDD 三件式\|requirements.md" CLAUDE.md 在 orchestrator 實例上 = 0grep -c "上游" CLAUDE.md 在 repo 實例上 ≥ 1。

2.3 邊界規則(寫進兩份憲法,並由 hook 兌現)

  1. 框架區唯讀:任何內容變更走框架 repo 提案 → bump → update 拉下來。
  2. 本地補充區隨便寫:update 永不讀、永不寫、永不比對。
  3. 實例要覆寫框架區的某條規則 → 不准就地改,在本地補充區寫「例外聲明 + 理由 + 日期」。 這樣 diff 永遠乾淨,而例外仍然留痕可審。

2.4 漂移偵測:manifest sha256

system-dev/.template-manifestinstall 產生,update 維護),TSV 一行一產物:

<dest 路徑>	<class>	<安裝時 version>	<安裝時 sha256>

class 沿用 update.sh 既有四類語意:overwrite(模板/邏輯檔)/keep(使用者資料檔)/ add-if-missing(新資料檔)/keep-with-template(使用者會手填的客製檔)。

update 對每個 overwrite 類產物跑三態判定:

實檔 sha vs manifest sha 遠端 sha vs manifest sha 判定 動作
相同 相同 沒變 no-op(不下載、不列報表)← 兌現 EARS-1.2.2
相同 不同 乾淨、有新版 覆蓋,列「已更新」
不同 任意 漂移 不覆蓋;新版另存 <檔>.new;列入 ⚠️ 漂移清單

漂移清單的輸出格式(白話,leo 讀得懂):

⚠️  下列 3 個檔被手改過,這一版沒有覆蓋它們:
   .claude/hooks/sdd-guard.sh          → 新版已放在 sdd-guard.sh.new,請 diff
       你可以:① 把你的改動寫成框架提案(推薦,一次修全家)
               ② 放棄本地改動:mv sdd-guard.sh.new sdd-guard.sh

舊實例遷移(沒有 manifest 的 1.18.xupdate 偵測到無 manifest → 進「一次性補植」: 以本版遠端內容為基準建 manifest,凡當下與遠端不一致者一律先標成漂移(保守:寧可多報不漏報), 並把現有 CLAUDE.md 整份包進 sdt:local 區、框架區從 profile 重鋪, 輸出「你的舊 CLAUDE.md 已完整保留在本地補充區,請自行搬移重複段落」。整段冪等,重跑不再動。


3. 設計答案②:AGENT_ROLE 兩軸身分在 hook 裡怎麼機械判定

3.1 兩個來源,零自陳

來源 誰寫 讀不到時
scope system-dev/.profile(單行 repoorchestrator install.sh--profile 或偵測+人確認一次) 視為 repo(多數實例;且此時 orchestrator 專屬閘不觸發,仍有 common 閘在)
role 環境變數 AGENT_ROLEorchestratorengineer ① install 依 profile 寫進 .claude/settings.jsonenv 當預設
② 派工端 spawn subagent 時注入
③ 人工 override
依 scope 推定orchestrator profile → orchestratorrepo profile → engineer

為什麼 scope 不放 settings.jsonsettings.json 是「使用者資料檔」,update 永不覆蓋, 而且 CI/獨立腳本也要讀得到。system-dev/.profileVERSION 同層,一致且好找。

3.2 身分矩陣(含那個不存在的格子)

AGENT_ROLE=orchestrator AGENT_ROLE=engineer
orchestrator profile PM 本尊 總管 repo 裡的技術 subagent
repo profile 不存在 → exit 2,要求修正環境 寫 code 的 subagent

「repo profile × orchestrator」被攔的訊息要說清楚:成員 repo 沒有 PM—— 要 PM 的動作請回總管 repo 做(分離 §二「空格也是封路」)。

3.3 lib/role-lib.shcommon,被 source 不獨立掛)

sdt_repo_root()    # 由 ${BASH_SOURCE} 往上找,不假設 CLAUDE_PROJECT_DIR(雲端可跑)
sdt_rel_path "$f"  # 絕對/相對 → repo 相對路徑(抄 guard-cross-project 的 case 寫法)
sdt_scope()        # 讀 system-dev/.profiletrim;讀不到回 repo
sdt_role()         # 讀 $AGENT_ROLE;空 → 依 sdt_scope 推定
sdt_assert_identity()  # 檢查矩陣空格,命中 → 印訊息 exit 2
sdt_file_path_from_stdin  # 統一的 JSON 解析(jq → python3 → grep 三段 fallback

為什麼是函式庫不是 hook:六支新 hook 都要做同樣四件事(解析 JSON、算相對路徑、判 scope、判 role)。 各寫一份=四處維護同一條規則,正是分離 §六.4 要避免的病。

3.4 為什麼角色 hook 屬 common,不按規格放進各自 profile

分離 §三把 engineer 角色 hooks 畫在 profiles/repo/orchestrator 角色 hooks 畫在 profiles/orchestrator/照做會漏一格:總管 repo 裡也會 spawn engineer subagent (矩陣右上角),若 engineer 的封路 hook 只裝在 repo profile,那顆 subagent 在總管 repo 裡 改得動 journeys.md ⇒ G2「考生改考卷被攔截」在最該生效的地方失效。

⇒ 本設計改為:role 軸的 hook 全部屬 common(兩 profile 都裝),scope 軸的 hook 才按 profile 分。 唯一 scope 專屬的是 orchestrator-scope-guard.sh(總管禁入成員 repo 寫實作)。


4. 設計答案③:12 條規則落成哪些 hook(改既有 vs 新增)

規則數 ≠ 檔案數。J1/J2/J3 都是「PreToolUse Write|Edit 依 role×path 判定」, 拆三支=三次解析同一包 JSON、三處維護同一張路徑表。合併為一支、規則編號保留在程式碼註解與訊息裡。

4.1 JDD §六 八條

規則 內容 落點 既有/新增
J1 orchestrator 寫 src/***.py*.ts… → 攔 role-guard.sh 新增(規格說「既有 hook 已涵蓋則跳過」——已確認 pre-write-guard.sh 是空殼且不認 role不涵蓋
J2 orchestrator 寫 tasks.mdrequirements.mddesign.md → 攔 role-guard.sh 新增(同上)
J3 engineer 寫 journeys.mdroot.md*.featuremd 內 Gherkin 區塊 → 攔(命門 role-guard.sh 新增
J4 root.md 🔴 卡缺【要驗證+對帳日】→ 攔 jdd-format-guard.sh 新增
J5 tasks.md 新增的 task 缺站號 → 攔 jdd-format-guard.sh 新增
J6 sprint 收尾判準:tasks 全關 → 指定站 Gherkin 全過 station-done-guard.sh 新增(規格標 [修改],但 template 內沒有任何 sprint 收尾 hook——delivery-police.sh 只存在於 InkStoneCo 實例 ⇒ 對框架而言是新增,見決策 D6)
J7 站相關實作變動 → 查站點索引表 → 列重考清單 regression-scope.sh 新增(提醒不擋)
J8 root.mdjourneys.md 出現技術名詞 → 警告/攔 jdd-format-guard.sh 新增

4.2 分離 §六 四條

內容 落點 既有/新增
S1 實例寫入安裝產物區 → 攔;--framework-dev 例外 install-artifact-guard.sh 新增
S2 框架範本混入實例專名 → CI fail scripts/check-no-instance-names.sh非 hook 新增
S3 update 漂移偵測 update.sh .template-manifest 改既有腳本
S4 guard-cross-project 職責不重疊 profiles/orchestrator/hooks/orchestrator-scope-guard.sh 新增於框架(實體改寫自實例那支,見 D6

4.3 既有檔改動清單

改什麼 為什麼
template/.claude/hooks/session-start-recall.sh sdt_scope() 分流注入:orchestrator → root/journeys 摘要 本 sprint 未點亮站;repo → 現行 principles/status/mistakes 唯一真正的「改既有 hook」;藍圖 §0「routine 起牀讀站號」的落點
scripts/install.sh --profile、自動偵測+人確認、改讀 manifest、產 .profile.template-manifest、CLAUDE.md 三段組裝、build_hooks_json() 加 profile 維度與 env.AGENT_ROLE E1 主體
scripts/update.sh 改讀 manifest、三態判定、漂移報表、舊實例 marker 補植遷移 S3 EARS-1.2.2
template/CLAUDE.md 演進為 template/profiles/repo/CLAUDE.md原路徑保留一份轉址說明,避免舊 update.sh 404 D3 向下相容
§0.5 (a) 類 6 行註解 改寫成通用敘述 S2 前置清潔

合計:新增 hook 6 支role-guardjdd-format-guardstation-done-guardregression-scopeinstall-artifact-guardorchestrator-scope-guard 共用函式庫 1 支lib/role-lib.sh,不獨立掛); 改既有 hook 1 支session-start-recall.sh);改既有腳本 2 支install/update); 新增非 hook 腳本 1 支check-no-instance-names.sh)。

4.4 settings.json 掛載順序(install 依 profile 組裝)

SessionStart:   session-start-recall.shprofile 分流)
                [W3 插槽:policy plugin 的 SessionStart hook 自動排在框架 hook 之後]
PreToolUse(Write|Edit|MultiEdit):
                1. install-artifact-guard.sh   ← 先擋「改機制」,最外層
                2. role-guard.sh               ← 再判角色
                3. jdd-format-guard.sh         ← 再驗格式
                4. orchestrator-scope-guard.sh ← 僅 orchestrator profile
                5. sdd-guard.sh(既有)
                6. pre-write-guard.sh(既有空殼)
                7. wiki-secret-scan.sh(既有)
PreToolUse(Grep|Glob|Read|Bash):  wiki-first-search.sh(既有)
PreToolUse(Task):                 subagent-wiki-guard.sh(既有)
Stop / TaskCompleted:             station-done-guard.sh、regression-scope.sh

順序原則:範圍大的擋在前(改機制 → 角色 → 格式),讓錯誤訊息指向最根本的那條規則。


5. W3 插槽(本波只留座位,不做 plugin)

分離 §五 載入順序原樣文件化到 profiles/*/docs/plugin-load-order.md

SessionStart
 1. profile 憲法(scope 軸:這個資料夾的 CLAUDE.md
 2. framework hooks 上鏈(common  profile
 3. 已安裝 policy plugin 注入(primer 推到眼前、白名單 hook 排入鏈尾、skill 就緒)
 4. session-start-recallwiki status 快照,現行機制)

框架要做的只有兩件(分離 §四明文):

  1. 文件化「政策包= Claude Code 官方 plugin」的約定與載入順序——框架不發明平行外掛格式
  2. 在兩份 profile 憲法留 must-read 注入點(一段標題 + 一行說明「政策包的必讀會出現在這裡」), 讓 plugin 的 SessionStart hook 有地方推內容。

⚠️ W3 動手前必讀官方文件code.claude.com/docs/en/plugins.mdplugins-reference.md), 不憑記憶寫 plugin.json。本 SDD 預先規定 plugin 的 schema。


關鍵決策

# 決策 選擇 原因 放棄的選項
D1 安裝清單怎麼管 manifest TSVcommon/repo/orchestrator 各一份),install 與 update 共讀 現行清單硬編在兩支腳本裡已經重複;加 profile 會變四份必然漂移。manifest 讓「加一個產物」=加一行資料 繼續硬編(四份清單手動同步)
D2 common/profiles/ 放哪 template/ 底下 所有安裝產物的遠端根是 $TEMPLATE_SOURCE/template;放 repo 根會開第二個 base URLpublish-exclude 與 mirror 規則也要跟著改。分離 §三的樹是示意(它把 install.sh 也畫在根,實際在 scripts/ 照規格字面放 repo 根
D3 既有檔要不要實體搬進 common/ 不搬。既有檔原地不動,靠 manifest 宣告它屬 common update.sh 的自我更新在腳本尾端 ⇒ 舊實例跑的是舊腳本、路徑寫死,搬檔=這一輪整排 404。1.16.0 已經被「來源改動=自動更新死掉」咬過一次 照規格字面實體搬移(斷所有舊實例的更新)
D4 「本地補充區」怎麼劃 HTML 註解界標 框架區 sha256 md 渲染不可見、grep 定位得到、CC 讀得到;sha 讓漂移可機械判定 靠檔尾約定(無邊界=無法偵測)/另開 CLAUDE.local.mdagent 不保證會讀)
D5 角色 hook 屬 common 還是各 profile 屬 common 總管 repo 裡也會 spawn engineer;照規格分裝會讓那顆 subagent 改得動 journeys.mdG2 在最該生效處失效(§3.4) 照規格分裝進各 profile
D6 guard-cross-project 怎麼「修改」 上收進框架 orchestrator-scope-guard.sh,實例版於 W4 退役 它根本不在 template 裡,是實例自己發明的。就地改=在實例改機制=違反本案要立的第一條鐵律 在實例上就地改(自打嘴巴)
D7 J1/J2/J3 三條規則的檔案數 合成一支 role-guard.sh 同一個 hook 事件、同一份身分判定、同一張路徑表;拆三支=三處維護一條規則 一條一支(規格字面「逐條實作」)
D8 閘 #2(實例專名)怎麼上線 腳本 逐行豁免標記 基線報表,(a) 類本波清、(b)(c) 類標豁免待 W3 現況 8 檔 20 行命中;一上線全紅會逼出假性清理(把 arcrun 換成「某工作流引擎」=資訊沒了問題還在) 硬上線(CI 立刻全紅)/先全部改寫(假性清理)
D9 --framework-dev 怎麼實作 repo 根的 .sdt-framework-dev(框架 repo 自帶並 commit),輔以 env SDT_FRAMEWORK_DEV=1 Claude Code 沒有 --framework-dev 這個官方 flag(規格假設不成立)。用檔案=框架 repo 天生就有,零記憶負擔 造一個 CLI flag(做不到)/純靠環境變數(每次要記得設)
D10 本 SDD 的 status draftconfirm 後升 active D35 ②③;本 repo 現有 0 份 active,升活性不需搬移任何任務 直接寫 active(搶活性)

技術限制

  • 相容 macOS bash 3.2set -u 下空陣列展開要先判長度——install.sh 既有踩過)。
  • 不假設有 jqJSON 解析走 jq → python3 → grep 三段 fallback(沿既有 hook 慣例)。
  • 不假設 CLAUDE_PROJECT_DIR 存在:路徑一律由 ${BASH_SOURCE} 往上推(雲端可跑)。
  • hook 一律「解析失敗即放行」,寧可漏擋不誤殺;每支頂部寫誠實限制。
  • 遠端檔案路徑($REPO_URL/...)對既有實例是契約,本波只增不移。

驗收標準

以 requirements.md §四 的 G1G7 為唯一驗收線。收工時每題必須附實測輸出 狀態只有三種:✅ 通(附證據) / ◐ 半通(標明缺什麼) / ❌ 斷

  • G5 本波上限為 ◐ 半通(插槽就位、政策包在 W3)——不得標
  • 另加兩條非功能驗收:
    • 乾淨環境雙 profile 安裝各 < 10 分鐘(分離 §八 預測①,實測計時)
    • bash scripts/update.sh 在 InkStoneCo 實例上跑出的漂移清單 = 4 支(§0.4 基線, 對得上=偵測正確;對不上=偵測有偽陰/偽陽)

附錄 A:三個 marker 檔的格式規格(task 0.3

位置 內容 誰寫 誰讀
.profile 實例 system-dev/.profile 單行:repoorchestrator(前後空白會被 trim install.sh --profile role-lib.shsdt_scope()update.sh、CI
.template-manifest 實例 system-dev/.template-manifest TSVdest class version sha256(安裝當下的雜湊) installupdate update.sh 的三態判定
.sdt-framework-dev 框架 repo 根(實例不該有) 任意文字,存在即生效 框架 repo 自帶並 commit install-artifact-guard.sh
  • 三者都是「機器可讀的事實」,不是設定選項——agent 不得靠它們表達意圖,只能讀。
  • .profile 讀不到 → 視為 repo(代價寫在 role-lib.sh 註解裡,不假裝沒有)。
  • .sdt-framework-dev 出現在實例裡 = 有人在關掉自己的封路,git diff 看得見

附錄 B:本波實作的兩支機械閘(先於一切 task,防炸用)

擋什麼 實測
實例專名 scripts/check-no-instance-names.sh scripts/instance-names.txt 框架範本混入實例專名 基線 22 行 → 處置後 0 違規/13 行檔級豁免;注入違規行可 fail 並指出檔案:行號
相容路徑 scripts/check-legacy-paths.sh 搬檔/改名導致舊實例 update 整排 404 追蹤 35 條已發佈路徑;移走 template/CLAUDE.md 可正確 fail

為什麼這兩支要排在所有 task 之前(總管裁定):它們炸的是既有的東西,不是新功能沒做好。 專名閘晚做 → 之後每加一個範本檔都可能再混進實例名,債只會更大; 相容閘晚做 → Phase 1 一搬 CLAUDE.md 就把所有舊實例的自動更新弄死,而且沒有下一次更新能修它


相關文件

  • requirements.md(本卷)/tasks.md(本卷)
  • docs/3-specs/SDD-LIFECYCLE.mdD35 生命週期)
  • docs/3-specs/install-layout/design.md(安裝產物佈局的既有決策,本案沿用其「不污染用戶根目錄」原則)
  • 上游提案:InkStoneCo/system-dev/docs/3-specs/pending-changes.md §三 W2
  • 需求輸入:~/Desktop/總管/{JDD-template-upgrade,分離導入規格,總管系統藍圖v3}.md