# Implementation Plan: Save Waist No Feedback Fix

## Overview

This plan fixes the BlocListener race condition in `TrackVisceralFatScreen` where the `_isLoading` gate is consumed by an intermediate `HealthDataLoading` state before `HealthDataOperationSuccess` arrives. The fix replaces the fragile gate pattern with direct state-type checking filtered by `operationType == 'add_waist'`, matching the proven pattern from `add_mood_screen.dart`.

The implementation follows the exploratory bugfix workflow: write tests to confirm the bug exists, write preservation tests to protect existing behavior, then implement the fix and verify both test suites pass.

## Tasks

- [x] 1. Write bug condition exploration test
  - **Property 1: Bug Condition** - BlocListener Ignores HealthDataOperationSuccess After Intermediate HealthDataLoading
  - **CRITICAL**: This test MUST FAIL on unfixed code - failure confirms the bug exists
  - **DO NOT attempt to fix the test or the code when it fails**
  - **NOTE**: This test encodes the expected behavior - it will validate the fix when it passes after implementation
  - **GOAL**: Surface counterexamples that demonstrate the BlocListener's `_isLoading` gate is consumed by `HealthDataLoading` before `HealthDataOperationSuccess` arrives
  - **Scoped PBT Approach**: Scope the property to the concrete failing case — submit a valid waist measurement, BLoC emits `HealthDataLoading("Adding waist entry...")` then `HealthDataOperationSuccess(operationType: 'add_waist')`, and assert that success snackbar and navigation occur
  - Create a widget test in `test/property_tests/` that:
    - Mounts `TrackVisceralFatScreen` with a mocked `HealthDataBloc`
    - Fills in a valid waist value and submits the form
    - Emits `HealthDataLoading` followed by `HealthDataOperationSuccess(operationType: 'add_waist')` from the mock BLoC
    - Asserts a `SnackBar` with text "Waist measurement saved successfully" is found
    - Asserts `Navigator.pop` is called (screen navigates back)
  - Use `bloc_test` or `mockito` with `whenListen` to control state emissions
  - Generate random valid waist values (30–300 cm range) using `glados` to demonstrate the property holds for any valid input
  - Run test on UNFIXED code
  - **EXPECTED OUTCOME**: Test FAILS (snackbar never appears, navigation never happens — this proves the bug exists)
  - Document counterexamples: "For any valid waist value X, submitting triggers HealthDataLoading which resets _isLoading=false, so HealthDataOperationSuccess is ignored"
  - Mark task complete when test is written, run, and failure is documented
  - _Requirements: 1.1, 1.2, 1.3, 2.1, 2.2, 2.3_

- [x] 2. Write preservation property tests (BEFORE implementing fix)
  - **Property 2: Preservation** - Non-Waist-Success State Handling Unchanged
  - **IMPORTANT**: Follow observation-first methodology
  - Observe on UNFIXED code:
    - Submit invalid waist (empty/out of range) → form validation prevents submission (no BLoC event dispatched)
    - BLoC emits `HealthDataError` after submission → error snackbar appears with red background, user stays on screen
    - BLoC emits `HealthDataOperationSuccess(operationType: 'save_profile')` → no waist success snackbar, no navigation
    - Height/gender profile save via prompt → prompt-specific snackbar via `ScaffoldMessenger` directly, screen remains
  - Write property-based tests capturing observed behavior:
    - **Error handling**: For any `HealthDataError` state emitted after `_isLoading` is true, an error snackbar is shown and the screen does NOT navigate away
    - **Non-waist operation types**: For any `HealthDataOperationSuccess` with `operationType != 'add_waist'` (generate random operation type strings), the listener does NOT show waist success snackbar and does NOT navigate
    - **Profile prompt saves**: Height/gender save buttons trigger their own snackbars without affecting BlocListener navigation
    - **Submit button disabling**: After pressing save, the submit button is disabled while `_isLoading` is true
  - Use `glados` to generate random non-'add_waist' operation types for stronger guarantees
  - Verify all tests PASS on UNFIXED code (these behaviors already work correctly)
  - **EXPECTED OUTCOME**: Tests PASS (confirms baseline behavior to preserve)
  - Mark task complete when tests are written, run, and passing on unfixed code
  - _Requirements: 3.1, 3.2, 3.3, 3.4, 3.5_

