跳轉到

D-20260802-11|觀戰可驗結果與共用 Result 生命週期

背景與驅動力

共用 RacePage 已讓 participant 與 spectator 使用同一場景生命週期,但 spectator-stream 終局仍只有房主送出的 race-over 字串。該字串不能證明 MatchResult 已定稿,也沒有原 RoomId;直接據此顯示結果會形成第二套、不可驗證的結果權威。

考慮過的選項

  • 由房主把完整 MatchSummary 放進 spectator-stream:快,但觀戰端只能信任房主,否決。
  • 收到 race-over 後以目前頁面狀態拼出摘要:會把 provisional UI 冒充定稿結果,否決。
  • transport 只送結果參照,內容一律讀既有 verified MatchResult(採納)。

決定

  • 正常終局改送 result-ready { matchId, roomId };matchId 必須是 64 位小寫 digest,roomId 必須是 canonical UUIDv4。它只是查詢與返回房間的 context,不是結果內容或資格證明。
  • race runtime 只有在已驗證套用的 MatchResultEvent 出現後才廣播 result-ready。觀戰端 還要將兩個 id 與目前 RoomSession 比對;不一致即回原 RoomPage。
  • spectator ResultPage 不接受 transport summary,只用 matchId 查 ledger-backed MatchRecord; 未完成時顯示驗證中,查無或驗證失敗不顯示 provisional result 並回原 RoomPage。
  • participant 的現場 summary 同樣只在鏈上確認後產生;角色共用公開排名、回合、最快圈、 結束原因、破壞統計與 rating/reward 欄位。participant 可再戰,spectator 只有手動回房。
  • RoundResult 必須將 endReason 納入多簽內容;首發前沒有舊正式紀錄,缺欄資料不是 current shape 並在 admission 拒收。歷史 TrueSkill delta 由 economySettlement 的 verified baseLogHeadCids 重播既有 deterministic rating transition。
  • noteMatchOver 只清 active-match hint,保留 RoomSession admission context,使用者看完結果 再手動回 /room/:roomId。觀看來源重建失敗改為中性 source-unavailable 並直接回房;原 host 離線本身不是終局。

後果與影響

MatchResult 多簽與 ledger admission 維持唯一結果權威;spectator-stream 不承載可偽造的摘要。 正常終局與異常斷線成為不同 discriminator,wire 可 fail-closed。舊 MatchResult 可繼續顯示, 但只有新紀錄保證具備可驗的回合結束原因。