# Scheduling E2E Evidence — 2026-08-31 through 2026-09-02

## Scope and safety

- Environment: non-production `dev2`, test store `ou00` (`America/Chicago`).
- All created rows used unique `E2E-*` markers.
- Credentials were loaded from `.env` by the login helpers and were not placed in prompts, reports, or this document.
- Every deterministic fixture described below was deleted with an exact ID + marker guard; database read-back confirmed zero marked rows remained.
- A final global read-only sweep found two stale fixtures from earlier failed lifecycle attempts (`I` and `J`). The fail-closed cleanup helper removed each exact marker, and a second global read-back returned **0 `E2E-*` shift rows**.

## Passing Midscene runs

| Surface | Result | Evidence |
|---|---|---|
| Live iOS scheduling navigation | Pass | `midscene_run/report/ios-live-scheduling-navigation-2026-08-31_23-05-55-a07e6a61.html` |
| Team iOS scheduling navigation | Pass | `midscene_run/report/ios-team-scheduling-navigation-2026-08-31_23-16-06-bb6fff75.html` |
| Web marker cleanup | Pass | `midscene_run/report/web-scheduling-marker-cleanup-2026-08-31_22-46-05-29a5824f.html` |

The two iOS runs used rebuilt simulator apps targeting `https://dev2.buyerkiosk.com` and authenticated sessions loaded through the credential-safe helper.

## Deterministic database and iOS accessibility evidence

### Web-created overnight shift persistence

`midscene_run/output/scheduling-shift-lifecycle-db-evidence-20260831-K.json`

- Midscene created the marked Open Shift before later exceeding its replanning limit at the action-menu step.
- Exact database read-back showed an unassigned shift from `2026-10-06 03:00:00Z` to `07:00:00Z`.
- Elapsed duration: exactly 4 hours.
- Cleanup deleted the exact marked row and verified zero remained.

### Team publication boundary

`midscene_run/output/scheduling-cross-app-deterministic-evidence-20260831-L.json`

For one shift assigned to the authenticated Team test user on October 12:

1. Draft + Team refresh: `Day off / No shifts on this date`.
2. Published + Team refresh: one shift visible, `10:00 PM` to `2:00 AM`.
3. Unpublished + Team refresh: `Day off / No shifts on this date`.

This verifies fail-closed draft visibility, published visibility, overnight labels, and explicit-refresh convergence against dev2. The marked fixture was removed and absence verified.

### Live manager edit and explicit unassignment

`midscene_run/output/scheduling-live-manager-deterministic-evidence-20260831-M.json`

- Live rendered the marked draft as `Open Shift`, `22:00 - 02:00`, `4.0h`.
- The edit form preserved September 6, `10:00 PM` to `2:00 AM`, displayed `Total: 4.0 hours`, and identified the shift as overnight.
- Live assigned an eligible employee; exact database read-back showed a non-null `employeeId` with unchanged UTC instants.
- Live then selected `Open Shift (No assignment)` and saved; exact database read-back showed `employeeId: null` with unchanged UTC instants.
- The fixture was deleted with an exact guard and zero marked rows remained.

### Live manager UI creation

`midscene_run/output/scheduling-live-create-deterministic-evidence-20260901-N.json`

- A rebuilt iOS 26.5 simulator app targeting the ngroked dev2 working tree opened the real manager Create Shift form.
- Live submitted an open draft for Wednesday, September 2 with marker `E2E-LIVE-20260901-N`, 9:00 AM–5:00 PM, and displayed 8.0 hours.
- Exact database read-back found shift `2981`, `employeeId: null`, `publishedAt: null`, and canonical `14:00Z–22:00Z` timestamps.
- The run exposed and repaired a blocking keyboard UX defect: entering notes obscured the fixed Create Shift action. Strict RED/GREEN coverage now keeps the action above a 300 px keyboard inset; the focused test passed **1/1** and the full shift-form screen suite passed **21/21**.
- Independent fail-closed review passed with no security concerns or logic errors. Suggested follow-ups are stronger keyboard-transition/view-padding coverage and separating the pre-existing `clearEmployeeId` change into its own review unit.
- Exact ID + marker cleanup deleted one row, verified zero remaining, and an independent marker sweep also found zero rows.

### Team publication visibility, production realtime, delayed convergence, and app resume

`midscene_run/output/scheduling-team-visibility-evidence-20260901.json`

