Skip to content

docs: confirmation contract and ACU cap design for cloud handoff (#4, proposal 6) - #21

Open
hessabi wants to merge 1 commit into
TheOnlyFusionCube:mainfrom
hessabi:docs/cloud-handoff-approval-design
Open

hessabi wants to merge 1 commit into
TheOnlyFusionCube:mainfrom
hessabi:docs/cloud-handoff-approval-design

Conversation

@hessabi

@hessabi hessabi commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

This is the written confirmation contract for proposal 6, promised in #4, posted for pushback before any code. It adds one file, design/cloud-handoff-approval.md, and changes no behavior. It lives under design/ rather than docs/, because docs/ is the Pages site.

What it decides

  • Two-phase handoff. handoff --plan computes the exact payload (task, destination, API version, cap, diff scope) with no network call and writes a 0600 plan file. handoff --approve <plan-id> recomputes everything, refuses on any hash mismatch, and creates at most one session per plan.
  • Approval paths.
    • An interactive TTY prompt, defaulting to No, with a separate prompt for the diff.
    • For noninteractive callers, hash-bound --confirm and --confirm-diff tokens.
    • A bare handoff <task> without a TTY plans, exits 3, and never creates a session.
    • There is no --yes and no env-var bypass.
  • Diff consent. The diff is never attached by default. It needs --include-diff at plan time plus a separate confirmation. The plan shows the file list, byte counts and a secrets warning, and the 100 KB limit is kept.
  • ACU cap. Taken from --max-acu, then DEVIN_COMPANION_MAX_ACU, then a user-level config file set with setup --set-max-acu.
    • There is no default, and only a positive safe integer is accepted.
    • A missing cap stops with setup guidance.
    • The cap is part of the payload hash, so any change needs a fresh plan.
    • It is sent as max_acu_limit on v1 (personal key) and v3 (service key). The doc quotes the spec text and lists its gaps.
  • Honest limits. A threat model, plus a plain statement of what this doesn't prove: an agent with shell access that the host auto-approves can still plan and approve on its own.
  • Test plan. Covers missing and invalid caps, denial, omitted and approved diffs, and both v1 and v3 payloads.

What I need from you (section 9)

  1. Allow the noninteractive --confirm path, or TTY-only approval?
  2. Plan expiry: 15 minutes, single use?
  3. Cap config location: a shared user-level file, or the plugin data dir?
  4. Is breaking the one-shot handoff <task> contract acceptable (exit 3, with --wait and --background moving to --approve)?
  5. Do you know the real at-limit behavior and bounds of max_acu_limit, and do you want a local ceiling?

No implementation starts until you've pushed back on this.

@TheOnlyFusionCube TheOnlyFusionCube left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Design review — comments only; not policy sign-off or approval to implement. This is a strong foundation for #4: plan-before-create, separate diff handling, fail-closed missing cap, v1/v3 coverage, and an explicit threat model align with the issue.

Shared blocking decision with #22: integrity is not human authorization. In sections 3.3–3.5 the plan/JSON output itself supplies both 12-hex confirmation values. An agent with auto-approved shell can read them and complete Path B without a person; AskUserQuestion instructions and a host shell-command approval are not automatically an independent consent boundary. Please stop calling this path an "attestation" or treating its tokens as evidence of human or separate diff consent. A hash binds an operation to a payload, not an approver. TTY is also interactive UX, not proof, since an agent can allocate a PTY.

Recommended direction, pending explicit maintainer choice: retain a portable two-phase plan + operation digest protocol, but have a separate, trusted human-controlled host interaction authorize creation and independently authorize including the diff. A host adapter must actually guarantee a user decision, and either execute the approved action itself or provide a one-use, short-lived, scope-bound authorization the agent cannot mint or self-approve. An auto-allowed shell prompt, a hash echoed by --plan, model-written "yes", and an env/config bypass do not qualify. If a client has no trusted host capability, non-TTY agents and unattended CI may plan but must fail closed before session creation; the user can invoke the approval step separately in a terminal as a documented best-effort manual path. Keep Claude's disable-model-invocation: true and remove broad Bash(node:*) preauthorization, but do not rely on either alone. Specify trust prerequisites and fallback for Claude Code, Codex and other clients.

Requested changes before implementation:

  1. Split payloadSha256 / diffSha256 integrity from an explicit approval source (e.g. trusted_host, manual_tty_unverified); never record "attested" or "human_approved" solely because --confirm was supplied. Bind trusted authorization to the complete operation, destination/account, task/context, cap, actual transmitted diff bytes/scope, expiry and plan ID; require an independent diff grant. Provide a safe way to inspect the exact diff to be sent, with secrets/truncation warnings.
  2. State a normative unattended outcome: no trusted, pre-authorized operation-specific grant => approval_required, zero authenticated create requests. No ambient "CI mode" or blanket persisted permission. If unattended creation is a requirement, propose out-of-band human approval, not another CLI flag.
  3. Make the plan lifetime explicit (15 minutes and single-use seems reasonable), and specify safe expiry/consumption cleanup (the proposed .consumed file must not retain task/context indefinitely), atomic concurrent approval handling, and ambiguous network-timeout handling. Changes to destination, branch, context, diff or cap must invalidate authorization.
  4. No numeric ACU default from #4 is firm. Missing cap => refuse; positive safe integer on both v1 and v3; display the value and bind it into the full digest. Shared XDG/platform user-level config seems preferable to Claude-only state for portability, but env/CLI/config are agent-mutable inputs, not a budget security policy. Do not promise max_acu_limit is a hard dollar ceiling; defer an arbitrary local maximum until Devin's actual bounds and at-limit behavior are established.
  5. The non-TTY one-shot behavior change is justified by #4, but treat exit 3 / approval_required, --wait/--background placement, JSON shapes, migration docs and release notes as deliberate compatibility work. Add tests for agent self-approval via auto-allowed shell, pseudo-TTY/automated responses, absent host approval, denied diff, and stale/consumed plans.

Decisions requested: (a) trusted host-mediated non-TTY authorization with plan-only fallback vs deliberately weaker hash-only acknowledgments; (b) whether independently pre-authorized unattended creation is supported initially; (c) 15-minute expiry and shared user-level cap config; (d) one-shot compatibility break; (e) defer a local cap ceiling until verified. The preferences above are recommendations, not final authorization. Please cross-link the chosen policy with #22 before implementation.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants