# RC7 Google Maps Runtime Implementation Notes

**Governing issue:** #261
**Status:** CLOSED — ACTIVE SYNTHETIC-ONLY MANAGED CANARY
**Closure source:** `main@47285575862cbf08845eaeabe093afea1ea79bd1`

## Source reconciliation checkpoint

The corrective branch has completed its one-time atomic source reconciliation. The permanent branch no longer contains the temporary reconciler, formatter or diagnostic workflows. Environment schema, application adapter, unit tests, managed workflow, bootstrap, contract verifiers, trigger, status register and live ledger now describe the same service-identity OAuth architecture. A clean Node 24 runner using the repository-locked dependencies applied Prettier to the isolated adapter test and then passed both its target check and the complete backend `format:check` command before the temporary tooling was removed.

## Scope decision

RC7 activates only:

- Maps SDK for Android for native map display;
- Geocoding API v4 behind the DIREKT backend for bounded Zambian search-area normalization.

Places is not required because the approved manual area/landmark field remains functional and accessible. Routes is not required because PostGIS already owns public service-area matching and public-premises distance semantics. Neither omitted API may be enabled merely for completeness.

## Existing authority preserved

PostGIS remains canonical for private bases, consented public premises, public service-area geometry, matching and distance calculations. Google Maps does not become a trust, ranking, verification, publication or payment authority.

Publication rules remain unchanged:

- mobile providers: public service area only; no base marker or base distance;
- fixed premises: a marker only for a consented public premises point;
- hybrid: consented public premises plus the separate public service area;
- exact private coordinates: never public, logged, telemetered or included in provider payloads.

Android still requests no fine, coarse or background device-location permission. The my-location layer remains disabled. Manual/list discovery remains a first-class fallback.

## Root-cause correction

The first managed design restricted a backend API key to a reserved Public Cloud NAT address while calling a Google API. That model cannot prove the intended source address: traffic to Google APIs uses Private Google Access, and Public Cloud NAT does not translate that traffic to its external address. The Geocoding provider therefore returned `REQUEST_DENIED` even though the key metadata, quota and canary container were otherwise correct.

RC7 now rejects that architecture permanently. The backend path contains:

- no backend Maps API key;
- no backend Maps Secret Manager value;
- no Direct VPC egress requirement;
- no Cloud Router, Cloud NAT or static egress address;
- no IP-based backend credential restriction.

## Owner-budget attestation correction

The first exact-main service-identity run, `30210742617/1` on `1c6acd7972caca838f27b4e5c4a521c92cbfc7c4`, failed before Android key mutation, image build, Cloud Run Job creation or Firebase Test Lab. The GitHub deployer correctly lacked `billing.budgets.list` on the owner billing account.

RC7 does not broaden CI to billing-account viewer. The owner bootstrap directly verifies the real one-unit budget and then writes non-secret project labels for verified amount, currency and UTC check time. The exact-main proof reads only those project labels, rejects an attestation older than eight hours, and permanently prohibits managed `gcloud billing budgets` access.

## Ranked-candidate correction

The next exact-main proof, run `30225624823/1` on `6378be60199ce567671a4a307dedf5288b8be1ca`, passed exact-source checks, WIF, the fresh one-JPY owner budget attestation, quota verification, Android key restriction, immutable image execution and cleanup. The private backend canary then failed with a sanitized `outside_zambia` result before Firebase Test Lab. Artifact `8638498996` has digest `sha256:55c3b9f581ee899b5f1cac7e2a99e5d7851faedb00def2ba887e760e22a8a56a`; `cleanup.cloud_run_job_deleted=true` and `cleanup_failed=false`.

Geocoding v4 `regionCode=ZM` influences ranking but is not a strict country filter. The prior adapter treated `results[0]` as authoritative. The corrective adapter now iterates ranked results, validates every candidate before use, resolves country from `postalAddress.regionCode` or the typed country address component, and selects only the first candidate that also remains within the unchanged Zambia latitude/longitude bounds. Empty results remain `not_found`, structurally malformed-only results remain `invalid_provider_response`, and valid but non-Zambian-only results remain `outside_zambia`. Raw coordinates, formatted addresses, provider payloads and OAuth material are still excluded from logs and evidence.

## Android Test Lab evidence correction

Exact-main run `30226241329/1` on `58c3b36d15ca8b602ed2365242c93d965a7ff08d` proved the backend service-identity OAuth Geocoding v4 canary, fresh one-JPY owner attestation, quota, Android key restriction, immutable image and cleanup. The remaining result was one failed API 36 instrumentation case in Test Lab matrix `matrix-3gndt2ks91n33`. Artifact `8638705116` has digest `sha256:49fbc387d06eeb7061ca1c8923a313c8dff22f534e2940398f7d4df26d55233c`; `cleanup.cloud_run_job_deleted=true` and `cleanup_failed=false`.

The managed proof now verifies the SHA-1 certificate embedded in the final debug APK and requires it to equal the certificate restriction applied to the synthetic Android key. When Test Lab fails, the authenticated exact-main job queries the Testing and Tool Results APIs and writes a whitelisted receipt containing matrix state, step outcome, test-case identity and bounded stack traces. Raw logs, opaque tool outputs, credentials, API-key values, coordinates and participant data remain excluded. The instrumentation assertion still requires `discovery-map-ready`; a privacy-safe fallback is diagnostic evidence, not a pass.

## Deterministic APK certificate correction

Exact-main run `30228282694/1` on `40faf2e8e708994f448a3877cc9475739a0957a4` passed exact-source controls, WIF, the fresh one-JPY budget attestation, quota verification, Android key restriction, immutable backend execution, Geocoding v4 OAuth and Cloud Run cleanup. The Android build then completed successfully with 70 actionable tasks, including 34 restored from Gradle cache, but the script exited before writing the final APK certificate artifact or starting Test Lab. Artifact `8639272798` has digest `sha256:ddc1101960be5ca7d6daaea263a10bad5e25b697886bcf23cb5e2bb79c028323`; `cleanup.cloud_run_job_deleted=true` and `cleanup_failed=false`.

The next proof runs `clean` with `--no-build-cache`, extracts the certificate from the newly packaged APK, writes a sanitized expected/actual certificate receipt before validation, and fails closed on an `apksigner` error, malformed fingerprint or mismatch. Raw `apksigner` stderr is neither printed nor uploaded. The unexecuted Test Lab failure parser is also corrected to retain the real matrix ID through a literal `\1` backreference.

## APK signer-label correction

Exact-main run `30230004924/1` on `7c899295b176f767fd3da53f19b029b5582eae8a` passed backend service-identity OAuth, the fresh one-JPY budget attestation, quota, restricted Android key metadata, clean no-build-cache APK creation and Cloud Run cleanup. Artifact `8639806488` has digest `sha256:6ee216fb0e416c3013c4d26ea9246afaeb9fd663a84de89816689489533111b4`. `apksigner` exited zero, but the v2 parser returned no digest because it matched only `Signer #1`; Test Lab correctly did not start.

Android's `apksigner` output can identify certificate records with a numbered signer label or an SDK-range signer label. The corrected parser accepts both forms, normalizes and deduplicates all SHA-1 records, and requires exactly one unique digest equal to the key restriction. Multiple different digests, malformed output, a signer-tool failure or a mismatch all fail closed after the sanitized v3 certificate artifact is written. Raw signer stdout and stderr are never printed or uploaded.

## APK signer-stream correction

Exact-main run `30230730145/1` on `28481cd2d83a32259bd5b30784afefd575a51c58` passed backend service-identity OAuth, the fresh one-JPY budget attestation, quota, restricted Android key metadata, clean no-build-cache APK creation and Cloud Run cleanup. Artifact `8640052645` has digest `sha256:ec3f89f20a59df2d5d92d40b3429b10c2c3d6684c25a07059489d035e3437e82`. `apksigner` exited zero, but stdout-only parsing returned zero certificate digests; Test Lab correctly did not start.

The corrected extractor parses both private signer stdout and stderr through the same strict numbered/SDK-range SHA-1 pattern, normalizes and deduplicates matches, and still requires exactly one unique digest equal to the Android key restriction. The sanitized artifact records only `parsedStreams: ["stdout", "stderr"]`; raw signer streams remain ephemeral, are never printed and are never uploaded.

## Certificate SHA-1 field correction

Exact-main run `30231201667/1` on `e5c93419da91bc2276c0d02fa87568ac0e75b22f` passed backend service-identity OAuth, the fresh one-JPY budget attestation, quota, restricted Android key metadata, clean no-build-cache APK creation and Cloud Run cleanup. Artifact `8640205143` has digest `sha256:c545c1e4e49ba54d2269882af5a3cae0f8366e699b34b639f9f4dca7a9a853da`. Both private signer streams were parsed, but the remaining signer-prefix/start-of-line constraint returned zero digests; Test Lab correctly did not start.

AOSP's `ApkSignerTool.printCertificate` emits the stable field `<name> certificate SHA-1 digest: <hex>`. The corrected parser matches the exact `certificate SHA-1 digest:` field anywhere in either private stream, independent of the presentation prefix. It does not match `public key SHA-1 digest`. Matches are normalized and deduplicated, and exactly one digest must equal the Android key restriction. Raw signer streams remain ephemeral, unprinted and unuploaded.

