# Test Specification — C6 Tile Cache + Spatial Index

Component-scoped. Suite-level coverage in `_docs/02_document/tests/*.md`.

## Acceptance Criteria Traceability

| AC ID | Acceptance Criterion (one-line) | Test IDs | Coverage |
|-------|---------------------------------|----------|----------|
| AC-8.1 | Imagery via Suite Sat Service offline cache, ≥0.5 m/px | FT-P-15, FT-P-16, **C6-IT-01** | Covered |
| AC-8.2 | Tile freshness <6 mo (active-conflict) / <12 mo (rear) | FT-N-05, **C6-IT-02** | Covered |
| AC-8.4 | Mid-flight tile generation with quality metadata | FT-P-17, **C6-IT-03** | Covered |
| AC-NEW-3 | FDR ≤64 GB / flight, no silent drops (mid-flight tiles count toward C13 — C6 must not block) | NFT-LIM-02, **C6-IT-04** | Covered |
| AC-NEW-6 | System rejects/downgrades stale tiles | FT-N-05, FT-N-06, **C6-IT-05** | Covered |
| RESTRICT-SAT-2 | Cache budget 10 GB across operational area | NFT-LIM-03, **C6-IT-06** | Covered |

---

## Component-Internal Tests

### C6-IT-01: filesystem layout byte-identical to `satellite-provider`

**Summary**: tiles written by C11 `TileDownloader` and tiles emitted at mid-flight by C5/C6 produce identical filesystem paths and JPEG byte content for the same `(zoomLevel, lat, lon)` coordinate.

**Traces to**: AC-8.1 (interop with `satellite-provider` for the upload return path)

**Description**: download a known tile via C11 TileDownloader (against the real `satellite-provider` mock fixture); generate the same tile via the mid-flight orthorectification path (C5 + C6); assert (a) filesystem path equality, (b) JPEG bytes equality, (c) `tiles` table row equality on `(zoomLevel, lat, lon, source, content_sha256)`.

**Input data**: a single Derkachi-area tile (`zoom=18, lat≈49.94, lon≈36.31`).

**Expected result**: byte-identical layout.

**Max execution time**: 10 s.

---

### C6-IT-02: freshness gate at write-time

**Summary**: a tile with `produced_at < now - active_conflict_max_age` is rejected at C6 insert if the target sector is `active_conflict`.

**Traces to**: AC-8.2

**Description**: insert a synthetic tile with `produced_at = now - 7 months` into an `active_conflict` sector; assert C6 raises a freshness-rejection error and does NOT write to disk or DB. Repeat with `stable_rear` — assert the tile is written but flagged `freshness_downgraded`.

**Input data**: synthetic tile fixtures with controlled timestamps.

**Expected result**: rejection in active_conflict; downgrade-write in stable_rear.

**Max execution time**: 5 s.

---

### C6-IT-03: mid-flight tile insert with quality metadata

**Summary**: every tile written via the F4 mid-flight gen path has full `quality_metadata` (covariance, inlier count, source-label provenance).

**Traces to**: AC-8.4

**Description**: simulate F4 — feed C5 a 60 s sequence; the orthorectifier emits N tiles; assert each tile's row in `tiles` has non-null `quality_metadata.covariance_norm`, `quality_metadata.inlier_count`, `quality_metadata.source_label`. Empty quality metadata fails the test.

**Input data**: scripted F4 fixture.

**Expected result**: 100% of mid-flight tiles have full metadata.

**Max execution time**: 90 s.

---

### C6-IT-04: write throughput exceeds peak F4 demand

**Summary**: C6 sustains the peak mid-flight write rate (1 tile / 2 s typical, ~5/s peak) without queueing-induced backpressure on C5.

**Traces to**: AC-NEW-3 (no-silent-drop gate)

**Description**: synthetic burst — 100 tiles enqueued at 5 Hz; assert (a) all 100 land in `tiles` table within 30 s, (b) no tile dropped, (c) C5's write-side queue depth never exceeds the configured ceiling.

**Input data**: synthetic burst fixture.

**Expected result**: 100/100 written; no drops.

**Max execution time**: 60 s.

---

### C6-IT-05: stale-tile reject + downgrade across the F1 / F4 / F5 boundary

**Summary**: in F5 (steady-state retrieval), a tile flagged `freshness_downgraded` is returned with the downgrade flag, and any consumer that depends on freshness (e.g., spoof-rejection check) sees the flag.

**Traces to**: AC-NEW-6

**Description**: write a `freshness_downgraded` tile via C6-IT-02's stable_rear path; query via the C2/C3 fetch path; assert the returned tile carries the downgrade flag and that the consumer-side label propagates into the `EstimatorOutput.source_label`.

**Input data**: as C6-IT-02.

**Expected result**: downgrade flag survives the round-trip.

**Max execution time**: 10 s.

---

### C6-IT-06: 10 GB cache budget enforcement

**Summary**: when the operational-area working set hits 10 GB, C6 evicts oldest tiles by LRU; never silently dropping a tile that would put the system over budget.

**Traces to**: RESTRICT-SAT-2

**Description**: synthetic load that fills the cache to 10 GB - 50 MB; insert another 100 MB of tiles; assert (a) total disk usage stays ≤ 10 GB, (b) eviction count matches insert count above the threshold, (c) every eviction is logged at INFO with the evicted tile_id.

**Input data**: synthetic tile generator.

**Expected result**: 10 GB cap held; LRU eviction visible in logs.

**Max execution time**: 5 min on Tier-1 (disk-bound).

---

## Performance Tests

### C6-PT-01: per-tile read latency on Tier-2 (mmap hit)

**Traces to**: AC-4.1 (read-side; mmap is the design assumption for C2/C2.5/C3 hot paths)

**Load scenario**: 3 Hz × 10 candidate tiles per frame × 10 min replay; OS page cache warm.

**Expected results**:

| Metric | Target | Failure Threshold |
|--------|--------|-------------------|
| `get_tile_pixels` p95 (warm) | ≤ 0.5 ms | 5 ms |
| `get_tile_pixels` p95 (cold first read) | ≤ 50 ms | 200 ms |

---

## Security Tests

### C6-ST-01: content-sha256 mismatch rejects insert

**Summary**: a tile insert with a content_sha256 that doesn't match the actual JPEG bytes is rejected at C6 (defends against the cache-poisoning path D-C10-3 covers at takeoff).

**Traces to**: defensive (D-C10-3 + AC-NEW-7 cumulative)

**Test procedure**:
1. Compute SHA-256 of a known JPEG.
2. Submit insert with the JPEG bytes + a deliberately-wrong SHA-256.
3. Assert insert is rejected and the DB row is not created.

**Pass criteria**: insert rejection + no row.
**Fail criteria**: insert accepted or partial row created.

---

## Acceptance Tests

Covered transitively via FT-P-15 / FT-P-16 / FT-P-17 / FT-N-05 / FT-N-06.

---

## Test Data Management

| Data Set | Source | Size |
|----------|--------|------|
| Single Derkachi tile (`zoom=18`) | curated | <1 MB |
| Synthetic tile fixtures with controlled timestamps | scripted | ~50 MB |
| Synthetic 10 GB cache fill set | scripted, deterministic | 10 GB on disk |
| `flight_derkachi/normal_segment_60_stills/` for F4 simulation | shared | shared |

**Setup**: ephemeral Postgres + filesystem under `tests/tmp/c6/<test-id>/db/` and `…/tiles/`.
**Teardown**: drop tmp directory.
**Data isolation**: per-test ephemeral DB + filesystem.
