# Add Data Waist Link Fix - Bugfix Design

## Overview

Two bugs prevent full access to visceral fat tracking:

1. The Add Data screen's `TabController` is hard-coded with `length: 3` and only defines tabs for Weight, Blood Pressure, and Mood — no waist/visceral fat tab exists.
2. The Track Visceral Fat screen guards height/gender profile prompts with `userProfile != null`, but `DatabaseService.getUserProfile()` returns `null` when no profile row exists. This means new users (the exact audience who need prompts) never see them.

Both fixes are small, localised changes with clear preservation boundaries.

## Glossary

- **Bug_Condition (C)**: The conditions that trigger each bug — (1) navigating to Add Data and expecting a waist tab, (2) having no user_profile row and expecting prompts
- **Property (P)**: The desired correct behaviour — (1) a waist/visceral fat tab is present and navigable, (2) prompts display when profile data is missing regardless of whether a row exists
- **Preservation**: Existing Weight, Blood Pressure, and Mood tabs continue to work; prompts remain hidden when profile fields are already set; dismissal behaviour is unchanged
- **AddDataScreen**: The tabbed data-entry hub in `lib/screens/add_data_screen.dart`
- **TrackVisceralFatScreen**: The waist entry screen in `lib/screens/track_visceral_fat_screen.dart`
- **HealthDataBloc**: BLoC managing health data state including `userProfile` field
- **UserProfile**: Model with nullable `heightValue`, `heightUnit`, `gender` and convenience getters `hasHeight`/`hasGender`
- **DatabaseService.getUserProfile()**: Returns `UserProfile?` — `null` if no row exists in the single-row `user_profile` table

## Bug Details

### Bug Condition

The bugs manifest under two independent conditions:

**Bug 1 — Missing waist tab:** Every user who navigates to Add Data cannot find waist tracking. The tab simply does not exist in the UI.

**Bug 2 — Profile prompts hidden for new users:** A user who has never saved any profile data (no row in `user_profile` table) will never see the height or gender prompts on the Track Visceral Fat screen.

**Formal Specification:**
```
FUNCTION isBugCondition(input)
  INPUT: input of type {screen: String, userProfileRow: UserProfile?}
  OUTPUT: boolean

  // Bug 1: Add Data screen has no waist tab
  IF input.screen == 'AddDataScreen'
    RETURN true  // waist tab always missing

  // Bug 2: Profile prompts hidden when no DB row
  IF input.screen == 'TrackVisceralFatScreen'
    AND input.userProfileRow == null
    RETURN true  // prompts will not display

  RETURN false
END FUNCTION
```

### Examples

- **Bug 1**: User opens Add Data → sees Weight, Blood Pressure, Mood tabs. Expected: also sees a Waist/Visceral Fat tab.
- **Bug 2a**: New user (no profile row) opens Track Visceral Fat → height prompt not shown. Expected: height prompt is shown because height is not set.
- **Bug 2b**: New user (no profile row) opens Track Visceral Fat → gender prompt not shown. Expected: gender prompt is shown because gender is not set.
- **Correct case**: Existing user with height set (profile row exists, `heightValue` != null) opens Track Visceral Fat → height prompt correctly hidden.

## Expected Behavior

### Preservation Requirements

**Unchanged Behaviors:**
- Weight, Blood Pressure, and Mood tabs on Add Data screen must continue to work exactly as before (content, navigation, recent entries)
- When a user profile row exists with `hasHeight == true`, the height prompt must remain hidden
- When a user profile row exists with `hasGender == true`, the gender prompt must remain hidden
- When a user profile row exists with neither field set (`hasHeight == false && hasGender == false`), both prompts must continue to display (this case already works)
- Dismissing a prompt must continue to hide it for the remainder of the session
- The waist measurement form, validation, date picker, notes, tips, and save flow on TrackVisceralFatScreen must remain unchanged

**Scope:**
All inputs that do NOT involve the Add Data tab list or the profile-prompt conditional logic should be completely unaffected. This includes:
- Weight, blood pressure, and mood entry workflows
- Chart screens and navigation
- Home screen quick actions
- Database operations for waist entries and existing metrics