- The real Team iOS app remained fail-closed for the assigned draft, showed it only after publication plus authoritative REST refresh, and removed it after unpublish plus refresh.
- `full_team_schedule_provider_test.dart`: **35/35 PASS**, covering delayed-refresh follow-up, completion-boundary events, stale-publication suppression, and bounded sustained-event reconciliation.
- `full_schedule_screen_test.dart`: **11/11 PASS**, including app-resume invalidation and visible-data refetch.
- `schedule_event_stream_provider_test.dart`: **12/12 PASS**, covering feature gating, connection ordering, single-channel enforcement, parsing, deduplication, and malformed-message survival.
- Production realtime implementation and controlled dev2 convergence pass. `midscene_run/output/E2E-TEAM-REALTIME-20260902-H-evidence.json` proves the Team token grants only `subscribe` on `kiosk_ou00` and grants no manager channel, draft creation does not leak during a recorded 15-second event window, authoritative `schedule.published` arrives before REST-visible publication, and editing that published shift emits a redacted `shift.deleted` visibility revocation rather than exposing the draft payload.
- The live event sequence advanced monotonically from `68` to `69` across separate HTTP requests. Team REST then excluded the returned-to-draft shift; neither draft creation nor the later draft deletion leaked an event during recorded `negativeWindowMs: 15000` windows. Exact ID + exact marker cleanup dry-ran first, deleted shift `3003`, publish record `18`, and four linked audit rows, then verified zero shift/publish/audit rows.
- `midscene_run/output/E2E-TEAM-REALTIME-20260902-I-prepublication-cleanup.json` records an intentionally injected failure immediately after shift creation and before publication. The process exited `1`; exact marker/shift pre-publication cleanup deleted shift `3004` and its one linked audit row, then verified zero shift/publish/audit rows.
- Backend Scheduling + MobileScheduling + focused Staff Chat verification passed **1,792 tests / 6,994 assertions**, with 5 deprecations and 2 skipped. Template replacement and AI suggestion application now enforce `publishedAt IS NULL` at both candidate and conditional-write boundaries, so automation cannot silently mutate a published Team-visible shift. The final independent backend rereview passed with no security or logic findings (**79 tests / 654 assertions** in its primary focused run). The final Team remediation validates store scope before every Chat subscription entry, cancels old-store listeners before new-store HTTP, fully serializes `connect`/`ensureConnected`/`disconnect` transitions, and prevents an awaited `leaveChannel()` from clearing newer channel state or recreating an old-store subscription. Its focused service/provider/chat command passed **71 tests** and the broader selected realtime/scheduling/chat command passed **148 tests**; targeted Flutter analysis reported no issues and `git diff --check` was clean. The bounded final independent client rereview passed with no security concerns or logic errors; its focused race regression and full `chat_notifier_test.dart` run passed **1** and **45** tests respectively.

### Cross-app DST, overnight, split-shift, and calendar boundaries

`midscene_run/output/E2E-BOUNDARY-20260901-A-evidence.json`

- Seven exact isolated fixtures covered spring-forward (`01:30 CST–03:30 CDT`, **1h**), fall-back (`00:30 CDT–02:30 CST`, **3h**), overnight (**4h**), two split shifts (**3h + 4h = 7h**), a Sunday→Monday week boundary (**4h**), and a January→February month boundary (**4h**).
- Database read-back matched canonical UTC instants, assignment, publication state, and elapsed duration for all seven rows.
- Authenticated Web schedule API, Live manager daily API, and Team daily API each returned all seven IDs with correct store-offset labels. Live and Team returned canonical `totalHours` values `1, 3, 4, 3, 4, 4, 4`; Team explicitly returned `isPublished: true`.
- Regression suites passed: Web **37 tests / 108 assertions** plus StoreTime Jest **12/12**; Live selected boundary suites **37/37**; Team selected boundary suites **66/66**.
- Cleanup required exact shift ID plus exact marker for every row, deleted seven rows, and seven independent marker scans each verified zero remaining.
- Cleanup exposed a separate tooling defect: repeated runs of `fix-flash-file.php` accumulated duplicate `ReturnTypeWillChange` attributes until Slim could not parse. A strict idempotence regression failed RED (`24` attributes vs `6`), then passed GREEN **1 test / 13 assertions** after correcting the literal-backslash regex. Independent review is pending.

## Failed or incomplete AI-driven runs

| Run | Result | Classification |
|---|---|---|
| Web shift lifecycle | Failed: replanned 20 times | The create/persistence portion succeeded; edit/publish/unpublish/delete was not completed by Midscene. |
| Web cross-app setup | Failed: replanned 20 times | The fixture was created; deterministic DB/iOS steps supplied later visibility evidence. |
| Team draft-hidden YAML | Failed: replanned 20 times | Deterministic WDA refresh and accessibility read-back supplied the visibility assertion instead. |

Representative reports:

- `midscene_run/report/web-scheduling-shift-lifecycle-2026-08-31_22-33-54-a2409589.html`
- `midscene_run/report/web-scheduling-cross-app-setup-2026-08-31_23-19-06-cf9d94ae.html`
- `midscene_run/report/ios-team-scheduling-draft-hidden-2026-08-31_23-33-12-3fa16a33.html`

These failures are not counted as passing lifecycle tests. Raising the replanning limit is not considered evidence of correctness.

## Remaining E2E gaps

- Payroll live E2E now passes after exact-store migration of `scheduleTimesheetExports` and its integrity constraints to `ou00`; control store `pc00` remained unchanged. An isolated approved timesheet exported as CSV over authenticated HTTP, a same-key retry returned the same export ID/hash/body, durable audit count remained one, and database read-back confirmed one marked row plus the immutable CSV snapshot. Dry-run-first cleanup left zero fixture or audit rows. Deterministic coverage remains **125 tests / 554 assertions**. Evidence: `midscene_run/output/E2E-PAYROLL-20260901-B-evidence.json`.
- Exact-store migration-runner hardening passed final independent fail-closed review with no security concerns or logic errors. The runner strictly parses one lowercase target, rejects global/mixed operations before execution, preflights target existence even for empty migrations, exits nonzero on missing targets or migration errors, preserves legacy untargeted empty-store no-op behavior, and retains a defensive apply-time guard. Reviewer verification passed **7 tests / 13 assertions**, PHP lint, and diff checks. Process-level regression tests remain a non-blocking hardening suggestion; project-wide PHPStan retains unrelated baseline diagnostics.
- Production Team realtime convergence and its final independent fail-closed review pass; the Team path is closed and was not broadened for pending-request pagination.
- AI live E2E now passes after exact-store cadence migration to `ou00`. The run also exposed and repaired a provenance defect: persisted suggestions generated a new UUID instead of retaining the dispatched job ID. A RED/GREEN contract now propagates the dispatch ID through both AI and math jobs/optimizers; after an idle-queue worker reload, live read-back proved job and suggestion both used `989e90b0-fe81-4bc4-ad0b-3db1c6fcf364`. Math optimization reached `OPTIMAL`, produced one assignment for isolated draft shift `2991`, applied it atomically with `appliedCount:1` and `rejectedCount:0`, retained `publishedAt:null`, and persisted `aiSuggestionId:771`. Focused coverage passed **443 tests / 1,998 assertions** with two deprecations; prior broader coverage remains **556 / 2,673**. Independent fail-closed linkage review passed with no security concerns or logic errors after running **80 tests / 289 assertions**, repository race/linkage tests **4 / 14**, PHPStan, lint, and diff checks. Exact job, suggestion, shift, and availability cleanup all verified zero remaining rows. Evidence: `midscene_run/output/E2E-AI-20260901-C-evidence.json`.
- Pending-request single and batch terminal errors expose scoped canonical codes on dev2 while retaining legacy raw prefixes and separate human-readable messages. Genuine pagination now uses signed canonical store/filter/sort-bound cursors, deterministic composite ordering, strict Live metadata and identity checks, repeated-cursor rejection, impossible-total rejection, and generation-bound mutations. After explicit authorization, final E2E collector RED/GREEN coverage corrected duplicate-identity and repeated-cursor detection, required terminal accumulated count to equal stable `totalCount`, retained the upper-bound check, and removed the runner's fabricated `duplicateIdentityCount` field. The E2E suite passed **10/10**. Fresh evidence `midscene_run/output/E2E-PENDING-PAGINATION-20260902-H-evidence.json` proves 21 exact `ou00` rows across three real pages at limit 7, stable total and traversed count 21, exact ID coverage, dry-run-first cleanup, 21 deletions, and zero remaining. The final independent fail-closed review passed with exact Web, Live, and E2E manifest matches, no security concerns, and no logic errors. Query-level scalability is not claimed because source rows are still fully gathered and hydrated before in-memory sorting and slicing. Earlier error evidence remains at `midscene_run/output/E2E-PENDING-20260901-A-evidence.json`.
- A separate compatibility-tooling defect was found while cleaning fixtures: repeated execution of `userfrosting/fix-flash-file.php` duplicated `#[\ReturnTypeWillChange]` until Slim's `Flash.php` no longer parsed. The matcher was corrected under a RED/GREEN regression, repeated execution and `php -l` passed, and an independent fail-closed review approved the change with no security concerns or logic errors. The reviewer confirmed **1 test / 13 assertions**, all three reviewed PHP files lint-clean, and exactly one attribute on each of the six target methods. Byte-for-byte idempotence, explicit `preg_replace()` failure handling, and atomic file replacement remain non-blocking hardening suggestions.

