feat(v1.4): Trust & safety — Remote Config balance, GDPR + abuse finish, map friends toggle#170
Open
code418 wants to merge 1 commit into
Open
feat(v1.4): Trust & safety — Remote Config balance, GDPR + abuse finish, map friends toggle#170code418 wants to merge 1 commit into
code418 wants to merge 1 commit into
Conversation
…sh, map friends toggle Implements v1.4 "Trust & safety" from docs/plans/ROADMAP.md. Remote Config game balance (ship-gate pair): - New functions/src/_config.ts reads the RC server template (getServerTemplate + evaluate) with a 5-min cache and never throws; pure sanitisers enforce safety bounds (radius [10,100], points [1,50]) and fall back to the hard-coded constants. Wired into startScoring + _recomputeScores. - RemoteConfigService gains claimRadiusMeters / pointsForCipher / pointsByMonarch (defaults = current constants) + force-refetch on login; functional radius + points-display consumers route through them. cross_language_sync_test now pins the RC defaults == constants and client bounds == server bounds. GDPR account deletion (audit + finish): - Strip the new deviceIdHash on claim anonymisation; future-proof claims-photos/ prefix delete via the new testable storagePrefixesForUser; unit tests for deleteUserDocs + storagePrefixesForUser. Kept self-contained (no extension). Abuse detection (stays shadow mode): - New repeatedDeviceSignal + pure evaluateClaimSignals combiner; onClaimCreated counts distinct accounts per device hash over 24h (composite index added). Client sends a dependency-free persisted-random deviceIdHash (DeviceIdService). SHADOW_MODE stays true (enforcement is Phase 2). Scores-tab county map: - CountyHeatmap.friendsOnly (pure pickCountyLeaderEntry): the Map tab now honours the same Friends-only switch — off shows the global county leader. Gates: functions build + lint clean, 463 TS tests; flutter analyze clean, 439 Dart tests. Version 1.3.2+16 -> 1.4.0+17. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements v1.4 "Trust & safety" from
docs/plans/ROADMAP.md. Two of the three workstreams (GDPR deletion, shadow-mode abuse) were already largely shipped; this PR builds the one real ship-gate gap (Remote Config game balance), finishes/audits the other two, and adds a requested scores-tab map toggle.Ship gate
claim_radius_meters+points_by_monarchend-to-end (client + Cloud Functions) with safety bounds enforcedSHADOW_MODEstaystrueWorkstreams
A — Remote Config game balance (ship-gate pair)
functions/src/_config.ts: reads the RC server template (getServerTemplate+ evaluate), 5-min in-memory cache, never throws. PuresanitiseClaimRadius/parsePointsOverride/resolvePointsForMonarchenforce bounds (radius[10,100], points[1,50]) and fall back to the hard-coded constants. Wired intostartScoring+_recomputeScores.RemoteConfigServicegainsclaimRadiusMeters/pointsForCipher/pointsByMonarch(defaults = current constants) + force-refetch on login; functional radius + points-display consumers route through them.cross_language_sync_testnow also pins RC defaults == constants and client bounds == server bounds.B — GDPR deletion (audit + finish) — strips the new
deviceIdHashon anonymisation; future-proofclaims-photos/prefix delete via testablestoragePrefixesForUser; added unit tests fordeleteUserDocs+storagePrefixesForUser. Kept self-contained (no Delete-User-Data extension — it can't anonymise claims).C — Abuse device-id signal (stays shadow mode) — new
repeatedDeviceSignal+ pureevaluateClaimSignals;onClaimCreatedcounts distinct accounts per device hash over 24h (composite index added); client sends a dependency-free persisted-randomdeviceIdHash(DeviceIdService). Enforcement/voiding stays Phase 2.D — Friends-only toggle on the scores-tab map —
CountyHeatmap.friendsOnly(purepickCountyLeaderEntry); the Map tab now honours the same Friends-only switch (off = global county leader). Client-only, no backend change.Verification
analyzeclean, 439 Dart tests passing. All logic written test-first.Manual steps before ship
claim_radius_meters+points_by_monarchto both the client and server templates (server template is separate) with values equal to the code defaults. Until then everything safely uses the constants.SHADOW_MODE === truein the deployed abuse detector.Deliberate roadmap divergences (documented in ROADMAP.md)
onUserDeletedfunction, not the extension.firebase_app_installations, to avoid the firebase_core version ceiling.🤖 Generated with Claude Code