# Remozio plan review: revision 15

**Scope:** complete plan text, plus the round-8 disposition. This is a plan-only review. I ran no tests, browsed nothing, and inspected no source.

The revision 15 fixes are directionally sound: floors stay proposed until activation, root anti-rollback no longer relies on the candidate's own checks, and UI prompts are recaptured only when never consumed.

Three findings remain. All are low severity, and none of the corrections worsens UX.

## Findings

### 1. Low: custody of tunnel and push-gateway credentials is unspecified

**Sections:** §3 "Key custody and pre-login transport"; §16 "Cloudflare Tunnel endpoint" and "Keep push separate from the live proxy"; §15 "Required notification service".

The custody rule covers only transport keys: dedicated-account-private storage, and no interactive account can read them.

Two other Mac credentials have no custody rule:
- the cloudflared tunnel credential ("stay on the Mac")
- the Mac's push-gateway submission credential

§16 also does not say which account runs cloudflared.

**Failure scenario:**
- A malicious same-user process, which is in scope, reads the tunnel credential.
- It runs rogue connectors off-machine. The edge can route phone connections to them.
- End-to-end payload encryption and pinned identities still prevent forgery or disclosure.
- However, the attacker gains durable relay-position metadata and can intermittently black-hole remote approvals.
- This persists after the local malware is removed, until someone rotates the credential.
- A stolen push credential similarly permits wake/notification spam to enrolled phones.

These are availability and metadata effects only, not authority. They are still a concrete custody gap against an in-scope attacker, and a persistent one.

**Minimal correction:**
- Apply the transport-key custody rule to both credentials, including the same-user isolation validation.
- Run cloudflared under the dedicated transport account.
- Specify rotation and revocation for both credentials in repair and uninstall.
- Add a same-user read-attempt acceptance case in §16.

### 2. Low: on-disk bundle replacement versus process activation is undefined

**Sections:** §17 "Automatic activation and optional drain"; §17 "Sparkle release delivery"; §3 live identity validation; §18 acceptance item "Attempt app-only replacement during a live adapter permit. Defer relaunch…".

The plan requires two things:
- live code-identity validation on every privileged XPC request
- quiescence for every component "replaced or terminated"

The §18 acceptance item, however, implies the app bundle may be replaced on disk while an old GUI adapter keeps running, with only the relaunch deferred.

The plan does not say whether on-disk replacement of a bundle containing a running role counts as replacement. That covers the adapter, and the helper if it is bundled.

**Failure scenario:**
- A Sparkle app-bundle install lands during a 1Password unlock permit.
- The running old adapter's later RPCs (credential reception, permit acknowledgment) are checked against changed on-disk code.
- Depending on actual platform behavior, which I am not asserting, validation may fail. The result is an Unknown outcome that the drain design was meant to prevent.
- Alternatively, validation may pass against code that no longer matches the persisted role identity.

**Minimal correction:**
- Define on-disk replacement of any bundle containing a running role as part of activation, subject to the same quiescence rule. Sparkle's install step is deferred, not just the relaunch.
- Alternatively, add "live validation of a still-running process after on-disk replacement" to the §17 update-continuity feasibility gate, with defined behavior on failure.
- Reword the §18 acceptance item accordingly.

### 3. Low (remote-coding UX): command submissions are not retried at the update boundary

**Sections:** §17 "Automatic activation and optional drain" and "State across restarts"; §8 "Process I/O and terminal outcomes".

UI captures rejected with Update installing are retried automatically. Commands only receive a "retryable" nonzero status.

**Failure scenario:**
- An unattended coding agent issues `remozio sudo -- …` at the brief replacement boundary.
- It gets a nonzero exit and likely treats it as a failure.
- The remote session stalls or takes a wrong branch, for no reason the user chose.

**Minimal correction:**
- Have the frontend transparently wait through the bounded Update installing window, showing status, then resubmit.
- This is safe because nothing was captured, approved, or consumed.
- Resubmission gets fresh capture, a fresh caller-identity check, and a fresh decision.
- The frontend returns the distinct status only if the window is exceeded.

This correction improves UX and needs no consultation.

## Assessed, no finding

- **Scope and keys:** scope classification and key separation for the one-time controls and the update-scheduling purpose.
- **Relay:** resistance to relay compromise.
- **Negotiation:** downgrade and replay protection, including one immutable contract per request and no re-encoding.
- **Floors and rollback:** floor commit timing versus drain, and root anti-rollback independent of the candidate binary. Both are contingent on the §3/§17 placement gate and its consultation path.
- **Restarts:** the restart matrix, and recapture limited to never-consumed requests.
- **Routing:** presence routing, which is delivery-only.
- **Audit:** transaction atomicity and secret exclusions.
- **Deferred items:** the pending idle-interval and retention preferences, and the interim local-command routing state. The last is explicitly gated in §14.

## Remaining verification limits

Several properties depend on scheduled feasibility evidence:
- protected placement and anti-rollback enforcement
- per-generation isolation of receiving keys
- single-biometric credential release
- AX control/effect association for Little Snitch and 1Password
- descriptor-based execution
- Access background authentication
- Android key persistence across biometric changes

**SUBSTANTIVE FINDINGS REMAIN**
