[AZ-447] autodev Steps 1-4 baseline: docs, tests, refactor specs

Captures the full output of autodev existing-code Phase A through
Step 4 (Code Testability Revision) for the Azaion UI workspace:

- Step 1 Document: _docs/02_document/ (FINAL_report, architecture,
  glossary, components/, modules/, diagrams/, system-flows,
  module-layout) plus _docs/00_problem/ + _docs/01_solution/ +
  _docs/legacy/ + _docs/how_to_test + README.
- Step 2 Architecture Baseline: architecture_compliance_baseline.md.
- Step 3 Test Spec: _docs/02_document/tests/ (environment,
  test-data, blackbox/performance/resilience/security/
  resource-limit tests, traceability-matrix), enum_spec_snapshot,
  expected_results/results_report.md (98 rows), plus the
  run-tests.sh + run-performance-tests.sh runners.
- Step 4 Code Testability Revision: 01-testability-refactoring/
  run dir (list-of-changes C01-C07, deferred_to_refactor,
  analysis/research_findings + refactoring_roadmap) and the 7
  child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/
  plus _dependencies_table.md.
- _docs/_autodev_state.md pins the cursor at Step 4 / refactor
  Phase 4 entry so /autodev resumes cleanly.

Epic AZ-447 (UI testability gates) tracks the 7 child tasks that
will land in subsequent commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 00:38:49 +03:00
parent da0a5aa187
commit 510df68bcf
84 changed files with 13065 additions and 0 deletions
@@ -0,0 +1,224 @@
# Performance Tests
The Azaion UI is a thin SPA; the dominant performance concerns are bundle size, auth-refresh transparency, SSE responsiveness, and UI reflection of server-confirmed state changes. Server-side throughput is OUT of scope here — this file covers the UI's observable timing only.
### NFT-PERF-01: Initial JS bundle ≤ 2 MB gzipped
**Summary**: The sum of gzipped initial-route JS chunks in `dist/` stays within the architecture's stated budget.
**Traces to**: AC-11, O13
**Metric**: gzipped byte total of initial JS entries.
**Profile**: static
**Preconditions**:
- `bun run build` has produced `dist/`.
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Run `vite build` (or read the build manifest if already built) | `dist/` produced |
| 2 | Walk Vite's `manifest.json` to enumerate entry chunks (non-async) | list of initial chunks |
| 3 | Gzip-size each chunk (Node `zlib.gzipSync(content, {level:9})` or equivalent) | per-chunk size |
| 4 | Sum sizes | total bytes |
**Pass criteria**: total ≤ 2 097 152 bytes (2 MB). Documentary today — no CI gate (AC-11 status: "target, not currently enforced"). Test exists so the gate flips to blocking the day CI wires it up.
**Duration**: ≤ 60 s.
**Expected result source**: `results_report.md` row 40.
---
### NFT-PERF-02: Auth refresh — exactly one network round trip per cycle
**Summary**: A single 401-triggered refresh round consists of exactly one `POST /api/admin/auth/refresh` plus one retry of the original request.
**Traces to**: AC-01, AC-23
**Metric**: count of `/api/admin/auth/refresh` requests per refresh event.
**Profile**: fast
**Preconditions**:
- Authenticated session.
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Issue an authenticated request that returns 401 once, then 200 on retry | network log captured |
| 2 | Count refresh requests fired in the cycle | exactly 1 |
**Pass criteria**: refresh count == 1 per cycle (`results_report.md` row 12 — exact).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 12.
---
### NFT-PERF-03: SSE bearer-rotation reconnect ≤ 5 s
**Summary**: When the bearer rotates while N SSE streams are open, all streams close and reopen with the new token within 5 s.
**Traces to**: AC-24
**Metric**: per-EventSource time from `close()` observed to next `OPEN` readyState (after reconnect with new token).
**Profile**: fast — `quarantined` until SSE refresh-reconnect is implemented (Step 8 hardening)
**Preconditions**:
- Two EventSources open (live-GPS + annotation-status).
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Trigger a refresh that rotates the bearer | new bearer in memory |
| 2 | For each EventSource: time from old `close` to new `OPEN` | dt_i (ms) |
| 3 | Inspect new URLs for new token in query string | new `?token=` value |
**Pass criteria**: `max(dt_i) ≤ 5 000 ms`; both streams close+open exactly once (`results_report.md` row 13).
**Duration**: ≤ 30 s.
**Expected result source**: `results_report.md` row 13.
---
### NFT-PERF-04: Live-GPS SSE opens within 5 s of flight select
**Summary**: After clicking a flight in the Header, the live-GPS EventSource reaches `OPEN` quickly.
**Traces to**: AC-08
**Metric**: time from select-flight click to EventSource `readyState === 1` (OPEN).
**Profile**: e2e (suite live-gps simulator emits events at 1 Hz)
**Preconditions**:
- Authenticated; flight selectable.
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Click a flight | one EventSource constructed to `^/api/flights/[0-9]+/live-gps(\?|$)` |
| 2 | Wait for `OPEN` | dt (ms) |
**Pass criteria**: `dt ≤ 5 000 ms` (`results_report.md` row 34).
**Duration**: ≤ 10 s.
**Expected result source**: `results_report.md` row 34.
---
### NFT-PERF-05: Live-GPS SSE closes within 1 s of deselect
**Summary**: Deselecting the flight tears down the live-GPS stream promptly.
**Traces to**: AC-08
**Metric**: time from deselect to `CLOSED`.
**Profile**: e2e
**Preconditions**:
- Continuation of NFT-PERF-04.
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Deselect the flight | EventSource closes |
| 2 | Wait for `CLOSED` | dt (ms) |
**Pass criteria**: `dt ≤ 1 000 ms` and no remaining open live-GPS sources (`results_report.md` row 35).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 35.
---
### NFT-PERF-06: Annotation-status SSE unsubscribes within 1 s on page unmount
**Summary**: Navigating away from `/annotations` closes the status-events SSE within 1 s.
**Traces to**: AC-09
**Metric**: time from unmount to `CLOSED`.
**Profile**: fast
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Mount `/annotations` then unmount | EventSource transitions |
| 2 | Measure dt | ms |
**Pass criteria**: `dt ≤ 1 000 ms` (`results_report.md` row 25).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 25.
---
### NFT-PERF-07: Bulk-validate UI reflects new status within 2 s
**Summary**: After a successful bulk-validate, every selected row shows `Validated` quickly.
**Traces to**: AC-07
**Metric**: time from server 200 to last DOM row update.
**Profile**: fast
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Select N items, click Validate | request issued |
| 2 | Stub responds 200 | UI updates begin |
| 3 | Wait for all N rows to show `Validated` | dt (ms) |
**Pass criteria**: `dt ≤ 2 000 ms` (`results_report.md` row 37).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 37.
---
### NFT-PERF-08: Panel-width persistence debounce ≤ 1 s after resize-end
**Summary**: A drag-end on a resizable panel triggers a single PUT within 1 s (debounced).
**Traces to**: AC-21
**Metric**: time from `mouseup` (drag-end) to outbound PUT; PUT count per drag.
**Profile**: fast — `quarantined` until Step 4 writer is added
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Drag and release a divider | event captured |
| 2 | Wait for PUT or 1 s timeout | dt (ms); count |
**Pass criteria**: exactly 1 PUT within ≤ 1 000 ms; URL = `/api/annotations/settings/user`; body contains `panelWidths` (`results_report.md` row 64).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 64.
---
### NFT-PERF-09: Settings save error surfaces within 2 s
**Summary**: A 500 on settings save produces an error toast and resets the `saving` flag within 2 s.
**Traces to**: AC-27
**Metric**: time from server 500 to error visibility + state reset.
**Profile**: fast — `quarantined` until Step 4 try/finally fix
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Trigger save, stub responds 500 after T ms | failure delivered |
| 2 | Wait for error toast and `saving === false` | dt (ms) |
**Pass criteria**: `dt ≤ 2 000 ms` (`results_report.md` row 68).
**Duration**: ≤ 5 s.
**Expected result source**: `results_report.md` row 68.
---
### NFT-PERF-10: First Contentful Paint on `/flights` ≤ 3 s on mid-range edge hardware
**Summary**: A warm-cache load of the default authenticated route renders the main pane within 3 s.
**Traces to**: AC-11 (target), H2 (edge deploys)
**Metric**: `performance.getEntriesByName('first-contentful-paint')[0].startTime`.
**Profile**: e2e — documentary (no enforcement today; no AC binds a hard FCP budget)
**Preconditions**:
- Warm browser cache (second visit).
- Edge-profile container: 2 vCPU, 4 GB RAM (the hardware-assessment phase confirms the figure).
**Steps**:
| Step | Consumer Action | Measurement |
|------|----------------|-------------|
| 1 | Navigate to `/flights` post-login | navigation completes |
| 2 | Read FCP entry | ms |
**Pass criteria**: FCP ≤ 3 000 ms (row 98 — threshold_max).
**Duration**: ≤ 30 s.
**Expected result source**: `results_report.md` row 98.