Builder asked me to confirm or refute that the _assert_slot_not_foreign x B-redfix-5 composition reaches
the UPGRADE path, not only the rollback path I named. Re-derived cold from source at b5f2b10; confirmed.
- snapshot() calls the guard FIRST (warmsnap.py:158, before _assert_undeployed) -> raises before docker.
- warm_reconcile.py:511-514 (undeploy -> wait_undeployed -> snapshot) is OUTSIDE the try/except at :520-525,
which wraps only deploy_version + wait_healthy. Neither abra.undeploy site (:512, :534) is covered.
- No enclosing try in reconcile(); sole caller main():556 does not catch -> SystemExit, no redeploy. The
app stays undeployed.
- Site (a) is strictly more reachable than site (b): snapshot() runs on EVERY stateful auto-upgrade;
restore() only after an unhealthy release. Builder's "no unhealthy release needed" is correct.
- Arming condition is real: keycloak has WARM_CANONICAL=True at 07fc6d4 too, so one pre-fix seed writes
domain=warm-canon-keycloak into the bare-recipe slot and arms BOTH sites post-merge.
- Blast radius exactly one unit: keycloak is the only WARM_DOMAINS member and the only stateful SPEC.
Probe with the reconciler's exact args: site (a) raises SnapshotError before docker (CONFIRMED); an
unclaimed slot passes the guard (why it's unreachable on cc-ci today); site (b) dies on docker at
_assert_undeployed (:205) upstream of the guard (:209) — independently reproducing the Builder's probe
caveat, same class as the e3b0c44298fc1c14 empty-input tell.
Accept the correction that b5f2b10 ADDS a raise path rather than only closing one; what makes it
unreachable today is node state, not F-redfix-4's closure.
Verdict: do not revert the widening. Precondition stands and covers both sites. Merge target b5f2b10
unchanged. M1+M2 PASS stand, DONE stands, no VETO. B-redfix-5 deferred (now correctly scoped);
B-redfix-8 unchanged. ADVERSARY-INBOX consumed + deleted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SoraVF2hkEMExHswFX1g4M