Skip to content

feat(abuse): shadow-mode claim anomaly detector (v1.4)#167

Open
code418 wants to merge 1 commit into
masterfrom
feat/abuse-detection-shadow
Open

feat(abuse): shadow-mode claim anomaly detector (v1.4)#167
code418 wants to merge 1 commit into
masterfrom
feat/abuse-detection-shadow

Conversation

@code418

@code418 code418 commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Summary

Implements the v1.4 Trust & safety roadmap item "Abuse detection (impossible-travel & claim anomalies)" in shadow mode — the detector observes every claim, records flags for internal review, and never blocks or voids a claim. The existing 1900 m/min hard reject in startScoring is left intact.

Ship-gate clause satisfied: "impossible-travel detector in shadow mode logging flags but not blocking."

Plan: ~/.claude/plans/wise-shimmying-thompson.md (one of v1.4's four items, scoped full-depth).

What's included

Backend

  • functions/src/_abuseSignals.ts (new) — pure, TDD'd helpers: impossibleTravelSignal, outOfWindowSignal, coordClusterSignal, summariseFlags, applyTrustDecay, coordKey + tunable constants. The shadow flag threshold (1500 m/min) sits below the live hard reject (1900) so it can actually fire (a load-time guard enforces this).
  • functions/src/startScoring.ts — accepts/validates optional clientTsMs; enforceTravelSpeedLimit now returns the computed speed; each claim persists clientTsMs, travelSpeed, coordKey6. Hard reject unchanged.
  • functions/src/abuse.ts (new) — onClaimCreated 2nd-gen Firestore trigger in europe-west4 (eur3 Eventarc region, mirroring onFriendAdded) writes moderationFlags + decays server-only trustScores; never throws. reviewFlag admin callable stamps a flag reviewed (no voiding yet).

Client

  • clientTsMs sent with claims (claim_quiz_sheet.dart, wear_claim_page.dart).
  • lib/admin/admin_abuse_screen.dart (new) — Open/Reviewed queue mirroring the reports screen, wired into the Home admin menu.

RulesmoderationFlags (admin-read, server-write) + trustScores (server-only).

Roadmap — App Check enforcement moved v1.4 → v1.7 (gated on iOS AppleProvider work).

Design notes / deviations

  • Trust score is stored in a server-only trustScores/{uid} collection rather than on users/{uid} — that doc is world-readable, so a trustScore field there would leak. Flat moderationFlags/trustScores collections realise the roadmap's moderation/flags / users.trustScore intent in a rules-correct way.
  • Detector runs as an out-of-band trigger (zero added claim-path latency) — ideal for a no-user-effect shadow detector.

Verification

  • cd functions && npm test400 passing
  • flutter test413 passing; flutter analyze → clean
  • firestore.rules validated (Firebase MCP)
  • Not yet done (needs device/deploy): emulator claim-loop check that flags fire without blocking; firebase deploy --only functions,firestore:rules to create the onClaimCreated Eventarc trigger in europe-west4.

Deferred follow-ups (separate PRs)

  • Device-hash-reuse signal (device_info_plus + crypto) + the two-signal false-positive guard.
  • Enforcement phase: trust-score gating / step-up + claim voiding (reuse recomputeUserAggregates); move thresholds + SHADOW_MODE to Remote Config.

🤖 Generated with Claude Code

Adds the v1.4 Trust & safety "abuse detection" item in shadow mode: the
detector observes every claim, records flags for internal review, and never
blocks or voids a claim. The existing 1900 m/min hard reject in startScoring
is left intact.

Backend:
- _abuseSignals.ts: pure, unit-tested helpers (impossible-travel, out-of-window,
  coordinate-cluster signals; severity rollup; trust-score decay; coordKey).
  Shadow flag threshold (1500 m/min) sits below the hard reject so it can fire.
- startScoring: accepts/validates optional clientTsMs; enforceTravelSpeedLimit
  returns the computed speed; each claim persists clientTsMs, travelSpeed and
  coordKey6 for the detector.
- abuse.ts: onClaimCreated 2nd-gen trigger (europe-west4, eur3 Eventarc region)
  writes moderationFlags + decays server-only trustScores; never throws.
  reviewFlag admin callable stamps a flag reviewed (no voiding yet).

Client:
- Send clientTsMs with claims (claim_quiz_sheet, wear_claim_page).
- admin_abuse_screen.dart: Open/Reviewed queue mirroring the reports screen,
  wired into the Home admin menu.

Rules: moderationFlags (admin-read, server-write) + trustScores (server-only).
Trust score is kept out of the world-readable users/{uid} doc so it can't leak;
flat moderationFlags/trustScores collections realise the roadmap's intent.

Roadmap: App Check enforcement moved v1.4 -> v1.7 (gated on iOS AppleProvider).

Tests: 400 functions tests + 413 flutter tests pass; flutter analyze clean;
firestore.rules validated.

Deferred follow-ups: device-hash signal + two-signal guard; enforcement/voiding;
move thresholds to Remote Config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant