# Remozio plan review, round 1

**Scope:** This review covers only the plan text. I ran no tests, read no source, and browsed nothing. Items the plan already schedules as feasibility gates are not treated as defects:

- privileged installation (§3)
- sudoers compatibility (§8)
- single-biometric credential release (§7)
- descriptor-based exec (§8)
- AX trees and field targeting (§9)
- Android background delivery (§5)

## Findings

### F1: The Mac-side key that receives credentials is not placed inside a same-user trust boundary (High)

**Sections:** §2 ("UI details are assertions from an authenticated, signed adapter"), §3 (the per-user agent owns phone transport and the AX adapters), §5 (pinned identities), §7 ("Release a credential only to the paired adapter").

**Failure scenario:**
1. Commands are protected because the root service verifies the phone's signature.
2. UI requests and credential release are different. Both end inside the per-user agent, which runs in the same user domain as the in-scope malicious unprivileged caller.
3. The plan never says where the agent's pinned transport or adapter signing key is stored, or what stops a same-user process from reading it. Examples would be a user-writable file, the default keychain ACL, or a user-writable LaunchAgent plist that points at a substitute binary.
4. A process holding that key can impersonate the Mac to the phone. It can send a realistic "1Password unlock" request, and after one normal biometric approval it receives the vault password.
5. None of the §10 acceptance tests covers this case.

**Minimal correction:**
- Generate the adapter/transport identity as a non-exportable key, Secure Enclave-backed where possible, with an access-group ACL that admits only the Remozio team-signed agent.
- Or have the root service hold the key and sign UI requests after checking the agent's audit token and code signature.
- State the residual risk that remains if the agent binary itself is subverted.
- Add these acceptance tests:
  - A same-user process cannot read or use the key.
  - A same-user process cannot originate a UI request.
  - A same-user process cannot receive a credential package.

**UX impact:** None.

### F2: Command approvals depend on a GUI login session, which is unstated (Medium-High)

**Sections:** §3 (the per-user agent carries phone transport; the service has "no general network listener"), §2 (OS login is out of scope), §10 (the "Mac sleep/logout/reboot" test).

**Failure scenario:**
1. A remote coding agent runs over SSH, or on a Mac that rebooted after an update and has no GUI login.
2. No Aqua-session agent exists, so no transport to the phone exists.
3. `remozio sudo` waits until expiry, and the user sees a stall with no explanation.
4. Excluding OS-login and FileVault *interception* is not the same as excluding command approval without a GUI session. The plan does not say which behavior is intended.

**Minimal correction:** Specify the session model for the command path and choose one option:
- **(a)** A background-capable unprivileged transport component, such as a LaunchAgent that can run outside Aqua or a dedicated-user daemon. The UI adapters stay GUI-only.
- **(b)** Document that command approvals require a GUI login. The frontend then fails fast with a distinct status and a clear message.

**UX impact:** ⚠️ Option (b) reduces remote functionality and **requires user consultation**. Option (a) has no UX cost.

### F3: The phone does not show the verified caller identity (Medium)

**Sections:** §3 and §8 capture trusted caller identity and "distinguish verified process identity from caller-provided rationale." However, the §8 display list covers only executable, argv, working directory, target user, and environment changes.

**Failure scenario:**
1. A malicious same-user process submits a request identical to one the user expects from the coding agent. It could also submit a plausible variant in a different directory.
2. Both requests appear in the inbox, and nothing on screen distinguishes them.
3. The user approves the attacker's request.

**Minimal correction:**
- Include verified requester identity in the signed payload and in a compact detail row:
  - executable path and team ID
  - PID and parent chain
  - TTY or SSH session
  - Mac user
- Label caller-supplied rationale as unverified.

**UX impact:** None. This is added information, not an added step.

### F4: "Deny needs no biometric" conflicts with every signing-key use requiring biometrics (Medium)

**Sections:** §1 ("Deny needs no biometric"), §6 (denial is a separate signed purpose), §7 (the signing key requires BIOMETRIC_STRONG for every use).

**Failure scenario:** One of two things happens:
- Implementers make denial require a biometric, which silently worsens UX.
- Denial is unauthenticated, and no rule says who may cause a denied state.

