# AZ-620 — Phase B: build_pre_constructed seeds c6_descriptor_index + c6_tile_store

**Task**: AZ-620_pre_constructed_phase_b_c6_storage
**Name**: AZ-618 Phase B: build_pre_constructed seeds c6_descriptor_index + c6_tile_store
**Description**: Second subtask of AZ-618. Extends `airborne_bootstrap.build_pre_constructed(config)` to populate the C6 storage entries used by C2 / C2.5 / C3.
**Complexity**: 3 points
**Dependencies**: AZ-619 (build_pre_constructed skeleton), AZ-303 (TileStore), AZ-306 (faiss DescriptorIndex). All in `done/` once AZ-619 lands.
**Component**: runtime_root (cross-cutting)
**Tracker**: AZ-620
**Epic**: AZ-602 (parent: AZ-618 umbrella)

## Outcome

- `build_pre_constructed(config)` adds keys `c6_descriptor_index` (DescriptorIndex instance) and `c6_tile_store` (TileStore instance) on top of the AZ-619 contract.
- A misconfigured `BUILD_FAISS_INDEX=OFF` against a config that selects a C2 strategy needing the index raises `AirborneBootstrapError` naming both the missing flag and the consuming component.
- New unit tests under `tests/unit/runtime_root/test_az620_pre_constructed_phase_b.py`.

## Scope

### Included

- Internal builders `_build_c6_descriptor_index(config)` and `_build_c6_tile_store(config)` calling the existing C6 Public API factories (likely `runtime_root.storage_factory.build_descriptor_index` and the matching tile store factory — confirm exact entry-point names during implementation).
- BUILD-flag mismatch surfaces a clear `AirborneBootstrapError` with consuming-component slug + missing flag.
- New unit tests covering AC-620.1 + AC-620.2.

### Excluded

- All keys outside this phase (AZ-619 / AZ-621 / AZ-622 / AZ-623).
- `runtime_root.main()` integration (AZ-624).

## Acceptance Criteria

**AC-620.1: c6 keys populated**
Given a default airborne `Config` with `BUILD_FAISS_INDEX=ON`
When `build_pre_constructed(config)` is called
Then the dict additionally contains `c6_descriptor_index` (DescriptorIndex instance) and `c6_tile_store` (TileStore instance).

**AC-620.2: BUILD_* flag mismatch raises clear error**
Given a config selecting `c2_vpr.strategy="net_vlad"` (requires descriptor_index)
And `BUILD_FAISS_INDEX=OFF`
When `build_pre_constructed(config)` is called
Then it raises `AirborneBootstrapError` whose message names both `c6_descriptor_index` (the missing key) and `BUILD_FAISS_INDEX` (the gating flag) and `c2_vpr` (the consuming component slug).

**AC-620.3: unit tests exist** — `pytest tests/unit/runtime_root/test_az620_pre_constructed_phase_b.py` exercises AC-620.1 + AC-620.2.

## Constraints

- MUST NOT modify per-component factory signatures.
- MUST NOT introduce new `BUILD_*` env flags.
- MUST be additive on top of AZ-619.

## Implementation Notes

- The exact factory entry-points for descriptor index and tile store live under `src/gps_denied_onboard/runtime_root/storage_factory.py` (or equivalent — confirm during implementation). `module-layout.md` line 159 references `runtime_root.storage_factory.build_descriptor_index`.

## Evidence

- Umbrella spec: `_docs/02_tasks/todo/AZ-618_airborne_bootstrap_pre_constructed.md`
- AZ-303 / AZ-306 task specs in `_docs/02_tasks/done/` for C6 runtime classes
