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>
103 lines
4.6 KiB
Bash
Executable File
103 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
||
# check-legacy-paths.sh — 相容閘:已發佈的安裝/更新腳本會抓的每個遠端路徑,都必須還在
|
||
#
|
||
# 這支存在的理由(SDD jdd-dual-profile 發現⑦ + 決策 D3):
|
||
# install.sh / update.sh 是**逐檔 curl**:檔案清單與遠端路徑**寫死在腳本裡**。
|
||
# 而 update.sh 的「自我更新」在腳本**尾端**——舊實例這一輪跑的是**舊腳本**。
|
||
# ⇒ 只要框架把某個既有檔搬走/改名,舊實例的那一輪就是**整排 404**,
|
||
# 而且它們不會自動好:更新機制本身壞了,就沒有下一次更新來修它。
|
||
#
|
||
# 前科:1.16.0「update/install 來源改指 Gitea」——來源一改,
|
||
# 舊實例的自動更新當場死掉(CHANGELOG 1.16.0 有記)。同一種病。
|
||
#
|
||
# 所以鐵律是:**遠端路徑對既有實例是契約,只增不移。**
|
||
# 要搬版面 → 先在原路徑留相容檔(轉址說明/原內容),確認本閘綠了才准動。
|
||
#
|
||
# 作法:
|
||
# 從「已發佈版本」的 install.sh / update.sh 裡抽出所有 $REPO_URL/... $TEMPLATE_URL/...
|
||
# $SCRIPTS_URL/... 引用,映射回本 repo 的實體路徑,逐一確認檔案存在。
|
||
#
|
||
# 誠實限制:
|
||
# · 只驗「路徑還在不在」,不驗內容還對不對(舊腳本抓到新內容仍可能語意不相容)。
|
||
# · 基準是 git 裡的已發佈版本(預設 HEAD);再更老的版本若引用過更多路徑,
|
||
# 本閘看不到——要驗更早的版本,用 BASE=<commit> 指定。
|
||
#
|
||
# 用法:
|
||
# bash scripts/check-legacy-paths.sh # 以 HEAD 為已發佈基準
|
||
# BASE=dc4fe67 bash scripts/check-legacy-paths.sh
|
||
set -euo pipefail
|
||
|
||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
cd "$REPO_ROOT"
|
||
|
||
# ⚠️ 基準**不能**用 HEAD——這是實測踩到的:
|
||
# 把 install.sh 改成清單驅動之後,HEAD 裡的硬編路徑從 35 條掉到 29 條,
|
||
# **閘保護的範圍就跟著縮水 6 條**——而那 6 條正是還沒更新的舊實例仍然會去抓的。
|
||
# 用 HEAD 當基準,閘會隨著每次提交自我弱化,最後變成「只保護今天的自己」。
|
||
# ⇒ 基準必須是「**外面實際在跑的那一版**」=最後一次真的發佈出去的 commit。
|
||
# 發新版、且確認真的送出去之後,才把下面這行往前挪。
|
||
LAST_RELEASED_DEFAULT="dc4fe67" # 1.18.0
|
||
BASE="${BASE:-$LAST_RELEASED_DEFAULT}"
|
||
|
||
# ── 取出基準版本的兩支腳本 ────────────────────────────
|
||
TMP="$(mktemp -d)"
|
||
trap 'rm -rf "$TMP"' EXIT
|
||
|
||
for s in install.sh update.sh; do
|
||
if ! git show "$BASE:scripts/$s" > "$TMP/$s" 2>/dev/null; then
|
||
echo "⚠️ 基準 $BASE 沒有 scripts/$s,略過" >&2
|
||
: > "$TMP/$s"
|
||
fi
|
||
done
|
||
|
||
# ── 抽出遠端引用 → 映射成本地實體路徑 ──────────────────
|
||
# $REPO_URL/x → template/x
|
||
# $TEMPLATE_URL/x → template/x
|
||
# $SCRIPTS_URL/x → scripts/x
|
||
extract_paths() {
|
||
grep -oE '\$\{?(REPO_URL|TEMPLATE_URL|SCRIPTS_URL)\}?/[A-Za-z0-9._/-]+' "$1" 2>/dev/null \
|
||
| sed -e 's|\${*REPO_URL}*/|template/|' \
|
||
-e 's|\${*TEMPLATE_URL}*/|template/|' \
|
||
-e 's|\${*SCRIPTS_URL}*/|scripts/|' \
|
||
|| true
|
||
}
|
||
|
||
ALL="$( { extract_paths "$TMP/install.sh"; extract_paths "$TMP/update.sh"; } | sort -u )"
|
||
|
||
if [ -z "$ALL" ]; then
|
||
echo "⚠️ 在 $BASE 的腳本裡找不到任何遠端引用——抽取規則可能過時,本閘等同關閉" >&2
|
||
exit 1
|
||
fi
|
||
|
||
TOTAL=0
|
||
MISSING=0
|
||
MISSING_LIST=""
|
||
|
||
while IFS= read -r p; do
|
||
[ -z "$p" ] && continue
|
||
TOTAL=$((TOTAL + 1))
|
||
if [ ! -e "$p" ]; then
|
||
MISSING=$((MISSING + 1))
|
||
MISSING_LIST="${MISSING_LIST} ✗ ${p}"$'\n'
|
||
fi
|
||
done <<< "$ALL"
|
||
|
||
if [ "$MISSING" -gt 0 ]; then
|
||
cat >&2 <<EOF
|
||
════════════════════════════════════════════════
|
||
❌ 相容閘:已發佈腳本會抓的路徑不見了($MISSING / $TOTAL)
|
||
════════════════════════════════════════════════
|
||
$MISSING_LIST
|
||
後果(不是理論,是 1.16.0 真的發生過):
|
||
舊實例跑 update 時對上面每個路徑 curl 404 → 更新失敗 →
|
||
**更新機制本身壞掉,之後也不會有下一次更新來修它**。
|
||
|
||
正解:搬版面時在原路徑留相容檔(轉址說明或原內容),
|
||
本閘綠了才准繼續。遠端路徑是契約,只增不移。
|
||
EOF
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ 相容閘:已發佈腳本(基準 $BASE)引用的 $TOTAL 個路徑全部還在"
|
||
exit 0
|