Skip to content

fix(approvals): revoking a session rule needs control, not the lease (r7.3) - #76

Merged
guohai merged 1 commit into
mainfrom
fix/revoke-no-lease
Oct 17, 2026
Merged

guohai merged 1 commit into
mainfrom
fix/revoke-no-lease

Conversation

@guohai

@guohai guohai commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Found in a live test with Astation: revoking an Atem session rule needed the session's lease. The user tapped Revoke without holding control, Atem refused it, and the rule kept auto-allowing. Revoking only takes a permission away, so it shouldn't need control.

Contract §6a, r7.3

  • Any attachment with control can revoke a rule with approval_rule_revoke (session-v1 and chat-v1), with or without the lease.
  • A view-only attachment gets forbidden, and a closed session gets session_closed. A rule that isn't active for that exact process gets stale_target.
  • lease_epoch is optional and never checked. A revoke never takes, renews or moves the lease.
  • acquire is not accepted: the payload stays exactly {rule_id}.
  • Receipts, journaling and duplicate handling are unchanged.
  • runtime.log now records each revoke (session and rule id only, no command text).
  • The shared fixture is renamed approval-rule-revoke-needs-control-not-the-lease.json. Docs and the Astation handoff are updated.

Tests

  • New tests cover a revoke without the lease, view-only refused, an unknown rule or other process, another attachment's lease left untouched, and the next identical command asking again.
  • Full cargo test passed twice (1663 unit tests plus every binary test), and runtime_fixtures_binary passed.
  • Real-agent suite: Claude approvals and Codex chat passed. Codex approvals failed twice with a Codex-side "Internal server error", then passed on rerun.

For Astation: don't acquire before a revoke, and don't put acquire in its payload.

Generated with SMT smt@agora.build

…(r7.3)

A user tapped Revoke in Astation without holding control; Atem refused the
approval_rule_revoke with stale_lease and the rule kept auto-allowing.

approval_rule_revoke (session-v1 and chat-v1) is now admitted from any
attachment with `control`, with or without the lease: view-only is
forbidden, a closed session session_closed, and the rule must be active for
the binding's exact process (else stale_target). The binding's lease_epoch
is optional and never checked (a stale one is not refused); a revoke never
takes, renews or moves the lease. `acquire` is refused: the payload stays
exactly {rule_id}, so a client can't believe a revoke gave it control.
Journaling, receipts and duplicate/request_id_reused semantics are
unchanged. runtime.log gets one line per remote revoke naming the rule and
session, never the command.

Contract §6a r7.2 -> r7.3. The shared fixture is renamed to
approval-rule-revoke-needs-control-not-the-lease and covers a control
attachment revoking while another holds the lease, view-only, an inactive
rule, another process, acquire, a duplicate and the holder still renewing.
AGENTS.md, agent-chat-host.md, agent-chat-api.md and the Astation handoff
note updated.

🤖 Built with SMT <smt@agora.build>
@guohai
guohai merged commit 71ffc8e into main Oct 17, 2026
1 check passed
@guohai
guohai deleted the fix/revoke-no-lease branch October 17, 2026 18:31
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.

1 participant