# Map — Coverage Matrix (v0.2.0)

**Module ID:** `oscar.map`
**Version:** 0.2.0

A row is satisfied when: (a) the source file exists, (b) the implementation matches the rule, and (c) the fragment is bound and SHIPPED.

## Constitutional Fragments

| Fragment | Status | Bound file(s) | Rule |
|---|---|---|---|
| oscar.map.model.001 | SHIPPED (v0.1.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | model per §43 Map Module |
| oscar.map.view.001 | SHIPPED (v0.1.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | view per §43 Map Module |
| oscar.map.store.001 | SHIPPED (v0.1.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | store per §43 Map Module |
| oscar.map.geometry-types.3.001 | SHIPPED (v0.1.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | geometry-types.3 per §43 |
| oscar.map.tree-integration.001 | SHIPPED (v0.1.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | tree-integration per §43 |
| oscar.map.selection-shared.002 | SHIPPED (v0.2.0) | app/src/map/MapView.tsx, app/src/map/SidePanel.tsx | Two-way shared selection |
| oscar.map.side-panel.002 | SHIPPED (v0.2.0) | app/src/map/SidePanel.tsx | Side panel fields + actions |
| oscar.map.filter-chips.002 | SHIPPED (v0.2.0) | app/src/map/FilterChips.tsx | Filter chips for kind/date/name |
| oscar.map.export-menu.002 | SHIPPED (v0.2.0) | app/src/map/ExportMenu.tsx | Export menu 6 formats |
| oscar.map.documents-view.002 | SHIPPED (v0.2.0) | app/src/views/Documents.tsx | Documents view |
| oscar.map.vertex-editing.002 | SHIPPED (v0.2.0) | app/src/map/MapView.tsx | Vertex drag handlers |
| oscar.map.versioning.002 | SHIPPED (v0.2.0) | app/src/map/MapView.tsx, app/src/data/models/MapLayer.ts | Layer versioning rules |
| oscar.map.report-types.002 | SHIPPED (v0.2.0) | app/src/map/ExportMenu.tsx | Report type templates |
| oscar.map.annotation-stub.002 | SHIPPED (v0.2.0) | app/src/data/models/Annotation.ts | Annotation schema |
| oscar.map.cloud-sync-stub.002 | SHIPPED (v0.2.0) | app/src/data/models/MapLayer.ts, app/src/data/models/Document.ts | Forward-compat sync fields |

## Doctrinal Files

| File | Status | Purpose |
|---|---|---|
| recipe.md | UPDATED to v0.2.0 | Product description, structural contract, reconstruction notes |
| codex.md | UPDATED to v0.2.0 | C1-C10 behaviour inventory + state machines |
| rules.md | UPDATED to v0.2.0 | 15 rules including versioning, document-snapshot, annotation, cloud-sync, two-way selection, empty-filter |
| plan.md | UPDATED to v0.2.0 | 3-phase plan, binding order |
| ingredients.json | UPDATED to v0.2.0 | Module dependencies + data shapes |
| module-meta.json | UPDATED to v0.2.0 | Module index, fragment registry |
| coverage-matrix.md | UPDATED to v0.2.0 | This file |

## Expected Implementation Files (per recipe.md §C and plan.md Phase 2)

| File | Purpose | Fragment binding | Status (v0.2.0 doctrine phase) |
|---|---|---|---|
| app/src/map/MapView.tsx | Leaflet container + drawn layer + pending layer + vertex-drag + selection bridge + base-layer tile swap (Map/Sat/Hyb) + zoom-control position + filter derivation (kind/date/name) + filter-aware drawn-layer redraw + auto-deselect when filtered out + version bump on save + LayerVersion audit record write | view.001, selection-shared.002, vertex-editing.002, versioning.002, filter-chips.002 | EXISTS (v0.1.0) — EXTENDED in v0.2.0 Items 1 + 2 (selection + base-layer toggle + filters) + Item 5 (vertex editing) + Item 6 (version bump + audit record write) |
| app/src/map/VertexEditor.tsx | Vertex drag state machine (enter/save/cancel) + preview shape + draggable vertex markers | vertex-editing.002, versioning.002 | SHIPPED in v0.2.0 Item 5 (helper); Item 6 wired the save path to bump version + write LayerVersion |
| app/src/data/models/LayerVersion.ts | LayerVersion shape: { id, layer_id, version, coords, created_at, updated_at } | versioning.002 | SHIPPED in v0.2.0 Item 6 |
| app/src/data/persistence/idb.ts | layer_versions store registration with by-layer-id + by-created-at indexes (DB v19) | store.001 + versioning.002 | EXISTS (v0.1.0) — EXTENDED to v19 in v0.2.0 Item 6 (layer_versions store) |
| app/src/map/SidePanel.tsx | Selection side panel + v{n} badge next to kind badge | side-panel.002, versioning.002 | SHIPPED in v0.2.0 Item 1 (selection surface); v{n} badge added in Item 6 |
| app/src/map/exporters.ts | Per-format generators (PDF/PNG/SVG/GeoJSON/KML/Print) — PDF has Version column, all formats embed layerVersions in metadata | export-menu.002, versioning.002 | SHIPPED in v0.2.0 Item 3; Item 6 added Version column to PDF table |
| app/src/map/FilterChips.tsx | Filter chip row | filter-chips.002 | SHIPPED in v0.2.0 Item 2 (kind multi-select + date single-select + name substring + clear all) |
| app/src/map/ExportMenu.tsx | Export format picker + per-format generators + Document write path | export-menu.002 | SHIPPED in v0.2.0 Item 3 (PDF/PNG/SVG/GeoJSON/KML/Print). Report-type picker (site visit / client / planning / expert witness) lands in step 15. |
| app/src/data/models/Document.ts | Document shape (type, layerIds, layerVersions, createdAt, metadata, syncState, syncedAt, serverVersion) | documents-view.002, cloud-sync-stub.002 | SHIPPED in v0.2.0 Item 3 |
| app/src/views/Documents.tsx | Saved documents index + re-download + delete + empty state + Map header link | documents-view.002 | SHIPPED in v0.2.0 Item 4 |
| app/src/App.tsx | Router entry for /documents route | documents-view.002 | SHIPPED in v0.2.0 Item 4 |
| app/src/data/models/Document.ts | Document shape (extended with optional `blob` field in Item 4 for re-download from snapshot) | documents-view.002, cloud-sync-stub.002 | SHIPPED in v0.2.0 Item 3 + extended in Item 4 |
| documentsRepo | IndexedDB documents store CRUD | documents-view.002 | EXISTS (v0.2.0 Item 3) |
| app/src/data/models/MapLayer.ts | Extended MapLayer shape with version + sync fields | model.001, versioning.002, cloud-sync-stub.002 | EXISTS (v0.1.0) — will be EXTENDED in implementation phase |
| app/src/data/models/Document.ts | Document shape (new) | documents-view.002, cloud-sync-stub.002 | NOT YET — Phase 2 step 12 |
| app/src/data/models/Annotation.ts | Annotation shape (new) | annotation-stub.002 | NOT YET — Phase 2 step 16 |
| app/src/data/persistence/idb.ts | IDB store registration, DB v19 (documents store v18, layer_versions store v19) | store.001 + versioning.002 + new stores | EXISTS (v0.1.0) — EXTENDED to v18 in v0.2.0 Item 3 (documents store), to v19 in v0.2.0 Item 6 (layer_versions store). Items 16 will add annotations store. |

## Rules Compliance Matrix

| Rule | Source fragment | Satisfied when |
|---|---|---|
| §1 Capability declaration (Leaflet, not SVG) | codex.md §C1 | MapView.tsx imports leaflet; no SVG fallback path |
| §2 Do-not-proceed rule | rules.md §2 | CI fails App-VP tests |
| §3 Contract primacy | rules.md §3 | recipe + codex have no contradictions; conflicts resolved per rules |
| §4 Anti-drift enforcement | rules.md §4 | All 5 steps run after every doctrinal amendment |
| §5 Plan-as-law | rules.md §5, plan.md | Implementation follows plan order |
| §6 Fallback behaviour | rules.md §6 | All four fallback scenarios implemented |
| §7 User-simulator requirement | rules.md §7 | All 20+ C6 user sims pass |
| §8 Re-anchor cadence | rules.md §8 | C6 + coverage re-run between phases |
| §9 Coverage matrix | rules.md §9, this file | All rows marked satisfied |
| §10 Versioning rules | rules.md §10, versioning.002 | Significant edits bump version + write LayerVersion |
| §11 Document-snapshot rule | rules.md §11, documents-view.002 | Every export writes Document with layerVersions map |
| §12 Annotation rule | rules.md §12, annotation-stub.002 | Annotations stored; no auto-interpretation |
| §13 Cloud-sync stub rule | rules.md §13, cloud-sync-stub.002 | No behaviour reads/writes syncState |
| §14 Two-way selection rule | rules.md §14, selection-shared.002 | Single shared state; both surfaces subscribe |
| §15 Empty-filter rule | rules.md §15, filter-chips.002 | Empty filters = show all; "Clear all" affordance present |

## Drift Resolution (v0.2.0)

Pre-existing drift identified at v0.1.0:

- **codex.md §C1 + recipe.md §B + rules.md §1** declared "SVG-only, no Leaflet dependency"
- **MapView.tsx** has used Leaflet since v1
- **v0.2.0 resolution**: codex.md §C1, recipe.md §B, rules.md §1 explicitly lifted the SVG-only constraint; Leaflet is now the authoritative runtime renderer. No runtime change required for resolution — doctrine alignment only.

This is the only drift item. No other doctrinal/runtime discrepancy exists at v0.2.0.

## Drift Status

**Drift = 0** within doctrine at v0.2.0. All fragments consistent with codex, recipe, and rules. Implementation-phase drift (between doctrine and runtime) is not in scope for this coverage matrix — that drift is resolved during Phase 2 implementation and re-measured at Phase 3 verification per plan.md.

---

## END OF COVERAGE-MATRIX.MD (v0.2.0)