## 2026-09-01 deterministic continuation

### Fixture safety harness

Added a dry-run-by-default fixture helper and executable safety test:

- `scripts/scheduling-fixture.php`
- `tests/scripts/scheduling-fixture.test.php`

The helper is pinned to `ou00`, rejects malformed/wildcard markers, requires exact positive shift ID + exact marker guards for reads and cleanup, verifies setup/read-back, and verifies zero rows after cleanup. `php tests/scripts/scheduling-fixture.test.php` passed, and both PHP files passed `php -l`.

### Deterministic Web lifecycle attempts

| Marker | Result | Evidence / cleanup |
|---|---|---|
| `E2E-WEB-20260901-N` | **Failed before create**: the deterministic driver attempted to pointer-click a hidden context-menu item (`Node is either not clickable or not an Element`). No shift ID was returned. Exact marker dry-run and independent database read-back both found 0 rows. | `midscene_run/output/E2E-WEB-20260901-N-deterministic-web-lifecycle.json` |
| `E2E-WEB-20260901-O` | **Failed after Web UI create**: the create API returned shift ID `2960`, but the expected overnight UTC persistence assertion did not match. No later edit/assignment/publication steps were counted as executed or passing. | `midscene_run/output/E2E-WEB-20260901-O-deterministic-web-lifecycle.json`; exact dry-run found one row, then cleanup deleted ID `2960` guarded by the exact marker and read-back verified 0 remaining. |
| `E2E-WEB-20260901-P` | **Failed after Web UI create with diagnostic evidence**: the real request and DB both stored `03:00Z–08:00Z` for a requested `10:00 PM–2:00 AM` America/Chicago shift; the correct end is `07:00Z`. The shared Syncfusion picker constrained endpoint values to 8 AM–10 PM and coerced the 2 AM value before timezone conversion. | `midscene_run/output/E2E-WEB-20260901-P-deterministic-web-lifecycle.json`; cleanup deleted exact ID `2961` + marker and verified 0 remaining. |
| `E2E-WEB-20260901-AE` | **Passed** the real Web create, edit hydration, assign, explicit unassign, publish, unpublish, and soft-delete lifecycle. The 10:00 PM–2:00 AM America/Chicago request and database row both retained canonical `03:00Z–07:00Z`; assignment changes did not alter UTC timestamps; publish/unpublish fields changed and cleared as expected. | `midscene_run/output/E2E-WEB-20260901-AE-deterministic-web-lifecycle.json`; exact ID `2978` + marker cleanup deleted one row, verified 0 remaining, and an independent marker sweep also found 0 rows. |

Run P isolated the mismatch to the Web time-picker boundary rather than API or database persistence: the outgoing request already contained the wrong `08:00Z` end, and the database persisted that request exactly. The Web branch removes the same-day business-hour min/max from create/edit time pickers and prevents edit-modal hydration from mutating the stored end time. Because this machine is directly ngroked to `dev2.buyerkiosk.com`, no deployment step was required; run AE exercised the current local working tree through dev2. Focused template verification passed **5 tests / 17 assertions**, the store-timezone Jest suite passed **12/12**, and the post-fix broad scheduling suite passed **1,501 tests / 6,024 assertions** with 2 skipped and 2 deprecations. Independent fail-closed review of the original endpoint fix found no security or logic defects.

The package has no generic `npm test` script; that attempted baseline command failed with `Missing script: "test"` and is not classified as a product test failure.

## Verdict

The deterministic Web lifecycle, Live manager, Team REST/realtime visibility, time-boundary, payroll, AI, canonical pending-request error, exact-store migration safety, and fresh 21-row live pagination traversal pass. The pending-pagination technical gate is **closed** by a hash-bound independent review of the current `H` snapshot. Release packaging, versioning of this non-Git E2E directory, and disposition of unrelated repository-wide baselines remain separate open gates. Tests and selected live paths do not prove that the module is bug-free or that unrestricted enterprise rollout is approved.
