feat: add durable result policy core

This commit is contained in:
Josh Creek
2026-08-31 20:33:16 +01:00
parent b04f3318b9
commit 864e4e8aaf
3 changed files with 239 additions and 1 deletions
+159
View File
@@ -0,0 +1,159 @@
package domain
import (
"crypto/sha256"
"fmt"
"strconv"
"time"
)
const (
ResultDeliveryAlertAfter = 5 * time.Minute
ResultDeliveryReviewAfter = 30 * time.Minute
)
type IntegrityState string
const (
IntegrityCertified IntegrityState = "CERTIFIED"
IntegritySuppressed IntegrityState = "SUPPRESSED"
IntegrityReview IntegrityState = "REVIEW"
)
var (
ErrResultBinding = fmt.Errorf("result workload binding rejected")
ErrResultConflict = fmt.Errorf("conflicting result")
ErrResultInvalid = fmt.Errorf("invalid match result")
ErrReceiptMissing = fmt.Errorf("result receipt not found")
)
// WorkloadBinding is the identity extracted and validated by the secure
// credential adapter. The domain compares every binding dimension recorded by
// allocation; a shared service-account class is not sufficient on its own.
type WorkloadBinding struct {
Issuer string
Audience string
Namespace string
ServiceAcct string
PodUID string
GameServerUID string
MatchID string
ServerID string
}
type MatchResult struct {
MatchID string
ServerID string
ResultNonce string
Team0Score int
Team1Score int
IntegrityState IntegrityState
}
type ResultReceipt struct {
ResultID string
MatchID string
ResultNonce string
PayloadDigest [32]byte
IntegrityState IntegrityState
ReceivedAt time.Time
CommittedAt time.Time
}
type ResultStore struct {
expected WorkloadBinding
receipts map[string]ResultReceipt
}
func NewResultStore(expected WorkloadBinding) (*ResultStore, error) {
if err := validateBinding(expected); err != nil {
return nil, err
}
return &ResultStore{expected: expected, receipts: make(map[string]ResultReceipt)}, nil
}
// Submit is the durable-transaction boundary in miniature. Production code
// must persist the receipt, match transition, participant penalties/ratings,
// and outbox event atomically around this same decision.
func (s *ResultStore) Submit(resultID string, result MatchResult, binding WorkloadBinding, now time.Time) (ResultReceipt, bool, error) {
if resultID == "" || !sameBinding(s.expected, binding) {
return ResultReceipt{}, false, ErrResultBinding
}
if err := validateResult(s.expected, result); err != nil {
return ResultReceipt{}, false, err
}
digest := resultDigest(result)
if prior, ok := s.receipts[result.MatchID]; ok {
if prior.ResultID == resultID && prior.PayloadDigest == digest {
return prior, false, nil
}
return prior, false, ErrResultConflict
}
receipt := ResultReceipt{ResultID: resultID, MatchID: result.MatchID, ResultNonce: result.ResultNonce, PayloadDigest: digest, IntegrityState: result.IntegrityState, ReceivedAt: now}
s.receipts[result.MatchID] = receipt
return receipt, true, nil
}
func (s *ResultStore) Commit(resultID, matchID string, now time.Time) (ResultReceipt, error) {
receipt, ok := s.receipts[matchID]
if !ok || receipt.ResultID != resultID {
return ResultReceipt{}, ErrReceiptMissing
}
if receipt.CommittedAt.IsZero() {
receipt.CommittedAt = now
s.receipts[matchID] = receipt
}
return receipt, nil
}
type DeliveryHealth string
const (
DeliveryHealthy DeliveryHealth = "HEALTHY"
DeliveryAlert DeliveryHealth = "ALERT"
DeliveryReview DeliveryHealth = "REVIEW"
)
func DeliveryStatus(receipt ResultReceipt, now time.Time) DeliveryHealth {
if !receipt.CommittedAt.IsZero() {
return DeliveryHealthy
}
age := now.Sub(receipt.ReceivedAt)
if age >= ResultDeliveryReviewAfter {
return DeliveryReview
}
if age >= ResultDeliveryAlertAfter {
return DeliveryAlert
}
return DeliveryHealthy
}
func RatingEligible(receipt ResultReceipt) bool {
return receipt.IntegrityState == IntegrityCertified
}
func validateBinding(binding WorkloadBinding) error {
if binding.Issuer == "" || binding.Audience == "" || binding.Namespace == "" || binding.ServiceAcct == "" || binding.PodUID == "" || binding.GameServerUID == "" || binding.MatchID == "" || binding.ServerID == "" {
return ErrResultBinding
}
return nil
}
func sameBinding(a, b WorkloadBinding) bool { return a == b }
func validateResult(expected WorkloadBinding, result MatchResult) error {
if result.MatchID != expected.MatchID || result.ServerID != expected.ServerID || len(result.ResultNonce) < 16 || len(result.ResultNonce) > 128 || result.Team0Score < 0 || result.Team1Score < 0 {
return ErrResultInvalid
}
switch result.IntegrityState {
case IntegrityCertified, IntegritySuppressed, IntegrityReview:
return nil
default:
return ErrResultInvalid
}
}
func resultDigest(result MatchResult) [32]byte {
canonical := result.MatchID + "\x00" + result.ServerID + "\x00" + result.ResultNonce + "\x00" + strconv.Itoa(result.Team0Score) + "\x00" + strconv.Itoa(result.Team1Score) + "\x00" + string(result.IntegrityState)
return sha256.Sum256([]byte(canonical))
}
+79
View File
@@ -0,0 +1,79 @@
package domain
import (
"errors"
"testing"
"time"
)
func testBinding() WorkloadBinding {
return WorkloadBinding{Issuer: "https://issuer", Audience: "cosmic-result", Namespace: "games", ServiceAcct: "match-server", PodUID: "pod-1", GameServerUID: "gs-1", MatchID: "match-1", ServerID: "server-1"}
}
func testResult() MatchResult {
return MatchResult{MatchID: "match-1", ServerID: "server-1", ResultNonce: "nonce-1234567890", Team0Score: 3, Team1Score: 2, IntegrityState: IntegrityCertified}
}
func TestResultStoreBindsWorkloadAndMakesIdenticalDuplicateInert(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, err := NewResultStore(binding)
if err != nil {
t.Fatal(err)
}
first, created, err := store.Submit("result-1", testResult(), binding, now)
if err != nil || !created || !RatingEligible(first) {
t.Fatalf("first result = %+v created=%v err=%v", first, created, err)
}
replay, created, err := store.Submit("result-1", testResult(), binding, now.Add(time.Minute))
if err != nil || created || replay.ReceivedAt != now {
t.Fatalf("duplicate result = %+v created=%v err=%v", replay, created, err)
}
wrong := binding
wrong.PodUID = "pod-2"
if _, _, err := store.Submit("result-2", testResult(), wrong, now); !errors.Is(err, ErrResultBinding) {
t.Fatalf("wrong pod accepted: %v", err)
}
}
func TestConflictingResultIsInertAndIntegritySuppressesRating(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, _ := NewResultStore(binding)
if _, _, err := store.Submit("result-1", testResult(), binding, now); err != nil {
t.Fatal(err)
}
conflict := testResult()
conflict.Team0Score = 99
prior, _, err := store.Submit("result-2", conflict, binding, now)
if !errors.Is(err, ErrResultConflict) || prior.ResultID != "result-1" || prior.CommittedAt != (time.Time{}) {
t.Fatalf("conflict mutated receipt: %+v err=%v", prior, err)
}
suppressed := testResult()
suppressed.MatchID = "match-2"
suppressed.IntegrityState = IntegritySuppressed
secondBinding := binding
secondBinding.MatchID = "match-2"
secondStore, _ := NewResultStore(secondBinding)
got, _, err := secondStore.Submit("result-2", suppressed, secondBinding, now)
if err != nil || RatingEligible(got) {
t.Fatalf("suppressed result eligibility = %+v err=%v", got, err)
}
}
func TestResultDeliveryHealthSeparatesOutageFromIntegrity(t *testing.T) {
now := time.Unix(1000, 0)
binding := testBinding()
store, _ := NewResultStore(binding)
receipt, _, err := store.Submit("result-1", testResult(), binding, now)
if err != nil {
t.Fatal(err)
}
if DeliveryStatus(receipt, now.Add(5*time.Minute-time.Nanosecond)) != DeliveryHealthy || DeliveryStatus(receipt, now.Add(ResultDeliveryAlertAfter)) != DeliveryAlert || DeliveryStatus(receipt, now.Add(ResultDeliveryReviewAfter)) != DeliveryReview {
t.Fatal("pending delivery thresholds are wrong")
}
committed, err := store.Commit("result-1", "match-1", now.Add(31*time.Minute))
if err != nil || DeliveryStatus(committed, now.Add(2*time.Hour)) != DeliveryHealthy {
t.Fatalf("committed delivery status = %+v err=%v", committed, err)
}
}