Activity Framework & Sticker 系統 Phase 3 就緒性審查:blocker 識別、介面修復與 Phase 邊界判定¶
文檔資訊
- 分類: debugging
- 難度: advanced
- 預估閱讀時間: 6 分鐘
- 標籤:
activity-framework,sticker,phase3,interface-mismatch,go,readiness-check,GetPlayerProgress,ResolveContentClosure,ScheduleConfigLoader
摘要¶
針對 Activity Framework 與 Sticker 系統進行 Phase 3 就緒性審查。發現三個真正的 pre-Phase 3 blocker:sticker 編譯失敗(GetPlayerProgress 型別不符)、ResolveContentClosure 仍是 stub、ScheduleConfigLoader 缺失。同時澄清 main.go 未接線是 Phase 3 本身的工作,不應列為 blocker。修復了 GetPlayerProgress 介面不相容後正式進入 Phase 3。
關鍵學習¶
-
Phase 3 就緒性審查需區分『Phase 3 前必修』vs『Phase 3 本身要做』的邊界
-
go test ./internal/modules/sticker/...build fail 是直接 blocker,不能靠整合測試掩蓋 -
介面契約(如 GetPlayerProgress 回傳型別)的不相容會在 go build 階段就阻斷,不是 runtime 問題
-
ResolveContentClosure stub 會讓 activity admission / config sync / settlement 都處於半殘狀態
-
文件治理要同步:readiness register 的 OPEN/Closed 狀態必須在修復後立即更新
技術細節¶
問題背景
Activity Framework 與 Sticker 系統在進入 Phase 3 前需要通過就緒性審查,但審查過程中發現多個問題。
Blocker 1:GetPlayerProgress 介面型別不符(直接 build fail)
// activity_handler.go:37 期望的介面
GetPlayerProgress(...) ([]byte, error)
// sticker_season_handler.go:411 實際實作
GetPlayerProgress(...) (interface{}, error)
go test ./internal/modules/sticker/... 直接 build fail,這是 pre-Phase 3 必修 bug。
Blocker 2:ResolveContentClosure 仍是 stub
// sticker_season_handler.go:88
func (h *StickerSeasonHandler) ResolveContentClosure() {
return nil, nil // stub,尚未實作
}
以下三個 activity 核心路徑都依賴這個方法:
- activity_admission.go:67(admission 准入)
- activity_config_sync.go:274(config drift detection)
- activity_settlement_service.go:390(settlement frozen-config)
Blocker 3:ScheduleConfigLoader 缺失
activity_config_sync.go:48 只有 SetScheduleConfigLoader(...),但 production 的 LoadScheduleEntries 實作在 repo 中找不到,只有 test mock。activity_twirp.go:488 若 loader 未設定會直接報錯。
非 Blocker(Phase 3 本身的工作)
cmd/twirpserver/main.go:652 之後未註冊 activity/sticker 服務,這是 Phase 3 接線工作,不應列為 Phase 3 前的 blocker。
高風險缺口(不擋 Phase 3 開始,但擋上線)
Luban 有 pkg/config/luban/Enums_RewardType.go:43 定義 type 6/7,但 pkg/reward/resolver.go:22 只支援 item/currency/hero/talent_card 四種,若 sticker 配置用到 type 6/7 會在 runtime 爆掉。
What Changed¶
文件同步修復
C-1(shared reward_claims dedup)與 C-2(season_id schema + migration)兩個問題早已修復,但 docs/activity/07_release_readiness_register.md 的 §1.2 與 §1.3 仍標為 OPEN。依照文檔治理規範將這兩個項目更新為 Closed,並修正 docs/00_README.md:140 中 activity「尚未建立」的過期描述。
GetPlayerProgress 介面修復
修正 internal/modules/sticker/sticker_season_handler.go:411 的回傳型別,從 (interface{}, error) 改為 ([]byte, error),使其符合 activity_handler.go:37 的介面契約。修復後 go test ./internal/modules/sticker/... 通過,完成 commit,正式進入 Phase 3。
So What¶
清晰化 Phase 邊界非常關鍵
在 Phase 3 就緒性審查中,很容易把「Phase 3 本身要做的事」誤判為「Phase 3 前的 blocker」,這會讓 Phase 3 永遠無法開始。本次審查澄清了:main.go 接線是 Phase 3 工作,不是 blocker;真正的 blocker 是介面不相容這類破壞 build 的問題。
介面契約是最嚴格的邊界
GetPlayerProgress 的型別不符在 go build 階段就會阻斷,比任何 runtime 問題都更明確。這提醒跨模組整合前必須先確認介面契約一致,不能依賴整合測試去發現這類問題(整合測試有時會跳過 build fail 的模組)。
Trade-offs¶
- ResolveContentClosure 的修復範圍:若 Phase 3 前完整實作,可確保 activity content hash/drift detection 正確運作;但若留到 Phase 3,phase3 一接上就會是半殘狀態,需要接線工作和 stub 修復同步進行,增加 debug 難度
- ScheduleConfigLoader 缺失:可先用 mock 推進 Phase 3 接線驗證,但必須在上線前補上 production 實作,否則 PreviewConfigSync/SyncActivitiesFromConfig 完全無法運作
- reward type 6/7 支援:可以等到確認 sticker 配置是否真的用到再處理,但若真的用到且沒提前處理,會在 runtime 靜默失敗,難以定位
Try It Fast¶
# 驗證 sticker 模組是否編譯通過(Phase 3 前必做)
go test ./internal/modules/sticker/...
# 驗證 activity 模組
go test ./internal/modules/activity/...
# 驗證整合測試(注意:這個不會抓到 sticker build fail)
go test ./test/... -run "Activity|Sticker|Event"
# 確認 GetPlayerProgress 介面一致性
grep -n 'GetPlayerProgress' internal/modules/activity/activity_handler.go
grep -n 'GetPlayerProgress' internal/modules/sticker/sticker_season_handler.go
Recommendation¶
- Phase 3 前必修:確認
ResolveContentClosure實作(sticker_season_handler.go:88)不再是 stub,否則 phase3 接線後 content hash / drift detection 都是空殼 - Phase 3 前必修:補上 production 的
LoadScheduleEntries實作,不能只有 test mock - Phase 3 進行中:接線
cmd/twirpserver/main.go的 activity/sticker 服務(這才是 Phase 3 本身的工作) - 上線前必修:確認 sticker Luban 配置實際使用的 reward type,若有 type 6/7 需在
pkg/reward/resolver.go補上支援 - 文件治理:每次修復 blocker 後立即更新 readiness register,避免下次審查時誤判 OPEN 項目