Skip to content

OAUTH-001A2H — Reject precision-unsafe Strava activity IDs before client return #600

Closed

Description

@daliu

Officer impact: None — this is an internal, undeployed server response-validation correction. Safe activity IDs keep the same result; after a future protected Function release, a precision-unsafe activity ID receives the existing generic Strava activity-load failure. No officer action or verified current procedure changes.

Officer documentation: None — no screen wording, navigation, officer duty, collected or stored field, permission, account ownership, data movement, provider configuration, or deployment procedure changes. The existing Strava activity-failure procedure already covers the generic outcome.

Deployment evidence: None at issue creation. Source, tests, review, merge, website publication, exact runmprc.com state, Firebase deployment/readback, Strava/provider configuration or calls, production-data action, migration, and live behavior must be recorded separately. Synthetic tests must make no provider call.

Outcome

Reject a parsed successful Strava activity response when a selected activity ID is not a positive JavaScript safe integer. Keep every admitted ID in the existing numeric client shape and route every rejected payload through the existing fixed internal / Strava activity data could not be loaded. result.

Canonical tracker: #88. This is an atomic follow-up to complete/released OAUTH-001A2E/#325, whose contract explicitly recorded unsafe Long-number precision and React-key collision as residual risk. Exact clean main at publication: 57ac85b.

Confirmed defect

functions/strava.js currently admits a selected activity id when it is a positive finite integer no larger than the rounded signed-64-bit ceiling represented by Number. That includes values greater than Number.MAX_SAFE_INTEGER.

JavaScript cannot distinguish every mathematical integer above the safe ceiling. For example, adjacent large integers can parse to the same Number. The current projection returns that rounded ID to the browser, where it is used only as a React list key; it is not displayed, persisted, used in a provider request, or treated as membership, authorization, payment, or account authority.

Stored and authorization athlete IDs already require positive safe integers. This child aligns only the successful activity projection.

Security and compatibility invariant

  1. Preserve App Check, Auth, stored-connection, stored-token, refresh, provider URL/header, and concurrent-request order.
  2. Keep the current successful activity/statistics snapshot boundary.
  3. Require each selected activity ID to be a primitive positive safe integer.
  4. A missing, nonnumeric, nonfinite, fractional, nonpositive, or unsafe selected activity ID invalidates the entire activities payload.
  5. Return only fixed internal / Strava activity data could not be loaded., with no details, cause, provider value, token, or raw error.
  6. Validate activities before reading the optional statistics JSON body.
  7. Preserve that both bearer HTTP requests may already have started concurrently; do not claim cancellation or absence of the statistics request.
  8. Add no write, delete, timestamp, log, retry, provider call, or response field.
  9. Preserve exact output bytes and numeric type for IDs from 1 through Number.MAX_SAFE_INTEGER.
  10. Do not stringify, BigInt-convert, or otherwise guess at an ID already rounded by JSON/Number transport.

Smallest safe scope

  1. functions/strava.js
    • use the existing isPositiveSafeInteger helper for selected activity IDs;
    • remove the now-unused rounded Long ceiling constant and range helper;
    • change no other Strava path.
  2. functions/strava.test.js
    • add one separately named OAUTH-001A2H precision-safe activity-ID block;
    • add only the focused unsafe rejection and safe-ceiling compatibility evidence;
    • update the old rounded-Long acceptance control to the safe-integer ceiling.

No browser/service type, UI, stored athlete-ID, provider request, persistence, root doc, officer guide, Rules, package, workflow, or generated file is in scope.

Trustworthy test-first proof

Before runtime edits:

  • use an otherwise valid successful activity payload with id Number.MAX_SAFE_INTEGER + 1;
  • require the existing fixed internal failure;
  • prove activities JSON is read once and statistics JSON is not read;
  • prove both already-concurrent bearer requests occurred exactly once;
  • prove exact connection/secret reads and zero write, delete, timestamp, or console log;
  • prove a Number.MAX_SAFE_INTEGER activity ID still returns byte-for-byte as a number.

The untouched runtime must fail only the new unsafe-ID expectation while the safe-ceiling control and existing suite remain green.

Required green proof

  • focused Strava tests pass;
  • Functions lint and full Functions tests pass;
  • frontend, TypeScript, non-mutating lint, SPA, repository safety, diagnostic build, Rules, and real demo-only commerce-emulator gates pass;
  • diff/sensitive-output review passes;
  • three independent exact-head reviews approve security/design, tests/compatibility, and scope/docs/claims;
  • hosted exact-head and exact-main CI pass before closure;
  • preview, production, Firebase, provider, data, migration, and live states are recorded separately.

Migration and deliberate behavior change

No schema, Rules, index, stored-data, package, client, provider, or production-data migration. Safe current IDs retain the same numeric response. A legitimate provider ID above Number.MAX_SAFE_INTEGER will now receive the existing generic activity-load failure because the current numeric transport cannot represent it losslessly.

