# Phase 2A.2 Integrity Correction Handoff

- Project: `osm-lead-source-service`
- Subphase: Phase 2A.2 correction pass only
- Original reviewed head: `d3f62f3d07da804b0d51d63649208490e6b20aee`
- Prior lifecycle correction: `fad2429f596d727e1a02c58a5cdbd994576a5f9d`
- Final implementation correction: `b89bd77c939faf35ab55662e75c75ea4bfdc7da2` (`fix: preserve latest snapshot absence guard`)
- Incomplete-state coverage correction: `de9308111aed763b59918a22da31547dc0dfa669`
- Branch: `phase-2a/02-sidecar-schema`
- Pull request: #3, accepted for merge

## Corrections

Migration `0001_create_sidecar_schema` was corrected in place. No `0002`
migration was added. `last_seen_at` must equal the immutable matching
`source_snapshot_object.observed_at`; present rows use the latest observation,
and forged old timestamps are rejected. `first_missing_at` must equal the
complete first-missing snapshot's `reconciliation_completed_at` and remains
immutable through absence transitions.

The final correction keeps latest-snapshot completeness separate from
first-missing completeness. Every non-present state now requires a latest
snapshot with exactly `complete` status and a nonnull reconciliation completion
timestamp. A later `partial`, `failed`, or `unknown` latest snapshot cannot
advance an existing absence counter or transition it to `stale_confirmed`,
`remap_candidate`, or `deleted_in_osm`, even when the first-missing snapshot is
complete.

`source_snapshot` is now append-only finalized evidence: updates and deletes
are rejected, so a later processing attempt must be inserted as a new complete,
partial, failed, or unknown row. Mapping chronology requires
`first_mapped_at <= last_confirmed_at <= superseded_at` when applicable, and
supersession targets must be different, active mappings for the same Noco row.

The integration fixtures use explicit historical observation timestamps for
valid stale proof. Regression tests reject forged last-seen and first-missing
timestamps, evidence replacement during absence, snapshot rewrites/deletes,
invalid mapping chronology, and non-live supersession targets. Existing
complete-snapshot, two-distinct-snapshot, observation, region, boundary,
mapping, baseline, immutability, network, CLI, and migration safeguards remain
covered.

## Verification

- Local tests: 121 total; 66 unit, 54 sidecar integration, and 1 network-policy integration test.
- Latest-snapshot completeness regressions: all `partial`, `failed`, and `unknown` latest snapshots were rejected for absence-counter advancement and for `stale_confirmed`, `remap_candidate`, and `deleted_in_osm` transitions.
- Initial absence-establishment regressions: `partial`, `failed`, and `unknown` snapshots were rejected.
- Valid stale regression: genuinely old immutable observation accepted after two distinct complete missing snapshots.
- Forged timestamp regression: recent observation with a manually old `last_seen_at` rejected; contradictory `first_missing_at` rejected.
- Migration lifecycle: upgrade empty database, downgrade base with sidecar absent and PostGIS present, then re-upgrade successfully.
- Local checks: pip install, Ruff, format check, mypy, full pytest, build, CLI offline commands, and `git diff --check` passed.
- Final reviewed CI: run `29141331604`, job `86514991031`, success.

## Final acceptance

- Acceptance date: 2026-07-11.
- Accepted PR: #3.
- Accepted reviewed head: `c1be1e2798524d6eea25190128bcfa99dfcd7546`.
- Migration revision: `0001_create_sidecar_schema`.
- Final reviewed CI: run `29141331604`, job `86514991031`, success.
- Test counts: 66 unit tests, 54 sidecar integration tests, 121 total tests.
- Ruff, formatting, mypy, build, CLI, and doctor checks passed.
- Migration upgrade, downgrade, and re-upgrade passed; PostGIS remained
  installed after downgrade.
- Complete snapshots are structurally complete and append-only.
- Stale evidence is bound to immutable observation and snapshot timestamps.
- Two distinct complete absence snapshots are required.
- Partial, failed, and unknown snapshots cannot establish, advance, or
  transition absence.
- Region consistency, mapping history, baseline chains, immutability, and
  network restrictions passed review.
- No production or NocoDB access occurred. No production database,
  deployment, scheduler, writer, executor, PBF handling, MCP, or legacy
  scraper change occurred.
- Phase 2A.3 was not started.
- The final squash-merge SHA will be recorded in the external post-merge
  handoff because a committed file cannot contain its own future merge SHA.

## Safety boundaries

No production database, deployment, NocoDB access, PBF download, parser,
profile engine, scheduler, worker, writer, reconciliation executor, or
stale-delete execution was added. Production impact is none. Phase 2A.3 has
not started.
