# Test Validation Log — `@bytelyst/tracker-web`

This log tracks the validation/hardening effort for the tracker-web dashboard's test
suite. Every gate is run from the repo root, filtered to this package. A gate is only
marked green if it was actually executed and passed.

All commands are run as:

```bash
cd /Users/sd9235/code/mygh/learning_ai_common_plat
pnpm --filter @bytelyst/tracker-web <script>
```

---

## Baseline (before any changes)

Recorded at repo HEAD `77b074f3`.

| Gate          | Command                                             | Result | Notes                                                                                  |
| ------------- | --------------------------------------------------- | ------ | -------------------------------------------------------------------------------------- |
| typecheck     | `pnpm --filter @bytelyst/tracker-web typecheck`     | PASS   | `tsc --noEmit`, exit 0                                                                 |
| lint          | `pnpm --filter @bytelyst/tracker-web lint`          | PASS   | `eslint`, exit 0                                                                       |
| test (unit)   | `pnpm --filter @bytelyst/tracker-web test`          | PASS   | 8 files, 55 tests                                                                      |
| test:coverage | `pnpm --filter @bytelyst/tracker-web test:coverage` | RUNS   | 90.78% stmts / 84.78% branch (only files imported by tests are measured)               |
| build         | `pnpm --filter @bytelyst/tracker-web build`         | PASS   | `next build --webpack`, 14 routes                                                      |
| format:check  | `pnpm --filter @bytelyst/tracker-web format:check`  | FAIL   | `README.md`, `docs/roadmaps/UX_INTEGRATION_BYTELYST.md` not Prettier-formatted         |
| test:e2e      | `pnpm --filter @bytelyst/tracker-web test:e2e`      | FAIL   | 9 passed / 3 failed (see below)                                                        |
| size:check    | `pnpm --filter @bytelyst/tracker-web size:check`    | FAIL   | `bundlesize` cannot load — `iltorb` native module won't build on Node 25 (env blocker) |

### Baseline e2e failures (3)

1. `Tracker Login Page › shows error for invalid credentials` — depends on a live
   platform-service. With no backend, the login proxy returns 502
   "Platform service unavailable", which does not match `/failed|error|invalid/i`.
2. `Tracker — Public Roadmap › roadmap page can toggle between board and list view` —
   list view renders "No items found" (no backend data), so `table, [role='list']`
   never appears.
3. `Tracker — Health › GET /api/health returns ok` — the dev server has no
   `PLATFORM_API_URL` / `JWT_SECRET` / `DEFAULT_PRODUCT_ID` set, so `/api/health`
   correctly returns `degraded` (503), not `ok`.

