From 188edcf8b721863ff66a470cfb24429c13b8ed45 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 3 Aug 2026 08:57:11 +0000 Subject: [PATCH] =?UTF-8?q?test(selftest):=20=E8=A3=9C=E8=87=AA=E5=82=B3?= =?UTF-8?q?=E7=AB=A0=E7=AF=80=E7=9A=84=E6=A1=88=E4=BE=8B=EF=BC=8C753=20?= =?UTF-8?q?=E2=86=92=20764?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 涵蓋開段、to 不寫空欄位、每輪注入、新記憶自動掛當下那段、--chapter 指定別段、 已收掉的段不算「現在」、按起始日期排序、close 後沒有進行中的段、list 講得出 每段幾則記憶、memory/chapters/ 剛好被 Wiki 一個區涵蓋。 最後那條原本寫成讀 pl.AREAS(那是 persona-gitea 的匯出,persona-lib 沒有), 會 ?? {} 之後空轉必過。改成走 selftest 既有的 gt.AREAS/AREA_KEYS。 Co-Authored-By: Claude Opus 5 (1M context) --- scripts/selftest.mjs | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/scripts/selftest.mjs b/scripts/selftest.mjs index 1079d47..2d85da6 100644 --- a/scripts/selftest.mjs +++ b/scripts/selftest.mjs @@ -308,6 +308,60 @@ console.log("⑤-b 習慣記憶(--type habit)"); check("沒有慣例的人格整段不出現", pl.habitBrief("calmsplit") === ""); } +// 自傳章節:長期記憶與心智圖之間的時期層 +console.log("⑤-c 自傳章節(memory/chapters/)"); +{ + check("開一段(to 空著=還在這一段裡)", (() => { + const res = cli(["chapter", "add", "--session", S_HOST, "--name", "做 persona 這段", + "--from", "2026-07-01", "--body", "跟他一起把人格系統做起來的那段日子。"]); + const now = pl.currentChapter("alpha"); + return res.status === 0 && now?.name === pl.slugify("做 persona 這段") && now.open === true; + })(), JSON.stringify(pl.loadChapters("alpha"))); + check("to 沒有值就不寫那一行(不要寫成空欄位)", + !fs.readFileSync(pl.chapterPath("alpha", "做 persona 這段"), "utf8").includes("to:")); + check("現在這一段會注入,而且講明它是時期不是事件", (() => { + const ctx = pl.turnContext("alpha", S_HOST, "最近在忙什麼"); + return ctx.includes("現在這一段") && ctx.includes("做 persona 這段") && + ctx.includes("這是**時期**不是事件"); + })(), pl.turnContext("alpha", S_HOST, "最近在忙什麼").slice(0, 400)); + check("新固化的記憶自動掛在當下那一段", (() => { + cli(["consolidate", "--persona", "alpha", "--session", S_HOST, "--name", "章節歸屬測試", + "--body", "這則應該掛在做 persona 這段。"]); + const meta = pl.longTermEntries("alpha").find((m) => m._name === "章節歸屬測試"); + return meta?.chapter === pl.slugify("做 persona 這段"); + })(), JSON.stringify(pl.longTermEntries("alpha").map((m) => `${m._name}:${m.chapter || "-"}`))); + check("chapterMemories 查得回這一段的記憶", + pl.chapterMemories("alpha", "做 persona 這段").some((m) => m._name === "章節歸屬測試")); + check("--chapter 可以指定掛到別的一段", (() => { + cli(["chapter", "add", "--session", S_HOST, "--name", "在 SAO 那兩年", + "--from", "2022-11-06", "--to", "2024-11-07", "--body", "被關在那裡的兩年。"]); + cli(["consolidate", "--persona", "alpha", "--session", S_HOST, "--name", "第一次到第一層", + "--chapter", "在 SAO 那兩年", "--body", "第一次踏出起始城鎮。"]); + const meta = pl.longTermEntries("alpha").find((m) => m._name === "第一次到第一層"); + return meta?.chapter === pl.slugify("在 SAO 那兩年"); + })()); + check("已收掉的段不會被當成「現在這一段」", + pl.currentChapter("alpha")?.name === pl.slugify("做 persona 這段")); + check("章節按起始日期排序(不是按檔名)", (() => { + const rows = pl.loadChapters("alpha"); + return rows[0].name === pl.slugify("在 SAO 那兩年") && rows.at(-1).open === true; + })(), JSON.stringify(pl.loadChapters("alpha").map((c) => `${c.from}:${c.name}`))); + check("close 之後就沒有進行中的段了(不會退回上一段)", (() => { + cli(["chapter", "close", "--session", S_HOST, "--name", "做 persona 這段", "--at", "2026-08-03"]); + return pl.currentChapter("alpha") === null && pl.chapterBrief("alpha") === ""; + })(), JSON.stringify(pl.loadChapters("alpha"))); + check("chapter list 講得出每段有幾則記憶", (() => { + const out = cli(["chapter", "list", "--session", S_HOST]).stdout; + return out.includes("在 SAO 那兩年") && out.includes("記憶 1 則"); + })(), cli(["chapter", "list", "--session", S_HOST]).stdout); + check("memory/chapters/ 剛好被一個區涵蓋,而且是 Wiki 區(低頻設定)", (() => { + const hit = gt.AREA_KEYS.filter((key) => gt.AREAS[key].paths + .some((p) => (p.endsWith("/") ? "memory/chapters/x.md".startsWith(p) : "memory/chapters/x.md" === p))); + return hit.length === 1 && hit[0] === "wiki"; + })(), JSON.stringify(gt.AREA_KEYS.filter((key) => gt.AREAS[key].paths + .some((p) => (p.endsWith("/") ? "memory/chapters/x.md".startsWith(p) : "memory/chapters/x.md" === p))))); +} + console.log("⑥ 短期 → 長期的轉入條件"); check("有六條成文條件", pl.PROMOTION_RULES.length === 6); check("R1 高顯著度會成為候選",