Skip to content

feat: add body measurement history and explicit remeasurement - #204

Closed
krzysiek-kurek wants to merge 8 commits into
Anyesh:mainfrom
krzysiek-kurek:feat/body-measurement-history-remeasurement
Closed

krzysiek-kurek wants to merge 8 commits into
Anyesh:mainfrom
krzysiek-kurek:feat/body-measurement-history-remeasurement

Conversation

@krzysiek-kurek

@krzysiek-kurek krzysiek-kurek commented Sep 18, 2026

Copy link
Copy Markdown

Description

Adds time-aware body measurement history and an explicit remeasurement flow while preserving the existing profile snapshot for compatibility.

Backend

  • stores numeric body measurements as timestamped observations with source metadata
  • exposes current measurement state and history
  • adds an explicit POST /api/v1/users/me/body-measurements endpoint so remeasuring the same value still creates a new observation
  • keeps partial profile measurement updates additive instead of dropping unrelated measurements
  • backfills existing numeric profile measurements as legacy observations with unknown measurement time

Frontend

  • separates the last saved value from the current measurement session
  • keeps inputs empty until the user actively measures or edits a field
  • lets users clear accidental measurement activation
  • saves explicit measurements through the dedicated endpoint
  • preserves canonical values when switching metric/imperial units while a save is still pending

Related Issue

N/A — no matching open issue or pull request was found.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Checklist

  • I have read CONTRIBUTING
  • My code follows the project's existing style
  • I have added tests for the new behavior
  • All tests pass locally
  • I have checked the migration chain
  • No new dependencies were added

Testing

Scoped branch after rebasing onto current upstream/main:

  • backend: 727 passed
  • frontend: 181 passed
  • i18n checks: passed across all 8 locales
  • Ruff check / format: passed
  • TypeScript typecheck: passed
  • production build: passed
  • Alembic: single head
  • review regression tests: concurrent partial writes and NaN/Infinity handling covered
  • concurrency regressions: concurrent partial profile updates and concurrent explicit remeasurements preserve both metrics
  • non-finite regressions: NaN / ±Infinity are rejected with 422 instead of reaching persistence

Aggregate/self-hosted validation:

  • aggregate-focused backend measurement tests: 25 passed
  • aggregate-focused frontend measurement/session tests: 11 passed
  • the self-hosted production instance already contains the aggregate implementation of this feature
  • production database is at its current aggregate Alembic head, and the running backend contains the measurement history / remeasurement endpoints

Screenshots

Not included; this changes the behavior of the existing Settings → Body Measurements UI rather than introducing a new layout.

Additional Notes

  • Existing body_measurements profile data remains the compatibility snapshot.
  • Historical observations are stored separately.
  • Legacy values are represented with source = legacy_profile and no measured_at timestamp.
  • Re-submitting the same measurement through the explicit endpoint intentionally records a new observation.
  • The migration is based on the current upstream migration head; the self-hosted aggregate has a longer migration chain and was validated separately.

This change was developed with AI assistance (ChatGPT, OpenAI). The implementation and tests were reviewed and verified locally before submission.

Summary by Sourcery

Add time-aware body measurement history and explicit remeasurement while preserving compatibility with the existing profile snapshot.

New Features:

  • Add APIs for recording, viewing current state, and retrieving history for body measurement observations.
  • Introduce an explicit remeasurement flow that records repeated values as new timestamped observations.

Bug Fixes:

  • Preserve unrelated body measurements during partial profile updates and prevent concurrent updates from losing data.
  • Reject invalid, non-finite, and out-of-range measurement values before persistence.

Enhancements:

  • Backfill existing profile measurements as legacy observations while retaining the profile snapshot for compatibility.
  • Update the settings UI to distinguish saved values from active measurement drafts, support clearing activation, and preserve values across unit changes and pending saves.

Tests:

  • Add backend and frontend coverage for measurement history, remeasurement, validation, partial-update concurrency, and unit reconciliation.

@github-actions github-actions Bot added javascript Pull requests that update javascript code python Pull requests that update python code labels Sep 18, 2026
@sourcery-ai

