fix(submit): make usage merges device-aware

Merged
IV
6mo ago
+761-38

Summary

  • Attach a stable CLI submit device id to tokscale submit payloads.
  • Store submitted devices per user and merge daily rows by (submission, device, date) instead of only (submission, date).
  • Recalculate submission totals across all device rows while counting active days by distinct date to avoid multi-device regressions.

Why

Submitting from multiple machines currently shares one daily row per user submission. A later submit for the same date can replace another device's client breakdown because the merge cannot distinguish which local dataset is being refreshed.

Diff scope

  • crates/tokscale-cli/src/device.rs: resolves stable submit device identity from env/config, with TOKSCALE_DEVICE_ID and TOKSCALE_DEVICE_NAME overrides.
  • crates/tokscale-cli/src/main.rs: includes the device only in submit payloads, not graph JSON output.
  • packages/frontend/src/lib/validation/submission.ts: validates optional device metadata and folds the device id into the submission hash.
  • packages/frontend/src/lib/db/schema.ts and packages/frontend/src/lib/db/migrations/0006_add_submitted_devices.sql: add submitted_devices, backfill legacy rows, and change the daily uniqueness boundary.
  • packages/frontend/src/app/api/submit/route.ts: upserts submit devices, locks/merges rows for the current device, and recalculates aggregate totals across all devices.
  • packages/frontend/src/app/api/settings/submitted-data/route.ts: deletes submit device metadata together with submitted usage data.

Migration notes

  • Adds submitted_devices with a per-user unique device_key.
  • Backfills existing daily rows into a legacy-default device before making daily_breakdown.submitted_device_id required.
  • Replaces the old (submission_id, date) uniqueness constraint with (submission_id, submitted_device_id, date).
  • No submitted usage rows are deleted by the migration.

Safety

  • Legacy payloads without device remain valid and use the legacy-default bucket.
  • Same-device resubmits still replace that device's daily data; different devices on the same date retain separate rows.
  • Submission totals continue to sum all daily rows, while activeDays counts distinct active dates so it does not inflate across devices.
  • Device identity is generated locally for submit only; graph/report JSON output remains unchanged unless submitting.

Validation

  • cargo fmt --all -- --check — PASS.
  • cargo test -p tokscale-cli — PASS: 473 passed, 1 ignored; cli_tests: 88 passed.
  • /opt/homebrew/bin/cargo-clippy --package=tokscale-cli --all-features -- -D warnings — PASS.
  • bunx vitest run packages/frontend/__tests__ — PASS: 21 files, 182 tests.
  • bun run lint in packages/frontend — PASS, 0 errors; 7 existing warnings in untouched files.
  • git diff --check origin/main...HEAD — PASS, no output.

Rollback

Revert the merge commit. If the database migration has already been applied, rollback also needs to remove daily_breakdown.submitted_device_id, drop submitted_devices, and restore the previous (submission_id, date) uniqueness constraint.