A future lossless string/raw-JSON ID representation and any React-key/type migration remain separate work.

Explicit exclusions and residuals

Raw response-byte/memory bounds before response.json; lossless Long/string representation; React-key migration; token/athlete/account ownership binding; refresh concurrency/versioning/lifetime; scope policy; provider endpoint migration; disconnect/revoke/audit; reconciliation; IAM/encryption; App Check/Auth changes; stored connection/token/refresh/exchange changes; browser types/UI; Rules; packages; provider configuration; deployment; production data; migration; and live testing.

This child does not complete canonical #88 or any OAUTH-001A refresh-concurrency outcome.

Dependencies and coordination

Claim protocol

Creation is not a claim. Before edits: re-fetch exact main; create and push a unique codex branch; assign this issue; add status:in-progress; and post an exact UTC claim naming branch, base, paths, invariants, exclusions, and active competing claims. The claim remains active through trustworthy RED, implementation, independent exact-head review, hosted CI, merge, exact-main verification, closure, and explicit release.

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
    type:testingTest infrastructure and quality gates
    status:in-progressClaimed and actively being implemented
    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-02T04:43:48Z on branch codex/issue-600-strava-activity-id, exact released base 57ac85b.

    Exact ownership:

    1. functions/strava.js
      • replace only selected successful activity-ID admission with the existing positive-safe-integer predicate;
      • remove only the now-unused rounded Long ceiling constant and single-use integer-range helper.
    2. functions/strava.test.js
      • one separately named OAUTH-001A2H precision-safe activity-ID block;
      • focused unsafe rejection and safe-ceiling compatibility evidence;
      • update only the old rounded-Long acceptance control to the safe ceiling.

    Invariant: after all existing App Check/Auth, stored connection/token, refresh, and provider-request behavior, each selected activity ID must be a primitive positive safe integer. An unsafe ID invalidates the complete activities payload and returns only fixed internal / Strava activity data could not be loaded., before statistics JSON is read. Both already-concurrent bearer HTTP requests may have started. No provider value, token, error detail, write, delete, timestamp, or log is added. IDs from 1 through Number.MAX_SAFE_INTEGER keep the exact numeric client shape.

    Immutable exclusions: athlete/stored-account IDs; browser/service types and UI; provider URLs/headers/request order; raw response bytes; lossless Long/string migration; React-key migration; token/account/scope/refresh/revoke/audit/reconciliation/IAM/configuration; App Check/Auth; persistence; Rules; packages; workflows; root/officer docs; deployment; production data; migration; provider/live testing; canonical #88 completion.

    The unique empty remote branch was pushed from exact current main before this marker. Live issues, PRs, remote branches, dependencies, and path claims were re-read. Active #571, coordinating #504, and draft #462 are disjoint; no competing activity-ID precision claim exists. No source, test, documentation, package, or generated-file edit preceded this claim. This claim remains active through trustworthy RED, implementation, independent exact-head review, hosted CI, merge, exact-main/deployment truth audit, closure, and explicit release.

    Officer impact: None — this is an internal, undeployed server response-validation correction. Safe IDs keep the same result; a future protected Function release would route a precision-unsafe ID to the existing generic activity-load failure.

    Officer documentation: None — no screen wording, navigation, officer duty, collected/stored field, permission, ownership, data movement, provider configuration, or deployment procedure changes.

    Deployment evidence: none at claim time; source/tests/merge will not be described as website publication, runmprc.com verification, Firebase deployment/readback, Strava/provider action, production-data change, migration, or live behavior.

  4. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    TRUSTWORTHY RED recorded before runtime edits.

    • Exact base: 57ac85b.
    • Test-only binary diff SHA-256: 632d6fa0b151e9999bba9f1e7b7a5248b91bd25170cf84c8ca8e77e875a5fcdf.
    • Pinned Node 20 focused result: 689 cases total; 688 existing/control cases passed and exactly 1 new OAUTH-001A2H case failed.
    • Intended failure: an otherwise valid successful activity with id Number.MAX_SAFE_INTEGER + 1 resolved successfully, so the expected fixed activity-data failure was absent.
    • The RED helper already pins activities JSON once, statistics JSON zero, both already-concurrent bearer requests exactly once, exact connection/secret reads, zero writes/deletes/timestamps/logs, and no provider/token detail in a fixed error.
    • The new Number.MAX_SAFE_INTEGER positive control passed on untouched runtime and returned the exact ID as a number with both valid JSON bodies read once.
    • Only functions/strava.test.js changed. Runtime, packages, browser/UI, Rules, docs, providers, deployment, production data, migration, and live behavior were untouched.

    This is the claimed precision residual, not refresh concurrency, provider cancellation, or a lossless string-ID migration.

  5. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    IMPLEMENTATION CANDIDATE — exact reviewed-head request

    • Exact base: 57ac85b.
    • Candidate head: 426b123.
    • Candidate tree: 8351062fdd7d5f8f3bbef985620bb3f1748a91dd.
    • Exact two-file binary diff SHA-256: 98f68df14c8911ec29c531b93110be3e64ef5046be18dae7044cdf3d728ff849.
    • Scope: exactly functions/strava.js and the separately named OAUTH-001A2H test block plus existing bounds-control update in functions/strava.test.js.
    • Worktree is clean; diff and syntax checks pass.

    Outcome: selected successful activity IDs now use the existing positive-safe-integer predicate. The obsolete rounded Long source constant, single-use range helper, and its sole Number.isInteger alias were removed. IDs from 1 through Number.MAX_SAFE_INTEGER retain the exact number projection. The first unsafe integer takes the existing fixed activity-data failure before statistics JSON is read; both already-concurrent bearer requests still occur.

    Trustworthy RED on untouched source: exactly 1 intended failure after 688 existing/control passes. An otherwise valid activity with id Number.MAX_SAFE_INTEGER + 1 resolved successfully. The safe-ceiling positive control passed before the runtime change.

    Pinned local verification:

    • Focused Strava: 689/689.
    • Functions lint: passed.
    • Full Functions: 69 suites passed / 2 intentionally skipped; 7,492 passed / 64 intentionally skipped.
    • Frontend: 951/951.
    • TypeScript: passed.
    • Frontend lint: 118 files / 113 reviewed legacy errors / 6 reviewed warnings.
    • SPA: 11/11.
    • Workflow/release/artifact/dependency safety: 93/93.
    • Diagnostic build: passed.
    • Rules emulator: 418/418.
    • Real demo-only commerce emulator: 63/63.
    • Latest dependency audit snapshot: root 59 total with zero critical; root production 4; Functions 8. No dependency file changed and no forced update was applied.

    Three independent exact-head reviews are in progress.

    Officer impact: None — this is an internal, undeployed server response-validation correction. Safe IDs keep the same result; a future protected Function release would route a precision-unsafe ID to the existing generic activity-load failure.

    Officer documentation: None — no screen wording, navigation, officer duty, collected/stored field, permission, ownership, data movement, provider configuration, or deployment procedure changed. The existing failure procedure already covers the generic result.

    Deployment evidence: source, tests, local review, commit, and push only. The change is not merged. The website and runmprc.com were not published or verified; Firebase was not deployed/read back; Strava or another provider was not configured or contacted; production data, migration, and live behavior were not accessed, changed, or verified.

  6. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    PR VERIFICATION AND PREVIEW EVIDENCE

    PR #601 hosted CI run 30733062824 passed all five required jobs for exact head 426b123.

    Netlify deploy preview 6a6ecc961614c10008c6b73d is exact-head, deploy-preview context, state ready, HTTP 200, x-robots-tag noindex, and published_at null. It is not production website publication, runmprc.com verification, Firebase deployment/readback, Strava/provider configuration or contact, production-data action, migration, or live-behavior proof.

  7. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    COMPLETE / CLOSED / CLAIM RELEASED

    Outcome: Strava activity responses now reject positive numeric IDs above the JavaScript safe-integer ceiling before any activity data can return to the browser. Safe numeric IDs remain compatible.

    • Source merged: exact main 287bfa55af969daea189dad35d7d7ac1875fd1c3 via OAUTH-001A2H — Reject precision-unsafe Strava activity IDs #601; parent 57ac85b9f0248068e60dd741154877f1d539f3e4, tree 8351062fdd7d5f8f3bbef985620bb3f1748a91dd, and patch SHA-256 98f68df14c8911ec29c531b93110be3e64ef5046be18dae7044cdf3d728ff849 match the reviewed candidate.
    • Tests passed: trustworthy RED plus focused 689/689; all local relevant gates; PR CI 30733062824; and exact-main CI 30733206686, with all five jobs green.
    • Review: self-review and three independent exact-head reviews found no actionable issue.
    • Website: exact-head preview 6a6ecc961614c10008c6b73d was ready, HTTP 200, noindex, and unpublished. Exact-main production attempt 6a6ecdce9660310008ce2464 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 changed or verified. Production data/migration: none. Production behavior: not verified.
    • Officer impact: malformed provider IDs fail through the existing generic Strava failure path; no officer steps changed.
    • Officer documentation: None — no public page, collected field, account, permission, deployment duty, or recovery procedure changed. Existing Strava failure guidance remains accurate.

    Residual work remains separately scoped: lossless Long/string transport, React-key migration, raw-response byte bounds, refresh concurrency, provider governance, deployment, and live verification. No production secret or member data was used.

  8. 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