Skip to content

Unify approved and delegated effect execution; fail closed on missing executors #127

Description

@George-RD

Why

The current standing-rule mediation can turn ApprovalRequired into Allow and then call the generic action dispatcher. A catalogued action without a registered handler returns a successful stub response. This is not safe for reusable delegation:

  • email.create_draft is deliberately absent from the allowed-action handler registry because the working Gmail write lives in the separate post-approval path;
  • a standing rule for email.create_draft can therefore reserve/finalize budget and report success without creating a Gmail draft;
  • the owner-facing proposal in PR Superseded: prototype responsibility proposal copy #125 can promise less interruption even though the executable effect path is not connected;
  • future actions could repeat the same false-success pattern.

Approval source must not choose a different implementation. Per-instance approval and reusable delegated authority must converge on the same kernel-owned effect executor and immutable request semantics.

Scope

1. Effect executor registry

Introduce a catalog/registry-owned effect executor contract for effectful actions. A delegatable action must have exactly one executable adapter that accepts the kernel-built action request/resolved context.

The registry must distinguish:

  • catalogued but intentionally unavailable actions;
  • actions handled on the ordinary allowed path;
  • actions requiring per-instance approval or standing-rule mediation before the same executor runs;
  • internal/non-effect actions.

A missing executor MUST be a fail-closed typed error. It must never return stub: true as successful execution for an effectful or delegatable action.

2. Shared Gmail draft executor

Extract the existing approved Gmail draft write into one kernel-owned email.create_draft executor. Both paths must call it:

  1. exact digest-bound per-instance approval;
  2. a future scope-matched, budget-reserved standing-rule admission.

The executor must re-use the existing immutable payload/target re-derivation, recipient/thread/account checks, connector breaker, delivery-unknown fencing, audit, and idempotency behavior. The standing-rule path must not reconstruct those semantics from a shell payload.

3. Reservation correctness

  • No executor available: cancel any pre-effect standing-rule reservation.
  • Confirmed pre-effect failure: cancel reservation.
  • Confirmed success: finalize once.
  • Delivery unknown after an external write may have landed: retain/finalize and fence retry, matching the existing Gmail contract.
  • A successful result must mean the real effect executor ran or an explicitly non-effect action completed; never merely that an ID was known.

4. Delegation readiness

Action proposal/review must be able to ask the registry whether an action is execution-backed for reusable delegation. email.create_draft is not marked ready until the shared executor is wired.

TDD sequence

  1. Characterize the current failure with a test showing that standing-rule mediation for email.create_draft reaches the missing-handler stub and consumes budget without a Gmail write.
  2. Add a contract test that any effectful action missing an executor fails before reservation finalization.
  3. Extract the Gmail draft executor while preserving all current per-instance approval tests.
  4. Add tests proving per-instance approval and delegated admission call the same executor with the same target/payload semantics.
  5. Add delivery-unknown and audit-failure tests on both admission sources.

Invariants

  • The shell still sends intents; it never selects the executor or trusted target.
  • gate() and current policy precedence remain unchanged.
  • email.send remains denied.
  • Standing rules remain composition inputs; they do not become an alternate connector API.
  • No connector write happens without durable gate/audit evidence.

Done when

  • dispatch_allowed_action cannot report a successful stub for an effectful/delegatable action.
  • email.create_draft has one real executor used by both approval sources.
  • A standing-rule reservation is finalized only when the executor ran or the write outcome is truthfully delivery-unknown.
  • All existing digest-bound approval and Gmail mutation tests remain green.
  • The action descriptor from Define the protocol-neutral responsibility contract above standing rules #126 can deterministically report executor readiness.

Relationship

Parent: #123.

Requires: #126.

Blocks the scoped matching and Gmail end-to-end proof slices.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions