# Phase 2A.4 Review Handoff

Date: 2026-07-15
Repository: `lutzkind/osm-lead-source-service`
Phase: 2A.4 — profiles, normalization, and deduplication
Status: accepted; ready for squash merge
Authoritative pull request: #6
Authoritative branch: `phase-2a/04-profiles-normalization-deduplication-clean`
Base: `main` at `4fe68f3616920da8e35aa017528ce16c06e418ad`
Accepted reviewed head before acceptance commits: `5c8abf239224bf90e4f83301651e3f578e3d639e`
Accepted reviewed CI: run `29392820489`, job `87279785710`, success
Accepted reviewed test counts: 139 unit, 54 sidecar integration, 200 total

## Branch and PR warning

PR #5 and branch `phase-2a/04-profiles-normalization-deduplication` are disposable implementation helpers. They contain a one-off write-enabled GitHub Actions workflow used to construct and format the clean branch. They must not be reviewed as the acceptance candidate and must never be merged.

Only PR #6 is the Phase 2A.4 merge candidate. Its tree is based directly on the accepted `main` and does not contain the temporary formatter workflow.

## Implemented scope

- Immutable exact-version profile definitions and registry lookups.
- Deterministic include/exclude evaluation with explicit region overrides.
- Draft-only `luxeillum` and `saas_redesign` definitions.
- Shadow-only curated `legacy_parity` definition pinned to the legacy repository commit and selector blob.
- Structural rejection of production insert enablement.
- Bounded deterministic profile impact reports.
- Unicode-stable business-name and address normalization.
- IDNA business-domain normalization with localhost, single-label, credential-bearing, and IP-address rejection.
- Explicit-context phone normalization with bounded E.164-shaped output.
- Region-scoped, bounded, report-only duplicate-candidate generation.
- Oversized duplicate buckets represented only by SHA-256 references.
- No automatic merge, adoption, or mutation decision.

## Independent hardening applied

The clean candidate was hardened after adversarial review to:

- reject repeated regex groups and unsupported regex constructs;
- bound profile tag key/value inputs before regex evaluation;
- reject repeated source identities in profile impact reports;
- validate public rule, override, count, and candidate contracts before sorting or unpacking;
- reject IP literals as business domains;
- reject alphabetic phone junk after extension removal;
- avoid double-prefixing an already present calling code;
- validate normalized country, phone, and coordinate shapes;
- add regression tests for every listed branch.

## Safety boundaries

- Production profile insertion is structurally unavailable.
- No profile is approved for production targeting.
- No NocoDB connection or write surface is introduced.
- No direct Noco PostgreSQL write is introduced.
- No sidecar write is introduced.
- No production PBF download or ingestion is introduced.
- No adoption scanner or reconciliation executor is introduced.
- No stale deletion, deployment, scheduler, FastAPI service, or MCP service is introduced.
- The legacy scraper is unchanged.
- Phase 2A.5 has not started.

## Acceptance verification

Independent review found no remaining merge blocker on the accepted reviewed head.

Verified:

1. PR #6 is based on accepted `main` and is cleanly mergeable.
2. `.github/workflows` in PR #6 contains only the normal `ci.yml` workflow.
3. Ruff lint and formatting passed.
4. Strict mypy passed.
5. 139 unit tests, 54 sidecar integration tests, and 200 total tests passed on the same exact head.
6. Migration upgrade, downgrade, and re-upgrade passed.
7. Package build, offline CLI checks, and CI cleanup passed.
8. Built-in profiles remain draft or shadow-only and cannot authorize production inserts.
9. Duplicate generation remains region-scoped, bounded, and report-only.
10. No NocoDB, sidecar, production PBF, deployment, scheduler, MCP, or legacy-service mutation surface appears.

The final acceptance-commit SHA, squash-merge SHA, and post-merge CI are recorded externally because a committed file cannot contain its own future identifiers.

## Outstanding decisions

- Final approved `luxeillum` production profile rules.
- Final approved `saas_redesign` production profile rules.
- A complete compiled legacy selector snapshot if legacy parity is ever considered for activation.
- Phase 2A.5 may begin only after PR #6 is accepted, merged, and post-merge CI is verified.
