fix(submit): adopt legacy rows for first device submit

Merged
IV
6mo ago
+538-15

Summary

  • Fixes #248 by completing the remaining legacy-to-device cutover for multi-machine submissions.
  • Keeps the merged device-aware submit model from #517: modern devices still get separate daily buckets, and totals are still recalculated from all stored daily rows.
  • Adds regression coverage for the legacy cutover write path and for profile aggregation when multiple submitted devices have same-date rows.

Why

#517 fixed the normal modern case where multiple computers submit with stable device IDs, but migrated historical rows still live in the legacy-default device bucket. On current main, the first modern device-aware submit only looks for rows attached to the new device ID, so it can insert a new same-date row while the legacy row remains counted. That can double-count the same historical usage during the upgrade path and leave #248 reproducible for users with pre-device data.

Diff scope

  • packages/frontend/src/app/api/submit/route.ts: before writing incoming daily rows, the submit transaction now adopts a user's legacy daily rows into the first real device bucket when no modern device rows exist yet for that submission.
  • packages/frontend/__tests__/api/submitAuth.test.ts: adds a regression test that fails on current main because the route inserts a duplicate daily row instead of adopting the legacy row.
  • packages/frontend/__tests__/api/usersProfile.test.ts: adds read-path coverage proving same-date rows from multiple submitted devices render as one profile contribution with summed totals.

Branch integrity

  • Base branch: main
  • Validated base SHA: 64e278cdc4f55544576f3b42010644cd8ba6aa9d
  • Head SHA: 49a01dd44d89dc88ce55cd209f33569e53b1f10a
  • Ahead/behind: 0 behind / 1 ahead
  • Merge base: 64e278cdc4f55544576f3b42010644cd8ba6aa9d

Commit integrity

  • Introduced commit: 49a01dd44d89dc88ce55cd209f33569e53b1f10a fix(submit): adopt legacy rows for first device submit
  • The PR contains one logical data-integrity fix plus targeted regression tests.

Diff hygiene

  • git diff --name-status origin/main...HEAD: PASS, only the submit route and two targeted frontend test files changed.
  • git diff --check origin/main...HEAD: PASS, no output.
  • git diff --cached --check: PASS, no output before commit.

Validation mode and proof

  • Validation mode: Mode 3 - submit data-integrity change. The diff changes how legacy daily_breakdown rows are attributed during the device-aware submit transition, so targeted submit/profile/leaderboard coverage is required.
  • bun x vitest run __tests__/api/submitAuth.test.ts: PASS, 7 tests.
  • bun x vitest run __tests__/api/submitAuth.test.ts __tests__/api/usersProfile.test.ts: PASS, 13 tests.
  • bun x vitest run __tests__/api/submitAuth.test.ts __tests__/api/usersProfile.test.ts __tests__/lib/getLeaderboard.test.ts __tests__/lib/getGroupLeaderboard.test.ts: PASS, 22 tests.
  • bun x vitest run __tests__/lib/getLeaderboardAllTime.test.ts: PASS, 4 tests.
  • bun run lint -- src/app/api/submit/route.ts __tests__/api/submitAuth.test.ts __tests__/api/usersProfile.test.ts: PASS.
  • bash scripts/check-version-coherence.sh: PASS, Version coherence OK: 2.1.3.
  • Full frontend suite and Rust suite: not run locally because they are not required for this selected validation mode; the local proof targets the changed submit write path, profile read path, and public leaderboard aggregation.

Ledger and version proof

  • Ledger: not applicable - not required for selected validation mode/change family.
  • Version: PASS via bash scripts/check-version-coherence.sh.

Migration notes

  • Not applicable - no DB migration changed.
  • The fix uses the existing submitted_devices table and existing daily_breakdown.submitted_device_id uniqueness model.

Runtime safety

  • The adoption runs inside the existing /api/submit transaction after the user submission row is selected with FOR UPDATE.
  • Legacy rows are adopted only when the target modern device has no rows yet and the submission has no existing modern device rows, avoiding arbitrary reassignment for mixed/ambiguous accounts.
  • No new background jobs, blocking locks outside the existing transaction, unbounded queues, or schema invariants are introduced.
  • No invariant regression introduced.

CI context confirmation

  • Pending - remote CI has not run because this PR has not been opened yet.
  • CI context names unchanged.

Rollback plan

  • Rollback: revert this PR.
  • DB downgrade: not applicable.
  • Data repair: not applicable.
  • Operational caveats: none known.

Known residual risks

  • Existing accounts that already have both legacy rows and modern device rows are intentionally not auto-reassigned because the original device attribution is ambiguous.
  • Remote CI remains pending until the PR is opened.

Summary by cubic

Fixes #248 by adopting legacy daily_breakdown rows into the first modern submitted device on the first device-aware submit, preventing duplicate same-date rows and double-counted totals. Keeps #517 behavior: modern devices still have separate daily buckets and totals are recalculated from all rows.

  • Bug Fixes
    • In packages/frontend/src/app/api/submit/route.ts, inside the /api/submit transaction, when no modern-device rows exist for the submission and the incoming device is modern, reassign that submission’s legacy rows to the device; otherwise keep legacy rows separate.
    • Adds regression tests in packages/frontend/__tests__/api/submitAuth.test.ts and packages/frontend/__tests__/api/usersProfile.test.ts covering adoption (no duplicate insert), preserving legacy rows when another modern device already submitted, and profile aggregation into a single per-date contribution with summed totals.