- [x] 3. Fix BlocListener race condition in TrackVisceralFatScreen

  - [x] 3.1 Implement the fix
    - Replace the `_isLoading` gate pattern in the BlocListener with direct state-type checking
    - Remove `if (_isLoading) { setState(() { _isLoading = false; }); ... }` wrapper
    - Add check: `if (state is HealthDataOperationSuccess && state.operationType == 'add_waist')` → show success snackbar, reset `_isLoading = false`, call `Navigator.of(context).pop(true)`
    - Add check: `else if (state is HealthDataError && _isLoading)` → show error snackbar, reset `_isLoading = false`
    - Keep `_isLoading = true` in `_submitForm()` to disable the submit button during loading
    - Do NOT change `_onAddWaistEntry` in the BLoC — only the listener in `track_visceral_fat_screen.dart`
    - Match the proven pattern from `add_mood_screen.dart` which checks `state is HealthDataOperationSuccess && state.operationType == 'add_mood'` directly
    - _Bug_Condition: isBugCondition(input) where input.event IS AddWaistEntryEvent AND stateSequence CONTAINS HealthDataLoading BEFORE HealthDataOperationSuccess AND _isLoading is reset by HealthDataLoading_
    - _Expected_Behavior: When BLoC emits HealthDataOperationSuccess with operationType == 'add_waist', listener shows snackbar "Waist measurement saved successfully" and calls Navigator.pop(true)_
    - _Preservation: Error handling still shows error snackbar and keeps user on screen; non-waist operation types are ignored; profile prompt saves unaffected_
    - _Requirements: 2.1, 2.2, 2.3, 2.4, 3.1, 3.2, 3.3, 3.4, 3.5_

  - [x] 3.2 Verify bug condition exploration test now passes
    - **Property 1: Expected Behavior** - Success Feedback After Waist Save
    - **IMPORTANT**: Re-run the SAME test from task 1 - do NOT write a new test
    - The test from task 1 encodes the expected behavior (snackbar + navigation for valid waist save)
    - When this test passes, it confirms the expected behavior is satisfied
    - Run bug condition exploration test from step 1
    - **EXPECTED OUTCOME**: Test PASSES (confirms bug is fixed — snackbar appears and navigation occurs)
    - _Requirements: 2.1, 2.2, 2.3_

  - [x] 3.3 Verify preservation tests still pass
    - **Property 2: Preservation** - Non-Waist-Success State Handling Unchanged
    - **IMPORTANT**: Re-run the SAME tests from task 2 - do NOT write new tests
    - Run preservation property tests from step 2
    - **EXPECTED OUTCOME**: Tests PASS (confirms no regressions — error handling, profile saves, and non-waist operations all behave the same)
    - Confirm all tests still pass after fix (no regressions)

- [x] 4. Checkpoint - Ensure all tests pass
  - Run full test suite: `flutter test`
  - Ensure all property tests pass (both bug condition and preservation)
  - Ensure all existing tests pass (no regressions in other screens)
  - Ask the user if questions arise

## Notes

- The fix is scoped to a single file: `lib/screens/track_visceral_fat_screen.dart`
- The BLoC layer (`health_data_bloc.dart`) is NOT modified — the bug is purely in the UI listener pattern
- The proven pattern from `add_mood_screen.dart` is the reference implementation
- Property-based tests use `glados` (the existing PBT library in this project)
- Widget tests use `bloc_test` / `mockito` for BLoC mocking with controlled state emissions
- Exploration test (task 1) is expected to FAIL on unfixed code — this is correct and confirms the bug
- Preservation tests (task 2) are expected to PASS on unfixed code — this confirms baseline behavior

## Task Dependency Graph

```json
{
  "waves": [
    { "id": 0, "tasks": ["1", "2"] },
    { "id": 1, "tasks": ["3.1"] },
    { "id": 2, "tasks": ["3.2", "3.3"] },
    { "id": 3, "tasks": ["4"] }
  ]
}
```