sourcery-ai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduces time-aware body measurement history alongside the existing profile snapshot, with validated and concurrency-safe APIs for explicit remeasurement and additive profile updates. The settings UI now distinguishes saved values from active drafts, supports clearing and explicit confirmation, and preserves canonical values across unit changes and pending saves.

Sequence diagram for explicit body measurement remeasurement

sequenceDiagram
    actor User
    participant Settings as SettingsUI
    participant API as UsersAPI
    participant Service as BodyMeasurementService
    participant DB as Database

    User->>Settings: handleConfirmMeasurement()
    Settings->>API: POST /users/me/body-measurements
    API->>API: normalize_measurement_value()
    API->>Service: record_measurements()
    Service->>DB: lock_user_for_measurement_update()
    Service->>DB: insert BodyMeasurementObservation
    Service->>DB: update user.body_measurements snapshot
    API->>Service: current_state()
    Service-->>API: current measurement state
    API-->>Settings: BodyMeasurementStateResponse
    Settings-->>User: show saved measurement
Loading

Entity relationship diagram for body measurement history

erDiagram
    USER ||--o{ BODY_MEASUREMENT_OBSERVATION : has
    USER {
        uuid id PK
        jsonb body_measurements "compatibility snapshot"
    }
    BODY_MEASUREMENT_OBSERVATION {
        uuid id PK
        uuid user_id FK
        string metric
        numeric value
        string unit
        datetime measured_at
        string source
        datetime created_at
    }
Loading

File-Level Changes

Change Details Files
Add a timestamped observation model and migration while retaining the profile snapshot as the compatibility projection.
  • Create per-user observations with metric, normalized numeric value, unit, measured/created timestamps, and source metadata.
  • Backfill valid numeric snapshot values as legacy observations with unknown measurement time.
  • Preserve non-numeric profile fields and existing snapshot compatibility behavior.
backend/app/models/body_measurement.py
backend/app/models/__init__.py
backend/migrations/versions/c9d0e1f2a3b4_add_body_measurement_observations.py
Expose measurement recording, current state, and history through validated API endpoints and service operations.
  • Add POST, current-state GET, and history GET endpoints under /users/me/body-measurements.
  • Normalize and reject non-finite, non-positive, and out-of-storage-range values before persistence.
  • Record repeated explicit values as new manual observations and derive current state from the snapshot plus latest matching observation.
backend/app/api/users.py
backend/app/services/body_measurement_service.py
Make profile and explicit measurement writes additive and safe under concurrent updates.
  • Record changed numeric profile values without creating observations for unchanged values.
  • Merge partial measurement patches instead of replacing unrelated snapshot entries.
  • Lock the user row during measurement updates so concurrent metric writes preserve both snapshot and history changes.
backend/app/api/users.py
backend/app/services/body_measurement_service.py
backend/tests/test_body_measurement_remeasurement.py
Separate saved measurement values from active frontend drafts and route explicit measurements through the dedicated API.
  • Keep saved numeric values as placeholders until a field is focused, then support editing, confirmation, and clearing activation.
  • Submit numeric drafts as canonical metric values and continue sending clothing-size changes as targeted profile patches.
  • Reconcile drafts and saved displays across unit changes, including while a save is pending.
frontend/app/dashboard/settings/page.tsx
frontend/lib/hooks/use-user.ts
Add regression coverage for history semantics, validation, concurrency, session behavior, and unit reconciliation.
  • Verify legacy state, changed-versus-unchanged observations, repeated remeasurement, partial writes, and invalid numeric inputs.
  • Cover frontend activation/clearing, targeted saves, canonical unit conversion, and pending-save reconciliation.
backend/tests/test_body_measurement_remeasurement.py
backend/tests/test_users.py
frontend/tests/settings-measurement-unit-reconciliation.test.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="backend/app/api/users.py" line_range="119-125" />
<code_context>
                 )

+    if "body_measurements" in update_data:
+        measurement_patch = update_data["body_measurements"]
+        await BodyMeasurementService(db).record_profile_changes(current_user, measurement_patch)
+        if measurement_patch is not None:
+            update_data["body_measurements"] = {
+                **(current_user.body_measurements or {}),
+                **measurement_patch,
+            }
+
     for field, value in update_data.items():
