# Profile Edit Collapsible Bugfix Design

## Overview

Users cannot view or edit their height and gender values after the initial one-time prompts disappear on the Track Visceral Fat screen. The fix adds an always-visible collapsible "Height & Gender" section (using Flutter's `ExpansionTile`) that lets users view and update their profile data at any time, while preserving the existing first-time prompt UX for users who haven't yet set their values.

## Glossary

- **Bug_Condition (C)**: The condition where a user has previously saved height/gender values and the one-time prompts are no longer displayed, leaving no UI path to view or edit those values
- **Property (P)**: A collapsible "Height & Gender" section is always visible on the Track Visceral Fat screen, enabling viewing and editing of profile data regardless of whether values are set
- **Preservation**: Existing one-time prompt behavior, waist measurement submission, form interactions, snackbar confirmations, and prompt dismissal behavior must remain unchanged
- **TrackVisceralFatScreen**: The screen in `lib/screens/track_visceral_fat_screen.dart` that handles waist circumference entry and profile prompts
- **UserProfile**: The model in `lib/models/user_profile.dart` with fields `heightValue` (double?), `heightUnit` (String?), `gender` (String?)
- **SaveUserProfileEvent**: The BLoC event used to persist profile changes via `HealthDataBloc`
- **ExpansionTile**: Flutter widget that provides a collapsible/expandable section with a header and child content

## Bug Details

### Bug Condition

The bug manifests when a user has previously saved their height and/or gender values. Once saved, the conditional rendering logic (`if (userProfile == null || !userProfile.hasHeight) && !_heightPromptDismissed`) evaluates to false, hiding the prompts with no alternative UI to access those values.

**Formal Specification:**
```
FUNCTION isBugCondition(input)
  INPUT: input of type { userProfile: UserProfile, screenState: ScreenState }
  OUTPUT: boolean
  
  RETURN (input.userProfile.hasHeight OR input.userProfile.hasGender)
         AND input.screenState == 'track_visceral_fat_screen_displayed'
         AND NOT editUIAvailable(input.userProfile)
END FUNCTION
```

### Examples

- User sets height to 175 cm → height prompt disappears → no way to see "175 cm" or change it to 180 cm
- User selects gender "male" → gender prompt disappears → no way to see "male" or change it to "female"
- User accidentally enters height as 17.5 cm (typo, meant 175) → saves → cannot correct without clearing app data
- User has both height and gender set → neither prompt shows → complete loss of profile visibility on this screen

## Expected Behavior

### Preservation Requirements

**Unchanged Behaviors:**
- One-time height prompt must still appear for users with null `heightValue` (first-time experience)
- One-time gender prompt must still appear for users with null `gender` (first-time experience)
- Dismissing one-time prompts via close button must still hide them for the session
- Waist measurement form (input, unit selector, date picker, notes) must function identically
- Form submission via "Save Waist Measurement" button must save and navigate back with success feedback
- Success snackbar confirmations for profile saves must continue to display
- Validation logic for waist and height fields must remain unchanged

**Scope:**
All inputs that do NOT involve viewing/editing profile data in the collapsible section should be completely unaffected by this fix. This includes:
- Waist circumference data entry and validation
- Date/time selection
- Notes field interaction
- Form submission flow
- Tips widget display
- One-time prompt appearance for first-time users

## Hypothesized Root Cause

Based on the bug description, the root cause is a UX design gap rather than a code defect:

1. **No Persistent Edit UI**: The screen only provides one-time prompts for setting profile data. Once values are saved, the conditional guards (`!userProfile.hasHeight`, `!userProfile.hasGender`) prevent the prompts from rendering, and no alternative edit UI exists.

2. **Conditional Rendering Without Fallback**: The `_buildHeightPrompt` and `_buildGenderPrompt` widgets are wrapped in `if` conditions that check for null values. When values are set, nothing replaces them in the widget tree.

3. **State Model Limitation**: The `_heightPromptDismissed` / `_genderPromptDismissed` flags only control session-level visibility of the one-time prompts. There is no concept of an "always-visible profile section" in the current state model.

4. **No Separation of Concerns**: The same widgets serve both the "first-time setup" and "ongoing edit" use cases. A dedicated collapsible section is needed to separate these concerns.

## Correctness Properties

Property 1: Bug Condition - Collapsible Section Always Visible

_For any_ screen state where `TrackVisceralFatScreen` is displayed, the collapsible "Height & Gender" section SHALL be rendered in the widget tree regardless of whether `userProfile.hasHeight` is true, `userProfile.hasGender` is true, or both are false.

**Validates: Requirements 2.1, 2.2, 2.3**

Property 2: Preservation - Existing Form and Prompt Behavior

_For any_ interaction that does NOT involve the new collapsible section (waist input, date picker, notes, form submission, one-time prompt appearance/dismissal), the fixed code SHALL produce exactly the same behavior as the original code, preserving all existing functionality.

**Validates: Requirements 3.1, 3.2, 3.3, 3.4, 3.5**

## Fix Implementation

### Changes Required

**File**: `lib/screens/track_visceral_fat_screen.dart`

**Approach**: Add an always-visible collapsible `ExpansionTile` section for "Height & Gender" that displays current profile values and allows editing. Keep existing one-time prompts intact for first-time users.

**Specific Changes**:

1. **Add Collapsible Section Widget**: Create a new `_buildProfileEditSection` method that returns an `ExpansionTile` (or `Card` wrapping an `ExpansionTile`) with:
   - Title: "Height & Gender"
   - Initially collapsed (`initiallyExpanded: false`)
   - Trailing expand/collapse icon (built-in with `ExpansionTile`)

2. **Collapsible Section Content**: When expanded, display:
   - Current height value with unit (or "Not set" if null)
   - Height edit fields (reuse `ValidatedNumberField` + unit dropdown pattern)
   - Current gender value (or "Not set" if null)
   - Gender selection chips (reuse `ChoiceChip` pattern)
   - A "Save Changes" button that calls `SaveUserProfileEvent`

3. **Add State Variables**: Add `_editingHeight`, `_editingHeightUnit`, `_editingGender` state variables for the collapsible section's edit state (separate from the one-time prompt state variables to avoid interference).

4. **Insert in Widget Tree**: Place the collapsible section in the `Column` children after the Notes card and before the one-time prompts:
   ```
   _buildNotesCard(theme),
   SizedBox(height: 16),
   _buildProfileEditSection(theme, userProfile),  // NEW
   SizedBox(height: 16),
   // existing one-time prompts (unchanged)
   ```

5. **Initialize Edit State from Profile**: When profile loads or the section expands, populate edit fields with current `userProfile` values so the user sees their existing data.

6. **Save Logic**: Reuse the existing `SaveUserProfileEvent` pattern — create a `UserProfile` with the edited values and dispatch to `HealthDataBloc`. Show success snackbar on save.

## Testing Strategy

### Validation Approach

The testing strategy follows a two-phase approach: first, surface counterexamples that demonstrate the bug on unfixed code, then verify the fix works correctly and preserves existing behavior.

### Exploratory Bug Condition Checking

**Goal**: Surface counterexamples that demonstrate the bug BEFORE implementing the fix. Confirm that once profile values are set, no edit UI is accessible.

**Test Plan**: Write widget tests that set up a `TrackVisceralFatScreen` with a pre-populated `UserProfile` (height and gender set) and assert that no edit controls for height/gender are findable in the widget tree.

**Test Cases**:
1. **No Height Edit When Set**: Render screen with `heightValue: 175, heightUnit: 'cm'` → assert no height input field is visible (will fail on unfixed code confirming the bug)
2. **No Gender Edit When Set**: Render screen with `gender: 'male'` → assert no gender selection chips are visible (will fail on unfixed code confirming the bug)
3. **Both Set, No Edit UI**: Render with full profile → assert neither height nor gender edit controls exist (will fail on unfixed code)
4. **Null Profile Shows Prompts**: Render with null profile → assert one-time prompts ARE visible (will pass on unfixed code, establishing baseline)

**Expected Counterexamples**:
- Widget tree contains no height/gender editing widgets when profile values are set
- Confirms that the only UI path (one-time prompts) is conditional on null values

### Fix Checking

**Goal**: Verify that for all inputs where the bug condition holds (profile values are set), the collapsible section is visible and functional.

**Pseudocode:**
```
FOR ALL input WHERE isBugCondition(input) DO
  result := renderTrackVisceralFatScreen_fixed(input)
  ASSERT collapsibleSectionExists(result)
  ASSERT canExpandSection(result)
  ASSERT displaysCurrentValues(result, input.userProfile)
  ASSERT canEditAndSave(result)
END FOR
```

### Preservation Checking

**Goal**: Verify that for all inputs where the bug condition does NOT hold (profile values are null), the one-time prompts still appear and all other form behavior is unchanged.

**Pseudocode:**
```
FOR ALL input WHERE NOT isBugCondition(input) DO
  ASSERT renderScreen_original(input).oneTimePrompts == renderScreen_fixed(input).oneTimePrompts
  ASSERT renderScreen_original(input).formBehavior == renderScreen_fixed(input).formBehavior
END FOR
```

**Testing Approach**: Widget testing is recommended for preservation checking because:
- It verifies the widget tree structure matches expectations
- It catches regressions in conditional rendering logic
- It validates that user interactions (tap, input, submit) produce the same outcomes

**Test Plan**: Observe behavior on UNFIXED code first for one-time prompts and form interactions, then write tests capturing that behavior.

**Test Cases**:
1. **One-Time Height Prompt Preserved**: Render with null height → verify height prompt appears with close button and save button
2. **One-Time Gender Prompt Preserved**: Render with null gender → verify gender prompt appears with choice chips and save button
3. **Prompt Dismissal Preserved**: Render with null height → tap close → verify prompt disappears
4. **Form Submission Preserved**: Enter valid waist measurement → tap save → verify `AddWaistEntryEvent` is dispatched and navigation occurs
5. **Snackbar Confirmation Preserved**: Save height via one-time prompt → verify success snackbar appears

### Unit Tests

- Test that `_buildProfileEditSection` renders an `ExpansionTile` with correct title
- Test that collapsed state shows only the header
- Test that expanded state shows current height value and unit
- Test that expanded state shows current gender value
- Test that "Not set" labels appear when profile values are null
- Test that save button dispatches `SaveUserProfileEvent` with correct values
- Test height validation in the collapsible section

### Property-Based Tests

- Generate random `UserProfile` states (combinations of null/non-null height, heightUnit, gender) and verify the collapsible section is always rendered
- Generate random height values within valid range and verify they display correctly when expanded
- Generate random sequences of expand/collapse/edit/save actions and verify state consistency

### Integration Tests

- Test full flow: load screen with existing profile → expand section → edit height → save → verify updated value persists
- Test that collapsible section and one-time prompts coexist correctly when only one value is set (e.g., height set, gender null)
- Test that saving from the collapsible section shows the same snackbar feedback as saving from one-time prompts
