2f5d9f3bb2
SDD: docs/3-specs/jdd-dual-profile(active)。編號 task 26/33 完成,Phase 4-5 未開工。 ■ Phase 2 JDD 文件範本(orchestrator profile) 範本形狀對齊「實際跑出來的那兩份」(總管已寫的 root.md 15 卡、journeys.md J-1 九站), 不是照規格憑空造: - 卡片是巢狀 bullet(`- **P1** 🟢 …` + 子項放來源/對帳),非規格畫的平行文字行 - 站點索引**巢狀 bullet 不用表格**(表格會把層級壓平,看不出從屬) - 兩份都保留「這卷還缺什麼(誠實記)」收尾段——規格沒有,但那是防假綠的地方 新增:root.md / journeys.md / sprint.md / triage-map.md 四範本(add-if-missing, 填了就永不覆蓋)+ plugin-load-order.md(W3 插槽,框架不發明平行外掛格式) ■ Phase 3 封路 hook(八條規則落六支檔) - role-guard(J1+J2+J3)★命門:考生不能改考卷。六組實測含「考題藏在別的 md 裡」也擋 - jdd-format-guard(J4+J5+J8):紅卡缺對帳日/任務缺站號/PM 文件混技術名詞 - station-done-guard(J6):收工判準是站的考題全綠,不是任務全關 - regression-scope(J7):動實作 → 列出要重考哪幾題(只提醒不擋) - install-artifact-guard(S1):實例不改機制 - orchestrator-scope-guard(S4):總管不進成員 repo 動實作(從實例上收進框架, 路徑清單改由實例自填,範本零專名) 掛載鏈依「範圍大的擋在前」:改機制 → 角色 → 位置 → 格式 → 既有三支 ■ 還清兩件舊債 - update.sh 檔案清單改讀 manifest(舊硬編降為抓不到來源時的 fallback) ——install/update 兩份手抄清單漂移的根因全修 - CLAUDE.md 界標補植:舊實例全文原封包進本地區、框架區重鋪、原檔備份、冪等 ——解開「沒界標⇒不敢覆蓋⇒框架改的憲法永遠送不到既有實例」這個死結 ■ 修掉三個自己造的問題(實測抓出來的,不是想出來的) - jdd-format-guard 誤擋真實 journeys.md 的「這卷還缺什麼」自述段 → 排除法改**正面圈定**(只掃卡片本體與站內文),說明區/自述段/索引自然不在範圍 - install-artifact-guard 把 pre-write-guard.sh 也擋了——而它的錯誤訊息正叫人去改那支 → 使用者自訂插槽列為最優先放行 - check-legacy-paths 用 HEAD 當基準會**自我弱化**:改成清單驅動後保護範圍 35→29 條 → 基準改指最後一次真正發佈的版本 ■ 實測(全部貼過輸出) - G2 考生改考卷:6/6,含 orchestrator 寫 code/engineer 改考題/考題藏別處 - G4 憲法分流:兩環境重裝,總管版技術軌關鍵字 0、成員版上游指針 8,界標 4/4 - G6 實例改機制:4/4,含框架開發標記放行與自訂插槽放行 - G7 CI 擋實例名:注入違規 → 指出檔案行號 exit 1 - G3 進度以站計量:起牀推「J-1 已點亮 2/9 站」、收工列未亮站並禁用任務數當理由 - 回歸考、界標補植冪等、orchestrator-scope-guard 四組:全通 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
4.5 KiB
Bash
98 lines
4.5 KiB
Bash
#!/bin/bash
|
||
# orchestrator-scope-guard.sh — 總管不進成員 repo 動實作(分離規格 防糾纏閘 S4)
|
||
#
|
||
# 只裝在 orchestrator profile。掛 PreToolUse(Write|Edit|MultiEdit)。
|
||
#
|
||
# ── 與 role-guard 的分工(刻意分兩支,不重疊)────────────
|
||
# role-guard 管「這個**角色**能寫什麼**類型**的檔」(code?考卷?任務池?)
|
||
# orchestrator-scope-guard 管「總管能不能進這個**位置**」(成員 repo 的地盤)
|
||
# 兩件事正交:總管在自己家寫 md 沒問題,進成員 repo 寫 md 也沒問題(那是交辦),
|
||
# 但進成員 repo 寫實作檔就是越界——那是該 repo 的 engineer 的事。
|
||
#
|
||
# ── 為什麼「只擋非 .md」──────────────────────────
|
||
# .md 放行是刻意的:總管要能在成員 repo 裡留交辦文件、筆記、規格討論。
|
||
# 擋的是「總管自己下去改人家的實作」——那會讓該 repo 的 CC 完全不知道發生什麼事,
|
||
# 而且繞過了該 repo 自己的規格與 wiki 紀律。
|
||
#
|
||
# ── 自動派工放行 ────────────────────────────────
|
||
# 當「總管派出去的 subagent 已經戴著該 repo 的人格」時,它寫該 repo 的 code 是合理的
|
||
# (心智已經在那個 repo 裡,context 是隔離的)。雙重夾:
|
||
# ① 環境變數 CLAUDE_CODE_CHILD_SESSION=1(subagent 標籤;總管主 session 沒有)
|
||
# ② 路徑在下方白名單內
|
||
# ⚠️ 隔離保證是 prompt reset(軟的,靠監測),不是結構級。要絕對純淨走獨立 session。
|
||
#
|
||
# 誠實限制:擋的是路徑語法層。「把實作偽裝成 .md」或「該交辦卻判斷成可直改」
|
||
# 這種語意層越界擋不到。它是底線,不是萬能。
|
||
|
||
set -uo pipefail
|
||
|
||
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
. "$HOOK_DIR/lib/role-lib.sh" 2>/dev/null || exit 0
|
||
|
||
# 只在總管實例生效(裝錯地方就安靜退出)
|
||
[ "$(sdt_scope)" = "orchestrator" ] || exit 0
|
||
|
||
INPUT="$(cat)"
|
||
FILE_PATH="$(sdt_file_path "$INPUT")"
|
||
[ -z "$FILE_PATH" ] && exit 0
|
||
|
||
ROOT="$(sdt_repo_root)"
|
||
REL="$(sdt_rel_path "$FILE_PATH")"
|
||
|
||
# ── 成員 repo 目錄怎麼認 ─────────────────────────
|
||
# 不寫死任何專案名(框架不含實例資料)。兩種來源:
|
||
# ① 實例自填的清單:system-dev/.member-dirs(一行一個目錄前綴)
|
||
# ② 沒有該檔 → 動態偵測:頂層下「自己帶 .git 的子目錄」就是成員 repo
|
||
MEMBER_DIRS_FILE="$ROOT/system-dev/.member-dirs"
|
||
top="${REL%%/*}"
|
||
[ "$top" = "$REL" ] && exit 0 # 不在任何子目錄裡=總管自己的檔,放行
|
||
|
||
in_member_repo=1
|
||
if [ -f "$MEMBER_DIRS_FILE" ]; then
|
||
while IFS= read -r d; do
|
||
case "$d" in ''|'#'*) continue ;; esac
|
||
d="${d%/}"
|
||
case "$REL" in "$d"/*) in_member_repo=0; break ;; esac
|
||
done < "$MEMBER_DIRS_FILE"
|
||
else
|
||
[ -d "$ROOT/$top/.git" ] && in_member_repo=0
|
||
fi
|
||
[ "$in_member_repo" -eq 0 ] || exit 0
|
||
|
||
# ── 自動派工白名單(實例自填,框架不預設任何路徑)────
|
||
ALLOW_FILE="$ROOT/system-dev/.autodispatch-allow"
|
||
if [ "${CLAUDE_CODE_CHILD_SESSION:-}" = "1" ] && [ -f "$ALLOW_FILE" ]; then
|
||
while IFS= read -r a; do
|
||
case "$a" in ''|'#'*) continue ;; esac
|
||
a="${a%/}"
|
||
case "$REL" in
|
||
"$a"/*) echo "🤝 [orchestrator-scope-guard] subagent 放行:$a(自動派工)" >&2; exit 0 ;;
|
||
esac
|
||
done < "$ALLOW_FILE"
|
||
fi
|
||
|
||
# ── 成員 repo 內:.md 放行(交辦/文件),其餘擋 ────
|
||
case "$REL" in
|
||
*.md|*.MD|*.markdown) exit 0 ;;
|
||
esac
|
||
|
||
cat >&2 <<EOF
|
||
❌ BLOCKED by orchestrator-scope-guard(防糾纏閘 S4)
|
||
|
||
總管不進成員 repo 動實作。
|
||
|
||
成員 repo:$top
|
||
路徑:$REL
|
||
|
||
正確做法:
|
||
· 要那個 repo 改什麼 → 在**那個 repo** 開一張交辦(.md 放行),
|
||
給判準與考題,成品由該 repo 的 CC 按它自己的規格產出
|
||
· 你能派 subagent 去做 → 那才是正解,不是自己下去改,也不是叫人去開另一個 session
|
||
· 真要放行 subagent 自動寫某個 repo → 把路徑加進 system-dev/.autodispatch-allow
|
||
(⚠️ 加=放權,想清楚它影響誰)
|
||
|
||
為什麼擋:你直接改人家的實作,該 repo 的 CC 完全不知道發生過什麼事——
|
||
它的規格、wiki、驗收全部被繞過,下次它照自己的紀律工作時就會把你的改動蓋掉。
|
||
EOF
|
||
exit 2
|