@clipboard-health/ai-rules 2.41.1 → 2.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/skills/flaky-critic/SKILL.md +41 -2
  3. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/answer-key.json +242 -0
  4. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/cohort.md +37 -0
  5. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/input-hashes.txt +20 -0
  6. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-01.md +141 -0
  7. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-02.md +115 -0
  8. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-03.md +24 -0
  9. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-04.md +85 -0
  10. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-05.md +78 -0
  11. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-06.md +82 -0
  12. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-07.md +128 -0
  13. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-08.md +99 -0
  14. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-09.md +107 -0
  15. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-10.md +141 -0
  16. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-11.md +98 -0
  17. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-12.md +99 -0
  18. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-13.md +25 -0
  19. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-14.md +111 -0
  20. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-15.md +27 -0
  21. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-16.md +46 -0
  22. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-17.md +101 -0
  23. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-18.md +88 -0
  24. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-19.md +98 -0
  25. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/inputs/case-20.md +91 -0
  26. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts/verdicts.jsonl +20 -0
  27. package/skills/flaky-critic/references/backtests/2026-07-16-b8-prior-attempts.md +170 -0
  28. package/skills/flaky-critic/references/rubric.md +17 -2
@@ -0,0 +1,107 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Groundcrew
4
+
5
+ Repository: [mobile frontend]
6
+ GitHub repo: [mobile frontend]
7
+ Implementation workflow: use the `cb-work` skill or, if unavailable, the `core:go`/`go` skill.
8
+
9
+ ## Task
10
+
11
+ Stabilize the MPR V2 Playwright flow in `playwright/e2e/shift/timekeeping.spec.ts` by making `selectMinuteThatRequiresClockInApproval` avoid low-minute loop-boundary clicks that can settle the wheel into a same-hour future time.
12
+
13
+ Suggested smallest fix: update `getTargetMinuteForClockInApproval` so it avoids both `00` and the `01 -> 00` path. For this flow, a slightly later minute is still earlier than the actual worker clock-in because the shift is already in progress; it only needs to dirty the picker and trigger the approval step. A conservative helper shape is:
14
+
15
+ ```ts
16
+ function getTargetMinuteForClockInApproval(selectedMinute: number): number {
17
+ if (selectedMinute <= 1) {
18
+ return selectedMinute + 1;
19
+ }
20
+
21
+ return selectedMinute - 1;
22
+ }
23
+ ```
24
+
25
+ Consider using a slightly wider low-minute guard, for example `selectedMinute <= 5`, if local trace review shows the smooth scroll can settle across several low-minute values. Keep the change test-harness-only unless the implementation investigation proves a real product bug in `WheelTimePicker` click/scroll-end behavior.
26
+
27
+ ## Acceptance Criteria
28
+
29
+ - [ ] The MPR V2 E2E helper no longer clicks `0 minutes` when the selected minute is `1`.
30
+ - [ ] The helper still reaches the approval-step UI by waiting for the earlier-clock-in approval copy and enabled `Next` button.
31
+ - [ ] The change body includes this implementation ticket ID.
32
+ - [ ] Targeted formatting/linting and the smallest practical Playwright verification are run or the Playwright environment blocker is documented.
33
+
34
+ ## Flake Details
35
+
36
+ ```json
37
+ {
38
+ "repo": "[mobile frontend]",
39
+ "test": "Missed punch request should complete MPR V2 flow: already started working, edit clock-in, and submit timesheet",
40
+ "file": "playwright/e2e/shift/timekeeping.spec.ts:920",
41
+ "framework": "playwright",
42
+ "isNewFlaky": false,
43
+ "failures": [
44
+ {
45
+ "error": "Error: Clock-in approval state not reached after clicking 55 minutes; selected minute: 55; Next enabled: false; approval copy: <not visible>\n\nCall Log:\n- Timeout 30000ms exceeded while waiting on the predicate",
46
+ "stack": "Error: Clock-in approval state not reached after clicking 55 minutes; selected minute: 55; Next enabled: false; approval copy: <not visible>\n\nCall Log:\n- Timeout 30000ms exceeded while waiting on the predicate\n at selectMinuteThatRequiresClockInApproval (/home/runner/work/[mobile frontend]/[mobile frontend]/playwright/e2e/shift/timekeeping.spec.ts:147:6)\n at /home/runner/work/[mobile frontend]/[mobile frontend]/playwright/e2e/shift/timekeeping.spec.ts:975:11\n at WorkerMain._runTest (/home/runner/work/[mobile frontend]/[mobile frontend]/node_modules/dd-trace/packages/datadog-instrumentations/src/playwright.js:1692:5)",
47
+ "branch": "gh-readonly-queue/main/change-[reference redacted]-139c9148f92f65dc0d8f2a8f642c56fea71e4e95",
48
+ "pipeline": "[external evidence reference]",
49
+ "commit": "eece17af4aa80924757ee2444f013dadb956d75e",
50
+ "durationMs": [attempt reference redacted],
51
+ "shard": "3/4",
52
+ "timestamp": "2026-06-25T14:06:34Z"
53
+ }
54
+ ]
55
+ }
56
+ ```
57
+
58
+ ## Plan Output
59
+
60
+ **Test ID:** `a51c4867d1e5326a80d8-240a586ace394c9bb6fb`
61
+
62
+ **Confidence:** 4/5. The LLM report, trace steps, and screenshot directly show the failed UI state. One link is inferred: the report does not expose the wheel column `scrollTop` or scroll-end events, so the exact mechanism that moves from `0` to high-50s minutes is inferred from the step sequence and component behavior.
63
+
64
+ **Failure surface:** User action no-op / test harness. The click actions completed, but the expected approval-state transition did not remain reachable. No relevant backend request was emitted during the failed picker-selection loop.
65
+
66
+ **Current main status:** Still applicable on current `origin/main`/branch head `e12d296a7e8`. No open GitHub change labeled `flaky-test-fix` was found. Recent main commits `893373a2abb` and `ba607976ecd` stabilized this same MPR picker area but do not cover the `selectedMinute === 1 -> click 0` low-minute boundary seen here.
67
+
68
+ **Symptom:** `selectMinuteThatRequiresClockInApproval` timed out at `playwright/e2e/shift/timekeeping.spec.ts:147`. The final diagnostic was: `Clock-in approval state not reached after clicking 55 minutes; selected minute: 55; Next enabled: false; approval copy: <not visible>`.
69
+
70
+ **Root Cause:** The test helper derives each retry target from the currently selected minute and usually subtracts one. When the selected minute is `1`, it clicks `0 minutes`. In this live E2E flow the looped `WheelTimePicker` uses smooth scrolling and scroll-end recentering; after the low-minute boundary click, subsequent retries observed/clicked high minute values (`57`, `56`, `55`, `54`). Those same-hour high-minute selections were in the future relative to browser time, so `useClockInTimeValidation` showed the future-time error, hid the approval copy, and left the footer as disabled `Save` instead of enabled `Next`.
71
+
72
+ **Evidence:**
73
+
74
+ - LLM report summary for run [reference redacted]`: 45 total, 44 passed, 1 flaky; this test failed on attempt 1 and passed on attempt 2.
75
+ - Failed attempt timeline reached `Adjust clock in` at offset `68591ms`, then the helper clicked minute options `0`, `57`, `56`, `55`, and `54` before timing out.
76
+ - Passing retry reached `Adjust clock in` at offset `28654ms`, clicked `2 minutes`, saw the approval copy, found `Next` enabled, and completed the full flow.
77
+ - Failure screenshot shows the adjustment sheet with error copy `This time (7:54 AM) is in the future. Please end your shift before requesting shift payment.`, selected `54` minutes, and a disabled `Save` button.
78
+ - The product validation path in `validateClockInTimestamp` marks selected times after `startOfMinute(new Date())` as `IN_FUTURE`; `TimekeepingAdjustmentBottomSheet` only labels the footer `Next` when `requiresApproval` is stable.
79
+ - Network summary had retained-request caps (`instancesDroppedByGroupCap: 29`, `instancesEvictedAfterAdmission: 14`), but no failed backend request explains the picker transition. The only retained 4xx was an unrelated `worker-payouts/last` 404.
80
+
81
+ **Proposed Fix:** Test harness only, in `playwright/e2e/shift/timekeeping.spec.ts`.
82
+
83
+ Update the minute target helper to avoid low-minute loop-boundary targets. At minimum, handle `selectedMinute <= 1` by clicking a later safe minute, not `0`. This keeps the selected adjusted time earlier than the actual worker clock-in in this scenario while avoiding the looped wheel boundary that can settle into future high-minute values.
84
+
85
+ Optionally improve diagnostics in `getMinuteSelectionDiagnostics` to include the visible footer button text, visible intent/error copy, selected hour/minute/meridiem labels, and browser `new Date().toISOString()` so the next failure is self-contained.
86
+
87
+ **Observability to Reach 5/5:**
88
+
89
+ - Frontend/test reporter: include selected hour/minute/meridiem, all visible intent/error banner text, visible footer button names, and browser current time in the helper failure message.
90
+ - If the low-minute fix does not settle the flake, add temporary Playwright trace diagnostics for the minutes listbox `scrollTop` and selected option before/after each click to prove whether `WheelColumn` scroll-end recentering is overriding `onSelect`.
91
+ - Backend telemetry is not required for this failure unless a future occurrence emits `validate_timekeeping_action` during the failed transition.
92
+
93
+ **Sibling Candidates:**
94
+
95
+ - Primary: `playwright/e2e/shift/timekeeping.spec.ts` helper `getTargetMinuteForClockInApproval` / `selectMinuteThatRequiresClockInApproval`.
96
+ - Review but do not preemptively patch: `src/appV2/redesign/components/WheelTimePicker/WheelColumn.tsx`, because a real product click/scroll bug would need separate proof.
97
+
98
+ **Validation Plan:**
99
+
100
+ - `npx oxfmt --check playwright/e2e/shift/timekeeping.spec.ts`
101
+ - `npm run lint -- playwright/e2e/shift/timekeeping.spec.ts`
102
+ - If the local Playwright environment is available: `npx playwright test --config ./playwright.config.ts --project "Mobile Chrome" playwright/e2e/shift/timekeeping.spec.ts --grep "already started working"`
103
+ - If Playwright setup is missing, run/document `npm run playwright:setup` and the blocker, then rely on CI for the live E2E run.
104
+
105
+ **Open Questions:** None blocking. The implementation can proceed with a test-harness-only change.
106
+
107
+ **Residual Risk:** This flow still depends on live E2E services and real wall-clock time. If the wheel component itself can override clicked selections after smooth scroll in normal user interaction, the test-harness fix will reduce flakes but not address that broader product behavior.
@@ -0,0 +1,141 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Groundcrew
4
+
5
+ Repository: [admin frontend]
6
+ Implementation workflow: implement this ticket using the `cb-work` skill if available. If `cb-work` is unavailable, use the `core:go`/`go` skill. Follow this repo's AGENTS.md implementation workflow and run the documented verification.
7
+
8
+ In the change body, include this implementation ticket ID and investigation ticket `[ticket redacted]`.
9
+
10
+ ```bash
11
+
12
+ ```
13
+
14
+ ## Task
15
+
16
+ Stabilize the shared Playwright E2E Cognito user provisioning path so freshly created facility/workplace/HCP users are not used for Cognito Admin API mutations before they exist in the staging Cognito user pool `us-west-2_HV1ibP3I6`.
17
+
18
+ Do not create per-test fixes. Diagnose and fix the shared setup path used by these fingerprints.
19
+
20
+ ## Required Fix Shape
21
+
22
+ Implement one shared Cognito readiness/de-stressing mechanism instead of increasing per-test retries.
23
+
24
+ Required readiness signal:
25
+
26
+ - After [backend service]/test-helper user creation returns successfully, wait for `AdminGetUser` to succeed for the exact synthetic E2E user in pool `us-west-2_HV1ibP3I6` before calling `AdminSetUserPasswordCommand` or `AdminUpdateUserAttributesCommand`.
27
+ - For worker/HCP setup, also verify the returned Cognito user has enough expected identity attributes to safely apply the requested user-type attribute update. If the backend creates the user under a normalized username instead of raw email, resolve that username once and use it consistently for all later Cognito Admin calls.
28
+ - Treat `UserNotFoundException` as readiness-not-yet-met. Do not call password or attribute mutations until readiness is confirmed.
29
+
30
+ Required retry bound and behavior:
31
+
32
+ - Use a bounded wait that is long enough for staging Cognito propagation, with capped backoff and jitter. The existing 5 attempts spaced 2s apart is the observed insufficient bound; replace it with an explicit total timeout such as 60-90s unless investigation shows a better staging-specific bound.
33
+ - Retries must be idempotent. Re-running setup should not create duplicate users, repeatedly reset passwords for the same readiness miss, or fan out multiple identical Cognito Admin calls for one synthetic user.
34
+ - When many users are created in one setup path, limit or serialize Cognito Admin readiness/mutation calls enough to avoid adding burst pressure to Cognito/[backend service]. Prefer a small shared queue or existing repo helper over a new dependency.
35
+
36
+ Required exhaustion metadata:
37
+
38
+ - On timeout, fail with a single enriched error that includes pool ID, synthetic email or canonical username, setup helper path, requested mutation type (`password` or `userType`), total elapsed time, attempt count, last AWS exception name/code/status/request ID if available, last successful readiness state, GitHub run/job identifiers if available from env, and the originating test file/worker where practical.
39
+ - Keep real-user PHI out of logs. The failing users here are synthetic Playwright users, but helper logging should still avoid leaking unrelated user data.
40
+
41
+ ## Observability to Reach 5/5 Confidence
42
+
43
+ Current confidence is 4/5 that this is one shared setup/backend-provisioning failure mode because direct staging [backend service]/Cognito telemetry was unavailable during investigation. The implementation should close that gap before the ticket is considered fully canonical.
44
+
45
+ Collect or add enough observability to prove which path is true:
46
+
47
+ - [backend service]/test-helper creates/imports the Cognito user successfully, but Cognito propagation is eventually consistent and the frontend harness must wait for `AdminGetUser` readiness.
48
+ - [backend service]/test-helper returns success before it has deterministically created/imported the Cognito user, so the true fix belongs in [backend service] or its test-helper contract.
49
+ - Cognito/backend throttling or burst pressure is delaying creation/readiness, so the harness must reduce concurrent Admin calls and expose enough timing data to verify the reduction.
50
+
51
+ Concrete signals to capture in Datadog, CI logs, or targeted helper instrumentation:
52
+
53
+ - Timestamp of [backend service]/test-helper user-create response for the synthetic email.
54
+ - Timestamp and outcome of each readiness probe, including `AdminGetUser` success or `UserNotFoundException`.
55
+ - Timestamp and outcome of the subsequent `AdminSetUserPasswordCommand` / `AdminUpdateUserAttributesCommand`.
56
+ - Total elapsed time from backend user-create success to Cognito readiness, grouped by helper path and user type.
57
+ - Any Cognito throttling, AWS SDK status, or [backend service] error/trace ID tied to the synthetic user creation.
58
+
59
+ Do not close this as 5/5 confidence from local green tests alone. Either attach the staging telemetry/CI evidence in the change or document why the fix had to move to [backend service]/auth infrastructure and link the follow-up implementation.
60
+
61
+ ## Storm Details
62
+
63
+ Shared error signature:
64
+
65
+ ```text
66
+ Error: Cognito user '[EMAIL]' does not exist in pool 'us-west-2_HV1ibP3I6' after 5 attempts. Ensure the user is provisioned in Cognito before running E2E tests.
67
+ ```
68
+
69
+ Tests bundled: 6
70
+ Repos affected: 1
71
+ CI runs affected: 2
72
+ First failure: 2026-07-06T11:38:20Z
73
+ Last failure: 2026-07-06T11:43:46Z
74
+
75
+ - `9166129be528` — `playwright/e2e/myAccount.spec.ts:88`
76
+ - `26803343548f` — `playwright/e2e/auth.spec.ts:103`
77
+ - `43dfbdb912d9` — `playwright/e2e/placements/acceptApplication.spec.ts:144`
78
+ - `9bbc4081a989` — `playwright/e2e/facilityOnboarding.spec.ts:32`
79
+ - `63172183d01a` — `playwright/e2e/homeHealth/fullLifecycle.spec.ts:876`
80
+ - `6b98dfce6bf1` — `playwright/e2e/auth.spec.ts:182`
81
+
82
+ Runs:
83
+
84
+ - [[external evidence reference]]([external evidence reference])
85
+ - [[external evidence reference]]([external evidence reference])
86
+
87
+ ## Investigation Findings
88
+
89
+ Failure surface: test setup/auth/data, before browser user-flow assertions.
90
+
91
+ Shared dependency: staging [backend service]/test-helper user creation plus AWS Cognito user pool `us-west-2_HV1ibP3I6`. CI config sets `E2E_ENVIRONMENT=staging` and `E2E_SERVICE_NAME=[backend service]`.
92
+
93
+ Shared helper path:
94
+
95
+ - `playwright/helpers/cognitoPassword.ts` calls `AdminSetUserPasswordCommand` for freshly created facility users and throws after five `UserNotFoundException` retries spaced 2s apart.
96
+ - `playwright/helpers/cognitoUserTypes.ts` has the sibling pattern for `AdminUpdateUserAttributesCommand` used by worker/HCP setup.
97
+ - Failing tests reach these through shared helpers such as `createFacilityUserWithRetry`, `createLtcFacilityWithUser`, `createHomeHealthcareWorkplaceWithUser`, `createHcfWithAssignedShiftWithRetry`, and `loginWithCognitoPassword`.
98
+
99
+ Representative CI evidence:
100
+
101
+ - Run [reference redacted]`, job `e2e-playwright-1`: `Created facility user ... email: playwright-gtygfpwvlhf@playwright-hcf.com`at`2026-07-06T11:43:07Z`, followed immediately by `Cognito user ... not found (attempt 1/5)`through attempt 4, then the test fails from`playwright/helpers/cognitoPassword.ts:65`.
102
+ - Run [reference redacted]`, job `e2e-playwright-1`: same sequence for `playwright-fovjnxnxzsj@playwright-hcf.com`; the helper fails after five attempts from `playwright/helpers/cognitoPassword.ts:65`.
103
+ - The failures occurred on separate self-hosted runners in the `cbh` group (`m8a.4xlarge`, `us-west-2b`), not one stale workspace.
104
+ - Current `origin/main` still has the same relevant setup code; no open `flaky-test-fix` change was found for this exact signature/fingerprints.
105
+
106
+ Datadog/incident check:
107
+
108
+ - Local Datadog CLI credentials were unavailable (`dog` and `~/.dogrc` absent).
109
+ - [incident.io]([external evidence reference]) telemetry has no configured telemetry datasource, so direct Datadog logs/metrics/traces could not be queried from this session.
110
+ - [incident.io]([external evidence reference]) did not show Cognito/staging/user-create incidents in `2026-07-06T11:00:00Z` to `2026-07-06T12:00:00Z`.
111
+ - One unrelated incident existed in the window: `INC-423` Stripe Payment Issues for Workers.
112
+ - One Platform Datadog alert existed in the window: production HCF login high latency at `2026-07-06T11:05:36Z`; this does not directly explain staging Cognito user provisioning.
113
+
114
+ Current confidence: 4/5 that this is one shared setup/backend-provisioning failure mode, not six independent test flakes. Confidence is not 5/5 because direct Datadog traces/logs for staging [backend service]/Cognito provisioning were unavailable.
115
+
116
+ ## Acceptance Criteria
117
+
118
+ - [ ] The shared setup path waits on or deterministically creates/validates Cognito users before `AdminSetUserPassword`/`AdminUpdateUserAttributes` are called.
119
+ - [ ] Readiness is based on a concrete `AdminGetUser` success signal, with a documented timeout/backoff bound and clear behavior for `UserNotFoundException`, throttling, and final timeout.
120
+ - [ ] Timeout failures include the exhaustion metadata listed above so future flakes can be debugged from CI logs without rerunning the investigation.
121
+ - [ ] Retries are idempotent and do not amplify Cognito/backend throttling.
122
+ - [ ] The implementation reduces call burstiness where the shared setup creates multiple users or applies multiple Cognito mutations in one flow.
123
+ - [ ] The fix applies to all contained fingerprints, not individual test assertions.
124
+ - [ ] If [backend service] or auth infrastructure is the true fix locus, document the frontend harness evidence and implement in the correct repo or add the needed observability before closing.
125
+ - [ ] Add or update focused tests for the shared helper behavior where practical.
126
+ - [ ] Run the documented relevant verification for the changed repo.
127
+
128
+ ## Suggested Starting Points
129
+
130
+ - `playwright/helpers/cognitoPassword.ts`
131
+ - `playwright/helpers/cognitoUserTypes.ts`
132
+ - `playwright/api/user.ts`
133
+ - `playwright/api/facility.ts`
134
+ - `playwright/api/homeHealth.ts`
135
+ - `playwright/helpers/login.ts`
136
+
137
+ Also inspect backend/test-helper behavior for `/api/facilityUser`, `/api/user/create`, and any JIT Cognito import path that should make new users appear in `us-west-2_HV1ibP3I6`.
138
+
139
+ ## Related
140
+
141
+ Investigation: `[ticket redacted]`
@@ -0,0 +1,98 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Groundcrew
4
+
5
+ Repository: `[admin frontend]`
6
+ Implementation workflow: use the `cb-work` skill or, if unavailable, the `core:go` skill.
7
+
8
+ Include this implementation ticket ID in the change body.
9
+
10
+ ```bash
11
+
12
+ ```
13
+
14
+ ## Flake details
15
+
16
+ ```json
17
+ {
18
+ "repo": "[admin frontend]",
19
+ "test": "Chat (redesign) — mobile chat from shift details on mobile renders as a stacked bottom sheet and can be ended",
20
+ "file": "playwright/e2e/chat.spec.ts:241",
21
+ "framework": "playwright",
22
+ "isNewFlaky": false,
23
+ "failures": [
24
+ {
25
+ "error": "Error: expect(page).toHaveURL(expected) failed\n\nExpected pattern: /chatWorkerId=/\nReceived string: \"[external evidence reference]"\nTimeout: 4000ms\n\nCall log:\n - Expect \"toHaveURL\" with timeout 4000ms\n 8 × unexpected value \"[external evidence reference]"\n\n\nCall Log:\n- Timeout 30000ms exceeded while waiting on the predicate",
26
+ "stack": "Error: expect(page).toHaveURL(expected) failed\n\nExpected pattern: /chatWorkerId=/\nReceived string: \"[external evidence reference]"\nTimeout: 4000ms\n\nCall log:\n - Expect \"toHaveURL\" with timeout 4000ms\n 8 × unexpected value \"[external evidence reference]"\n\n\nCall Log:\n- Timeout 30000ms exceeded while waiting on the predicate\n at clickUntilUrl (/opt/actions-runner/_work/[admin frontend]/[admin frontend]/playwright/e2e/chat.spec.ts:125:6)\n at /opt/actions-runner/_work/[admin frontend]/[admin frontend]/playwright/e2e/chat.spec.ts:264:13\n at WorkerMain._runTest (/opt/actions-runner/_work/[admin frontend]/[admin frontend]/node_modules/dd-trace/packages/datadog-instrumentations/src/playwright.js:1692:5)",
27
+ "branch": "main",
28
+ "pipeline": "[external evidence reference]",
29
+ "commit": "40f5b4ebe9cc9d01c4ef6129a67e238087690723",
30
+ "durationMs": 60384,
31
+ "shard": "4/4",
32
+ "timestamp": "2026-07-02T15:01:43Z"
33
+ }
34
+ ]
35
+ }
36
+ ```
37
+
38
+ ## Plan output
39
+
40
+ **Test ID:** `03dd965d45c5`
41
+
42
+ **Confidence:** 4/5. The artifact directly proves chat opened while `chatWorkerId` was absent. The missing link is exact identification of the competing history writer because current reporter output does not log URL writes.
43
+
44
+ **Failure surface:** Product/client state drift. The click was not a no-op and the backend chat-channel request succeeded; the failure is the client URL state not reflecting the open chat panel.
45
+
46
+ **Current main status:** Current `origin/main` still has the failing code path. The failing commit `40f5b4e` already included prior test-only hardening from change [reference redacted] and change [reference redacted]. No later relevant changes touched `playwright/e2e/chat.spec.ts`, `useChatPanel`, or `useShiftDeepLinking`.
47
+
48
+ **Symptom:** The Playwright test clicked the mobile Shift Details `Chat` button, then `clickUntilUrl(... /chatWorkerId=/ ...)` timed out for 30s. The final URL remained `/schedule?date=2026-07-03&view=day&shiftId=6a467d5e35d466dbaffea56b`.
49
+
50
+ **Root cause:** The shift-details chat modal and the URL are two sources of truth. In this occurrence the chat modal state and worker info were set, but `chatWorkerId` was missing from the URL. The earlier retry helper correctly avoids re-clicking once chat is visibly open, so it cannot repair this state drift.
51
+
52
+ **Evidence:**
53
+
54
+ - LLM report for run [reference redacted]`: attempt 1 failed; attempt 2 passed.
55
+ - Failure timeline: at ~28.6s, `Click getByRole('button', { name: 'Chat', exact: true })` completed; at ~29.07s, two `POST [external evidence reference] calls returned `201`with request body`{"facilityId":"6a467d5ca3fe1f1fd5fb40e5","agentId":"6a467d5936acbdb4f58f3d02"}`.
56
+ - Screenshot/page snapshot at failure show `Close chat`, `Chat messages`, and the disabled `Chat message` textbox mounted in the stacked bottom sheet.
57
+ - The URL assertion still saw no `chatWorkerId` for the entire retry budget.
58
+ - change [reference redacted] originally included a guarded URL reconciliation effect in `useChatPanel`, then removed it before integration. Its own notes say to re-add it if this exact flake recurs.
59
+
60
+ **Proposed fix:** Product fix in `src/appV2/redesign/Chat/hooks/useChatPanel.ts` plus focused hook tests.
61
+
62
+ 1. Reintroduce the guarded reconciliation from change [reference redacted]'s removed commits:
63
+ - import `useLocation` in `useChatPanel`;
64
+ - track `chatOpenedShiftId` in a ref;
65
+ - set that ref when chat opens from a click or deep link;
66
+ - clear it when chat closes or when shift-change cleanup runs;
67
+ - while chat is open and `chatWorkerInfo.workerId` exists, if `location.search` lacks the matching `chatWorkerId` and `chatOpenedShiftId.current === shiftId`, call `updateChatUrlParameter(chatWorkerInfo.workerId)`.
68
+ 2. Keep the shift guard. Without it, a later shift change could resurrect `?shiftId=B&chatWorkerId=A`.
69
+ 3. Add/restore `useChatPanel.test.tsx` coverage:
70
+ - restores `chatWorkerId` when another URL writer drops it while chat is open on the same shift;
71
+ - does not restore `chatWorkerId` after switching to another shift;
72
+ - preserves existing close/toggle/deep-link behavior.
73
+ 4. Do not add more Playwright retries/timeouts for this symptom; the app state is already visibly open, so extra clicking would mask URL/state drift.
74
+
75
+ **Observability to reach 5/5:** Add temporary or permanent frontend debug telemetry for query-param modal URL writes in this area:
76
+
77
+ - In `useChatPanel.updateChatUrlParameter`, log old URL, new URL, workerId, shiftId, and reason (`open`, `close`, `repair`) in non-PII-safe structured form.
78
+ - In `useShiftDeepLinking.updateUrl` / `buildShiftDeepLinkUrl`, log old URL, new URL, shiftId/inviteId, and whether `chatWorkerId` was preserved or removed.
79
+ - Ideally emit these as Datadog RUM actions or console debug gated for E2E so the Playwright LLM report captures the writer sequence next time.
80
+
81
+ **Sibling candidates:** Query-param-driven drawer/sheet hooks that maintain separate React modal state and URL params: `useShiftDeepLinking`, `useChatPanel`, My Professionals profile/chat URL state, MonthlyView selected slot/chat URL state.
82
+
83
+ **Validation plan:**
84
+
85
+ - `npm run test:v2 -- src/appV2/redesign/Chat/hooks/useChatPanel.test.tsx src/appV2/redesign/DailyView/hooks/useShiftDeepLinking.test.tsx`
86
+ - `npm run lint:fast -- src/appV2/redesign/Chat/hooks/useChatPanel.ts src/appV2/redesign/Chat/hooks/useChatPanel.test.tsx`
87
+ - If a deployed environment is available, rerun `playwright/e2e/chat.spec.ts` for the mobile project against staging/development.
88
+
89
+ **Open questions:** None blocking. A larger URL-as-source-of-truth modal model would be cleaner, but the guarded reconciliation is the smallest fix supported by this artifact.
90
+
91
+ **Residual risk:** If a different writer repeatedly strips `chatWorkerId` every render, reconciliation could loop or hide a deeper ownership bug. The shift guard and tests reduce stale-worker risk, and URL-write telemetry would make any remaining loop diagnosable.
92
+
93
+ ## Prior related context
94
+
95
+ - `[ticket redacted]`: prior investigation.
96
+ - `[ticket redacted]`: duplicate prior investigation.
97
+ - `[ticket redacted]`: prior implementation for the same family of mobile chat URL flakes.
98
+ - change [reference redacted]: test-only hardening available after removing the exact product-side reconciliation that this recurrence now supports.
@@ -0,0 +1,99 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Groundcrew
4
+
5
+ Repository: [mobile frontend]
6
+ Implementation workflow: use the `cb-work` skill when available. If that skill is unavailable, use the `core:go` skill.
7
+
8
+ ## Task
9
+
10
+ Fix the flaky Playwright flow where the rate-negotiation `SlideToConfirmButton` sometimes does not invoke the proposal action, leaving the test on `/shift-negotiation/:shiftId` after the slide gesture instead of navigating back to `/shift/:shiftId`.
11
+
12
+ Include this implementation ticket ID in the change body.
13
+
14
+ ## Flake Details
15
+
16
+ ```json
17
+ {
18
+ "repo": "[mobile frontend]",
19
+ "test": "Rate Negotiations new UI should propose new rate for a shift and end negotiation",
20
+ "file": "playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts:369",
21
+ "framework": "playwright",
22
+ "isNewFlaky": false,
23
+ "failures": [
24
+ {
25
+ "error": "Error: expect(page).toHaveURL(expected) failed\n\nExpected: \"[external evidence reference]"\nReceived: \"[external evidence reference]"\nTimeout: 30000ms",
26
+ "stack": "rateNegotiationv2.spec.ts:466",
27
+ "branch": "main",
28
+ "pipeline": "[external evidence reference]",
29
+ "commit": "7638c4bd74e598414254053d8c97e0611dbad943",
30
+ "durationMs": 52870,
31
+ "shard": "2/4",
32
+ "timestamp": "2026-07-06T16:26:13Z"
33
+ }
34
+ ]
35
+ }
36
+ ```
37
+
38
+ ## Plan Output
39
+
40
+ Confidence: 4/5. The failure artifact directly shows the slide CTA still open after the gesture, and the component code has a concrete stale-state completion check. Confidence is not 5/5 because the LLM report hit network retention caps, so absence of a retained `POST /negotiation` is strong but not absolute proof that no mutation request was emitted.
41
+
42
+ Failure surface: User action no-op, with product component behavior as the likely root and test harness diagnostics as a secondary improvement.
43
+
44
+ Current main status: The affected code path still exists on current `origin/main`/HEAD `a58a6893d9c025196f1b10bff49b548f2cd03910`. No open change with label `flaky-test-fix` matched this test or file. Commit `77129b26883` landed after the failing commit and only adds `workerAuthToken` to shift-offer setup; it does not address the slide/no-op path.
45
+
46
+ Symptom: In failed attempt 0, the test executes `slideToConfirmButton(page, "Slide to propose $33.00/hr")`, then `expect(page).toHaveURL(shiftDetailsPath)` times out at `playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts:467`. The actual URL stays `/home-v2/shift-discovery/list/shift-negotiation/6a4bd731b22f99dbbc009a7d`.
47
+
48
+ Root cause: `SlideToConfirmButton` decides whether the slide completed in `handlePointerUp` using React state `offsetX`. During a fast drag/release, especially under CI load, the last `pointermove` can call `setOffsetX(...)` but `pointerup` can still observe the previous render's `offsetX` value. That makes the component reset to 0 and skip `onConfirm()`, even though the pointer moved far enough. The Playwright helper triggers this edge by moving and releasing quickly after the rate-negotiation footer migration to `SlideToConfirmButton` in commit `7638c4bd74e`.
49
+
50
+ Evidence:
51
+
52
+ - LLM report `/tmp/playwright-llm-report-28806486162/llm-report.json` has one flaky test in the shard: 15 passed, this test passed only on retry.
53
+ - Failed timeline: `Bounding box getByText('Slide to propose $33.00/hr').locator('../..')` at 20536ms, `Mouse move` at 20541ms, `Mouse down` at 20545ms, `Mouse move` at 20562ms, `Mouse up` at 21272ms, then `Expect "toHaveURL"` fails at 21275ms.
54
+ - Failure screenshot shows the `Shift Rate Negotiation` bottom sheet still open with `Slide to propose $33.00/hr`; it is not in loading/success state and has not navigated away.
55
+ - Retained negotiation network entries around the slide are reads only: `GET /api/negotiation/shifts/:shiftId?offerId=...` at 19826ms and 20878ms. There is no retained `POST /negotiation` proposal write near the slide. The report did hit network caps (`instancesDroppedByGroupCap: 17`, `instancesEvictedAfterAdmission: 10`), so this supports but does not solely prove the no-op.
56
+ - `src/appV2/redesign/system/ui-components/components/SlideToConfirmButton/index.tsx` lines 177-209 update `offsetX` in `handlePointerMove` and read `offsetX` in `handlePointerUp` to decide `offsetX / currentMax >= 0.8`.
57
+ - `playwright/utils/button.ts` lines 43-59 uses a generic fast mouse drag for every `SlideToConfirmButton`; `playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts` uses it at lines 464 and 634. Timekeeping E2Es also use the same helper.
58
+ - There is no dedicated `SlideToConfirmButton` component test file covering fast drag/release behavior.
59
+
60
+ Proposed fix:
61
+
62
+ 1. In `src/appV2/redesign/system/ui-components/components/SlideToConfirmButton/index.tsx`, stop using render-state `offsetX` as the source of truth inside `handlePointerUp`. Compute the release offset from the current `PointerEvent` (`event.clientX - dragStateRef.current.startX`) and/or keep the latest clamped offset in a ref that is updated synchronously in `handlePointerMove`. Use that computed/ref value for the threshold check, then update state for rendering.
63
+ 2. Keep the reset/complete state transitions the same: partial drags reset to 0; completed drags set to max, mark complete, and call `onConfirm()` exactly once.
64
+ 3. Add focused appV2 component coverage for `SlideToConfirmButton`: a fast drag that crosses the threshold and releases immediately calls `onConfirm`, a partial drag does not, and disabled/loading states still do not call `onConfirm`. Prefer user-facing queries where possible; if the current component lacks accessible semantics, keep the test scoped to the rendered CTA text and pointer events.
65
+ 4. Improve E2E diagnostics around the proposal action in `playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts`: after sliding, wait for the deterministic proposal mutation or a post-success route/UI signal so a future no-op fails at the missing `POST /negotiation`/confirm signal instead of a 30s URL timeout. Avoid arbitrary sleeps or blind retries.
66
+
67
+ Observability to reach 5/5:
68
+
69
+ - Add deterministic Playwright evidence around the slide action: wait for the `POST /negotiation` request/response after the proposal slide and include its absence in the failure path.
70
+ - If touching the component, consider adding temporary debug output gated by the existing E2E/debug localStorage pattern or test-only attachments for slide metrics (`startX`, release delta, max offset, threshold result) if the component remains hard to diagnose in traces.
71
+ - No backend telemetry is required for this plan unless the deterministic wait proves the mutation is emitted and failing server-side.
72
+
73
+ Sibling candidates:
74
+
75
+ - `playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts:634` uses the same helper in the counter-proposal path.
76
+ - `playwright/e2e/shift/timekeeping.spec.ts` uses `slideToConfirmButton` for clock-out flows at lines 663, 755, 858, and 1010.
77
+ - All product uses of shared `SlideToConfirmButton` inherit the stale pointer-state behavior, including shift cancel, timekeeping, booking confirmation, Clipboard Score, and rate negotiation.
78
+
79
+ Validation plan:
80
+
81
+ - `npm run test:v2 src/appV2/redesign/system/ui-components/components/SlideToConfirmButton/SlideToConfirmButton.test.tsx`
82
+ - `npm run test:v2 src/appV2/Negotiations/RateNegotiationBottomSheet.test.tsx`
83
+ - With a valid `playwright.env`, run `npx playwright test playwright/e2e/rateNegotiations/rateNegotiationv2.spec.ts --project "Mobile Chrome" --config ./playwright.config.ts`
84
+ - Run the repo's standard verification command if required by the final diff scope.
85
+
86
+ Open questions: None blocking. The highest-confidence local fix is in the shared slide component; the E2E change should improve diagnostics, not mask the product behavior.
87
+
88
+ Residual risk: If fixing the slide component reveals a real backend/post-success navigation issue after `POST /negotiation`, the deterministic E2E wait should expose that as a different failure surface with a request/response artifact.
89
+
90
+ ## Acceptance Criteria
91
+
92
+ - [ ] Fast slide/release over the completion threshold reliably calls `onConfirm` in `SlideToConfirmButton`.
93
+ - [ ] Partial/disabled/loading slide cases remain unchanged.
94
+ - [ ] The rate-negotiation proposal E2E waits on a deterministic proposal or post-success signal instead of relying only on a later URL timeout.
95
+ - [ ] Validation commands above pass or any environment-only blocker is documented in the change.
96
+
97
+ ## Related
98
+
99
+ Investigation ticket: `[ticket redacted]`
@@ -0,0 +1,25 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Flaky Test Report
4
+
5
+ The following E2E test in `[admin frontend]` is among the **top 10 flakiest tests** (last 30 days) on the [Datadog Flaky Tests Management]([external evidence reference]) dashboard. Owned by **Synapse**.
6
+
7
+ ### Affected Tests
8
+
9
+ | \# | Test | Failures (30d) | File | Repo |
10
+ | --- | ---------------------------------------------------------------------------------------------------------------- | -------------- | ---------------------------------- | ------------------------------------------------- |
11
+ | 1 | `Daily View — Admin User should navigate to daily view, display shifts, interact with filters and shift details` | 6 | `playwright/e2e/dailyView.spec.ts` | [[admin frontend]]([external evidence reference]) |
12
+
13
+ ### Datadog Links
14
+
15
+ - [Flaky Tests Dashboard]([external evidence reference])
16
+
17
+ ### Context
18
+
19
+ This test exercises the Daily View page for an Admin User — navigating to it, verifying shifts are displayed, and interacting with filters and shift details. Previous investigations ([ticket redacted], [ticket redacted]) canonical earlier occurrences, but the test continues to flake.
20
+
21
+ ### Recommended Next Steps
22
+
23
+ 1. Check Datadog CI test traces for the specific failure error messages
24
+ 2. Compare with previous fix in [ticket redacted] to see if the same root cause has regressed
25
+ 3. Investigate filter interaction timing or data loading race conditions
@@ -0,0 +1,111 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Groundcrew
4
+
5
+ Repository: [admin frontend]
6
+ Implementation workflow: use the `cb-work` skill. If unavailable, use the `core:go` skill.
7
+
8
+ Include this implementation ticket ID in the change body.
9
+
10
+ ```bash
11
+
12
+ ```
13
+
14
+ ## Flake Details
15
+
16
+ ```json
17
+ {
18
+ "repo": "[admin frontend]",
19
+ "test": "Home Health Full Lifecycle complete home health workflow: create case, manage visits, verify and reject occurrences, close case",
20
+ "file": "playwright/e2e/homeHealth/fullLifecycle.spec.ts:876",
21
+ "framework": "playwright",
22
+ "isNewFlaky": false,
23
+ "failures": [
24
+ {
25
+ "error": "Error: expect(locator).toBeVisible() failed\n\nLocator: getByRole('dialog').getByText('Cancel Regular visit')\nExpected: visible\nTimeout: 30000ms\nError: element(s) not found\n\nCall log:\n - Expect \"toBeVisible\" with timeout 30000ms\n - waiting for getByRole('dialog').getByText('Cancel Regular visit')\n",
26
+ "stack": "Error: expect(locator).toBeVisible() failed\n\nLocator: getByRole('dialog').getByText('Cancel Regular visit')\nExpected: visible\nTimeout: 30000ms\nError: element(s) not found\n\nCall log:\n - Expect \"toBeVisible\" with timeout 30000ms\n - waiting for getByRole('dialog').getByText('Cancel Regular visit')\n\n at /opt/actions-runner/_work/[admin frontend]/[admin frontend]/playwright/e2e/homeHealth/fullLifecycle.spec.ts:1272:81\n at /opt/actions-runner/_work/[admin frontend]/[admin frontend]/playwright/e2e/homeHealth/fullLifecycle.spec.ts:1252:7\n at WorkerMain._runTest (/opt/actions-runner/_work/[admin frontend]/[admin frontend]/node_modules/dd-trace/packages/datadog-instrumentations/src/playwright.js:1692:5)",
27
+ "branch": "main",
28
+ "pipeline": "[external evidence reference]",
29
+ "commit": "c0fc2cd743575ada27d544cea455e13cd45caf28",
30
+ "durationMs": 51423,
31
+ "shard": "2/4",
32
+ "timestamp": "2026-07-05T01:07:09Z"
33
+ }
34
+ ]
35
+ }
36
+ ```
37
+
38
+ ## Investigation Plan Output
39
+
40
+ **Test ID:** [ticket redacted] / sighting-key `a5a77ac290d27dc9`
41
+
42
+ **Confidence:** 4/5. The trace and failure screenshot directly show the cancel button click completed, no dialog was present afterward, and the case visits section was collapsed at failure. The exact React state transition that collapsed/unmounted the visits subtree is inferred rather than directly instrumented.
43
+
44
+ **Failure surface:** User action no-op / test harness race. The action target existed and Playwright completed the click, but the expected dialog did not start/render before the visit subtree was collapsed/unmounted. No cancellation backend request was emitted.
45
+
46
+ **Current main status:** Still present on current `origin/main` / HEAD `56b4dfa7131b6f6b84989145d8f0c2657811c252`. The failing path in `playwright/e2e/homeHealth/fullLifecycle.spec.ts` still does a single click followed by `page.getByRole("dialog").getByText("Cancel Regular visit")`. `CaseCard` still stores expansion state locally with `useModalState(ModalStatus.ended)` and `Collapse unmountOnExit`, and `CancelVisitDialog` still lives under `VisitActions` inside that collapsible visit subtree.
47
+
48
+ **Symptom:** In Step e, `findVisitRowByWorker` found the booked worker row and the row's `Cancel Visit` button. The test clicked it, then timed out for 30s waiting for `getByRole('dialog').getByText('Cancel Regular visit')` at `playwright/e2e/homeHealth/fullLifecycle.spec.ts:1272`.
49
+
50
+ **Root Cause:** The cancel-visit path is less resilient than the other hardened home-health dialog helpers. It assumes the visit subtree remains expanded and that one button click will synchronously expose the cancel dialog. In the failed attempt, the subtree was collapsed by the time the dialog assertion began, so the `CancelVisitDialog` mounted under `VisitActions` was not present. Because the helper returns a `Locator` after finding the row but does not re-check expansion or retry opening the dialog, the test can lose the row/dialog state between row lookup and assertion.
51
+
52
+ **Evidence:**
53
+
54
+ - LLM report artifact `playwright-llm-report` for run [reference redacted]` has schema v3 summary: 52 total tests, 49 passed, 1 flaky, 0 final failures. This test failed once and passed on retry.
55
+ - Failed attempt error: `getByRole('dialog').getByText('Cancel Regular visit')` timed out after 30000ms at line 1272.
56
+ - Failed attempt trace: `findVisitRowByWorker` reloaded the page, expanded case visits, observed the booked worker link `Playwright Iiuwfojg`, observed that row's `Cancel Visit` button, then completed the click without a click-level error.
57
+ - Trace call evidence: click `call@1019` canonical to `<button aria-label="Cancel Visit" ...>`, completed at point `{x:433.12,y:516.25}`, and had no Playwright error. The next assertion `call@1023` waited 30000ms and timed out.
58
+ - Failure screenshot and `error-context` page snapshot show the target case card visible but collapsed with `Show Case Visits`, and no dialog in the DOM.
59
+ - Network evidence around the failed click shows no `PATCH /[home-health service]/api/v1/*/visits/*` cancellation request after the click. No backend cancellation request started, so this is not a backend cancellation failure.
60
+ - Existing fix check: no open change with `flaky-test-fix` matched `fullLifecycle.spec.ts` or home-health E2E. Recent main commits touched this spec for other modal/row lookup flakes, but none directly address this cancel-dialog open path.
61
+
62
+ **Proposed Fix:** Test harness fix in `playwright/e2e/homeHealth/fullLifecycle.spec.ts`.
63
+
64
+ 1. Add a helper for opening the cancel-visit dialog that mirrors the hardened patterns already used for verify/reject dialogs:
65
+ - Accept `page`, the case/row lookup inputs, the target visit id when available, and the expected dialog title.
66
+ - In a bounded `expect(async () => ...).toPass(...)`, ensure the case visits section is expanded, ensure the target row/action button is visible and enabled, click the button only when the expected dialog is not already open, and assert the cancel dialog title plus confirmation text are visible.
67
+ - Treat only these states as retryable: the case visits section is collapsed after lookup, the target row or action button detaches before the click, the target action is temporarily hidden/disabled, or the expected dialog title plus confirmation text are not visible after the open click while no cancellation `PATCH` has started.
68
+ - Treat these states as non-retryable: a cancel dialog opens for a different visit, the helper has already clicked the dialog confirmation button, a cancellation `PATCH /visits/{id}` request has started, or the selected visit id no longer matches the expected visit.
69
+ - Re-clicking `Cancel Visit` is idempotent only before confirmation because the row action opens a client-side dialog; no backend cancellation mutation starts until the dialog's confirmation button is clicked. If the matching dialog is already open, the helper should return/assert it instead of clicking again.
70
+ - There is no single deterministic completion signal to wait on for dialog open. The row click only changes React modal state inside `VisitActions`, and `CancelVisitDialog` is mounted under the collapsible `CaseVisits` subtree with `Collapse unmountOnExit`; the cancellation network request happens later on confirmation. A bounded web-first assertion on the specific dialog title and confirmation text is therefore the narrowest observable signal.
71
+ - Attach diagnostics on failure: whether `Show Case Visits` or `Hide Case Visits` is visible, visible dialog texts, visible action button labels, target worker/link count, target visit id if known, and visible visit IDs.
72
+ 2. Use the helper for Step e's booked-visit cancellation. Consider using it for Step d's unbooked cancellation too, since Step d has the same single-click/single-dialog-assertion anti-pattern.
73
+ 3. Keep the cancellation response wait scoped to the expected visit id for Step e, as it already is. For Step d, if practical, scope the `PATCH /visits` wait to the selected CNA visit id or add enough diagnostics to prove which visit was patched.
74
+ 4. Confirm whether modification reason is required under this test user. If required in local/staging auth context, fill `Reason for change` before clicking the dialog's `Cancel Visit`; if not required, leave unchanged. The field is conditional via `useIsModificationReasonRequired()`.
75
+
76
+ **Observability to Reach 5/5:**
77
+
78
+ - Add test diagnostics in the new helper for dialog-open failures: expanded/collapsed case visits state, target row count, target button count, dialog count/text, visible action labels, and a short case-card text snapshot.
79
+ - Add reporter or helper-level network notes for whether a `GET /visits/{id}` or `PATCH /visits/{id}` was observed after the open click. This would distinguish “dialog never mounted” from “dialog mounted loading/error state and then unmounted.”
80
+ - Product telemetry is not required for the immediate fix, but if this reappears outside tests, add a lightweight analytics/log event for cancel dialog open failures or visit-action click-to-dialog transitions in the Home Health case dashboard.
81
+
82
+ **Sibling Candidates:**
83
+
84
+ - Step d in `playwright/e2e/homeHealth/fullLifecycle.spec.ts` (`Cancel an unbooked CNA regular visit`) uses the same direct cancel click and broad `page.getByRole("dialog")` assertion.
85
+ - Other `VisitActions` dialogs under the collapsible `CaseVisits` subtree are already partially hardened for edit/verify/reject/remove flows; review any remaining direct `page.getByRole("dialog")` open assertions in this spec before stopping.
86
+
87
+ **Validation Plan:**
88
+
89
+ - `npm run lint:fast -- playwright/e2e/homeHealth/fullLifecycle.spec.ts` if the script accepts file args; otherwise `npm run lint:fast`.
90
+ - Run the targeted deployed-env Playwright test if available in this repo/environment, or the repo's documented Playwright command for `playwright/e2e/homeHealth/fullLifecycle.spec.ts` against staging.
91
+ - At minimum, run the relevant TypeScript/lint check after editing: `npm run typecheck` if a full check is acceptable; otherwise the narrowest documented check the repo supports.
92
+
93
+ **Open Questions:** None blocking. The implementation can proceed with the conservative test-harness fix.
94
+
95
+ **Residual Risk:** The full lifecycle spec remains long and has many backend/test-data dependencies. This fix should stabilize the cancel-dialog open race, but separate flakes in auth, backend eventual consistency, case visit row lookup, or occurrence verification can still surface in the same test.
96
+
97
+ ## Acceptance Criteria
98
+
99
+ - [ ] Step e opens the booked-visit cancel dialog through a bounded deterministic helper rather than a one-shot click/assertion.
100
+ - [ ] The helper documents and enforces retryable vs non-retryable states before retrying an open click.
101
+ - [ ] The helper only re-clicks `Cancel Visit` while no matching dialog is open, no confirmation click has happened, and no cancellation `PATCH` has started.
102
+ - [ ] The helper uses the specific dialog title and confirmation text as the bounded web-first assertion because there is no earlier deterministic open-completion signal.
103
+ - [ ] Step d either uses the same helper or is explicitly ruled out with evidence.
104
+ - [ ] Failure diagnostics identify whether the case visits section is collapsed, the target row/action is missing, a dialog is loading/erroring, a different visit dialog is open, or no dialog exists.
105
+ - [ ] The change body includes this implementation ticket ID.
106
+
107
+ ## Related Tickets
108
+
109
+ Investigation source: [ticket redacted]
110
+
111
+ Prior related tickets from the source task: [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted], [ticket redacted].
@@ -0,0 +1,27 @@
1
+ # Historical plan snapshot
2
+
3
+ ## Parent
4
+
5
+ [ticket redacted] (flakiness program spec), Workstream C.
6
+
7
+ ## Groundcrew
8
+
9
+ Repository: [admin frontend]
10
+ Implementation workflow: use the `core:cb-work`/`cb-work` skill when available. If that skill is unavailable, follow this repo's [AGENTS.md/CLAUDE.md]([external evidence reference]) implementation workflow and run the documented verification.
11
+
12
+ ## What to build
13
+
14
+ [ticket redacted] (available) made the backend return the Cognito username from admin user creation. Username-based Cognito operations are strongly consistent; the harness's current resolve-by-email path goes through the eventually consistent alias index, which is the root cause of the "Cognito user does not exist" storm family. Switch the Playwright harness to consume the returned username for all post-creation Cognito operations, then **delete the armor that only existed to absorb the lookup race**: the PreSignUp readiness probe, oversized readiness budgets (the ~90s window), and any throttle/retry logic whose sole purpose was surviving alias-index lag. Keep armor that guards genuinely different hazards (e.g. cross-process rate-limit throttling for call volume).
15
+
16
+ First step: verify the username field is actually present in the staging environment's responses (the contract available; deployment matters). If absent, stop and report rather than building against a phantom.
17
+
18
+ ## Acceptance criteria
19
+
20
+ - [ ] Harness user setup consumes the username from the creation response; no post-creation resolve-by-email remains on the setup path.
21
+ - [ ] Obsolete probe/budget/retry code is deleted, each deletion named in the change body with the hazard it guarded now being impossible.
22
+ - [ ] Auth-dependent spec pass rate is unchanged or better across repeated CI runs (state the runs checked).
23
+ - [ ] A classification note distinguishes deleted armor (lookup-lag) from retained armor (rate-limit volume) so reviewers can check the boundary.
24
+
25
+ ## Notes
26
+
27
+ Evidence: staging-seed-reliability deep dive; [ticket redacted] storm; consumer-side mitigations 152fe5ea8d7/32c31abeeef. Mobile mirror is a separate ticket that adopts this ticket's approach.