adventure-table

M01-N Closeout Checklist

M01-N — Character Sheet HTML Export closeout scope:

Verification evidence

2026-09-06 最終驗證,分支 m01-n-character-sheet-html-export HEAD 60778a5

cd apps/web
npm test -- --run
31 test files / 158 tests passed

npm run build
tsc --noEmit clean;vite build 成功

npm run test:e2e:docker
99 passed, 3 skipped (6.7m);xge-less 第二輪 7 passed

docker compose config
exit 0

Playwright 走 npm run test:e2e:docker,對容器化的 server / web 執行。3 個 skip 中的 2 個是 m03c-character-import.spec.ts 保留給 xge-less 第二輪的案例,該輪已通過;剩下 1 個為既有的 KI-M01J-001test.fixme()),與 M01-N 無關。KI-P1D-001 本輪未重現,但不以單次通過推論根因已修復。

Backend 於 f74e482 執行全套 pytest:966 collected、exit 0、2 skipped。60778a5 只改 apps/web/src/features/character-sheet/,未觸及 backend、DB 或打包相依,故未重跑。

M01-N 相關前端覆蓋為 5 個測試檔共 32 個測試:

檔案 測試數 對應測試指南
apps/web/src/features/character-sheet/CharacterSheetHtmlExport.test.ts 15 9.2 / 9.3
apps/web/src/features/character-sheet/CharacterSheetHtmlExport.static.test.ts 5 9.3
apps/web/src/features/character-sheet/CharacterSheetHtmlExport.build-copy.test.ts 1 9.2
apps/web/src/features/character-sheet/CharacterSheetHtmlExportButton.test.tsx 3 9.2
apps/web/src/features/character-io/ExportCharacterButton.test.tsx 8 9.2

前四個檔案為 M01-N 專屬(24 個測試);ExportCharacterButton.test.tsx 沿用 M03-B 既有檔案,其中 M01-N 新增的是 HTML action 只掛在 Character Sheet placement 的那組斷言,不另建第二套 harness。

瀏覽器覆蓋為 apps/web/e2e/m01n-character-sheet-html-export.spec.ts(2 條真後端 flow:兩種範圍各產出一份檔案、HTML 輸出與既有 JSON 輸出彼此獨立)。

M01-N Closeout Evidence

Scope / expected inventory: 兩種輸出範圍 + A4 列印樣式 + 匯出物品閱讀順序
Content / schema validation: N/A — 不新增內容、不改 schema
Domain legality / calculations: N/A — 不改 Python domain
Persistence / versioning: N/A — 輸出不寫入任何狀態
Localization completeness: PASS(`m01nCharacterSheetExportCopy.ts` 17 條 copy × zh-TW / en 全覆蓋;實際輸出檔雙語確認無混語)
Runtime without docs: N/A — 不從 docs materialize
Focused API integration: N/A — 不新增 endpoint、不改 DTO
Focused Playwright: 2 / 2;合併回 main 前全套 E2E 99 passed / 3 skipped
Restart persistence: N/A — 無持久狀態
Human smoke: PASS(使用者於 2026-09-06 確認:離線雙擊開啟、列印預覽、zh-TW / en 各一份)
M03 standalone compatibility: PASS(靜態 — 零 `apps/server` 改動、無新 server 相依、import boundary 未變)
Downstream P compatibility: N/A — 不碰 shared Character contract
Existing focused regression: PASS(前端 158、build、docker compose config、全套 backend pytest)
Known manual/deferred effects: PDF 產生交給瀏覽器列印;不做歷史版本輸出、批次輸出與輸出檔內互動

關門過程中修正的問題

  1. 索引配對會靜默標錯數字。 applyBuildOnlyProjection() 原本以 DOM 出現順序把 .slot-card / .resource-list > div / .prepared-limit / .condition-chip 對應到投影資料。角色卡日後只要改變這些清單的順序或數量,輸出就會把錯的數值配到錯的列,而且不會有任何錯誤訊號。已改為 pairCharacterSheetIndexRows():以 data-sheet-index-key 做穩定鍵配對,key 缺漏、重複、對不上或有資料項沒配到列時一律拋錯,讓輸出失敗而不是產出錯的角色卡。

  2. 角色配置的法術位面板副標仍寫「伺服器狀態」。 build-only 輸出裡沒有任何 server state,那個副標會誤導讀者。已改為「容量」。

  3. 匯出渲染器與頁面資料存取混在同一個檔案。 CharacterSheetPage.tsx 同時承擔 query 取數與 861 行的呈現,匯出卻只需要後者。已抽出 CharacterSheetView.tsx(純呈現,861 行),CharacterSheetPage.tsx 縮為 79 行的資料存取層並 re-export view;靜態測試要求 view 不得出現 getCharacterSheet / listContent / patchCharacterState / fetch

  4. 列印排版浪費紙。 法術原本兩張一排、物品一張一排,一個中等角色會印成好幾頁。已改為列印時法術三張一排、物品兩張一排。

  5. 匯出的物品欄沒有閱讀順序。 已裝備、未裝備的武器護甲與雜物混在一起。已在匯出 transform 內排序為「已裝備 → 其餘武器/護甲 → 其他」,同組維持原順序;排序只作用於匯出檔,真人角色卡順序不變。

Boundary

已知限制

Handoff

M01-N 已完成並關門。M01 不是 full closeout;A~N 是目前已交付的 baseline,下一個新的 M01 工作從 M01-O 起編號。

下一步是 P2-A — Room Foundation & Web Entry

後續 Subphase 直接繼承 M01-N 的兩項 substrate,不得再造第二套:

M01-N 未新增任何 server 相依,P2 引入多人層時不需要為本 Subphase 調整 standalone import boundary gate。