## Hypothesized Root Cause

Based on the code analysis:

1. **Missing Tab (Bug 1)**: `AddDataScreen` creates `TabController(length: 3)` and defines exactly three `Tab` widgets and three `TabBarView` children. No fourth tab for waist/visceral fat was ever added during the visceral fat feature implementation.

2. **Null-Guard Logic Error (Bug 2)**: The conditional rendering in `TrackVisceralFatScreen.build()` uses:
   ```dart
   if (userProfile != null && !userProfile.hasHeight && !_heightPromptDismissed)
   ```
   This short-circuits to `false` when `userProfile` is `null`. The intent was "show prompt when height is not set", but the condition accidentally requires that a profile row exists first. The same pattern applies to the gender prompt.

3. **BLoC Passes Null Faithfully**: `_onLoadUserProfile` calls `DatabaseService.getUserProfile()` which returns `null` when the table is empty. The BLoC stores this `null` in `HealthDataLoaded.userProfile`. This is correct DB behaviour — the bug is purely in the UI conditional logic.

## Correctness Properties

Property 1: Bug Condition - Waist Tab Present on Add Data Screen

_For any_ navigation to the Add Data screen, the screen SHALL display a fourth tab for waist/visceral fat tracking that, when tapped, navigates the user to the Track Visceral Fat screen.

**Validates: Requirements 2.1**

Property 2: Bug Condition - Profile Prompts Shown When Profile Data Missing

_For any_ state where the user has no profile row in the database (userProfile is null) or has a profile row with height/gender not set, the Track Visceral Fat screen SHALL display the corresponding prompt(s) (height and/or gender) unless the user has dismissed them in the current session.

**Validates: Requirements 2.2, 2.3**

Property 3: Preservation - Existing Tabs Unchanged

_For any_ navigation to the Add Data screen, the existing Weight, Blood Pressure, and Mood tabs SHALL continue to display and function identically to their pre-fix behaviour.

**Validates: Requirements 3.5**

Property 4: Preservation - Prompts Hidden When Profile Fields Set

_For any_ state where the user has a profile row with height set (`hasHeight == true`), the height prompt SHALL remain hidden. For any state where gender is set (`hasGender == true`), the gender prompt SHALL remain hidden.

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

## Fix Implementation

### Changes Required

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

**Changes**:
1. **Add import** for `track_visceral_fat_screen.dart`
2. **Change TabController length** from `3` to `4`
3. **Add fourth Tab widget** for waist/visceral fat (icon: `Icons.straighten` or similar, text: 'Waist')
4. **Add fourth TabBarView child** — a new `_WaistEntryTab` widget that mirrors the pattern of other tabs (card linking to TrackVisceralFatScreen, recent entries table)

---

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

**Function**: `build()` method, lines 291–300

**Changes**:
1. **Fix height prompt condition** from:
   ```dart
   if (userProfile != null && !userProfile.hasHeight && !_heightPromptDismissed)
   ```
   to:
   ```dart
   if ((userProfile == null || !userProfile.hasHeight) && !_heightPromptDismissed)
   ```
2. **Fix gender prompt condition** from:
   ```dart
   if (userProfile != null && !userProfile.hasGender && !_genderPromptDismissed)
   ```
   to:
   ```dart
   if ((userProfile == null || !userProfile.hasGender) && !_genderPromptDismissed)
   ```

This inverts the null-check logic: prompts now show when the profile is missing OR when the specific field is not set.

## Testing Strategy

### Validation Approach

The testing strategy follows a two-phase approach: first, surface counterexamples that demonstrate the bugs on unfixed code, then verify the fixes work correctly and preserve existing behavior.

### Exploratory Bug Condition Checking

**Goal**: Surface counterexamples that demonstrate the bugs BEFORE implementing the fix. Confirm or refute the root cause analysis.

**Test Plan**: Write widget tests that render AddDataScreen and verify tab count, and render TrackVisceralFatScreen with a mocked BLoC returning null userProfile and verify prompt visibility.

