Skip to content

OAUTH-001A2I — Reject duplicate Strava activity IDs before client return #602

Closed

Description

@daliu

Officer impact: After a future protected Firebase Functions release, if Strava returns two recent activities with the same identifier, My Account will show the existing generic Strava loading failure instead of risking mismatched activity rows. There is no current officer-visible change, and no new officer action becomes available.

Officer documentation: None — this is a server-only provider-response admission boundary. It changes no public page, officer duty, collected field, permission, account, deployment step, or recovery procedure; the existing generic Strava failure guidance remains accurate.

Deployment evidence: None at creation. Closure must distinguish source changed, tests passed, code merged, website preview/publication, runmprc.com, Firebase deployment, Strava/provider configuration, production data, and live behavior. A green workflow does not prove the Function is live.

Problem

The bounded Strava activity projector validates each returned activity independently but does not require identifiers to be unique within the response. The browser uses each admitted identifier as the React list key. Two otherwise-valid records with the same identifier can therefore make the UI associate one row with another.

Invariant

A successful recentActivities projection contains at most five records whose copied positive safe-integer identifiers are pairwise distinct. Any duplicate makes the whole provider payload invalid. The server must not choose a winner, reorder, deduplicate, merge, or normalize provider records.

Allowed behavior and failure cases

  • A response with distinct valid identifiers returns the same records, order, numeric types, and fields as before.
  • The first repeated identifier rejects the whole activities payload through the existing fixed Strava data error before statistics JSON is read.
  • Validation remains bounded to at most five copied snapshots and does not invoke provider coercion/accessor hooks.
  • Auth, App Check, connection/secret reads, provider request count, refresh behavior, persistence, logs, and client schema do not change.

Atomic scope

  • functions/strava.js: reject a copied activity identifier equal to any previously accepted copied identifier before appending it.
  • functions/strava.test.js: add a separately named trustworthy RED and distinct-boundary compatibility proof.

Acceptance criteria

  • A test-only patch on exact pre-fix source fails only because duplicate valid activity IDs are accepted.
  • Duplicate IDs return the existing fixed internal Strava-data error; activities JSON is read once, statistics JSON is not read, both already-concurrent bearer requests remain exactly once, and there are no writes, deletes, timestamps, or logs.
  • Distinct identifiers including 1 and Number.MAX_SAFE_INTEGER return in original order as numbers.
  • Focused and full relevant checks pass.
  • Review finds no authorization, App Check, input-bound, privacy, logging, provider, persistence, compatibility, or production-fallback regression.

Dependencies and coordination

Parent: #88. The response projection boundary from #325 and safe-integer child #600 are complete, merged, and claim-released. Open #571, #504, #507, and draft PR #462 are disjoint. Create no lossless string/Long transport or React-key migration here.

Migration and compatibility

No schema or data migration. Existing unique safe numeric IDs remain byte-for-byte compatible. Previously admitted duplicate payloads now fail closed as one invalid provider response.

Explicit exclusions / stop conditions

Stop if another claimant owns either Strava file or this exact uniqueness outcome, or if work requires choosing one duplicate, lossless ID transport, client type/key changes, response-byte limits, refresh concurrency, provider governance, Firebase/website deployment, production data, or live Strava behavior. Never use a real member token or the production provider host.

Creation is not a claim. Before editing, assign the issue, create the exact branch, and post a timestamped CLAIMED marker naming the agent, branch, and base SHA.

