fix(collector): daemon 不再改用戶版控中的檔案,接 repo 只讀整理好的 wiki(#105/#104)
## #105 daemon 會改用戶的檔案(不可逆,先修) 2026-08-14 21:45 實撞:InkStoneCo 在看守清單裡,daemon 回報「已把 1 張舊卡片歸位」, 實際把 system-dev/wiki/cards/autonomy/ 整個子目錄壓平改名,16 個版控中的檔案變成刪除。 真兇是 MigrateCardNames 的一句假設:「那兩個目錄從頭到尾只有 daemon 會寫」。 那句話在 vault 上成立,在 repo 上不成立——system-dev/wiki/cards/ 是 template 的規約 路徑,而 template 就是要裝進開發者自己的 repo,那裡本來就有人家自己的檔案。 - 新增 repoguard.go:`.git` 判準(含 linked worktree),與 #104 共用同一個判準源 - 版控中的資料夾一個檔都不自動動;改成記帳+講給使用者聽,出口是 collector tidy --apply - Blocked 只算「確定是我們寫的」(帶 arcrun- 標記)——報使用者自己的卡等於發假訊息 - 落卡與工作區改走 .arcrun-rag/(與 vault 同待遇),自帶 .gitignore(*) 讓它對 git 隱形 - 非版控資料夾(含 vault)行為與 #60 第三輪完全一致,不推翻前兩輪的成果 ## #104 接上開發 repo 會把上萬個原始檔排進佇列 leo 的規格:「它要辨識這個庫已經有 wiki,那就直接 ingest 了」「只有文件要讀,程式碼不用讀」。 - 新增 ingestplan.go:掃描前先問「這個資料夾是什麼」——all/curated-wiki/docs-only - 排除靠路徑身分不靠副檔名:依賴、建置產物、templatefs 範本、linked worktree、巢狀子 repo - 策略與擋掉的數字經 TriggerPayload.Plan 走進 status.json,CLI 走 stderr(排除規則要看得見) - 子專案自己的 wiki 刻意不收,但一定列出來讓使用者知道去哪裡找 - 與 TemplateOwns(把 system-dev/ 整棵當開發用的)的對撞用身分化解,不拿掉任一條: 我們代裝的資料夾沒有 .git(舊規則照舊),他自己的 repo 有(收那份 wiki) ## 實測 #105:舊版 daemon 對真 repo 跑一輪 → git status 32 行(16 個 D + 16 個 ??,與 21:45 撞到的一字不差);新版跑同一輪 → 0 行。另有真 git init 的端到端測試。 #104:造出 leo 那棵樹的形狀(InkStoneCo + products/arcrun-rag + 3 份出貨 worktree, 967 個文件檔)→ 舊版送 91 個檔(多收的全是 -wt*ship/ 裡的 templatefs 範本、 benchmark 結果、docs-site 產物),新版送 32 個,全部落在 system-dev/wiki/ 底下。 MachineMark 規約新增唯一例外 IsMachineOwnedRel:.arcrun-rag/ 底下的檔以目錄名為標記 (.gitignore 的檔名是 git 定的,改不得)。迴歸網判準同步換過去。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UUwsLkFEGN8496bZTqhjFq
This commit is contained in:
@@ -192,18 +192,56 @@ func collectTemplateItems(absRoot string, isVault bool) []TidyItem {
|
||||
return items
|
||||
}
|
||||
|
||||
// CardMigration=MigrateCardNames 一輪的帳目。
|
||||
//
|
||||
// Blocked 不是「失敗」,是**刻意沒動**:那個資料夾在版控裡,我們沒有資格自己決定
|
||||
// 改別人版控中的檔案。它要被講出來(direct.go 收進 results ⇒ status.json ⇒ App),
|
||||
// 不是靜默跳過——#105 的紅線與 #104 同一條:「不要讓用戶猜」。
|
||||
type CardMigration struct {
|
||||
Moved int // 真的改名/搬移了幾個
|
||||
Blocked int // 認出是舊卡、但因為在版控裡而沒動的
|
||||
RepoRoot string // Blocked > 0 時:那個版控工作目錄的根
|
||||
}
|
||||
|
||||
// MigrateCardNames 把卡片產物區裡「位置不對或沒帶標記」的舊卡歸位。daemon 每輪自動呼叫。
|
||||
// 回傳實際動到的筆數。**只碰卡片產物區**,其餘一概不動。
|
||||
// **只碰卡片產物區**,其餘一概不動。
|
||||
//
|
||||
// 為什麼可以自動:那兩個目錄從頭到尾只有 daemon 會寫(見 cardsRelDirFor 的註解),
|
||||
// 不存在「誤把使用者的檔案改名」的可能。目標已存在就跳過,不覆蓋。
|
||||
// 🔴 第四輪=arcrun-rag#105(2026-08-14 實撞):**版控中的資料夾一個檔都不動。**
|
||||
//
|
||||
// 🔴 第三輪起也負責**搬移**(不只改名):監看根在 vault 裡時,舊版寫在可見目錄的卡
|
||||
// 會被搬進 `.arcrun-rag/wiki/cards/`。這是自動的,因為紅線寫著「不准要使用者去設定
|
||||
// 什麼開關才能保護自己的筆記」——他不該為了收拾機器留下的東西去學一個新指令。
|
||||
func MigrateCardNames(absRoot string) int {
|
||||
n := 0
|
||||
for _, it := range collectCardItems(absRoot) {
|
||||
// 前三輪(#60,f71e5a2/578ac2b)修的都是同一個場景的深度——「卡片會不會汙染
|
||||
// 使用者的**筆記庫**」,方向一路往「更自動」走,因為那條紅線是「不准要使用者
|
||||
// 去設定什麼開關才能保護自己的筆記」。**本輪不推翻那個方向**:非版控資料夾
|
||||
// (含 vault)的行為與 578ac2b 完全一致。
|
||||
//
|
||||
// 本輪修的是另一個場景——「監看的是他的 **git repo**」。上一版這裡的理由是
|
||||
// 「那兩個目錄從頭到尾只有 daemon 會寫,不存在誤把使用者的檔案改名的可能」。
|
||||
// 那句話在 repo 上錯了,而且錯得很貴:`system-dev/wiki/cards/` 是
|
||||
// system-dev-template 的規約路徑,而 template 就是要裝進**開發者自己的 repo**——
|
||||
// leo 的 `InkStoneCo` 裡那個目錄底下是他自己寫的知識卡(還有 `autonomy/` 這種
|
||||
// 他自己開的子目錄)。daemon 把它們壓平改名,**16 個版控中的檔案當場變成刪除**。
|
||||
//
|
||||
// ⇒ 判準加一問「這裡有沒有 `.git`」(見 repoguard.go 對「這夠不夠」的討論)。
|
||||
// 有=停手、記帳、講給使用者聽,要整理請他自己跑 `collector tidy --apply`
|
||||
// (那條路預設 dry-run,會先把要動什麼列給他看)。
|
||||
// 兩條紅線不衝突:「不要他學新選項才能保護筆記」管的是筆記庫;
|
||||
// repo 那邊 leo 的原話是「**預設應該是不動,要動要有出口**」。
|
||||
func MigrateCardNames(absRoot string) CardMigration {
|
||||
items := collectCardItems(absRoot)
|
||||
if repoRoot := DetectRepoRoot(absRoot); repoRoot != "" {
|
||||
// 只把**確定是我們寫的**(帶 arcrun- 標記、只是位置不對)算進 Blocked。
|
||||
// 沒帶標記的在 repo 裡預設就是使用者自己的檔案——把它們算進來,訊息就會變成
|
||||
// 「有 40 個舊卡片沒整理」,而那 40 張是 leo 自己寫的知識卡,
|
||||
// 報一個全錯的數字比不報更糟(#105 要的是誠實,不是熱心)。
|
||||
blocked := 0
|
||||
for _, it := range items {
|
||||
if IsMarked(filepath.Base(it.Rel)) {
|
||||
blocked++
|
||||
}
|
||||
}
|
||||
return CardMigration{Blocked: blocked, RepoRoot: repoRoot}
|
||||
}
|
||||
out := CardMigration{}
|
||||
for _, it := range items {
|
||||
from := filepath.Join(absRoot, filepath.FromSlash(it.Rel))
|
||||
to := filepath.Join(absRoot, filepath.FromSlash(it.To))
|
||||
if _, err := os.Stat(to); err == nil {
|
||||
@@ -213,10 +251,10 @@ func MigrateCardNames(absRoot string) int {
|
||||
continue
|
||||
}
|
||||
if err := os.Rename(from, to); err == nil {
|
||||
n++
|
||||
out.Moved++
|
||||
}
|
||||
}
|
||||
return n
|
||||
return out
|
||||
}
|
||||
|
||||
// Tidy 掃出所有舊產物;apply=false 只報告,apply=true 才真的改名/搬移。
|
||||
|
||||
Reference in New Issue
Block a user