## Final APK key-restriction correction

Exact-main run `30231743285/1` on `bcb30008c245a6a10ae3348b831259cef6dee441` passed backend OAuth, the fresh one-JPY budget attestation, quota, clean no-build-cache packaging and semantic certificate extraction. Artifact `8640363497` has digest `sha256:dfb312b7bebb8bbb2d6b45e2bd2d008fb04fa1475f6cfc73eaf4353f88bc9d83`. The final APK contained one valid SHA-1 certificate, but it differed from the provisional keystore fingerprint used to restrict the key before build; Test Lab correctly did not start and Cloud Run cleanup passed.

The corrected sequence retains a provisional package+certificate restriction only while the synthetic key value is retrieved and embedded. After the clean build, it extracts the actual APK certificate, updates the same key to exactly that package+certificate pair, verifies the API-key metadata and sole Maps SDK target, writes final sanitized evidence, waits 60 seconds for propagation, and only then starts Test Lab. A provisional mismatch is diagnostic rather than authoritative; the verified final APK restriction is the trust boundary. The key value never changes and is never uploaded.

## Closure receipt

Exact-main managed run `30234521983/1` on `47285575862cbf08845eaeabe093afea1ea79bd1` completed successfully. The contract job and privacy-safe runtime job both passed. Backend service-identity OAuth Geocoding returned `PASS`; the clean APK exposed one valid certificate; the Android key was re-restricted to that final certificate and Maps SDK target; Firebase Test Lab `MediumPhone.arm` API 36 passed 1/1 with zero flaky retries; manual/list fallback remained available; Cloud Run cleanup passed. Artifact `8641270327` has digest `sha256:24da53c0bd6fa885fa4a6814f70af090096192e6c5b7a03c89fba51416877fde`. The trigger is consumed and automatic main-push execution is removed. Production authorization, participant data and private-provider-coordinate publication all remained false.

## Credential and authentication boundary

Android and backend authentication remain separate:

1. **Android Maps key** — injected only at protected build time, restricted to the synthetic debug package/signing-certificate pair and Maps SDK for Android.
2. **Backend service identity OAuth** — the private Cloud Run Job uses its assigned user-managed runtime service account. The adapter obtains a metadata-server access token with `enforce_scopes=true` and only `https://www.googleapis.com/auth/maps-platform.geocode.address`, then calls Geocoding API v4 with an OAuth bearer token.

The backend token is short-lived, is never persisted or uploaded, and is never included in receipts. Production and controlled-pilot participant use remain disabled during RC7.

## Managed proof

The repository-controlled exact-main workflow performs one armed synthetic-only run after merge. It:

- confirms the reviewed SHA equals current `main` and authenticates through existing GitHub Workload Identity Federation;
- verifies only Maps SDK for Android and Geocoding dependencies are enabled and rejects Places or Routes;
- creates or updates only the Android package/signing/API-restricted synthetic key;
- builds an immutable backend image and runs a private Cloud Run Job under `direkt-api-runtime@direkt-dev-502701.iam.gserviceaccount.com`;
- proves a Zambia-bounded Geocoding v4 OAuth response without logging coordinates, formatted addresses or token material;
- builds a Maps-enabled preauthorization APK and requires `discovery-map-ready` on one API 36 Firebase Test Lab device with zero flaky retries;
- verifies the project budget alert and Geocoding per-minute quota;
- publishes a sanitized terminal PASS/FAIL receipt to Issue #261;
- deletes the temporary Cloud Run Job and fails if cleanup does not succeed.

The trigger must be changed from `STATUS=ARMED` to `STATUS=CONSUMED` in the closure change so later main pushes cannot repeat managed mutation automatically.

## Failure and fallback

A disabled capability, OAuth denial, quota rejection, map-load timeout or provider outage renders the same privacy-safe public location information as text and leaves list/manual discovery available.

Backend Geocoding has bounded input, Zambia constraints, timeout, a minimal response field mask, filtered output and sanitized errors. It does not store the input or result, and its managed canary logs neither coordinates nor formatted addresses.

## Cost controls

Managed activation verifies the restricted Android key, Geocoding OAuth scope, a Geocoding request ceiling, a project budget alert and Cloud Run Job cleanup. Places and Routes are excluded, so RC7 creates no quota or credential surface for them.

## Authorization boundary

RC7 does not authorize real participants, exact private-location publication, production authentication, production communications, real money, Phase 11 exit or Phase 12 release.