Activity

  1. added
    bugSomething isn't working
    priority:P1High-priority follow-up
    type:securitySecurity or privacy boundary
    area:authAuthentication and authorization
    size:XSOwner decision or very narrow change
    status:readyDependencies complete and ready to claim
    type:testingTest infrastructure and quality gates
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Aug 2, 2026
  2. self-assigned this
    on Aug 2, 2026
  3. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-02T05:06:20Z; branch codex/issue-602-strava-activity-ids; exact base 287bfa55af969daea189dad35d7d7ac1875fd1c3.

    Exact ownership is only the duplicate-ID comparison hunk in functions/strava.js and one separately named OAUTH-001A2I unique activity IDs test block in functions/strava.test.js. No client, string/Long transport, response-size, response-status, refresh, provider, documentation, deployment, data, or live outcome is claimed. This authoritative timestamp supersedes the earlier typed time; no tracked edit preceded the durable claim.

  4. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    CLAIM TIMESTAMP CORRECTION: the durable claim comment was posted before any tracked edit; the current UTC audit time is 2026-08-02T05:06:26Z. Branch, exact base, ownership, and exclusions are unchanged. Worktree remains clean.

  5. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    TRUSTWORTHY RED on exact base 287bfa55af969daea189dad35d7d7ac1875fd1c3. Test-only diff SHA-256: d3c034b1c0f54323897c13f4fdd47dacb50d3c7f1c588f2e996ef599b8812c3d.

    Pinned Node 20 focused Strava run: 691 total, 690 passed, exactly one failed. The sole failure is OAUTH-001A2I unique activity IDs > rejects a repeated valid ID before statistics JSON, because old runtime returns success. The distinct 1 and Number.MAX_SAFE_INTEGER ordered numeric compatibility control passes. No runtime edit preceded this RED.

  6. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    IMPLEMENTATION CANDIDATE on exact base 287bfa55af969daea189dad35d7d7ac1875fd1c3. Exact two-file patch SHA-256: 216d029f805fd5ffc5667e44ec1cab2fae97e71b346780d6a7dc14db3dfeffba.

    Outcome: after each provider activity is copied and fully validated, the at-most-five projector compares its safe numeric ID with prior accepted snapshots. Equality rejects the whole payload before append and before statistics JSON. The bounded nested loop makes at most ten primitive comparisons and invokes no raw provider getter, coercion, iterator, or new intrinsic. Distinct IDs retain provider order and numeric type.

    Verification:

    • Trustworthy RED: 691 total, 690 passed, exactly duplicate rejection failed on unchanged runtime.
    • Focused Strava: 691/691.
    • Functions lint: pass.
    • Full Functions: 69 suites pass / 2 skip; 7,494 pass / 64 skip.
    • Frontend: 18 suites, 951/951.
    • TypeScript: pass.
    • Deterministic frontend lint: 118 files, 113 reviewed legacy errors, 6 reviewed warnings.
    • SPA/workflow/release/dependency/artifact safety: 104/104.
    • Diagnostic production build: pass.
    • Firestore Rules on demo emulator/Java 21: 418/418.
    • Commerce journal on real demo-only emulator: 63/63.
    • Dependency audit unchanged: root 59 total / 4 production; Functions 8 total/production; no critical and no dependency-file diff.
    • git diff --check: pass; worktree contains only the two claimed files.

    Self-review covers authorization/App Check ordering, copied-input bounds, PII/logging, provider request count, persistence, schema/type/order compatibility, and production fallback. Two independent code/test reviews are GO with no findings; officer/documentation review is pending.

    Officer impact: duplicate provider rows fail through the existing generic Strava data error. Officer documentation: None — no officer procedure or available surface changes. Deployment evidence: source/test candidate only; no website, runmprc.com, Firebase, provider, production-data, or live action/verification.

  7. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    PR OPEN: #603 at exact head 945a647d2519fa6b87077122befd39bf08f62c80, tree 56fb8e3bd2ee741dfbb14fbf3ce4a5e09ccbb5c1, patch SHA-256 216d029f805fd5ffc5667e44ec1cab2fae97e71b346780d6a7dc14db3dfeffba. Exact two-file scope and all local gates are green. Claim remains active until hosted checks, exact-head review, merge, post-main verification, closure, and explicit release.

  8. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    DELIVERY REVIEW GO on exact head 945a647d2519fa6b87077122befd39bf08f62c80. Three independent reviews found no code, test, compatibility, officer, documentation, or scope issue. Hosted CI 30733746716 passed all five required jobs. Exact-head preview 6a6ed206d8ef7f0008e89b1e is ready, HTTP 200, noindex, and unpublished.

    This remains source/review evidence only. No website production publication, runmprc.com verification, Firebase deployment, Strava/provider action, production-data action, or live behavior is claimed. Claim remains active through merge and exact-main audit.

  9. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    COMPLETE / CLOSED / CLAIM RELEASED

    Outcome: the bounded Strava activity projector now rejects a provider payload when two otherwise-valid rows share the same copied safe-integer ID. It fails the whole payload before statistics JSON instead of returning duplicate React keys. Distinct IDs remain ordered numeric values.

    • Source merged: exact main dff1a40194bd1f25938ac16564a6ce27bbb9eab5 via OAUTH-001A2I — Reject duplicate Strava activity IDs #603; parent 287bfa55af969daea189dad35d7d7ac1875fd1c3, tree 56fb8e3bd2ee741dfbb14fbf3ce4a5e09ccbb5c1, and patch SHA-256 216d029f805fd5ffc5667e44ec1cab2fae97e71b346780d6a7dc14db3dfeffba match the reviewed candidate.
    • Tests passed: trustworthy RED; focused 691/691; all local relevant gates; PR CI 30733746716; and exact-main CI 30733851679, with all five jobs green.
    • Review: self-review and three independent exact-head reviews found no actionable issue.
    • Website: exact-head preview 6a6ed206d8ef7f0008e89b1e was ready, HTTP 200, noindex, and unpublished. Exact-main production attempt 6a6ed2d81ba2a10008a53e38 is error/unpublished. GitHub deployments for the merge SHA are empty.
    • runmprc.com: still advertises WEB-002A — Publish bounded Shop and Events permissions containment #473 control/source 9ad6837756cdd409d296009fde5082eeeae5c059 / 39ab8649df411262c8109a3c81a57bc38f1e168b; this merge is not claimed live there.
    • Firebase: not deployed or verified. Strava/outside provider: no configuration or provider action changed or verified. Production data/migration: none. Production behavior: not verified.
    • Officer impact: only after a future protected Firebase Functions release will duplicates use the existing generic My Account failure. There is no current officer-visible change.
    • Officer documentation: None — existing SOURCE ONLY / NOT LIVE Strava failure guidance remains accurate, and no officer procedure, diagram, permission, account, field, or deployment duty changed.

    Residual work remains separately scoped: response-status admission, response-byte limits, lossless String/Long transport, client key migration, refresh concurrency/reconciliation, provider governance/configuration, Firebase deployment, and live verification. No production secret, provider call, or member data was used.

  10. removed their assignment
    on Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authAuthentication and authorizationarea:stravaStrava integrationbugSomething isn't workingpriority:P1High-priority follow-upsize:XSOwner decision or very narrow changetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions