# Performance Test Report — Cycle 4

**Date**: 2026-05-13
**Cycle**: Phase B / Cycle 4 (AZ-512 — admin class inline edit)
**Runner**: `scripts/run-performance-tests.sh --static-only` (generated by test-spec Phase 4)
**Mode**: static-only profile executed (NFT-PERF-01); e2e profile (NFT-PERF-02..10) records SKIP because the Playwright perf project is still not wired (carries from cycle 3)
**Verdict**: **PASS** (one Pass + documented SKIPs + three documented Quarantines)

---

## Scope

Re-baseline the gzipped initial-JS bundle metric (NFT-PERF-01) after AZ-512 added ~80 lines of inline-edit code to `src/features/admin/AdminPage.tsx` plus 7 new i18n keys × 2 locales in `src/i18n/{en,ua}.json`. No new packages, no new external endpoints, no new lazy-load boundary (AdminPage continues to import statically from `src/App.tsx:8`, so its bytes count toward the initial-JS bundle).

E2E-stack-bound scenarios (NFT-PERF-02..10) are out of scope for this cycle's measurement because:
1. The Playwright perf project remains unwired (same status as cycle 3 — tracked in `perf_2026-05-13_cycle3.md` "E2E profile status").
2. AZ-512's surface is contained client-side state + one HTTP PATCH that does not yet exist server-side (the live endpoint is gated by AZ-513 in the `admin/` workspace). There is no live-stack perf path to measure until AZ-513 ships.

---

## Results

| Scenario | Verdict | Measured | Threshold | Source |
|----------|---------|----------|-----------|--------|
| NFT-PERF-01 (initial JS bundle, gzipped) | **PASS** | **291 332 B** (≈ 284.5 KB) | ≤ 2 097 152 B (2 MB) — AC-11 / row 40 of `results_report.md` | `dist/assets/*.js` summed via `gzip -c \| wc -c` after `bun run build` |
| NFT-PERF-02 (auth refresh round-trip p95) | SKIP | n/a | ≤ 200 ms — row 11 of `results_report.md` | Deferred — Playwright perf project not yet wired |
| NFT-PERF-03 | QUARANTINE | — | Step 8 hardening (SSE refresh rotation) | Carried |
| NFT-PERF-04..07 | SKIP | n/a | various | Deferred — Playwright perf project not yet wired |
| NFT-PERF-08 | QUARANTINE | — | Step 4 fix (panel-width persistence) | Carried |
| NFT-PERF-09 | QUARANTINE | — | Step 4 fix (settings save error surfacing) | Carried |
| NFT-PERF-10 (warm-cache FCP on /flights) | SKIP | n/a | ≤ 3 000 ms (edge profile) | Deferred — Playwright perf project not yet wired |

---

## Bundle delta vs prior cycles

| Cycle | Measured (bytes, gzipped) | Δ vs prior cycle | % of 2 MB budget | Source |
|-------|---------------------------|------------------|------------------|--------|
| 2 | 290 465 | new baseline | ~13.85% | `perf_2026-05-12_cycle2.md` |
| 3 (post AZ-510/AZ-511) | 290 575 | **+110 B (+0.04%)** | ~13.85% | `perf_2026-05-13_cycle3.md` |
| 4 (post AZ-512) | **291 332** | **+757 B (+0.26%)** | **~13.89%** | this report |

Net change vs cycle-2 baseline: +867 bytes / +0.30% / +0.04 percentage-points of budget across two feature cycles. Bundle growth remains in line with the rate of feature growth — no regression, no concern.

---

## Bundle-size impact analysis — what cost the +757 bytes

| Change | Pre-min source | Estimated minified+gzipped contribution |
|--------|----------------|------------------------------------------|
| `src/features/admin/AdminPage.tsx` new state (4 hooks), handlers (`handleStartEdit`/`handleCancelEdit`/`handleUpdateClass`/`handleEditKeyDown`), conditional row JSX, validation, PATCH wiring | ~80 LoC of TS + JSX | ~500–600 B |
| `src/i18n/en.json`, `src/i18n/ua.json` — `admin.classes` flat-string → nested object (`title` + 6 edit keys) per locale | 7 keys × 2 locales × ~25 B/key (English) + Cyrillic UA chars ~2× UTF-8 | ~150–200 B |
| Module doc / blackbox / traceability / report deltas | docs only | 0 (excluded from `dist/`) |

The delta is dominated by the inline-edit handler and JSX; i18n is a small fraction. **Order-of-magnitude consistent with a tight ~80-line UI feature.** No accidental imports of `mission-planner/`, no new `react-i18next` plugins, no new icon set, no new third-party lib pulled in.

---

## E2E profile status

Carried verbatim from `perf_2026-05-13_cycle3.md` — the Playwright perf project remains unwired. Same unblock path:

> NFT-PERF-02..10 require a Playwright performance-config profile that loads the suite stack, performs the scenario, and emits timing measurements consumable by the runner. The project's existing Playwright config drives functional e2e only (no perf assertions / reporters). Wiring this is a Phase B candidate (own ticket, ~5-point task; not in scope for AZ-512).

No new blocker — the gap has the same shape it had in cycle 3. AZ-512 does not change the e2e-perf surface; the planned Playwright wiring (a future ticket) is what unblocks NFT-PERF-02..10.

---

## Verdict

**PASS** for cycle 4. The single executable scenario (NFT-PERF-01) is at 13.89% of the 2 MB threshold with a +0.26% cycle-over-cycle increase explained entirely by AZ-512's documented additions. All SKIPs and QUARANTINES carry forward from cycle 3 with the same rationale. **No bundle regression and no new perf concern introduced.**

## Self-verification (test-run / perf-mode)

- [x] NFT-PERF-01 runner executed against a freshly built `dist/` (no stale build).
- [x] Threshold sourced from `_docs/00_problem/input_data/expected_results/results_report.md` (AC-11 / row 40 — same as cycle 3).
- [x] Measured value recorded with the exact byte count from the runner.
- [x] Cycle-over-cycle delta computed and explained.
- [x] No threshold breach.
- [x] E2E profile status carried with same unblock path as cycle 3 — no new perf gating ticket needed for AZ-512.
