fix(submit): make usage merges device-aware
Merged
IV
6mo ago+761+761+012345678901234567890123456789-38-38-01234567890123456789
Summary
- Attach a stable CLI submit device id to
tokscale submitpayloads. - 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, withTOKSCALE_DEVICE_IDandTOKSCALE_DEVICE_NAMEoverrides.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.tsandpackages/frontend/src/lib/db/migrations/0006_add_submitted_devices.sql: addsubmitted_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_deviceswith a per-user uniquedevice_key. - Backfills existing daily rows into a
legacy-defaultdevice before makingdaily_breakdown.submitted_device_idrequired. - 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
deviceremain valid and use thelegacy-defaultbucket. - 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
activeDayscounts 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 lintinpackages/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.