Sticker 模組文檔治理審查:冪等性設計、Settlement 契約與 Phase 分類決策¶
文檔資訊
- 分類: architecture
- 難度: advanced
- 預估閱讀時間: 8 分鐘
- 標籤:
document-governance,idempotency,settlement-contract,technical-debt,phase-classification,game-server,twirp,sticker-module
摘要¶
對 feat/sticker 分支進行全面文檔治理審查,識別文檔與程式碼不一致問題(F-series)、架構正確性 bug(A-series)、整合安全邊界(B-series)、容量決策(C-series)和驗證 gate(D-series)。最終收斂:A4(BumpDataVersionAndLog 缺失)已修,A1(OpenStickerPack request-level idempotency)是唯一剩餘 branch-local contract gap,其餘分類為 Phase 3 入口 blockers 或 go-live gates。
關鍵學習¶
-
文檔治理審查要區分三類問題:branch-local code bug、Phase 3 入口 blocker、production go-live gate,三類有不同的修正時機
-
OpenStickerPack 冪等性存在兩種設計路徑:explicit idempotency_keys gate(原承諾)vs 天然冪等(item consume + FOR UPDATE);不能靠改文檔降級契約承諾來結案
-
SettlePlayer 必須只讀 snapshot + frozen_config,不能讀 live Luban config,否則 rerun/replay 在內容變更後會產生不同結果,打破 immutable-settlement 契約
-
data_version + changelog 契約:任何修改 inventory/currency/stats 的操作都必須呼叫 BumpDataVersionAndLog,否則 client sync 契約失效
-
文檔 split-brain(多份規格互相矛盾)比純 code bug 更危險,因為它會讓後續開發者各自取用不同版本的「正確」定義
技術細節¶
文檔治理審查方法論¶
審查分兩個維度進行: 1. 文檔 vs 程式碼一致性(F-series):找出文檔與實際程式碼的具體差異,判斷哪一邊是 source of truth 2. 架構正確性(A/B/C/D-series):找出功能缺失、設計矛盾、未完成的整合
冪等性設計的兩種路徑¶
路徑一:Explicit idempotency_keys gate
優點:client 拿得到原始開包結果,支援 replay contract路徑二:天然冪等(FOR UPDATE + item consume)
優點:實作簡單,不需要額外 idempotency 表 缺點:第一次 commit 成功但回應丟失時,client 拿不到原始開包結果Settlement Contract 核心要求¶
SettlePlayer必須讀 frozen_config(snapshot 時凍結),不能讀 live config- 任何狀態變更必須呼叫
BumpDataVersionAndLog ResolveContentClosure必須輸出 deterministic closure bytes,支撐 content_hash
Phase 分類標準¶
| 分類 | 定義 | 修正時機 |
|---|---|---|
| Branch-local bug | 當前分支的 code/contract gap | 現在 |
| Phase 3 入口 blocker | Phase 3 開始前必須解決 | PR 前或 Phase 3 開始前 |
| Production go-live gate | 上線前必須完成 | 上線前 |
What Changed¶
已完成的修正¶
A4(BumpDataVersionAndLog)已在 sticker_season_handler.go:396 實作,注入 PlayerDataVersionPort,SettlePlayer 結尾呼叫 BumpDataVersionAndLog。這是最關鍵的 bug 修正。
F-series 文檔修正已完成,包含 OpenPack 函式簽名對齊(*rand.Rand 不是 context.Context)、UpdateProgress 時序、data_version bump 描述、mapError 程式碼對齊、Twirp 介面名稱(StickerService 不是 StickerServiceServer)等。
識別但分類為 Phase 3 的項目¶
A2(ResolveContentClosure 仍是 placeholder)、A3(SettlePlayer 仍讀 live config)、A5(reward pipeline 未接完)、A6(mock/noop wiring 仍在)均確認為 Phase 3 入口 blockers,不是當前分支 bug。
唯一剩餘的 Branch-local Gap¶
A1 仍未收斂:sticker_service.go:128 沒有 request-level idempotency gate,而 07_test_plan.md:70、08_implementation_plan.md:352 仍要求原始承諾,04_usecase_flows.md:107 已被改成天然冪等版本,三份規格互相矛盾(split-brain 狀態)。
So What¶
這個審查流程建立了一個可複用的文檔治理 checklist,特別是「不能靠改文檔降級契約承諾來結案」這個原則。
對於遊戲伺服器的隨機抽卡 RPC,冪等性設計直接影響玩家體驗:第一次 commit 成功但回應丟失時,「天然冪等」方案無法讓 client 拿到原始開包結果,玩家只能推測狀態。這在 gameplay 場景下是 correctness/contract gap,不只是 UX 問題。
data_version + changelog 缺失的危險性:如果 SettlePlayer 改了 inventory/currency/stats 卻沒有 BumpDataVersionAndLog,client 的 sync 邏輯不會被觸發,玩家看到的資產狀態會與 server 不一致,直到下次強制 full-sync。
Trade-offs¶
- Explicit idempotency gate vs 天然冪等:前者增加 DB 表和查詢複雜度,但支援 replay contract;後者實作簡單,但失去 client 可取回原始結果的能力
- Phase 分類的鬆緊:分類太嚴(都列為現在要修)會阻塞 PR;分類太寬鬆(都推後)會讓技術債累積進 Phase 3
- 文檔降級 vs 補實作:改文檔放棄承諾速度快,但一旦降級就很難再往回拉;補實作成本高但契約一致性不打折
Try It Fast¶
# 驗證 BumpDataVersionAndLog 是否已在 SettlePlayer 中被呼叫
grep -n "BumpDataVersionAndLog" internal/modules/sticker/sticker_season_handler.go
# 確認 PlayerDataVersionPort 已注入
grep -n "PlayerDataVersionPort" internal/modules/sticker/sticker_season_handler.go
# 檢查 A1 split-brain:三份規格的冪等性描述
grep -n "idempotency" docs/sticker/04_usecase_flows.md
grep -n "idempotency" docs/sticker/07_test_plan.md
grep -n "idempotency" docs/sticker/08_implementation_plan.md
# 確認 openStickerPack 是否有 idempotency gate
grep -n "idempotency\|request_id" internal/modules/sticker/sticker_service.go
Recommendation¶
- 立即處理 A1:在合併 PR 前,必須選定單一冪等性設計路徑,並將
04_usecase_flows.md、07_test_plan.md、08_implementation_plan.md三份文件收斂到同一版本 - 建立 Phase 3 入口 checklist:將 A2/A3/A5/A6/D1 寫入追蹤文件,確保 Phase 3 開始前有 review gate
- 不降級契約承諾:對於已承諾的 replay contract,應補實作而非改文檔降級;一旦降級,後續要恢復承諾的成本更高
- 文檔 split-brain 要即時消除:任何規格互相矛盾的狀況應在發現當下解決,不要帶進下一個 phase
- 容量模型統一(C1):在 Phase 3 前確認全服容量基準(1M CCU/10M DAU vs 25M DAU)哪個適用於哪個文件,避免 sizing/benchmark/runbook 各自引用不同數字