# TODO:故事匯入(小說 → 人格記憶/語氣/情緒) 把小說變成一個人格的記憶,同時讓它從原作學語氣與情緒表達。 **技能:`/jsc-persona:persona-story`**(`skills/persona-story/`)。 開場的五題問答在 `reference/interview.md`,場景要抽什麼在 `reference/extract.md`。 機械那半是 `persona.mjs` 的 `novel` 與 `voice` 子指令。 三條界線先立,後面所有步驟都受它們約束: 1. **視角**:人格不在場、也沒人告訴他的事,最多進 `canon` 或別人的關係欄,**不能**變成他的 `event`。 2. **原文**:整本不入倉庫。只留摘要、他自己的台詞、以及可追回出處的章節標記。 3. **個性**:`SOUL.md` 不由流程自動改寫。匯入只出提案,使用者逐條核可才寫入。 --- ## 階段 -1:實作前一定要先問使用者(四題,沒答案不要開工) 這四題會決定檔案放哪、介面長什麼樣,答錯要重做。**問完拿到答案再進階段 0。** - [x] Q1 語氣檔放在人格倉庫的哪一層?→ **新開 `voice/`**(`samples.md` 原句、`reactions.md` 事件對反應) - [x] Q2 匯入要做成 CLI 子指令,還是全部由 skill 編排?→ **混合**:機械的進 CLI,判斷的留 skill - [x] Q3 同一部作品分多本匯入時,`first_seen` 的時間軸怎麼接續?→ **換算成西元日期** - [x] Q4 情緒基線差值超過多少才要人看?→ **差 10 以上** ## 階段 0:前置(做一次) - [x] 0.1 確認目標人格編號、作品名、章節檔清單、原文編碼 → **不預先問,由 skill 在匯入的當下問**(2026-08-03 使用者拍板)。 問法與順序寫在 `skills/persona-story/reference/interview.md`。 - [x] 0.2 建**正名表**:角色的各種譯名/簡稱/原文名 → 關係節點的 `name` → **從匯入的章節自動判斷候選,再給使用者確認**(2026-08-03 使用者拍板,覆蓋原本的「問譯名版本」)。 問他是哪個譯本等於要他猜;他手上那批寫的是什麼字,讀一次就知道了。 `novel scan` 抽候選(對話歸屬、敬稱結尾、片假名、高頻詞),附出現次數與一兩行上下文, 並猜關係節點分四種信心度(`exact`/`alias`/`fuzzy`/`unknown`); `novel name review`/`confirm --accept-exact`/`ignore` 做確認。 `names.json` 分 `map`(正名)與 `ignore`(確認過不是人名,例如地名與招式名)兩塊—— 已在其中之一的 token 下次掃不再出現,不然每加一章就要重看同一批。 `novel candidate add` 遇到 `about` 有未確認的 token 會擋下來。 - [x] 0.3 定**故事內時間軸**的表示法 → **西元日期**(Q3 拍板),另加 `date_source` 標 `canon`/`derived`/`guess`,見上面「換算日期不可以假裝是明寫的」那一節。 - [x] 0.4 定**顯著度配額** → 預設 `90+ 最多 5 則、80-89 最多 20 則`(`novel init --quota` 可調)。 超過配額由 `novel merge` 從低分往下壓一級(90+ → 85、80-89 → 75)並回報壓了幾則。 - [x] 0.5 定**跳過紀錄檔** → `memory/import//skipped.jsonl`, 一行一章(`chapter`/`reason`/`ts`),由 `novel skip` 寫入。 - [ ] 0.6 備份人格倉庫現況(`SOUL.md`、情緒基線、關係圖),匯入出錯要回得去 (2026-08-03 已有一份整包備份在 scratchpad;真的要匯之前再做一次新的。) ### 工作區長什麼樣(0.5 定案後的結果) memory/import// ├── work.json 書名、slug、建立時間、顯著度配額 ├── names.json 正名表(譯名 → 關係節點 name) ├── skipped.jsonl 跳過紀錄(章節、理由、時間) └── candidates.jsonl 記憶候選(欄位見下面那張表) ## 階段 1:每一章(可平行,一章一把劍) > 這一段是**執行程序**,不是要蓋的東西——真的匯一本書的時候才會逐項發生。 > 程序已經落地成技能:`skills/persona-story/SKILL.md` 第 ③ 節, > 七項與知情層級的細節在 `reference/extract.md`。下面的清單留著當對照表。 - [ ] 1.1 讀章節。只讀這一章,不要跨章推論 - [ ] 1.2 修亂碼 → 轉繁體中文 → 依正名表**正名** (必須在 1.3 之前;亂碼或簡體字形會讓名字比對失敗) - [ ] 1.3 判斷人格**在場或知情**。兩者皆否才跳過 - [ ] 1.4 跳過的章也要寫進跳過紀錄檔——靜默跳過會漏章,事後查不出來 - [ ] 1.5 把在場段落切成**場景**(換地點、換對手、換目的就切;一章通常 2 到 5 個) - [ ] 1.6 每個場景抽七項:故事內時間、地點、在場人物、發生什麼、**他**做了什麼、他當下情緒、他說過的原句一到兩句 - [ ] 1.7 標**知情層級**:我做的/我看到的/別人告訴我的/事後才知道 - [ ] 1.8 轉第一人稱、壓成摘要。原文長段不留,只留他自己的台詞 - [ ] 1.9 新人物**先建關係節點**(`relation node`),再寫記憶 (順序反了 `about` 對不到 id;`name` 用會被說出口的完整稱呼,親密度查 `persona-relation/reference/closeness.md`) - [ ] 1.10 輸出這一章的**記憶候選 JSON**(欄位見下) - [ ] 1.11 抽**語氣樣本**:他自己講的原句,照抄不改寫,附對象與場合(戰鬥/日常/道別) - [ ] 1.12 抽**情緒反應對照**:事件 → 他實際做了什麼(不要記「他感到什麼」) - [ ] 1.13 若這章與現有 `SOUL.md` 矛盾,開一則**個性校正提案**(只提案,不寫入) ### 記憶候選 JSON 欄位 ``` name 檔名用的 slug title 一句話標題 type canon(設定)/event(發生過)/insight(他自己的體悟)/promise(承諾)/boundary about 人名,照抄關係節點的 name,一字不差(解析只認完全相等) topics 2-4 個小寫關鍵詞,跨章沿用同一組 salience 照 0.4 的配額給,不要每則都高 emotion 那一刻的情緒(固化進欄位,不要重放去洗情緒基線) first_seen 故事內時間,不是匯入日期(寫進長期記憶時會落在 `happened_at`,見下方警告) source 書名+章節(可追回出處) body 第一人稱摘要 quote 他自己說過的原句(可省) know_level 1.7 的知情層級 date_source canon(原作明寫)/derived(推算)/guess(只抓大概) ← Q3 追加 ``` 寫進長期記憶時,`body` 會照 0.2.0 的格式切成「主旨/細節」兩層(衰減先吃細節), 並自動蓋上 `strength`/`when`/`where`/`mood`。`date_source: guess` 的記憶 在回答日期問題時走模糊態界線:可以說不確定、可以問,不可以斷言。 ### ⚠ 劇情時間不可以寫進 `first_seen`/`last_seen`(踩過一次) 那兩欄是**記憶的新鮮度時鐘**:`memoryStrength()` 拿 `last_seen` 算衰減。 把劇情日期塞進去等於宣告「這則記憶上次被想起是兩年前」——實測 2024 年劇情的記憶 匯進去的**那一秒**就是模糊 0%,而且掉到 0% 之後 `touchRecall` 不再更新它,永遠回不來。 只有 `canon` 與 `salience >= 80` 靠保護清單活下來,40 到 79 分的 event 全部出生即死。 所以兩種語意分成兩組欄位: | 欄位 | 意思 | 時間 | | --- | --- | --- | | `first_seen`/`last_seen` | 這則記憶什麼時候形成、上次什麼時候想起 | 真實時間(匯入當天) | | `happened_at`/`happened_until` | 故事裡這件事什麼時候發生 | 劇情時間(配 `date_source`) | 候選 JSON 照舊填 `first_seen`(那是抽場景時自然的講法),`novel write` 會把它搬到 `happened_at`,`first_seen`/`last_seen` 一律是匯入當天。 ## 階段 2:全書收斂(章節都跑完之後) - [ ] 2.1 跨章**去重合併**:同一件事只留一則;`salience` 取高、`first_seen` 取最早、`last_seen` 取最晚 - [ ] 2.2 依配額**重新定標**:90+ 只留真的改變他的那幾件 - [ ] 2.3 **人工抽查十則**,專看有沒有視角越界(他不該知道的事) - [ ] 2.4 批次寫入:一則一檔 `consolidate`;情緒欄位只固化不重放 - [ ] 2.5 更新關係圖與心智圖 - [ ] 2.6 跑 `relation doctor`,確認 `about` 全部對得上(歧義與對不到的都要處理完) - [ ] 2.7 重建索引、同步 Gitea - [ ] 2.8 另寫一則 meta 記憶:這批來自哪本書、哪些章、匯入日期 - [ ] 2.9 回歸驗收:問幾個只有書裡有的問題,看他答得出來、且不越界回答他不在場的事 ## 階段 3:語氣與情緒(跟記憶分開走) 記憶是「發生過什麼」,語氣與情緒是「他怎麼反應」。分三層存,改動權限不同。 | 層 | 存哪 | 誰能改 | 來源 | | --- | --- | --- | --- | | 語氣樣本 | 人格倉庫的語氣檔(例如 `voice/samples.md`) | 匯入流程可直接寫 | 1.11 累積的原句 | | 情緒反應規則 | 語氣檔的反應段 | 匯入流程可直接寫 | 1.12 的事件→反應對照 | | 個性(`SOUL.md` 的 Core Truths/Boundaries/Vibe) | `SOUL.md` | 只有使用者拍板才能改 | 1.13 的提案 | ### 3A 語氣(統計,可直接落地) - [ ] 3A.1 句長分布 → 定一句話的上限與斷句時機 - [ ] 3A.2 高頻詞與口頭禪 → 定他會說的字 - [ ] 3A.3 他**不會**說的說法 → 禁語表(比正面規則有效) - [ ] 3A.4 對不同人的稱呼與語氣差 → 對上語氣層(`bond` × 親近度) - [ ] 3A.5 沉默與迴避的時機 → 什麼時候不回答比回答像他 - [ ] 3A.6 場合差(戰鬥/日常/道別)→ 同一個人在不同場合的句子形狀 - [ ] 3A.7 語氣檔寫入後,抽幾句實際對話對照,看有沒有變成模仿腔 ### 3B 情緒 - [ ] 3B.1 每個場景只記「事件 → 他做了什麼」(情緒要演出來,不是旁白說明) - [ ] 3B.2 全書跑完才用**統計**定情緒基線 (逐則套 delta 等於讓最後一章決定他的性格) - [ ] 3B.3 統計每種情緒的觸發類型與強度上限 → 得到「什麼事讓他生氣而不是害怕」 - [ ] 3B.4 掩飾模式單獨記(嘴硬、換話題、講笑話)——這是人味的來源,不是情緒值 - [ ] 3B.5 基線寫入前跟現況比差值,超過門檻要人看 ### 3C 個性校正 - [ ] 3C.1 提案要寫齊:哪一章、原文依據、與 `SOUL.md` 哪一句衝突、建議怎麼改 - [ ] 3C.2 收斂階段把提案彙整成一份 diff - [ ] 3C.3 使用者逐條核可 - [ ] 3C.4 核可過的才寫進 `SOUL.md`,並固化一則 `insight` 記錄為什麼改 - [ ] 3C.5 沒核可的提案留著不刪——下一本書可能出現同樣的證據 --- ## 未決事項 四題已移到最前面的階段 -1,實作前先問使用者。這裡只留答案回填欄。 | # | 問題 | 使用者的答案(2026-08-03 拍板) | | --- | --- | --- | | Q1 | 語氣檔放哪一層 | 新開 `voice/`:`samples.md`(他自己講過的原句,附對象與場合)、`reactions.md`(事件 → 他做了什麼)。匯入流程可直接寫這一層,`SOUL.md` 維持只有使用者能改——權限界線要有實體隔離,不靠自律 | | Q2 | CLI 子指令或 skill 編排 | **混合**。機械的進 CLI(正名、去重合併、配額重定標、批次寫入、跳過紀錄),判斷的留 skill(在場與知情、切場景、第一人稱摘要、個性校正提案)。跟 `sleep` 同一個分工方式 | | Q3 | 分多本時時間軸怎麼接 | **換算成西元日期**(`first_seen: 2022-11-06`)。跟現有的 `strength`/衰減公式同型,`memoryStrength()` 直接算得動。原作沒明寫的地方要換算,所以下面 0.3 多一條規則:換算來的日期一律標記,不可以看起來跟明寫的一樣 | | Q4 | 情緒基線差值門檻 | **任一格差 10 以上就停下來給人看**(3B.5)。基線是氣質,改了等於換一個人 | ## 依 Q3 追加的規則(換算日期不可以假裝是明寫的) 換算成西元日期換來一個新風險:**猜出來的日期看起來跟原作明寫的一模一樣**。 所以 `first_seen` 之外要多一個欄位記來源: | `date_source` | 意思 | | --- | --- | | `canon` | 原作明寫的日期(SAO 開服 2022-11-06 這種) | | `derived` | 由明寫的日期推算(第 74 層攻略是開服後第幾天) | | `guess` | 只能抓大概(某卷「大約半年後」) | `guess` 的記憶在回答日期類問題時**不可以斷言**——這剛好接上 0.2.0 的模糊態界線: 可以說不確定、可以問,不可以斷言。