feat(offline): implicit net-state model, two-tier version gate, unified lobby
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m12s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m50s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m12s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m50s
Land the offline-model redesign (ANDROID_PLAN.md O1-O7): replace the explicit offline toggle with a single detected net-state machine, unify the lobby, and add a two-tier client-version gate. Contour-safe: both version vars empty => dormant, the wire change is additive, so web/pwa/vk/tg behaviour is unchanged unless the gate is deliberately configured. O1 net-state reducer (test-first). O2 store + wiring (connection/offline shims; +@capacitor/network). O3 remove the offline toggle + migrate the pref. O4 two-tier gate: hard update_required degrades to an offline Update/Play-offline notice (not terminal); soft GATEWAY_RECOMMENDED_CLIENT_VERSION -> X-Update-Recommended nudge. O5 unified lobby (device-local + greyed-from-cache server games; self-set identity; closes G-step-0). O6 create flows (with-friends online/offline segment + offline dict guard). O7 docs. Deploy/CI: wire the version gate through the deploy (GATEWAY_MIN_CLIENT_VERSION + GATEWAY_RECOMMENDED_CLIENT_VERSION as plain unprefixed vars via compose + ci.yaml + prod-deploy.yaml + write-prod-env.sh + .env.example) so the gate is live when set (test-contour commit-hash version fails open; empty => dormant). Disable the manual android-build CI workflow for now (rename .disabled). Bump the app bundle budget 127->130 KB for the added always-loaded wiring. Fix the UI Docker stage (gateway/Dockerfile): install --ignore-scripts so the Alpine/musl SPA build no longer tries to native-build sharp (a local android:assets tool, unused in the image); esbuild's binary is an optional dep so Vite still builds. Tests: gateway go green (two-tier gate over a real HTTP handler); docker build of the landing + gateway targets green locally; compose --no-interpolate confirms the gateway env; svelte-check 0/0, vitest 617, e2e 122/122 (chromium + webkit).
This commit is contained in:
@@ -70,6 +70,42 @@ func TestLoadMinClientVersion(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadRecommendedClientVersion verifies the soft-tier config: dormant (empty) by default, a
|
||||
// parseable version accepted (standing alone with no minimum, or at/above one), an unparseable one
|
||||
// rejected, and a recommended below the minimum rejected.
|
||||
func TestLoadRecommendedClientVersion(t *testing.T) {
|
||||
c, err := Load()
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if c.RecommendedClientVersion != "" {
|
||||
t.Errorf("RecommendedClientVersion = %q, want empty (soft tier dormant)", c.RecommendedClientVersion)
|
||||
}
|
||||
// Stands alone with no minimum configured.
|
||||
t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "v1.20.0")
|
||||
if c, err = Load(); err != nil {
|
||||
t.Fatalf("Load with a valid recommended version (no min): %v", err)
|
||||
}
|
||||
if c.RecommendedClientVersion != "v1.20.0" {
|
||||
t.Errorf("RecommendedClientVersion = %q, want %q", c.RecommendedClientVersion, "v1.20.0")
|
||||
}
|
||||
// At or above the minimum is accepted.
|
||||
t.Setenv("GATEWAY_MIN_CLIENT_VERSION", "v1.16.0")
|
||||
if _, err = Load(); err != nil {
|
||||
t.Fatalf("Load with recommended >= min: %v", err)
|
||||
}
|
||||
// Below the minimum is rejected.
|
||||
t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "v1.10.0")
|
||||
if _, err := Load(); err == nil {
|
||||
t.Fatal("Load: expected an error for a recommended version below the minimum, got nil")
|
||||
}
|
||||
// Unparseable is rejected.
|
||||
t.Setenv("GATEWAY_RECOMMENDED_CLIENT_VERSION", "dev")
|
||||
if _, err := Load(); err == nil {
|
||||
t.Fatal("Load: expected an error for an unparseable GATEWAY_RECOMMENDED_CLIENT_VERSION, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadAbuseDefaults verifies the anti-abuse ban defaults: disabled (prod-only),
|
||||
// the agreed thresholds, and no honeytoken.
|
||||
func TestLoadAbuseDefaults(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user