Reviewed rev 2 at `bd4ed0c4` against the clean worktree, after reading AGENTS.md. R1–R4 remain settled.

| Round-1 finding | Status | Why |
|---|---|---|
| 1. Picker bypasses pool exclusion | Resolved | Named-pool manifests now produce no candidates or guess; a distinct shared-pool eligibility gap remains below. |
| 2. Browser adoption changes the default | Resolved | Automatic inference happens after adoption detection; an untouched form no longer supplies an explicit region. |
| 3. Unnamed home prevents override | Resolved | Non-home app defaults require a named home, whose explicit code bypasses the fill. |
| 4. Mixed versions and rollback unspecified | Partly | Read-first rollout and a binary floor are specified; accepting that operational floor remains §17 Q3. |
| 5. Existing-canary `--region` undefined | Resolved | Equal proceeds; different refuses before record mutation or upload. |
| 6. Manifest absence versus failure unspecified | Resolved | The three policy states are distinguished, and legacy topology fields remain available. |
| 7. Absent-region explanation disappears | Resolved | `app_default` represents absent regions independently of the topology list; C8 is no longer count-dependent. |
| 8. Query hints reflected by redirects | Resolved | Hints move into POST bodies, with explicit redirect, logging, and audit privacy tests. |

The following findings are new.

1. **P1 — Automatic candidates can still include regions that cannot mint shared instances.**  
   **Spec:** §2, §6.1, §12, §16.

   `Hosting` checks reachability and activator configuration, without pool or inbound eligibility ([instancesplacement.go:189](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/instancesplacement.go:189)). However, an explicitly configured pool list excludes the shared `""` pool unless it contains it ([reconcile.go:1339](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/provision/reconcile.go:1339)), and `CARLOS_INBOUND=none` independently refuses new routed instances ([reconcile.go:925](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/provision/reconcile.go:925)).

   For example, UK has one reachable, hosting box configured with `CARLOS_POOLS=tito`. A new, ordinary app has no pooled manifest, so UK remains a candidate. The guess selects UK, the create door accepts the record, and no box provisions it. This is the reverse of round-1 finding 1: the **target box**, rather than the app, is pool-restricted.

   **Fix:** Require positive shared-pool and inbound eligibility for automatic candidates. Within the console-only scope, use an explicit operator-verified eligibility declaration and audit it before activation. Otherwise, publish the missing capabilities before enabling inference. Add reconciliation tests for named-pool-only and no-inbound targets.

2. **P1 — Losing the last placement publication disables the promised unavailable-default refusal.**  
   **Spec:** §7, §14, §15’s dormant-gate test.

   Failed edges reads become an empty result ([instancesplacement.go:87](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/instancesplacement.go:87)); with no placement-bearing files, `published` stays false ([instancesplacement.go:173](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/instancesplacement.go:173)). The create door then skips capability checks ([apiinstances.go:848](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/apiinstances.go:848)).

   Suppose an app stores `uk`, and the sole UK box is retired, leaving only the uncoded home. A no-region create fills `uk`, but dormancy permits it. The API writes an instance that cannot be provisioned, while `app_default` reports `absent`. §15 explicitly requires that acceptance, contradicting §7’s refusal promise.

   **Fix:** Preserve legacy dormancy for explicit requests and legacy home defaults, but require positive eligibility for a non-home **app-derived** default. Distinguish unavailable topology from confirmed absence where practical. Replace the conflicting test with last-region-removal and edges-read-failure cases.

3. **P2 — `auto` collides with a valid placement code.**  
   **Spec:** §5.5, §10.

   Placement codes accept lowercase letters up to 16 characters, so `auto` is valid ([provision.go:688](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/provision/provision.go:688)).

   On a deployment with a region named `auto`, the automatic option and that explicit region have identical submitted values. The browser cannot distinguish deliberate selection from inference. During adoption, an explicit choice can consequently be discarded.

   **Fix:** Use a sentinel outside the placement grammar, such as `@auto`, or encode explicit choices separately. Do not retroactively reserve a currently valid region code. Test a region—and named home—called `auto`.