**Test Cases**:
1. **Missing Waist Tab**: Render AddDataScreen, count tabs — expect 3 (will confirm bug on unfixed code)
2. **Null Profile Height Prompt**: Render TrackVisceralFatScreen with BLoC state `HealthDataLoaded(userProfile: null)`, check for 'Set Your Height' text — expect absent (confirms bug)
3. **Null Profile Gender Prompt**: Same setup, check for 'Set Your Gender' text — expect absent (confirms bug)
4. **Profile with Fields Set**: Render with `HealthDataLoaded(userProfile: UserProfile(heightValue: 170, heightUnit: 'cm', gender: 'male'))` — expect prompts absent (confirms preservation works even before fix)

**Expected Counterexamples**:
- Tab count is 3 instead of 4
- Height and gender prompt widgets are not found when userProfile is null
- Root cause confirmed: null-guard logic and missing tab definition

### Fix Checking

**Goal**: Verify that for all inputs where the bug condition holds, the fixed code produces the expected behavior.

**Pseudocode:**
```
FOR ALL input WHERE isBugCondition(input) DO
  IF input.screen == 'AddDataScreen' THEN
    result := renderAddDataScreen()
    ASSERT tabCount(result) == 4
    ASSERT findTab(result, 'Waist') != null
  IF input.screen == 'TrackVisceralFatScreen' AND input.userProfileRow == null THEN
    result := renderScreen(userProfile: null)
    ASSERT findWidget(result, 'Set Your Height') != null
    ASSERT findWidget(result, 'Set Your Gender') != null
END FOR
```

### Preservation Checking

**Goal**: Verify that for all inputs where the bug condition does NOT hold, the fixed code produces the same result as the original code.

**Pseudocode:**
```
FOR ALL input WHERE NOT isBugCondition(input) DO
  // Existing tabs still work
  ASSERT renderAddDataScreen_fixed().tabContent[0..2] == renderAddDataScreen_original().tabContent[0..2]
  
  // Profile prompts hidden when fields are set
  FOR ALL profile WHERE profile.hasHeight == true DO
    ASSERT heightPromptVisible(profile) == false
  END FOR
  FOR ALL profile WHERE profile.hasGender == true DO
    ASSERT genderPromptVisible(profile) == false
  END FOR
END FOR
```

**Testing Approach**: Property-based testing is recommended for preservation checking because:
- It generates many UserProfile configurations automatically (various combinations of null/set height and gender)
- It catches edge cases like partially-set profiles
- It provides strong guarantees that prompt visibility logic is correct for all non-buggy inputs

**Test Plan**: Observe behaviour on UNFIXED code first for profiles with fields set, then write property-based tests capturing that behaviour.

**Test Cases**:
1. **Existing Tab Preservation**: Verify Weight, Blood Pressure, Mood tabs continue to render and navigate correctly after adding fourth tab
2. **Height Prompt Hidden When Set**: Generate random profiles with `hasHeight == true`, verify prompt never shows
3. **Gender Prompt Hidden When Set**: Generate random profiles with `hasGender == true`, verify prompt never shows
4. **Dismissal Preservation**: Verify dismissing prompt still hides it for remainder of session

### Unit Tests

- Test that AddDataScreen renders exactly 4 tabs after fix
- Test that tapping the Waist tab navigates to TrackVisceralFatScreen
- Test profile prompt visibility for all combinations: null profile, empty profile, height-only, gender-only, both set
- Test prompt dismissal continues to work

### Property-Based Tests

- Generate random `UserProfile?` values (null, empty, partial, full) and verify prompt visibility matches the corrected logic: show when field is missing, hide when set
- Generate random tab indices and verify tab navigation works for all 4 tabs
- Generate profiles where `hasHeight` and `hasGender` are true and verify prompts are always hidden (preservation)

### Integration Tests

- Full flow: navigate to Add Data → tap Waist tab → verify TrackVisceralFatScreen opens
- Full flow: new user (empty DB) → open Track Visceral Fat → see height and gender prompts → fill and save → reopen screen → prompts hidden
- Full flow: existing user with profile → open Track Visceral Fat → prompts not shown → waist entry works correctly