</code_context>
<issue_to_address>
**issue (bug_risk):** Concurrent partial profile updates read the same old snapshot, then each writes a complete merged snapshot based on that stale value. The last transaction overwrites measurements written by the other transaction, even though both observations remain in history.

**Triggers:** When two profile measurement patches for different metrics are submitted concurrently.

**Suggested fix:** Apply the JSONB patch atomically in the database, or lock and refresh the user row before merging the snapshot.
</issue_to_address>

### Comment 2
<location path="backend/app/api/users.py" line_range="167-177" />
<code_context>
+            detail="at least one measurement is required",
+        )
+
+    for metric, value in data.measurements.items():
+        if metric not in MEASUREMENT_UNITS:
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail=f"unsupported body measurement: {metric}",
+            )
+        if value <= 0:
+            raise HTTPException(
</code_context>
<issue_to_address>
**issue (bug_risk):** A non-finite numeric value such as NaN passes the endpoint's `value <= 0` validation, then `_number` evaluates `result > 0` and raises `decimal.InvalidOperation` instead of returning a validation error. The request therefore produces an internal server error rather than a 422 response.

**Triggers:** When a client submits a JSON NaN value to the explicit body-measurement endpoint.

**Suggested fix:** Reject non-finite values with `math.isfinite(value)` before calling the service, and handle non-finite Decimal values in `_number`.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and this adds persisted measurement observations and backfills existing profile data, so a faulty value or timestamp can remain in history after the code is reverted. The current profile snapshot and observation table are bounded and can be corrected or rebuilt, but the migration and writes are not purely ephemeral.

Blocking findings: backend/app/api/users.py:125, backend/app/api/users.py:177


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread backend/app/api/users.py
Comment thread backend/app/api/users.py
@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/lib/hooks/use-user.ts" line_range="20" />
<code_context>
   role: string;
   onboarding_completed: boolean;
-  body_measurements?: Record<string, number | string> | null;
+  body_measurements?: Record<string, number | string | null> | null;
+}
+
</code_context>
<issue_to_address>
**issue (bug_risk):** When the profile contains a cleared size field represented as `null`, the settings initialization converts it with `String(value)`, so the input displays the literal text `"null"` instead of remaining empty.

**Triggers:** When a body-measurement size has been saved as null, such as after clearing it.

**Suggested fix:** Treat null values as empty strings during settings initialization, e.g. use `value == null ? '' : String(value)`.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and if the measurement projection or recording logic is wrong, incorrect values and historical observations can remain persisted after the code is reverted. The affected user measurement data is bounded and can be corrected or removed, but reverting alone does not undo it.

