# Perf gate preflight — health-check before PT-01

**Task**: AZ-1133_perf_gate_preflight
**Name**: Perf gate preflight — health-check before PT-01
**Description**: Add a preflight reachability check to `scripts/run-performance-tests.sh` so Step 15 fails fast with actionable instructions when the perf compose stack is not running.
**Complexity**: 1 point
**Dependencies**: AZ-492 (perf harness), AZ-1123 (perf compose documentation)
**Component**: test tooling — `scripts/run-performance-tests.sh` + deployment/test env docs
**Tracker**: AZ-1133
**Epic**: None

## Problem

Cycle 13 Step 15 first run failed at PT-01 because `API_URL` (`https://localhost:18980`) was unreachable — the perf overlay (`docker compose -f docker-compose.yml -f docker-compose.perf.yml up -d`) had not been started. The script proceeded through JWT mint/bootstrap and only surfaced the failure as a cryptic PT-01 HTTP error / non-zero exit, wasting operator time. This carry-over appears in cycle 13, 14, and 15 retros.

## Outcome

- `run-performance-tests.sh` verifies API reachability after JWT mint and before PT-01
- Unreachable API exits with exit code **7** and prints the canonical compose-up command
- Reachable API proceeds to PT-01 unchanged
- `environment.md` and `containerization.md` document the preflight behavior

## Scope

### Included

- Add `preflight_api_reachable` (or equivalent) helper in `scripts/run-performance-tests.sh`:
  - Probe `$API_URL` with the same `CURL_OPTS` / TLS trust as PT-01 (e.g. `curl --connect-timeout 5` to a lightweight endpoint — authenticated `GET /api/satellite/tiles/latlon` with valid coords is acceptable since JWT is already minted)
  - On connection failure / empty response → print error + `docker compose -f docker-compose.yml -f docker-compose.perf.yml up -d --build` and `exit 7`
- Update `_docs/02_document/tests/environment.md` § Performance tests — mention script preflight + exit 7
- Update `_docs/02_document/deployment/containerization.md` § Compose overlays — cross-link preflight

### Excluded

- Auto-starting the compose stack from the script (operator still starts it explicitly)
- Changing PT-01..PT-10 thresholds or scenario logic
- CI integration (perf remains local-only per `ci_cd_pipeline.md`)

## Acceptance Criteria

**AC-1: Preflight runs before PT-01**
Given `run-performance-tests.sh` with valid `JWT_SECRET` / iss / aud
When the script reaches the performance scenarios section
Then a reachability probe executes after JWT mint and before the PT-01 banner.

**AC-2: Unreachable API fails fast with instructions**
Given the perf compose stack is not running (`API_URL` connection refused or timeout)
When `run-performance-tests.sh` is executed
Then the script exits with code **7**, stderr/stdout includes the perf overlay `docker compose … up` command, and PT-01 does not run.

**AC-3: Reachable API proceeds unchanged**
Given the perf stack is up and `API_URL` accepts authenticated requests
When `run-performance-tests.sh` is executed
Then preflight passes silently (or with a single "API reachable" line) and PT-01..PT-10 behave as before.

**AC-4: Documentation reflects preflight**
Given the post-task docs
When `environment.md` and `containerization.md` are read
Then both mention the script preflight and exit code 7 when the stack is down.

## Non-Functional Requirements

**Reliability**
- Preflight must use the same TLS trust path as the rest of the script (`CURL_OPTS` / `certs/api.crt`).

**Compatibility**
- No change to default env vars (`API_URL`, `PERF_REPEAT_COUNT`, etc.).

## Unit Tests

| AC Ref | What to Test | Required Outcome |
|--------|-------------|-----------------|
| — | Shell-only change; no new C# unit tests required | N/A |

## Blackbox Tests

| AC Ref | Initial Data/Conditions | What to Test | Expected Behavior | NFR References |
|--------|------------------------|-------------|-------------------|----------------|
| AC-2 | Perf stack stopped; JWT env set | `./scripts/run-performance-tests.sh` | Exit 7 + compose instruction; no PT-01 timing output | Reliability |
| AC-3 | Perf stack running | `./scripts/run-performance-tests.sh` (smoke: `PERF_REPEAT_COUNT=1` if needed) | Exit 0 or threshold fail only after PT-01 starts | Compatibility |

## Constraints

- Preserve `set -euo pipefail` globally — preflight must not mask real curl failures in scenario bodies.
- Exit code **7** is reserved for "stack not up" to match cycle 13 perf report convention.

## Risks & Mitigation

**Risk 1: False negative when API returns 401/403**
- *Risk*: Preflight treats auth errors as "reachable" vs connection errors as "down" — must distinguish connection/TLS failure from HTTP 4xx.
- *Mitigation*: Use curl exit code / `--connect-timeout`; treat HTTP responses (even 401) as reachable.

**Risk 2: Preflight adds latency to every perf run**
- *Risk*: Extra round-trip before 10 scenarios.
- *Mitigation*: Single lightweight GET; acceptable vs minutes-long perf suite.
