Phase:M01 — Multi-Source Character Content Expansion
類型:M Phase(Modification / Maintenance Phase)
A~N 是截至 2026-09-06 已完成的 Character Content baseline;M01 現為長期保持 open 的 Character Content Expansion / Maintenance track。M01-O 已拍板為 XGE / TCE Feat Expansion。本文件定義 M01-O 與未來 M01-P+ 必須延續的工程契約,以及已完成 baseline 不可破壞的邊界。完成後必須為真以實作規格.md為準;測試證據以測試指南.md為準。
最後更新:2026-09-13
已完成:
M01-A — Multi-Source Content Pack Foundation
M01-B — PHB Character Origins & Background Expansion
M01-C — SCAG / GoS Background Expansion
M01-D — VGM Race Expansion
M01-E — SCAG Half-Elf Variant & Grant Replacement
M01-F — VRGR Lineage & Dhampir
M01-G — TCE Artificer Core
M01-H — TCE Artificer Advanced Features & Infusions
M01-I — TCE Optional Class Features & Fighting Styles
M01-J — 2014 Class Subclass Expansion
M01-K — PHB Feat & Spell Catalog Expansion
M01-L — VGM & SCAG Remaining Race Expansion / Generic Race Mechanics
M01-M — MTF Planar Race Expansion & Tiefling Bloodline / Variant System
M01-N — Character Sheet HTML Export
這些 Subphase 的完整歷史實作細節與 closeout 證據留在 git history、M01-*_CLOSEOUT.md 與現有測試中;它們不是待辦。
已拍板、尚未實作:
M01-O — XGE & TCE Feat Expansion
下一個未使用字母是 M01-P。 不預留任何字母給 Full M01 Integration & Closeout。M01可以長期保持 open,同時 P2、P3… 正常往前;每個新 M01 Subphase自己設計、自己 closeout。
未來只有在使用者正式拍板某批內容/角色系統維護工作時,才把該 Subphase加進三份 M01文件。不要預先拆 P/Q/R。
M01-O+ 開工時一律以當下 main 真正 codebase再次核對 signatures;不能假設 2026-09-06 的 file layout 永遠不變。
目前 baseline的重要語意:
CharacterBuild 是 immutable versioned snapshot。CharacterState 是 mutable live state。CharacterBuild。<pack-id>:<kind>:<index>;display string不是 identity。CharacterBuild.content_sources是 final Build actual provenance,不是 allowlist。data/多一個目錄就自動啟用。zh-TW / en localization使用 M02 SSOT,不建立 M01專用翻譯系統。任何新 M01 都必須延續這些邊界,除非新的正式 Subphase規格明確、有證據地修改 contract。
正式 runtime source:
data/<pack>/...
data/rules/...
existing localization SSOT
docs/暫用規則資訊/ 只作 human / maintainer authoring reference。
固定流程:
reference
→ authoring / normalization
→ checked-in data/<pack>/ + localization
→ runtime Content Registry
禁止 production runtime parse / fetch / import Markdown。正式 package沒有 docs/ 時仍要工作。
新 pack必須:
可擴充:choice、grant、replacement、level gate、lineage、optional feature、expanded option、retraining、subclass progression、feat prerequisite / acquisition、resource metadata、movement、closed conditional rule等。
禁止為 future books預造:
arbitrary expression language
user-authored scripts
generic Combat trigger DSL
generic effect interpreter
unbounded condition language
需要 P3/P4/P5/Rest/Adventure等 substrate的效果可以 structured + manual / deferred;不要從 M01偷跑未來 engine。
新內容若與既有機制同類,優先重用/泛化:
禁止 if <race/class/book name>散落成新 engine,除非那真的是來源特有 anomaly correction且有明確理由。
每個新 rule shape先回答:
永久角色決定? → Build / immutable Version
目前可變狀態? → CharacterState
Builder未確認輸入? → Draft
純 content fact? → data/<pack>
不能用 UI方便性決定 persistence ownership。
M01 不再只活在 P0/P1世界。P2 之後,每個新的 M01-O+ 開工前必須先盤點:
本次修改的 shared contracts
→ 現在有哪些 downstream P Phase consumer
→ 哪些需要 regression / migration / DTO compatibility
例如未來修改:
如果 P2已建立 Party Roster / Seat / Session對 Character identity的引用,就必須一併驗證那些 reference 不被新 M01破壞。
不要求每個小型 content-only M01把所有後續 P Phase全跑一次。 只驗直接受影響的 consumer;範圍依 dependency graph決定。
M03 closeout後:
app.content.*
app.domain.character*
shared character persistence / builder logic
必須維持 standalone-safe,不得因 P2多人系統出現後反向 import:
Room
Campaign
Session
Seat
Party Roster
multiplayer-only service
新 M01若碰到 protected Character / Content module,至少 static review:
app.standalone 仍不 import app.main。tests/test_m03_import_boundary.py / composition gate仍涵蓋新命名。新 M01若碰:
Character JSON envelope
builder_provenance
Version payload
State payload
StableKey resolution
import landing / reconstruction
則要同步 review Web↔Standalone exchange。schema變更必須 backward-safe或明確版本化,不得只讓 web path通過。
M02規則持續生效:
zh-TW / en。不要再安排「先英文、以後 M02補」。M02已是基礎能力,不是未來補翻譯的排程箱。
新增 optional JSON field原則上使用 backward-safe default,不因 convenience bulk rewrite所有舊 immutable Build / State。
只有真正需要 relational schema change時才用 Alembic,例如:
新 M01若影響歷史資料讀取,要明確涵蓋:
old Build JSON
old State JSON
old Version History
old builder provenance
old Character JSON export where applicable
Build Edit / Correction產生 Version N+1,不 in-place rewrite Version N。
M01不是 API redesign track。
優先延伸既有 endpoints / DTO;新 API只在既有介面無法合理表達時加入。Frontend保持:
不得為某本書建立平行 Builder、Content Library management、Book enable/disable workflow或 Marketplace,除非未來產品規格另外拍板。
A~N過程建立過很多跨 rule-shape hardening需求,例如:
未來若新 M01碰到其中一塊,應在該 Subphase順手收斂真正重複的 helper與新增 regression;不要把 technical debt全部推給一個不存在的 Full M01 closeout。
同樣地,未來 P Phase closeout若要跑 whole-character cumulative regression,可以引用 測試指南.md 的 cumulative baseline;不代表 M01被關閉。
完整 Magic Items、generic Attunement、item charges/recharge、magic-item modifier automation等目前沒有自動成為 M01 scope。
若使用者之後拍板,做法是:
M01-P / Q / ...
→ 明確 scope
→ 三份 M01 文件同步
→ 實作 / 驗證 / closeout該 Subphase
Artificer既有少量 staged item identity / attunement metadata繼續相容,但不等於 Magic Item subsystem已完成。
以下一律視為設計錯誤:
srd5.1。content_sources同時被當 allowlist與provenance。data/所有資料夾自動 enable未完成 pack。docs/暫用規則資訊/。角色卡上的名稱是前端向 presentation batch 解析出來的結果。若在 server 產生 HTML,等於把 M02 的 localized resolver 與整個角色卡版面在 Python 再實作一次,之後每次改角色卡都要維護兩份呈現邏輯。因此本 Subphase 不新增 server endpoint、不改 DTO、不動 Python。
附帶效果:輸出資料取自前端已持有的 sheet 資料,那份資料本來就經過 server 過濾,所以「只輸出看得到的東西」是結構上成立,不需要額外機制。P2 引入 Seat / Controller 後同樣成立。
用 createRoot 把輸出用的 React 樹掛在一個 detached 節點上,flushSync 後讀 innerHTML。
不得為此把 react-dom/server 加進 client bundle——它目前只在測試用,加進去等於為一顆按鈕擴大所有使用者的下載量。
角色卡的呈現元件必須被輸出重用,不另寫第二套版面。輸出模式與螢幕模式的差別只有三點:
三段全出,不受目前分頁影響
不輸出互動控制(按鈕、輸入、搜尋、分頁列)
依 scope 決定是否輸出 Current State 區段
scope 是輸出模式的參數,不是兩套元件。
inventory 整段來自 CharacterState.inventory_state,角色卡從未呈現 Build 的 starting_equipment。因此角色配置的物品欄是整段不輸出,不是改用 starting equipment 呈現:後者對已升級的角色沒有參考價值,且會逼出一個沒有其他用途的 DTO 欄位。
AC 由 calculate_armor_class(build, state, registry) 得出、會讀目前裝備。角色配置仍輸出 AC並在文件內註明基準,理由是沒有 AC 的角色參考卡難用,而靜默輸出一個依賴隱藏資料的數字不誠實。
樣式以建置期 inline 匯入(Vite ?inline)取得字串後寫進輸出檔的 <style>,不在執行期抓 document.styleSheets——後者在不同建置與瀏覽器下不可靠。
輸出檔內不得出現 <script>、外部 href/src、fetch 或任何網路依賴。字型只用系統字型堆疊。
下載走 Blob + URL.createObjectURL + <a download>,用後釋放物件 URL。檔名需對角色名做檔案系統安全處理。
輸出檔內含 @media print 區塊,只在列印/另存 PDF 時生效,螢幕呈現不受影響。至少處理:淺色底、移除純裝飾的光暈與陰影、卡片 break-inside: avoid、法術網格降欄以符合 A4 寬度。
輸出當下的 locale決定整份文件語言,之後不再變動。新增的 UI文案(按鈕、範圍選項、文件內標題與 AC註記)依 M01永久 contract同一 Subphase交齊 zh-TW / en。
角色卡 header既有的 Character JSON匯出按鈕不動(M03已驗收交付)。新增獨立的 HTML匯出入口,由它提供範圍選擇。合併成單一匯出選單留待日後產品層另行拍板。
CharacterSheetDTO、不改 Character JSON schema、不動 Alembic。tests/test_m03_import_boundary.py 不受影響。Authoring reference 固定為:
docs/暫用規則資訊/專長_TCE_XGE.md
正式資料分別 materialize 到既有 data/xge/ 與 data/tce/,並納入各自 manifest / registry validation。不要新增 xge-tce 混合 pack,也不要因 reference 合併成同一份 Markdown就混掉 source provenance。
實作時新增 deterministic inventory verifier(名稱可依現有 scripts 慣例),至少驗:
XGE feat count = 15
TCE feat count = 15
M01-O total = 30
duplicate StableKey = 0
wrong pack provenance = 0
先以 M01-K 現有 Feat data / acquisition schema做 gap analysis。以下既有能力必須重用,不另起 source-specific欄位:
code + params disabled reason。只有 30 個 Feats確實無法表示的 rule shape才新增 optional typed field;新增欄位需 backward-safe default,舊 PHB Feat不需要 migration rewrite。
Spellcasting atom 擴到 subclass-granted Spellcasting。 現行 {"type": "spellcasting"} 的判定只看 class 層(class data 有 spellcasting 或 class index 落在施法職業集合),Eldritch Knight / Arcane Trickster 這類由 subclass level 3 feature 授予 Spellcasting 的 Build 會被誤拒。M01-O 必須把判定改為以 candidate Build 的最終 facts 為準:
class-level Spellcasting(含 Artificer)
Pact Magic(Warlock)
subclass-granted Spellcasting feature(依已選 subclass 與已達 subclass level 判定)
三者任一成立即通過。判定沿用 canonical feature / subclass StableKey,不用 display name 也不硬列 subclass 名稱清單;未達授予 level 的 Build(例如 Fighter 2 尚未選 Eldritch Knight)仍拒絕。此擴充是共用 atom 的修正,Elemental Adept / Spell Sniper / War Caster 等既有 PHB Feat 會一併受益,closeout 必須把它們的 prerequisite regression納入 M01-K 直接受影響 suite。
M01-O 新增的 racial feat prerequisite不得用 display name比對。prerequisite resolver需要能基於 canonical Build facts判斷:
race StableKey / canonical ancestry tag
subrace / variant lineage identity
size category
OR / AND composition
至少支援:
race == dragonborn / dwarf / gnome / tiefling / half-orc / halflingrace in {elf, half-elf}subrace == drow / high-elf / wood-elfrace in {human, half-elf, half-orc},其中 phb2014:race:variant-human 雖然是獨立 race StableKey,仍正規化成 Human ancestry fact。race == dwarf OR size == smallVariant Human 不是 Human 的 subrace。 Resolver不得依 subrace 關係推導它;shared content facts / ancestry normalization 必須明確讓 phb2014:race:variant-human 滿足 Human ancestry prerequisite,同時保留它自己的 StableKey identity。Half-Elf variant、Tiefling bloodline / variant等既有 replacement composition也不得因此失去其 canonical base ancestry資格。若現有 Build只保存 StableKey而沒有 ancestry tag,應在 shared content facts/resolver補最小 normalization,不在每個 Feat資料內硬列所有 variant StableKey。
Prodigy / Skill Expert等選擇使用 generic nested choice:
Expertise candidate resolver看 candidate Build當下的最終 proficiency facts,並排除已經被同類 double-proficiency效果覆蓋的技能。若同一次 acquisition先選新 skill proficiency,再選 expertise,後一個 choice必須能看見前一個 choice產生的 candidate facts;不要靠前端自行拼候選清單。
Squat Nimbleness的 Acrobatics / Athletics使用同一 skill proficiency primitive;Chef / Poisoner工具熟練亦使用同一 tool proficiency grant。Artificer Initiate 必須從 canonical Artisan’s Tools pool 自選一種工具熟練,將被選工具 StableKey 保存成 acquisition nested choice;同一選擇同時產生「此工具可作為施展任何 INT-based spell 的法器」之 typed focus eligibility,不建立第二個互相可能不一致的工具選擇。 Fey Teleportation 的 Sylvan 使用既有 language grant,不只存在 description。
三個 TCE Feats不得複製 class option data:
Builder的 option identity仍保存原 canonical StableKey;Feat acquisition只保存 entitlement / selected refs / provenance。
需要最小通用的 acquisition-linked retraining policy,而不是用 feat名稱 hardcode:
never
on_any_level_up
on_asi_level_up
M01-O mapping:
Eldritch Adept → on_any_level_up,替換 1 invocation
Fighting Initiate → on_asi_level_up,替換該 Feat grant 的 style
Metamagic Adept → on_asi_level_up,替換其中 1 個 metamagic option
Level Up產生 candidate Build / Version N+1;Version N原選擇不可被原地改寫。Build Edit不應被拿來無條件繞過 retraining gate;若產品既有 Build Edit可做 correction,必須沿用其「修正」語意而不是把它變成免費 retraining。
固定法術與選擇法術都 reference canonical spell StableKey,不複製 spell definition。
需涵蓋:
這些是 Feat source的 spell access / free-cast grants,不得混寫成 class Known / Prepared。若 spell因其他 pack已有 canonical identity,直接 cross-pack ref;不要在 xge / tce 重複定義 spell。
Fey Touched / Shadow Touched / Telekinetic / Telepathic的 INT/WIS/CHA +1 選擇同時是該 Feat spellcasting ability。資料模型應讓 spell grant reference同一 acquisition choice結果,例如以 choice id / selected ability token關聯,而不是另外建立第二個可不一致的 casting-ability選擇。
可以由現有 shared substrate安全表示的 mechanic直接接線:
13 + DEX,仍允許 shield;不覆蓋較佳 AC candidate。+5 ft。spellcasting_focus eligibility,scope 固定「該被選工具可作為任何以 INT 為施法關鍵屬性的 spell 的法器」。firearms。 目前沒有 firearms equipment entity 時,不得建立 dangling StableKey,也不得為了 proficiency 順便 materialize DMG firearm catalog。若既有 generic proficiency shape能安全表示 category fact就沿用;否則只新增最小、封閉的 weapon-proficiency category primitive,canonical value 固定為 firearms,未來真正導入 firearm equipment時再由 equipment/combat resolver對接。60 ft、target 必須 visible、訊息使用角色已知語言且目標必須理解、communication 為單向、此能力本身不賦予目標 telepathic reply。這是 Build-owned static capability,不需要 Combat engine。這 2 Sorcery Points有特殊 restriction:
contributes 2 to sorcery-point capability
allowed use = metamagic only
not allowed = flexible casting / other sorcery-point spends
recharge = long rest
若既有 resource model只有「一個無差別整數池」,不得直接把 capacity +2後遺失用途限制。優先補 generic source-scoped resource contribution,例如 contribution保留 source_ref + allowed_spend_tags;presentation可顯示總量,但未來 spend resolver必須能知道哪些點受限制。若目前沒有自動 spend substrate,Current State至少要能不失真地保存/顯示該 contribution,不假裝一般 Sorcery Points完全等價。
每個 M01-O Feat都要明確標示 implementation level,延續 M01-K分類,可視實際 schema沿用/細化:
full_structural
static_derived
structured_deferred_roll
structured_deferred_reaction
structured_deferred_combat
structured_deferred_rest
structured_deferred_inventory
例如:
分類是 machine-readable boundary;不能只把「尚未自動」寫在 Markdown後讓 runtime無法知道。
M01-O原則上不新增 endpoint。既有 Builder choices / validation / Review / Character Sheet DTO能承接時只擴 content與typed mechanics。
Frontend只渲染 server choices:
code + params。若現有 DTO無法呈現某個已正式存入 Build的 nested selection,才做最小 additive DTO欄位;不得順便 redesign Character Sheet。
預期以 content data + backward-safe JSON extension為主,不預設需要 Alembic migration。只有實際 gap analysis證明需要 relational shape時才新增 migration。
至少保證:
old PHB feat Build仍可讀
M01-O Build reload/restart不丟 acquisition choices
Version History保存 retraining前後版本
content_sources derive xge / tce
Character JSON round-trip保留 M01-O StableKey與必要 selections
若新增 optional Build/State field,舊資料缺欄位必須有 safe default。
M01-O碰 Content Registry、Feat Builder與可能的 Build JSON optional fields,因此至少需要 M03 standalone compatibility review。新增 helper放 shared Character / Content層,不反向 import Room / Campaign / Session / Seat。
P2 Room Character Workspace是直接 UI consumer:至少確認在 Room內 Create / Level Up / Build Edit仍能取得新的 Feat choices。P3只要 Character identity / sheet payload contract未改,原則上做 static/focused compatibility即可;若最終實作改了 shared DTO/schema,再擴大到實際受影響的 P3 regression。