# V2.6 Performance Harness

V2.6 adds a deterministic large-data fixture and a small HTTP performance harness for the current hot paths. The goal is to make performance regressions visible before adding more background jobs and Xiaobao automation.

## Fixture Sizes

The fixture script creates only `perf-*` rows and can be rerun safely. It covers:

- products
- projects
- versions
- requirements
- version plans
- dev tasks
- test cases
- bugs
- work activities
- Xiaobao risk summaries

Preset sizes:

| Size | Purpose |
| --- | --- |
| `small` | Local smoke fixture. Fast dry-run and minimal database seed. |
| `medium` | Default performance gate for V2.6 hot APIs. |
| `large` | Stress fixture for query/index audit work. |

Stable anchors used by the harness:

```text
productId=perf-product-001
versionId=perf-version-001-001-001
userId=perf-user-dev-01
```

## Commands

Dry-run without database access:

```bash
node scripts/seed-large-dataset.mjs --size small --dry-run
node scripts/perf-check.mjs --base-url http://localhost:3001/api/v1 --dry-run
```

Seed a database:

```bash
pnpm perf:seed -- --size small
```

Run the hot-path harness against a running NestJS API:

```bash
pnpm perf:check -- --base-url http://localhost:3001/api/v1
```

Audit SQL plans and hot-path indexes:

```bash
pnpm perf:explain -- --dry-run
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/ftb_pm pnpm perf:explain
```

## Hot Probes

`perf-check` measures p50 and p95 latency, records HTTP status code counts, and exits non-zero when a request fails or p95 exceeds the current query budget.

| Probe | Endpoint | p95 Budget |
| --- | --- | ---: |
| Runtime version | `/health/version` | 500ms |
| Requirement pool | `/v2.2/requirements?productId=perf-product-001&q=REQ&limit=50` | 1000ms |
| Version detail | `/v2.2/versions/perf-version-001-001-001/detail-data` | 1500ms |
| Workspace | `/v2.2/workspace?userId=perf-user-dev-01` | 1200ms |
| Xiaobao warning | `/v2.2/xiaobao-warning?manager=true` | 1000ms |

The medium fixture is the V2.6 acceptance target. Large fixture runs are for index audit and explain-plan work, not for every local commit.

See `docs/performance-hot-queries.md` for query budgets, partition-key contracts, and required indexes.

## Runtime Ops Dashboard

`/admin/ops` provides the V2.6 runtime view for checking whether the hot paths and background workers stay healthy after fixture/perf runs.

It reads `GET /api/v1/ops/runtime` and shows:

- recent slow API requests captured by `ApiTimingInterceptor`
- recent slow Prisma query previews captured by `PrismaService`
- `background_jobs` totals and per-type queued/running/succeeded/failed counts
- recent failed jobs with redacted `lastError`
- dirty `xiaobao_risk_summaries` count

Access is guarded in the frontend by `ops:view`. Backend RBAC is currently an explicit `OpsPermissionAdapter` placeholder until the V2.5 RBAC contract lands.

Secret handling:

- request query strings are stripped before display
- SQL is shown only as a bounded query preview, without Prisma parameters
- key-like text such as `sk-*`, token, secret, password, and authorization is redacted

## Notes

- `seed-large-dataset` uses deterministic IDs and dates so repeated runs are comparable.
- Non-dry-run seeding deletes and recreates only `perf-*` rows.
- The harness intentionally depends on public API endpoints instead of calling Prisma directly; it measures the same path the frontend uses.