Blocking findings: frontend/lib/hooks/use-user.ts:20


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread frontend/lib/hooks/use-user.ts
@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/app/dashboard/settings/page.tsx" line_range="472-477" />
<code_context>
-        body_measurements: Object.keys(parsed).length > 0 ? parsed : null,
-      });
-      setMeasurementsDirty(false);
+      if (measurementsDirty) {
+        const sizeKeys = ['shirt_size', 'pants_size', 'dress_size', 'shoe_size'];
+        const sizeMeasurements: Record<string, string | null> = {};
+        for (const key of sizeKeys) {
+          const value = measurements[key]?.trim();
+          sizeMeasurements[key] = value || null;
+        }
+        await updateUserProfile.mutateAsync({ body_measurements: sizeMeasurements });
</code_context>
<issue_to_address>
**issue (broader_impact):** Editing one clothing-size field sends all four size keys, assigning `null` to untouched fields; the backend merges those nulls into the profile snapshot, so existing unrelated size values are erased on save.

**Triggers:** When a user has an existing pants, dress, or shoe size and edits only another size field.

**Suggested fix:** Send only size fields that were actually edited, or make the backend distinguish omitted fields from explicit clears before merging the patch.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and if the new recording or backfill logic is wrong, incorrect body-measurement observations and profile values remain after a revert; the history cannot be restored by rerunning the old code. The affected records are user-scoped and bounded, so they can be corrected or rebuilt with a repair migration.

Blocking findings: frontend/app/dashboard/settings/page.tsx:477


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread frontend/app/dashboard/settings/page.tsx Outdated
@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/tests/body-measurement-session.test.ts" line_range="15-19" />
<code_context>
+)
+
+describe('body measurement session UX', () => {
+  it('writes confirmed measurements through the explicit endpoint', () => {
+    expect(userHooksSource).toContain('useRecordBodyMeasurements')
+    expect(userHooksSource).toContain("'/users/me/body-measurements'")
+    expect(userHooksSource).toContain('api.post')
+  })
+
+  it('keeps measurement inputs empty and shows the last value as placeholder', () => {
</code_context>
<issue_to_address>
**issue (testing):** This test only searches source-code text and never renders the settings page or invokes the save flow, so it passes even when the hook is not wired correctly or confirmed measurements are sent through the wrong runtime path.

**Triggers:** When the endpoint wiring is changed without updating the literal source strings.

**Suggested fix:** Render the component with mocked hooks and assert that saving an activated measurement calls the mutation with the expected canonical value.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and if the history or current-state projection is wrong, this change can persist incorrect measurement observations and profile values beyond the request that created them. Reverting removes the new code, but already-written observations would need a bounded cleanup or recomputation rather than being automatically undone.

Blocking findings: frontend/tests/body-measurement-session.test.ts:19


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread frontend/tests/body-measurement-session.test.ts Outdated
@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="backend/app/models/body_measurement.py" line_range="22" />
<code_context>
+        UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
+    )
+    metric: Mapped[str] = mapped_column(String(32), nullable=False, index=True)
+    value: Mapped[Decimal] = mapped_column(Numeric(12, 4), nullable=False)
+    unit: Mapped[str] = mapped_column(String(16), nullable=False)
+    measured_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
</code_context>
<issue_to_address>
**issue (bug_risk):** The endpoint accepts any positive finite float, but observations use `Numeric(12, 4)` without range or precision validation. A value such as `0.00001` is rounded to zero in persistence while the profile snapshot retains the positive float, so the current-state response no longer matches the newly recorded observation and history reports a different value; sufficiently large values raise a database numeric overflow instead of returning the documented validation error.

**Triggers:** When a client submits a positive measurement outside the database column's representable precision or scale.

**Suggested fix:** Validate and quantize values against the `Numeric(12, 4)` constraints before creating the observation, rejecting values that would round to zero or overflow.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and this persists body-measurement observations and backfills existing profile data into a new history table, so an incorrect value or duplicate observation would outlive the request and require correction or history cleanup. The affected records are bounded and repairable, although reverting the code alone would not correct data already written.

Blocking findings: backend/app/models/body_measurement.py:22


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
)
metric: Mapped[str] = mapped_column(String(32), nullable=False, index=True)
value: Mapped[Decimal] = mapped_column(Numeric(12, 4), nullable=False)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The endpoint accepts any positive finite float, but observations use Numeric(12, 4) without range or precision validation. A value such as 0.00001 is rounded to zero in persistence while the profile snapshot retains the positive float, so the current-state response no longer matches the newly recorded observation and history reports a different value; sufficiently large values raise a database numeric overflow instead of returning the documented validation error.

Triggers: When a client submits a positive measurement outside the database column's representable precision or scale.

Suggested fix: Validate and quantize values against the Numeric(12, 4) constraints before creating the observation, rejecting values that would round to zero or overflow.

@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. A bad validation, unit conversion, or history projection could write incorrect body measurements and durable observation rows for users. Reverting the code would stop the new behavior but would not remove those persisted observations, although the impact is bounded to affected user records and can be corrected with data repair or later measurements.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/tests/body-measurement-session.test.ts" line_range="1-19" />
<code_context>
+import { readFileSync } from 'node:fs'
+import { resolve } from 'node:path'
+import { describe, expect, it } from 'vitest'
+
+const settingsSource = readFileSync(
+  resolve(process.cwd(), 'app/dashboard/settings/page.tsx'),
+  'utf8',
+)
+describe('body measurement session UX', () => {
+  it('keeps measurement inputs empty and shows the last value as placeholder', () => {
+    expect(settingsSource).toContain("value={measurementSession[field.key] ?? ''}")
+    expect(settingsSource).toContain('placeholder={measurements[field.key] ?? placeholder}')
+  })
+
+  it('marks focused measurements active and lets an accidental activation be cleared', () => {
+    expect(settingsSource).toContain('handleActivateMeasurement')
+    expect(settingsSource).toContain('onFocus={() => handleActivateMeasurement(field.key)}')
+    expect(settingsSource).toContain('handleDeactivateMeasurement')
+    expect(settingsSource).toContain('isActive &&')
+  })
+})
</code_context>
<issue_to_address>
**issue (testing):** The session UX test only searches the source text for implementation strings, so it passes even if the component does not render correctly, activation does not update state, or clearing does not work at runtime. It provides no behavioral coverage for the stated input/session invariant.

**Suggested fix:** Render the settings component with mocked hooks and assert the actual input values, placeholder, focus activation, and clear-button behavior.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and this adds persisted measurement observations and changes the profile snapshot, so an incorrect or concurrent update can leave users with a wrong current value or history after a revert. The damage is bounded and can be repaired from the observation history or corrected records, but reverting alone does not undo it.

Blocking findings: frontend/tests/body-measurement-session.test.ts:19


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +1 to +19
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'

const settingsSource = readFileSync(
resolve(process.cwd(), 'app/dashboard/settings/page.tsx'),
'utf8',
)
describe('body measurement session UX', () => {
it('keeps measurement inputs empty and shows the last value as placeholder', () => {
expect(settingsSource).toContain("value={measurementSession[field.key] ?? ''}")
expect(settingsSource).toContain('placeholder={measurements[field.key] ?? placeholder}')
})

it('marks focused measurements active and lets an accidental activation be cleared', () => {
expect(settingsSource).toContain('handleActivateMeasurement')
expect(settingsSource).toContain('onFocus={() => handleActivateMeasurement(field.key)}')
expect(settingsSource).toContain('handleDeactivateMeasurement')
expect(settingsSource).toContain('isActive &&')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (testing): The session UX test only searches the source text for implementation strings, so it passes even if the component does not render correctly, activation does not update state, or clearing does not work at runtime. It provides no behavioral coverage for the stated input/session invariant.

Suggested fix: Render the settings component with mocked hooks and assert the actual input values, placeholder, focus activation, and clear-button behavior.

@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/app/dashboard/settings/page.tsx" line_range="475-479" />
<code_context>
+
+    try {
+      await recordBodyMeasurements.mutateAsync({ [key]: canonicalValue });
+      const reconciledValue = formatMeasurementDisplay(
+        canonicalValue,
+        key,
+        'metric',
+        unitSystemRef.current,
+      );
+      setMeasurements((prev) => ({ ...prev, [key]: reconciledValue }));
</code_context>
<issue_to_address>
**issue (bug_risk):** Both reconciliation call sites pass five arguments to `formatMeasurementDisplay`, but the function accepts only four, so TypeScript compilation fails with an argument-count error.

**Suggested fix:** Add the intended fifth parameter to the function signature or remove the extra argument and perform the unit conversion separately.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 1 finding to address first, and this adds a persistent observation table, backfills legacy measurements, and writes new measurement values and history that would remain if the application code were reverted. Incorrect values or duplicate observations would be bounded and can be corrected or removed, so the impact is repairable rather than irreversible.

Blocking findings: frontend/app/dashboard/settings/page.tsx:479


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +475 to +479
const reconciledValue = formatMeasurementDisplay(
canonicalValue,
key,
'metric',
unitSystemRef.current,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Both reconciliation call sites pass five arguments to formatMeasurementDisplay, but the function accepts only four, so TypeScript compilation fails with an argument-count error.

Suggested fix: Add the intended fifth parameter to the function signature or remove the extra argument and perform the unit conversion separately.

@krzysiek-kurek

Copy link
Copy Markdown
Author

@sourcery-ai review

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. This writes durable measurement observations and backfills legacy profile data into a new table, so reverting the application does not remove potentially incorrect history. The affected values are bounded and users can correct current measurements, but historical rows require explicit cleanup or a migration rollback.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@krzysiek-kurek

Copy link
Copy Markdown
Author

Closing this draft for now while the measurement-history UX and semantics are being refined. The problem and proposed direction are tracked in #205. The implementation branch is being kept so the work can be resumed without losing the tested backend and migration work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update javascript code python Pull requests that update python code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants