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>
93 lines
4.4 KiB
Bash
93 lines
4.4 KiB
Bash
#!/bin/bash
|
||
# install-artifact-guard.sh — 實例不准改機制(分離規格 防糾纏閘 S1)
|
||
#
|
||
# 掛 PreToolUse(matcher: Write|Edit|MultiEdit)。**排在整條鏈的最前面**——
|
||
# 範圍最大的規則先擋,錯誤訊息才會指向最根本的那條。
|
||
#
|
||
# ── 擋什麼 ──────────────────────────────────────
|
||
# 寫入「安裝產物區」= 框架發下來的機制檔(hook、範本、安裝腳本、plugin 目錄)。
|
||
# 判準來自 system-dev/.template-manifest:**凡是框架管的檔(class=overwrite)都算**。
|
||
# 不另寫一份路徑表——兩處維護同一條規則,遲早不同步。
|
||
#
|
||
# ── 為什麼要擋(實測數據,不是潔癖)─────────────────
|
||
# 拿一個真實使用中的實例對照框架:6 支框架 hook 裡 **4 支已被手改**,
|
||
# 另有 11 支是實例自己發明的,而**沒有任何機制知道這件事**。
|
||
# 兩層後果:
|
||
# ① 框架之後修好的 bug,永遠送不到那些被手改的檔
|
||
# ② 手改的內容沒人審、也不會回饋給框架 ⇒ 同一個坑每個實例各踩一次
|
||
# 機制要改就回上游改,一次修全家;在自己家裡改,只有自己受惠、且下次更新就孤立。
|
||
#
|
||
# ── 怎麼放行 ────────────────────────────────────
|
||
# 框架 repo 自己開發時本來就要改這些檔 ⇒ 兩種放行方式:
|
||
# · repo 根目錄有 .sdt-framework-dev 檔(框架 repo 自帶並 commit,零記憶負擔)
|
||
# · 環境變數 SDT_FRAMEWORK_DEV=1(臨時情境)
|
||
# 注意:官方**沒有** --framework-dev 這個 CLI 參數(實查,非記憶),別去找。
|
||
#
|
||
# 誠實限制:擋直接寫檔。bash 繞道改檔擋不到。留痕可審,不宣稱防偽。
|
||
|
||
set -uo pipefail
|
||
|
||
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
. "$HOOK_DIR/lib/role-lib.sh" 2>/dev/null || exit 0
|
||
|
||
# ── 框架開發模式 → 放行 ────────────────────────────
|
||
ROOT="$(sdt_repo_root)"
|
||
[ -f "$ROOT/.sdt-framework-dev" ] && exit 0
|
||
[ "${SDT_FRAMEWORK_DEV:-}" = "1" ] && exit 0
|
||
|
||
INPUT="$(cat)"
|
||
FILE_PATH="$(sdt_file_path "$INPUT")"
|
||
[ -z "$FILE_PATH" ] && exit 0
|
||
REL="$(sdt_rel_path "$FILE_PATH")"
|
||
|
||
MANIFEST="$ROOT/system-dev/.template-manifest"
|
||
|
||
is_managed_artifact() {
|
||
# ⓪ 使用者的自訂插槽 → 一律放行,**這一條要排在最前面**
|
||
# 它們存在的目的就是給實例填自己的規則,而且 update 不會覆蓋它們。
|
||
# (踩過:本 hook 的錯誤訊息叫人「去改 pre-write-guard.sh」,
|
||
# 結果自己把那支也擋了——叫人走的路自己堵住,是最糟的一種閘。)
|
||
case "$1" in
|
||
.claude/hooks/pre-write-guard.sh) return 1 ;;
|
||
*.template.sh|*.template.md) return 1 ;;
|
||
.claude/settings.json) return 1 ;;
|
||
esac
|
||
# ① manifest 是權威:它說這是框架管的邏輯檔(class=overwrite)才擋
|
||
if [ -f "$MANIFEST" ]; then
|
||
if awk -F'\t' -v d="$1" '!/^#/ && $1==d && $2=="overwrite" {found=1} END{exit !found}' "$MANIFEST"; then
|
||
return 0
|
||
fi
|
||
fi
|
||
# ② manifest 還沒有/這個檔還沒登記(舊實例、或框架剛加的新檔)
|
||
# → 退回路徑慣例,別因為沒表就整條規則失效
|
||
case "$1" in
|
||
.claude/hooks/*|.claude/plugins/*) return 0 ;;
|
||
system-dev/scripts/*) return 0 ;;
|
||
esac
|
||
return 1
|
||
}
|
||
|
||
if is_managed_artifact "$REL"; then
|
||
cat >&2 <<EOF
|
||
❌ BLOCKED by install-artifact-guard(防糾纏閘 S1)
|
||
|
||
這個檔是**框架發下來的機制**,實例不改機制。
|
||
|
||
路徑:$REL
|
||
|
||
正確做法:
|
||
· 機制要改 → 回框架/政策包 repo 提案,bump 版本,實例再 update
|
||
(一次修全家,別人也拿得到;在這裡改只有你受惠,而且下次更新就孤立)
|
||
· 只是這個專案的特殊禁令 → 寫進 .claude/hooks/pre-write-guard.sh 的自訂區
|
||
(那支就是留給你填的插槽,不會被 update 覆蓋)
|
||
· 你就是在開發框架本身 → 這個 repo 根目錄該有 .sdt-framework-dev
|
||
|
||
為什麼擋(實測,不是原則潔癖):
|
||
對照過一個真實使用中的實例——6 支框架 hook 裡 4 支已被手改,
|
||
而沒有任何人知道。那 4 支從此收不到框架的任何修正。
|
||
EOF
|
||
exit 2
|
||
fi
|
||
|
||
exit 0
|