4. **P2 — Fleet `app_default.code` gives the deploy preflight the wrong value.**  
   **Spec:** §9.3, §11, §12.

   Fleet placement is resolved from the store or existing routes ([fleets.go:479](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/fleets.go:479)) and replaces the instance region ([apiinstances.go:798](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/apiinstances.go:798)). Nevertheless, §9.3 requires `app_default.code` to report the platform home for fleet-placed apps.

   An app storing region `uk`, currently placed on `fleet/acme`, therefore reports `ie`. `deploy --region uk` is refused despite matching the stored app region; `deploy --region ie` passes despite matching neither that region nor its fleet placement.

   **Fix:** Expose the stored app region separately from effective instance placement. Compare `deploy --region` against the stored region, and represent fleet placement explicitly rather than presenting the platform home as its destination.

5. **P2 — The prescribed `regionReq` cannot carry the IP needed inside `claimApp`.**  
   **Spec:** §5.5, §6.2, §8.1.

   `claimApp` receives a context and identity arguments, but no HTTP request ([server.go:3466](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/server.go:3466)). Its `addr` argument is the audit actor ([apicli.go:349](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/apicli.go:349)), whereas trusted IP extraction requires the request ([authcli.go:876](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/authcli.go:876)).

   Moving inference inside `claimApp` fixes adoption, but the specified `{explicit, tz, person}` structure loses the network address. Following that interface literally makes old-CLI and JavaScript-disabled browser requests fall back to home despite configured GeoIP.

   **Fix:** Pass an optional, request-local IP obtained through `s.clientIP` into `regionReq`, or provide a request-scoped lookup callback. Resolve it only after adoption is known, and never persist or log it.

6. **P2 — The rollback detector flags ordinary, correct deployments.**  
   **Spec:** §5.7, §14.

   The proposed detector identifies non-home apps with later records whose region is empty. Normal static deployment creates exactly that record ([deploy.go:858](/home/paulca/amadan.net/carlos/platform-nearest-region/deploy.go:858)); explicit home selection also normalizes to empty ([apiinstancemove.go:136](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/apiinstancemove.go:136)).

   A correctly operating non-home app with a static apex or deliberate home override is therefore reported as a rollback gap. §7 keeps `region_from` outside the persisted record, so those records cannot conclusively distinguish intentional overrides from old-console defaults.

   **Fix:** Exclude shapes that never inherit the app default, and describe remaining matches as **possible placement discrepancies**, not detected rollback violations. Reliable attribution needs additional persisted provenance or an independently recorded rollback interval.

The remaining requested checks support the design: the fill’s insertion preserves fleet precedence and pool/static/address-backed/replica exclusions; sidecars retain their separate door. Normalized inferred values still pass the manifest predicate, so I found no allow-list bypass. Migration ordering and the fixed rebuild lists match §5.2 ([store.go:402](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/store.go:402), [store.go:487](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/store.go:487)). Old JSON clients remain compatible through permissive decoding.

Existing migrated apps retain `""`, so the new unarmed-default refusal does not newly strand them. For non-home apps, an explicit override remains subject to the manifest: if every allowed region is unavailable, capacity or policy must change. POST-body hints and the proposed storage fields introduce no identified IP or coordinate retention requirement.

| §17 question | Recommendation |
|---|---|
| **Q1 — titogo completion** | **(b).** Include titogo adoption in operational completion if Ireland relief is the objective; unchanged callers on existing apps retain home placement. |
| **Q2 — latency** | **(a).** Ship placement separately and measure the actual request path before claiming latency gains. The cited DNS seam remains unimplemented at [apiinstances.go:1052](/home/paulca/amadan.net/carlos/platform-nearest-region/internal/console/apiinstances.go:1052). |
| **Q3 — rollback floor** | **(a), with explicit acceptance.** Preserve the region-aware binary during rollback and use the switch to disable new defaults. Below-floor rollback can violate placement promises; the proposed audit is not a preventive safeguard. |

All code citations supporting these findings were checked in this worktree. No files changed, no tests ran, and production configuration was not inspected.

**Verdict: not ready for planning.** Resolve candidate eligibility and the dormant-gate contradiction first, then correct the four implementation contracts above.