Root cause for all three: the e2e suite depends on a live platform-service and ambient
env, which violates the determinism requirement ("mock network at the route/proxy
boundary; don't depend on a live platform-service").

### Out-of-scope / environment blockers

- **`size:check` (bundlesize)**: `bundlesize@0.18.2` (latest, unmaintained) transitively
  requires `brotli-size@0.1.0` → `iltorb@2.4.5`, a deprecated native addon that does not
  compile on Node 25 (`Cannot find module './build/bindings/iltorb.node'`). `pnpm rebuild
iltorb` produces no `build/` output. The broken dependency lives in the root
  `node_modules` (shared infra, out of scope to patch), and no newer `bundlesize` exists.
  Bundle budgets are instead verified manually against the gzipped build output.

---

## Changes

Work proceeded as small, independently-pushed units. Commits (newest last):

| SHA        | Commit                                                                          |
| ---------- | ------------------------------------------------------------------------------- |
| `d0707f22` | docs(tracker-web): add TEST_VALIDATION_LOG with baseline gate results           |
| `8738d07d` | fix(tracker-web): format markdown + ignore e2e artifacts in prettier/git        |
| `1c231d66` | test(tracker-web): make e2e deterministic + add axe a11y and console checks     |
| `772609c9` | test(tracker-web): cover untested API routes + tracker-client, enforce coverage |

### What changed

1. **format:check** — Ran Prettier over `README.md` and
   `docs/roadmaps/UX_INTEGRATION_BYTELYST.md`. Added `.prettierignore` and
   `.gitignore` entries for `coverage/`, `test-results/`, `playwright-report/` so
   generated artifacts no longer break the format/lint gates. (`8738d07d`)

2. **e2e** — Rewrote `e2e/tracker.spec.ts` to be deterministic: all platform-service
   calls are mocked at the Next.js proxy boundary (`/api/tracker`, `/api/auth`), and
   `/api/health`'s required env vars are supplied via `playwright.config.ts`
   `webServer.env`. Added a login→dashboard happy path, board/list toggle, submit-modal
   and vote-prompt flows, axe-core accessibility assertions (serious/critical), and a
   no-unexpected-console-errors check. axe-core is resolved from the workspace (it is a
   transitive dep of `eslint-plugin-jsx-a11y`) so **no new dependency / lockfile change**
   was introduced. (`1c231d66`)
   - **Real bug fixed (in scope):** the axe gate flagged `select-name` (critical) —
     the roadmap type-filter and submit-modal `<select>` had no accessible name. Added
     `aria-label`s in `src/app/roadmap/page.tsx`.

3. **coverage** — Added unit tests for the untested proxy routes
   (`auth/mfa/verify`, `auth/oauth/[provider]`, `telemetry/ingest`), the
   `tracker-client` API surface (path/method/body + `x-product-id` injection), and
   `product-config`. Overall coverage rose from ~90% to **94.36% stmts / 86.58% branch
   / 94.28% funcs / 96.99% lines** (55 → 91 unit tests). Also fixed the vitest threshold
   config: the legacy `thresholds.global` nesting is ignored by the v8 provider, so the
   80% gate was silently disabled; it is now enforced and passing. (`772609c9`)

### Final gate results (all run from repo root, filtered to this package)

| Gate          | Command                                             | Result                                                    |
| ------------- | --------------------------------------------------- | --------------------------------------------------------- |
| typecheck     | `pnpm --filter @bytelyst/tracker-web typecheck`     | PASS (exit 0)                                             |
| lint          | `pnpm --filter @bytelyst/tracker-web lint`          | PASS (exit 0, 0 warnings)                                 |
| test (unit)   | `pnpm --filter @bytelyst/tracker-web test`          | PASS — 13 files, 91 tests                                 |
| test:coverage | `pnpm --filter @bytelyst/tracker-web test:coverage` | PASS — 94.36 / 86.58 / 94.28 / 96.99, thresholds enforced |
| build         | `pnpm --filter @bytelyst/tracker-web build`         | PASS — `next build --webpack`, 14 routes                  |
| format:check  | `pnpm --filter @bytelyst/tracker-web format:check`  | PASS                                                      |
| test:e2e      | `pnpm --filter @bytelyst/tracker-web test:e2e`      | PASS — 18 tests (chromium)                                |
| size:check    | `pnpm --filter @bytelyst/tracker-web size:check`    | BLOCKED (env) — verified manually, see below              |

### Coverage by file group (final)

| Group               | % Stmts | Notes                                                                                                                                                                           |
| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `app/api/**` routes | 89–100  | All proxy handlers covered incl. error + 502 paths                                                                                                                              |
| `lib/`              | ~92     | `tracker-client`, `telemetry`, `utils`, `product-config` covered                                                                                                                |
| `components/ui`     | 0       | `Primitives.tsx` not rendered — component render tests would need jsdom + @testing-library, which were not added to avoid a lockfile-churning dependency change (see blockers). |

### bundlesize budgets — manual verification

`size:check` (bundlesize) cannot execute in this environment (see blocker above), so the
gzipped sizes of the budgeted chunks were measured directly after `build`. All are within
budget with comfortable margin, e.g.:

- `framework-*.js`: 58.3 kB gzip (budget 100 kB)
- `main-*.js`: 37.3 kB gzip (budget 50 kB)
- `app/layout-*.js`: 3.6 kB gzip (budget 150 kB)
- largest route `app/dashboard/items/page-*.js`: 6.0 kB gzip (budget 30 kB)

No budget was raised; no regression observed.

### Out-of-scope / environment blockers (final)

- **`size:check`**: `bundlesize@0.18.2` → `brotli-size@0.1.0` → `iltorb@2.4.5` (deprecated
  native addon) will not compile on Node 25. The broken package lives in the root
  `node_modules` (shared infra), and no newer `bundlesize` exists. Verified budgets
  manually instead (above). No in-scope fix is possible without replacing the tool or
  patching shared infra.
- **Component render tests** (`components/ui/Primitives.tsx`): would require adding
  `@testing-library/react` + a jsdom/happy-dom environment. A `pnpm add` in this
  environment re-normalises the entire monorepo lockfile (observed: ~5.8k net line
  churn under `--offline`), which is an unacceptable shared-infra change for this task,
  so component-render coverage was intentionally left out. Component _logic_ is exercised
  end-to-end via the deterministic Playwright suite instead.
