Repository navigation
fix: data integrity and persistence locks (DATA-01..17, API-05, SEC-06) - #184
Merged
Merged
Conversation
DATA-01: the API no longer premerges a stale full record; updateMealEntry merges only the supplied fields under a row lock, so concurrent disjoint updates survive. DATA-02: a product-backed entry recalculates only when a nutrition input, the product or an explicit macro override changed, so group/label edits keep the stored snapshot while quantity/product changes still recalculate. DATA-05: linked quantities, serving multipliers and product defaults are rounded to numeric(8,2) precision before positivity checks and nutrition maths, and values that would store as zero are rejected. DATA-06: template application overwrites the template-local order and appends the block after the day's existing entries in template order. DATA-07: creates lock the group FOR SHARE and deletes keep group-then-meal lock order, so no active meal can reference a deleted group. DATA-11: clientMutationId is capped at 128 characters before persistence. DATA-13: append allocation clamps against an existing extreme sort_order instead of overflowing the integer column. DATA-14: present non-numeric optional numbers are rejected instead of silently becoming defaults. DATA-03: stats count eaten days by entry presence, not calories. DATA-04: HealthKit eligibility and sample clamping use the client's tzOffsetMinutes local day, documented in the generated OpenAPI. DATA-08: historical weight stats use only measurements on or before the selected reference date. DATA-09: named unique violations map to actionable conflicts (weight date, default group label). DATA-10: weight goals are validated strictly positive after rounding and wrong runtime types no longer clear a goal. DATA-12: the review queue flags missing source serving size from explicit provenance instead of the arithmetic fallback. DATA-15: barcode writes share the 4-20 byte domain both lookups accept. DATA-17: admin before-images are captured under the product row lock. API-05: the admin user detail exposes updatedAt without widening the session recipe payload. Regressions live in db::tests::data_integrity and the extended existing suites; verified with cargo test against a disposable PostgreSQL, the live packages/db suite (122 passed) and the web suite with the Rust backend.
DATA-16: the compact planned-shopping projection carries servingMultiplier and the shopping builder multiplies serving/count amounts by it, matching the backend nutrition; gram/ml stay unchanged. SEC-06: a browser-safe product projection strips internal provenance (contributor ids, source provider/confidence/metadata, correction links) from session search results, barcode save echoes and library page props, while nutrition and source labels stay. The shared db mock keeps real non-function exports so the projection constant survives module mocking. Covered by new browser-product and shopping-list unit tests plus the session-action serialization assertion.
…aging; drop temporary index stopgap
lnieuwenhuis
added a commit
that referenced
this pull request
Sep 17, 2026
…-staging Integrate DATA (#184) after controls (#183), migrations (#180), security (#178), build (#175) and benchmark (#179). Semantic resolution: keep DATA's BrowserFoodProduct types together with the UI-22 per-operation date/idempotency-key logic in food-search-modal.tsx (drop the mount-memoized todayStr/useMemo); all other overlaps auto-merged, including the promise-returning onSaveAsPreset against the controls recipe-builder changes. Preserves controls, security, benchmark and DATA/API-05 patch semantics alongside UI-03 client dirty-draft merging.
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.
Summary
Independent data-integrity release for DATA-01..17, API-05, SEC-06. Base origin/staging 6a2146a (PR #175). Two cherry-picks ONLY from fix/audit-data-integrity (43be1d03, dae8256c), excluding unrelated dev docs c6160bd. Original worktree untouched. No openfoodfacts.ts changes (API-04/UI-07 later integration preserved). No pagination/version changes (3.5.0 kept, pagination/3.6.0 owners preserved).
Fixes: meal PATCH merges under SELECT FOR UPDATE with group-first FOR SHARE ordering, product snapshot preserved unless nutrition inputs changed, stats eaten_days by entry presence including zero-calorie, HealthKit tzOffsetMinutes local-day clamp, quantity/multiplier/default-serving round-to-precision before positivity, template append_base+index, group delete/create sorted locking, weight stats as-of selectedDate, named unique conflicts to 409, goal strict positivity after round2 with invalid-type rejection, mutationId 128-char cap, missing-serving provenance via source_metadata null, sort-order bigint clamp, optional_f64 fallible, barcode 4-20 shared domain, shopping multiplier projection + builder, admin FOR UPDATE before-image, admin recipe updatedAt projection, BrowserFoodProduct redaction.
Verification
Disposable DB only: macro-tracker-data-staging-pg 127.0.0.1:55452 macro_tracker_data_staging_test, never normal/prod. Fresh release-tree runs:
Migrations
None. No fixture/migration files edited. DATA-09 test creates meal_groups_active_default_label_key IF NOT EXISTS as temporary until MIG-01/TEST-01 PR #180 merges, then removable no-op.
Breaking behavior
None. Compatible: PATCH accepts same keys (strips __*), shopping adds servingMultiplier field, BrowserFoodProduct omits 7 internal fields, stats now includes zero-calorie tracked days per held PR177 wording, HealthKit adds optional tzOffsetMinutes default 0.
Risks
MIG PR #180 concurrently open; stopgap harmless after. Contracts PR #177 HOLD pending DATA-03: this branch provides denominator (entry-presence incl zero-calorie) matching its wording. No pagination, no openfoodfacts, no new prod deps.