Phase:P1 — Character Builder Complete
本文件定義 P1 各 Subphase 如何驗收。P1-H 必須最終證明實作規格.md的 AC-P1-01 ~ AC-P1-12,而不是只證明「Wizard 可以按下一步」。
最後更新:2026-08-29
P1 的測試證據分為:
每個 Subphase 必須先通過自己的測試再進下一個;不要把 P1-A~G 的驗證全部拖到 P1-H。
所有 Builder fixture 必須 deterministic、可程式建立,不依賴人工先在 UI 建角色。
測試必須分清:
Draft legality
Build compile result
Current State seed / reconciliation
Character Sheet derived result
不能只 assert HTTP 200 或 can_confirm=true。
三份 P1 文件的 Subphase 標題必須完全一致。
對應主要契約:AC-P1-01、AC-P1-11、AC-P1-12 的基礎。
至少測:
blocking_error,而不是 Pydantic parse整份 Draft失敗。mode / source character / base version組合非法時被拒絕。流程:
Create Draft
↓
PATCH partial choices
↓
close DB / app session
↓
GET Draft
預期:
characters / character_versions / character_states rows。Create Draft
↓
Save
↓
Cancel / DELETE
預期:
至少有固定案例分別產生:
blocking_errorwarningnon_standard每筆 issue assertion:
can_confirm 正確。同一 Draft / same source:
GET
reload server-side view
GET again
Choice ID必須一致。
修改不相關欄位(例如 Character name)也不能導致所有 choice ids重生。
若採 optimistic revision:
P1-A 每次 CI 至少重跑:
對應主要契約:AC-P1-02、AC-P1-11。
至少驗:
針對 SRD content fixture至少驗:
Production SRD 5.1 目前只有 Acolyte,因此測試必須把『內容只有一筆』和『Builder 機制只能處理一筆』分開。
至少:
data/srd5.1/ production content。測試:
具體 Standard Array數字以 P1 rules data / test fixture為準,不在本指南複製規則表。
至少:
至少:
固定 fixture驗:
base generation
+ race/subrace permanent grants
= resolved Build score
P1-D後再增加 ASI / Feat。
Character Sheet重新計算時不再加 race grant第二次。
至少測:
至少覆蓋:
Real backend:
/characters
→ Create Character
→ 填 Name / Target Level
→ Race / Background
→ Ability method
→ Save
→ browser reload
reload後所有輸入與已選 reference保留。
blocking_error 且 can_confirm=false;P1-B 不依賴 P1-F Confirm endpoint。對應主要契約:AC-P1-03、AC-P1-04。
建立 deterministic scenarios:
Fighter 1→5
Fighter 1→5 → Wizard 1→5
Wizard 1 → Fighter 1 → Wizard 2...
每個 scenario assert:
class_progression[]。UI直接 Target Level 10仍必須有 10 個 progression nodes。
禁止只送:
fighter=5, wizard=5
卻無法知道順序。
至少以兩個不同 class順序驗:
Fighter → Wizard
Wizard → Fighter
預期 starting saves / proficiencies等依 Lv1 class不同;後加入 class只取得 multiclass grants。
至少:
每個代表 class至少測:
到達 level後:
驗:
至少:
len(hp_progression) == len(class_progression) == character_level。
修改中間 level後 compile / reload仍保持1:1。
流程:
建合法 Lv10 Draft
↓
修改 Lv3 class
預期:
至少一條:
Create target Lv10
→ level rail逐級選 Fighter 5 / Wizard 5
→ 選 subclass
→ 設 HP methods
→ reload
assert rail順序與已填資料保留。
對應主要契約:AC-P1-05。
建立 multiclass scenario,讓 total level與某 class ASI timing不同。
assert:
直接使用 production levels.json 的 Fighter level rows 驗 cumulative semantics:
Fighter Lv4: cumulative 1, previous 0 → delta 1 → 1 個 ASI/Feat node
Fighter Lv5: cumulative 1, previous 1 → delta 0 → 0 個 node
Fighter Lv6: cumulative 2, previous 1 → delta 1 → 1 個 ASI/Feat node
必測負向:
ability_score_bonuses > 0 當本級 occurrence,Lv5 測試必須失敗。delta >= 0。delta,不是只驗 boolean。至少測:
以 SRD可用 Feat fixture:
固定案例:
calculated ability不足 prerequisite
→ feat fail
加入合法 Numeric Override使 effective ability達標
→ feat pass
另驗:
Numeric Override
→ 不能讓 Lv1 Fighter提早選 Lv3 subclass
→ 不能創造額外 ASI occurrence
→ 不能把 choose 2改成 choose 3
對目前 SRD實際存在的 choice shapes做 parameterized tests:
測試應由 representative content entries驅動,不只手刻 dummy object。
若 Build新增 builder trace:
至少一條高等 Fighter:
progress to ASI level
→ 選 ASI
→ Summary能力更新
→ 改成 Feat
→ prerequisite提示
→ Review未來可讀
對應主要契約:AC-P1-06、AC-P1-10 的 spell state部分。
至少建立:
至少:
spellbook Build access。access_type="prepared"。驗:
若 P1-E調整 Prepared schema,必須加入 P0 Wizard fixture compatibility test。
至少一個 subclass / feature來源:
建立同一 spell由兩個 source取得的 scenario:
使用固定 progression scenarios比對 D&D 5e 2014 rules data預期。
至少含:
不要只測一個 Lv10數字;測 boundary / floor behavior。
spell_slots_level_2 = 2,adapter仍分類為 Pact Magic,不能進 normal combined-slot pool。spell_slots_level_N;禁止以欄位名稱判斷 pool type。若 State維持 used + remaining:
若 migration成usage-only:
對應主要契約:AC-P1-07、AC-P1-08、AC-P1-11。
從實際 SRD class data挑 representative nested options,至少覆蓋:
每個 scenario assertion:
P1 UI / API標準 Builder:
assert:
CharacterBuild.starting_equipment[] deterministic。Create Confirm後:
Build Starting Equipment
→ initial State inventory
assert第一次一致。
接著:
remove / add / quantity / equip state mutation
→ reload
assert live Inventory保持最後 State,不由 Build重新洗回。
Create Confirm fixture:
至少測:
can_confirm=false。故意在不同階段造成失敗:
預期每次:
P1-F migration / Create Confirm至少驗:
version_kind=legacy,Build payload canonical equivalent不變。version_kind=create。parent_version_id / correction lineage為 null。快速重複 Confirm:
至少一條 non-caster與一條 caster:
/characters
→ Create
→ 完整 Wizard
→ Review
→ Confirm
→ /characters/:id
→ reload
assert Character Sheet關鍵摘要與 Builder Review一致。
對應主要契約:AC-P1-09、AC-P1-10。
P1-F 已完成 schema migration / legacy backfill;P1-G 驗證後續版本沿用同一 metadata contract:
version_kind=legacy。version_kind=create。level_up / build_edit / correction。建立既有 Character:
current version N
↓
create level_up draft
assert:
assert:
Level Up Draft Cancel:
流程:
Create Draft A from v3
Create Draft B from v3
Confirm B -> v4
Confirm A
A必須被拒絕 stale_build_version;不可建立覆蓋v4的v5 based on stale data。
固定案例:
old current/max = 30/40
new max = 48
預期:
38/48
另測:
固定 usage fixture:
capacity下降 correction:
普通升級:
multiclass切換不同 hit die:
correction total下降:
Scenario A:新 Build仍允許既有 prepared → 完整保留。
Scenario B:Build correction移除 spell access → prepared變非法:
使用者修正 prepared choice後才可 Confirm。
Level Up前先建立非初始 Current State:
Level Up Confirm後assert上述保持,除非明確 invariant需要調整。
API / UI:
流程:
current v4
→ Correct Build Draft
→ Confirm
→ v5 correction
assert:
P1-H 對應 AC-P1-01 ~ AC-P1-12 全部。
至少跑:
pytest
包含:
data/srd5.1/ Character-Relevant content仍全綠。data/rules/dnd5e-2014/(若有)有 schema / manifest / required-value validation。必須驗:
npm install / ci
TypeScript build
Vitest
至少覆蓋:
完整 real backend:
Workshop
→ Create Lv1
→ Race / Background
→ Ability
→ Class / choices
→ Equipment
→ Review
→ Confirm
→ Sheet
→ reload
至少一條 target high level:
Confirm後讀 Character Sheet與Version 1。
Open existing character
→ Level Up
→ Add class level
→ choices
→ reconciliation preview
→ Confirm
→ Sheet
→ Version History
在 Builder中途 reload:
PostgreSQL full stack:
Create Draft / Character
↓
restart backend
↓
reload
Draft / Character / Version / Current State全部從 DB回復,不依賴 process memory。
既有 P0 fixture:
至少有以下 categories 的 deterministic acceptance:
| Scenario | 驗證重點 |
|---|---|
| Lv1 non-caster | starting grants / ability / equipment / initial State |
| High-level Fighter | subclass / ASI / Feat / HP progression |
| High-level Wizard | spellbook / prepared / slots |
| Prepared caster | prepared eligibility / State separation |
| Known caster | known progression / replacement |
| Fighter / Wizard | class order / P0 compatibility |
| two-source caster multiclass | combined slots / source separation |
| Warlock multiclass | Pact Magic pool separation |
具體數值存 test fixtures / rules data,文件不建立第二份規則表。
至少從 API層嘗試繞過 UI:
全部必須 Server拒絕且不留下 partial commit。
至少人工檢查:
只有以下全部成立才可進 P2:
P1-H 關門後才開始依當時 codebase規劃 P2 Subphases。