# Phase 2A.3 PBF Ingestion Foundation Handoff

- Project: `osm-lead-source-service`
- Phase: Phase 2A.3 — PBF ingestion foundation
- Status: accepted; ready to merge
- Repository: `lutzkind/osm-lead-source-service`
- Base branch: `main`
- Base commit: `0e392612a0fe1e2ca626b4e2b71f85d1c26fbe04`
- Implementation branch: `phase-2a/03-pbf-ingestion-foundation`
- Pull request: #4, open and unmerged at acceptance
- Corrected code head before acceptance documentation:
  `f4562c59dc2a4e29eccfdfad1b4cd77c90694136`
- Final reviewed PR head before this acceptance commit:
  `61cc6f10f61a2897c66773ce9fab207e6c7bf280`
- Corrected code CI: run `29179985294`, job `86615774810`, success
- Final reviewed PR-head CI: run `29180073414`, job `86615998289`, success
- Production impact: none

## Scope implemented

Phase 2A.3 adds:

- explicit verified-input integrity evidence with local path, SHA-256, byte
  count, and descriptive provenance
- bounded pyosmium streaming for nodes, ways, and relations
- detached immutable object records
- transactional sink completion and rollback boundaries
- combined operation/rollback failure reporting
- parser-complete metadata without reconciliation-completion authority
- synthetic fixture provenance
- loopback-only HTTP acquisition for approved test inputs
- strict response, checksum, size, URL, and metadata validation
- create-if-absent content-addressed PBF and metadata caching
- deterministic warm-cache metadata
- hard file, Blob, expansion, object, tag, reference, and member limits
- immediate duplicate protobuf field rejection
- file and cache stability checks
- exact-endpoint test network isolation

## Independent review corrections

The first independent review blocked merge because duplicate payload fields
could cause memory amplification and sink rollback failures were silently
ignored. The correction pass:

- stores at most one Blob payload and rejects the second immediately
- rejects duplicate Blob `raw_size` and BlobHeader type/datasize fields
- raises `PbfTransactionError` when the operation and `abort()` both fail
- preserves both failures in an `ExceptionGroup` cause
- tests abort failure after `accept()` and `finish()` failures
- tests wrong content type, unsupported content encoding, missing/invalid
  `Content-Length`, changed response URL, and non-200 responses
- preserves ETag, Last-Modified, URL, region, hash, size, and download timestamp
  through a bounded strict metadata sidecar
- rejects incomplete or conflicting cache pairs
- documents provenance as descriptive context rather than authorization

The final independent re-review found no remaining merge blocker.

## Synthetic fixture

```text
Size: 438 bytes
SHA-256: 1f181fa63b838de88c5c7d8ecff2a014ca52a9349c6470fd2656ad3c9e0ddb8c
Objects: 2 nodes, 1 way, 1 relation
```

The fixture is synthetic, contains no production or personal data, and is
decoded only into pytest temporary directories.

## Final reviewed verification

```text
Head: 61cc6f10f61a2897c66773ce9fab207e6c7bf280
CI run: 29180073414
CI job: validate / 86615998289
Conclusion: success
```

- Ruff lint and formatting passed.
- Strict mypy passed for 22 source files.
- 116 unit tests passed.
- 54 sidecar integration tests passed.
- 6 PBF loopback integration tests passed.
- 1 generic network-policy integration test passed.
- 177 total tests passed.
- Alembic upgrade, downgrade, and re-upgrade passed.
- Source distribution and wheel build passed.
- Disposable database and CI network resources were cleaned up.

## Handoff limitation

The repository handoff is authoritative. The direct session attempted to create
`/mcp-shared/chatgpt/osm-lead-source-service/phase-2a-03-accepted/`, but the
available Shell MCP policy rejected the required `mkdir` operation. The GitHub
PR, repository handoff, exact heads, tests, and CI provide the complete review
evidence; only the duplicate external bundle could not be created.

## Explicit exclusions

- no production Geofabrik region selection or download
- no production input authorization
- no unbounded ingestion
- no PostGIS persistence
- no NocoDB read or write
- no profiles, normalization, or deduplication
- no adoption scanner or reconciliation executor
- no scheduler, deployment, FastAPI, MCP, or legacy scraper change

Phase 2A.4 was not started.
