fix(collector): #60 監看的是筆記庫底下的子資料夾時,保護整個失效
真正的根因不是「vault 判斷漏了子庫」,是**判斷的方向搞反了**: 前兩輪問的都是「監看根**這一層**是不是 vault」,但 daemon 的產物一律落在 監看根底下——這兩件事只有在「監看根 == 庫根」時才等價,而那正好是前兩輪 唯一測過、也唯一不會出事的擺法。 使用者只要把庫底下的某一層加進監看(`KB/docs`、`KB/pages`、Obsidian 庫裡的 某個專案夾——很自然的用法),DetectVaultType 就回 VaultNone,整套保護退回 一般資料夾模式,卡片落在 `<監看根>/system-dev/wiki/cards/`:那個路徑就在 使用者的 graph 裡面,而且看得見,Logseq/Obsidian 每一張卡都收編成一頁。 前綴(第二輪)只擋得住撞名,擋不住「多出一堆機器頁」。 改法:把「這一層是不是庫」與「我寫的東西會不會落進誰的庫」拆成兩個判準。 - vault.go:新增 DetectVaultContext(往上找到最近的庫根)與 VaultDirUnder (往下擋:寫入目標會不會踩進子庫)。DetectVaultType 一字未改,繼續與 install.sh 對齊——往上找用較嚴的判準(logseq/ 要有 config.edn 或 journals//pages/ 佐證),因為那是替使用者猜、而且一次猜好幾層。 停在家目錄與檔案系統根,避免 `~/logseq` 這種常見資料夾把整個家目錄判成庫。 - extract.go:cardsRelDirFor 改用 DetectVaultContext。 - safewrite.go:落卡前過 ensureWritable 機械閘——目標踩進子庫就中止, 不靜靜寫進去。今天不會觸發,它防的是以後新增的寫檔點。 - tidy.go:收拾判準從「有沒有帶標記」擴充成「位置對不對 + 有沒有帶標記」, 舊版留在看得見位置的卡會被搬進隱藏目錄;MigrateCardNames 每輪自動做, 使用者不必下任何指令。報告多一個 VaultRoot,說清楚是誰的庫。 leo 派工單上的線索(庫在監看根**底下**)實測不成立:產物一律錨在監看根, 不會落進子庫。但那個「本來就沒破」原本沒有任何機制保證,所以照樣把兩種 格式的子庫情境永久寫進測試,加上 ensureWritable 當第二道保險。 驗證缺口(票上第 6 條):第二輪的足跡測試方向是對的,漏的是**觀測窗**—— snapshotTree 只拍監看根,而災情發生在監看根外面、庫裡面;且 fixture 只有 `root := vault` 一種擺法,測試與被測程式犯了同一個假設,所以永遠是綠的。 vault_subdir_test.go 把快照邊界改成筆記庫,並把「監看根與庫根的關係」升格 成測試維度(庫在上/庫在下/庫就是它/沒有庫 × Logseq/Obsidian)。 全程只用 t.TempDir() 與 mktemp -d;沒碰任何真實筆記庫、沒重啟任何 daemon。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+80
-3
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
# verify-60.sh — arcrun-rag#60 第二輪的五項驗收,一次跑完並把實測輸出印出來。
|
||||
# verify-60.sh — arcrun-rag#60 的驗收,一次跑完並把實測輸出印出來。
|
||||
#
|
||||
# 第三輪(2026-08-12)加了第 ⑤ 段:**監看根是筆記庫底下的子資料夾**。
|
||||
# 前兩輪的 fixture 一律是「監看根 == 庫根」,而那正好是唯一不會出事的擺法。
|
||||
#
|
||||
# 用法(在 repo 任何位置都可以):
|
||||
# bash collector/verify-60.sh 2>&1 | tee /tmp/verify-60.log
|
||||
@@ -29,8 +32,9 @@ echo "編譯:通過"
|
||||
hr "② 既有 Go 測試全綠(驗收條件⑤)"
|
||||
go test ./... || FAIL=1
|
||||
|
||||
hr "③ 足跡測試:真的有既有日誌檔的 vault,跑之前/跑之後的完整檔案清單(驗收條件①②④)"
|
||||
go test . -run 'Footprint' -v || FAIL=1
|
||||
hr "③ 足跡測試:跑之前/跑之後的完整檔案清單(驗收條件①②④)"
|
||||
# 第三輪起觀測窗是**筆記庫**而不是監看根——見 vault_subdir_test.go 開頭。
|
||||
go test . -run 'Footprint|VaultContext|VaultDirUnder|MigrateCardNames' -v || FAIL=1
|
||||
|
||||
hr "④ 舊產物收拾:在一個「已經被舊版 daemon 弄髒」的真 vault 上實跑(驗收條件③)"
|
||||
VAULT="$(mktemp -d)"
|
||||
@@ -113,6 +117,79 @@ echo
|
||||
echo "── 檢查四:冪等(再跑一次不該有任何動作) ──"
|
||||
go run ./cmd/collector tidy --folder "$VAULT" --apply || FAIL=1
|
||||
|
||||
hr "⑤ 第三輪:監看根是**筆記庫底下的子資料夾**(Logseq 與 Obsidian 各一組)"
|
||||
# 這一段用真的 CLI 在真的暫存筆記庫上跑,證明:
|
||||
# · 使用者在庫裡的檔案(journals/pages)一個都沒被動到
|
||||
# · 舊版留在看得見位置的機器產物被搬進隱藏目錄,庫裡不再有機器頁面
|
||||
# · 故意擺的同名檔(跟機器產物撞名的那個)原封不動
|
||||
subdir_case() {
|
||||
local kind="$1"
|
||||
local BASE; BASE="$(mktemp -d)"
|
||||
local V="$BASE/我的筆記庫"
|
||||
local W="$V/docs"
|
||||
mkdir -p "$W" "$V/journals" "$V/pages"
|
||||
|
||||
if [ "$kind" = "logseq" ]; then
|
||||
mkdir -p "$V/logseq"; echo '{:default-home {:page "contents"}}' > "$V/logseq/config.edn"
|
||||
else
|
||||
mkdir -p "$V/.obsidian"; echo '{}' > "$V/.obsidian/app.json"
|
||||
fi
|
||||
|
||||
# 使用者自己的東西,含一個**故意跟機器產物撞名**的檔
|
||||
echo '- 我自己寫的日記' > "$V/journals/2026_08_12.md"
|
||||
echo '- 我自己的讀書筆記' > "$V/pages/讀書筆記.md"
|
||||
echo '- 這個名字是我先取的' > "$V/pages/arcrun-會議記錄.md"
|
||||
# 舊版 daemon 留在**看得見**位置的機器產物(就在使用者的庫裡)
|
||||
mkdir -p "$W/system-dev/wiki/cards"
|
||||
echo '# 會議記錄' > "$W/system-dev/wiki/cards/arcrun-會議記錄.md"
|
||||
echo '# 2026_08_12' > "$W/system-dev/wiki/cards/2026_08_12.md"
|
||||
|
||||
echo "── [$kind] 收拾之前(整個筆記庫)──"
|
||||
(cd "$V" && find . -type f | sort)
|
||||
local MINE_BEFORE; MINE_BEFORE="$(find "$V/journals" "$V/pages" -type f -exec shasum {} \; | sed "s|$V/||" | sort)"
|
||||
|
||||
echo
|
||||
echo "── [$kind] collector tidy --folder <庫>/docs(先預覽)──"
|
||||
go run ./cmd/collector tidy --folder "$W" || FAIL=1
|
||||
echo
|
||||
echo "── [$kind] collector tidy --folder <庫>/docs --apply ──"
|
||||
go run ./cmd/collector tidy --folder "$W" --apply || FAIL=1
|
||||
|
||||
echo
|
||||
echo "── [$kind] 收拾之後(整個筆記庫)──"
|
||||
(cd "$V" && find . -type f | sort)
|
||||
|
||||
echo
|
||||
local MINE_AFTER; MINE_AFTER="$(find "$V/journals" "$V/pages" -type f -exec shasum {} \; | sed "s|$V/||" | sort)"
|
||||
if [ "$MINE_BEFORE" = "$MINE_AFTER" ]; then
|
||||
echo "✅ [$kind] 使用者在庫裡的檔案(含同名的 arcrun-會議記錄.md)內容與路徑完全未變"
|
||||
else
|
||||
echo "❌ [$kind] 使用者的檔案被動過:"; diff <(echo "$MINE_BEFORE") <(echo "$MINE_AFTER"); FAIL=1
|
||||
fi
|
||||
|
||||
# 庫裡不准再有「看得見的」機器產物:路徑中沒有任何 . 開頭的段、卻帶 arcrun- 前綴的檔
|
||||
local VISIBLE=0
|
||||
while IFS= read -r f; do
|
||||
case "$f" in */.*) continue;; esac # 隱藏路徑,筆記軟體不掃
|
||||
case "$(basename "$f")" in
|
||||
arcrun-會議記錄.md) [ "$f" = "./pages/arcrun-會議記錄.md" ] && continue;; # 這是使用者自己的
|
||||
esac
|
||||
case "$(basename "$f")" in
|
||||
arcrun-*) echo " ❌ [$kind] 庫裡還有看得見的機器產物:$f"; VISIBLE=1;;
|
||||
esac
|
||||
done < <(cd "$V" && find . -type f | sort)
|
||||
if [ "$VISIBLE" -eq 0 ]; then
|
||||
echo "✅ [$kind] 庫裡沒有任何看得見的機器產物(筆記軟體不會多出頁面)"
|
||||
else
|
||||
FAIL=1
|
||||
fi
|
||||
rm -rf "$BASE"
|
||||
}
|
||||
|
||||
subdir_case logseq
|
||||
echo
|
||||
subdir_case obsidian
|
||||
|
||||
hr "結果"
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "✅ 全部通過"
|
||||
|
||||
Reference in New Issue
Block a user