**Minimal correction:**
- Denials and status messages are authenticated by the phone's non-biometric transport identity over the E2E channel, not by the approval key.
- The service accepts a denial only through that authenticated path.
- Document that a forged denial can only cause denial of service.
- Apply the same rule to cancellation authority: only the originating caller or an authenticated phone may cancel.

**UX impact:** None. This preserves the stated UX.

### F5: No remote recovery or re-enrollment path for a remote-first product (Medium)

**Sections:** §5 ("local admin can revoke a lost phone and enroll a replacement"; enrollment uses QR plus a human-verifiable code; a biometric enrollment change invalidates keys), §2 ("Do not require physical proximity after enrollment").

**Failure scenario:**
1. A user away from the Mac adds a fingerprint, or loses the phone.
2. All per-Mac keys become invalid, and the enrolled credentials become unusable.
3. It is undefined whether "local administrator authorization" includes an admin over SSH or screen sharing.
4. The approval workflow may therefore be unrecoverable until the user is physically back at the Mac.

**Minimal correction:**
- Explicitly allow enrollment and revocation from any authenticated admin session. Example: `sudo remozio enroll` renders a terminal QR code plus a verification code over SSH.
- Define re-entry of enrolled UI credentials after key invalidation.
- Network messages alone still cannot enroll a device.

**UX impact:** This improves UX.

### F6: Caller lifetime conflicts with coding-tool command timeouts (Medium)

**Sections:** §8 ("Bind request to caller/session lifetime… default to normal attached CLI lifetime"), §5 (5-minute expiry), §10 stage 4.

**Failure scenario:**
1. Many agent harnesses kill tool calls after a fixed timeout.
2. The frontend dies while the user is still reading or authenticating.
3. The request is cancelled, and the approval comes back as stale.
4. From the user's side this looks like a silent failure, and they must re-trigger the command.
5. The effective response window becomes the agent's timeout, not the 5 minutes the plan intends.

**Minimal correction:**
- Stage 4 must measure the timeout behavior of each targeted caller integration.
- Document or configure longer tool timeouts.
- Show a distinct "requester exited" state on the phone.
- If a detached or resumable mode is desired, list it as a pending decision.

**UX impact:** Do **not** "fix" this by shortening the approval window. A detached-by-default mode changes execution semantics and needs **user consultation**.

### F7: The monotonic deadline's behavior across Mac sleep is unspecified (Low)

**Sections:** §6 ("A trusted monotonic deadline… Clock skew must not extend authority").

**Failure scenario:** If the chosen clock stops during system sleep, a request created before a long sleep keeps its authority well past its 5-minute intended lifetime. This contradicts the stated invariant.

**Minimal correction:**
- Require a clock that keeps counting during sleep.
- Or require that a request expires at the earlier of its wall-clock deadline and its monotonic deadline.
- Add this to the Mac sleep acceptance test.

**UX impact:** None.

### F8: It is not stated that the phone computes the digest it signs (Low)

**Sections:** §6 (the envelope carries an "immutable payload digest"; "Android… signs its canonical digest").

**Failure scenario:** A relay or agent sends a payload together with a mismatched digest. The phone displays the payload but signs the supplied digest. Service-side verification would catch this only if the service recomputes the digest from its own stored request. For UI requests, the owner of that record is itself unclear (see F1).

**Minimal correction:**
- State that the phone recomputes the digest from exactly the canonical bytes it parsed and rendered.
- State that the phone rejects any mismatch.
- Add a cross-language test vector for this case.

**UX impact:** None.

## What was assessed without findings

- License handling for the Flux design (§4)
- Replay, consumption, and the uncertain-outcome state machine (§6)
- Argv escaping and raw-byte preservation (§8)
- No-shell execution and redirection semantics (§8)
- Separation of UI revalidation from OCR (§9)
- Little Snitch scope binding (§9)
- 1Password unlock-versus-access semantics (§9)
- Scheduling of all adapters (§10)
- The UX-consultation rule (§1)

These are internally consistent, and the known limits of each are already stated or gated.

**Implementation verification limits:** The feasibility gates remain unproven. These include:
- CryptoObject credential release
- AX control stability and atomicity
- secure-field targeting
- Android delivery under Doze
- privileged-service installation on macOS 14+
- sudoers policy enforcement

**SUBSTANTIVE FINDINGS REMAIN**
