Repository navigation
App data (W7): attributed strap-data delete, sleep edits on a re-added strap, launch-seed attribution - #44
Merged
Merged
Conversation
…t from the shared namespace (W07-002) The engine writes every scored day under the canonical my-whoop-noop, whichever strap supplied it. Since W02-005's follow-up, deleteAllData left that namespace alone whenever another device was registered, so deleting a re-added strap's data, or the canonical strap's with a second one registered, kept every score computed from it on screen. scoreInputProvenance already names the day owner for each scored day's recovery, strain and Rest-point cells. deleteAttributedCanonicalRows runs first in the delete transaction: each cell naming the device goes; a day's row goes when no recovery or strain cell names another source, together with the day's unattributed cells; cells naming another source or an estimator stay. Sleeps and detected workouts carry no day key and go when only the device's heart rate covers them; edited nights stay. Days scored before provenance existed have no cells and stay.
…dex scan (W07-032) W07-002's sleep and workout delete asked whether any other source had heart rate inside each canonical session with a deviceId != predicate, which cannot use the (deviceId, ts) key: SQLite scanned the whole heart-rate index once per session, inside the delete's write transaction. On 115 days of 1 Hz rows that was 25 to 53 s with offload inserts and every store read waiting behind it. The other heart-rate sources are now read once by a skip scan over the key, and each session is probed with key lookups.
On an install whose active strap id is not my-whoop (any remove and re-add, ryanbr#814), Repository's computed sibling is whoop-<uuid>-noop, but the engine banks every detected night, and so every edit of one, under the canonical my-whoop-noop. selfHealEditedStages read only the active sibling, found no edited nights, and the day's totals, Rest and Charge kept the detected bounds. It now reads every id computedReadIds unions, returns one row per night (the active strap's copy winning), and writes each re-staging back to the namespace its row came from.
…y snapshot it supplied is cleared (W07-035) W07-002 kept a mixed day's whole dailyMetric row whenever any recovery or strain cell named another source. A row whose strain the deleted strap scored, beside a recovery a legacy snapshot kept from an older source, therefore kept the deleted strap's strain, sleep, HRV and resting HR, and lost its source badge as its provenance went. The row now belongs to the source its strain cell names (the pass that scored it), else its recovery cell. The owner's delete removes the row; when the deleted strap supplied only the legacy snapshot on another source's row, just the snapshot's columns are cleared.
… (W07-036) On a day only the deleted strap supplied, the sweep removed fitness_age but kept vo2max_est, because the VO2max cell's provenance names its estimator rather than a device. Both come from one Fitness Age computation over the same week, so the strap's VO2max stayed on screen beside a missing Fitness Age and kept feeding Body Age. The sweep now treats the estimator-named cell as unattributed.
… under the canonical id (W07-037) The attributed workout delete selected every workout under my-whoop-noop with no source filter, so a legacy workout the user had entered there, covered only by the deleted strap's heart rate, went with the detected bouts while edited nights were spared. Only detected bouts (sport "detected" or a computed source) are attributed now; a manual row stays.
…of another source (W07-038) The attributed delete kept a canonical night or detected workout when any other source had a single heart-rate sample inside it, so a sparse second source (a chest strap, an imported activity file) protected every overlapping session the deleted strap recorded. A session now goes when the device's heart rate inside it outnumbers every other source's; an even split stays.
…elete (W07-040) W07-002 added canonicalComputedId as "my-whoop" + suffix beside a bare "my-whoop" in exclusiveComputedSibling, and tested "the canonical namespace is this device's alone" as exclusiveSibling != canonicalComputedId. One canonicalDeviceId constant now feeds both, and the condition has a name. No behaviour change; the delete tests pass unchanged. W07-039 (the repeated provenance delete) is kept on purpose.
…egistered strap (W07-041, W07-042, W07-043) Three gaps W07-023 left in one function, fixed together: - Edited nights came from the active and canonical siblings only, while the Sleep tab shows every registered strap's computed nights; two re-adds later a nap under the first re-added strap was shown but never scored. The heal now reads through rawComputedReadIds, the Sleep tab's resolver, active first. - Only the copy scoring takes was healed, so a second edited copy the Sleep tab still shows went stale. Every copy is healed now. - restageFromRaw read raw under the active strap only, so a night the old strap recorded was never re-staged and a partial active read could overwrite it. The raw now comes from the strap with the most gravity inside the night.
… writers (W07-045) W07-016 documented that seedLastSynced and stampCompletedSync are the only writers of lastSyncedAt, each setting its origin first, but the property kept a public setter, so a direct write would leave the origin stale. The setter is private now; SyncChipStateTests stamps through stampCompletedSync.
… a completed sync (W07-044) W07-016's sink defaulted an unrecorded origin to completedSync, so a value whose writer it could not name would be logged as a completed sync with trigger=post-offload, the claim W07-016 removed. Such a value is now reported as unattributed, with its own neutral line and trigger.
…046) The persisted last-sync time is seeded from bootstrapStore, which beginBackfill retries on a later tick when the first open fails, for example on a relaunch while the phone is locked. The "Launch:" line and trigger=launch-seed could then appear after Connected, asserting a launch the code did not see. The line now reads "Seed: …" and the trigger is stored-seed.
…h chain (W07-047) W07-016's test subscribed to $lastSyncedAt directly, not to the chain the app runs (drop first, de-duplicate, 2-second debounce, origin read after it), so a change that broke the chain would still pass. The chain is now AppModel.lastSyncRefreshes(_:debounce:), which the app sinks and the test drives: a seed followed by a HISTORY_COMPLETE settles once as a completed sync, a seed alone as the stored seed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2 fix batch for W7 (App data layer), from the review passes in the tracker PR and a
/code-review xhighof the batch. One commit per fix (W07-041 … W07-043 share one, since they touch one function). Each row indocs/review/workstreams/W07-app-data.mdholds its V0, fix and V1.Deleting a strap's data (S2 W07-002, and the follow-ups)
The engine writes every scored day under the canonical
my-whoop-noop, whichever strap supplied it. A delete therefore had to leave that namespace alone whenever another device was registered, and the deleted strap's scores stayed on screen.scoreInputProvenancealready names each scored day's source. The delete removes what is attributed to the device: the cells naming it, the day rows it owns, and their unattributed cells.Sleep edits on a re-added strap (S2 W07-023, and the follow-ups)
On an install whose active strap is not
my-whoop, edited nights were read only from the active strap's computed sibling, while the engine banks them under the canonical id. Their edits never reached the day's totals, Rest or Charge.rawComputedReadIds), active strap first.Launch-seed attribution (follow-ups to W07-016, #42)
lastSyncedAthas a private setter.Seed: …withtrigger=stored-seed, since a retried bootstrap can seed afterConnected.AppModel.lastSyncRefreshes).Verification
Strand(macOS) builds.NOOPiOSbuilds without the watch app; this Mac has no watchOS runtime.doc_comment_lintis clean.Stacked on the Phase 2 tracker PR (#43).