f233eec9c2
leo 08-15 量測:266 檔真正算的 ~20 分鐘/<$0.5,使用者卻等 ~4 天(多在等 Workers AI 每日額度);而「有哪些檔案/最近改了什麼」本地掃一遍就有答案 (1,335 檔實測 0.254s),卻因 part_of 只在雲端 parse_card(萃取之後)生成 而排同一條隊、撞同一面額度牆。 - collector/inventory.go:Scan() 後、萃取迴圈前(額度冷卻閘之外),把 manifest 現況做成機械總覽卡(檔案清單/最近改動/目錄 part_of)POST 既有 rag_ingest_card ——零 LLM、零新 workflow、既有實例直接受益;自帶同頁名 upsert 防重複 - 冪等:內容 sha256 記 manifest.inventory_hash;失敗 10 分鐘退避(防 t195 同款 每 5 秒重撞);額度失敗訊息人話化,不裸露 4006/502 - 清單 ≤200 逐檔、關聯 ≤10 條:守 Workers 免費層 50 subrequests 天花板 - 不寫本機檔案、不動使用者原稿 實測(youlin stage yuga3bse,刻意無金鑰=零萃取):總覽卡 200 送達、rag_chat 正確回答「有哪些檔案/最近改了什麼」;重掃不重複(blocks 恆 5、triplets 恆 2); go test collector+supervisor+arcrun-app 全綠(新增 inventory_test.go 6 案)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
// template_install_test.go — daemon-beta task 2(代裝冪等/wiki 產物區不被掃)。
|
||
package collector
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
)
|
||
|
||
// 空資料夾一鍵鋪好:關鍵檔齊、版本讀得到。
|
||
func TestInstallTemplateFresh(t *testing.T) {
|
||
root := t.TempDir()
|
||
res, err := InstallTemplate(root)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(res.Installed) == 0 || len(res.Skipped) != 0 {
|
||
t.Fatalf("首鋪帳目異常:installed=%d skipped=%d", len(res.Installed), len(res.Skipped))
|
||
}
|
||
if res.Version == "unknown" || res.Version == "" {
|
||
t.Fatalf("版本讀不到:%q", res.Version)
|
||
}
|
||
for _, must := range []string{
|
||
"system-dev/wiki/status.md",
|
||
"system-dev/wiki/mistakes.md",
|
||
".claude/commands/wiki-capture.md", // claude 萃取路(task 3)依賴它
|
||
} {
|
||
if _, err := os.Stat(filepath.Join(root, must)); err != nil {
|
||
t.Fatalf("缺關鍵檔 %s:%v", must, err)
|
||
}
|
||
}
|
||
if !TemplateInstalled(root) {
|
||
t.Fatal("TemplateInstalled 應為 true")
|
||
}
|
||
}
|
||
|
||
// 冪等:重跑不覆寫;用戶改過的檔保持原樣。
|
||
func TestInstallTemplateIdempotent(t *testing.T) {
|
||
root := t.TempDir()
|
||
if _, err := InstallTemplate(root); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
marker := filepath.Join(root, "system-dev", "wiki", "status.md")
|
||
if err := os.WriteFile(marker, []byte("用戶自己的進度,不准動"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
res, err := InstallTemplate(root)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(res.Installed) != 0 {
|
||
t.Fatalf("重跑不應再鋪檔:installed=%v", res.Installed)
|
||
}
|
||
data, _ := os.ReadFile(marker)
|
||
if string(data) != "用戶自己的進度,不准動" {
|
||
t.Fatal("用戶檔被覆寫=冪等鐵律破功")
|
||
}
|
||
}
|
||
|
||
// 代裝後的 system-dev/ 不得被 direct 掃描當成原稿。
|
||
func TestScanSkipsTemplateArtifacts(t *testing.T) {
|
||
root := t.TempDir()
|
||
if _, err := InstallTemplate(root); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(filepath.Join(root, "我的筆記.md"), []byte("# hi"), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
cfg := &DirectConfig{
|
||
WatchFolders: []string{root},
|
||
Manifest: filepath.Join(t.TempDir(), "m.json"),
|
||
CypherURL: "https://x.example", Namespace: "demo",
|
||
MaxRemoved: DefaultMaxRemovedRatio,
|
||
}
|
||
results, exit, _ := RunDirectOnce(cfg, true)
|
||
if exit != 0 {
|
||
t.Fatalf("dry-run 失敗:%+v", results)
|
||
}
|
||
_, fileResults := splitInventory(results) // 結構先行:總覽卡另計
|
||
if len(fileResults) != 1 || fileResults[0].Path != "我的筆記.md" {
|
||
t.Fatalf("應只掃到用戶檔(template 產物須跳過),got %+v", results)
|
||
}
|
||
}
|