Compatibility: Pactmark 0.1.x.
Approval in Pactmark is not free-form text, a boolean column, or a Slack thumbs-up. It is a
record bound to a tenant, a run, an effect, a policy, a grant, a scope and an expiry — created by
atomically consuming a one-use proof.
The flow
Figure 1. The challenge is issued only after the actor is authenticated now, and it is consumed atomically together with the authorisation and credential reservations.What the approver must actually see
A preview that says “the agent wants to send a message” is not a decision aid. Pactmark’sEffectPreview is a schema with required fields:
string
required
The canonical target — not the raw string the model produced.
string
required
What class of operation this is, independent of its arguments.
Digest
required
The digest of what will actually be sent, so the preview cannot drift from the payload.
compensatable | irreversible
required
Note that
not_applicable is not an option here. If you are asking a human, it changes something.string
required
A plain statement of what happens in the world if this is approved.
Digest
Optional, for effects that modify existing state.
Digest
required
The identity of the preview itself, so the decision binds to what was shown.
The one-use proof
1
Authenticate first
The host authenticates the actor at decision time. A session from an hour ago is not the same
thing as authentication now.
2
Issue the challenge
issueDecisionChallenge returns an opaque challengeProof and an expiresAt. Submit it
directly to the decision command.3
Consume atomically
The runtime consumes the proof into a decision together with the authorisation and credential
reservations, in one transaction.
4
Replay returns the same result
The same command replayed returns the same semantic result. Different bindings conflict rather
than silently succeeding.
What approval can never waive
This list is enforced, not advisory. An approval that arrives is still subject to all of it:Authentication
An unauthenticated decision is not a decision.
Tenant isolation
An approver in one tenant cannot approve another tenant’s effect.
Missing grants
Approval does not create capability. A denied tool stays denied.
Schema and budget enforcement
An approved call still has to validate and still has to fit the budget.
Secret boundaries
Approval does not resolve a credential into anything the model can see.
Egress policy
An approved effect still cannot reach an undeclared origin.
Uncertain-effect rules
Approval cannot convert “we don’t know” into “it didn’t happen”.
Role and strength requirements
A wrong-role or weak-authentication decision dispatches nothing.
Human input is a different thing
Do not confusewaiting_for_approval with waiting_for_input:
InputRequested carries a safePrompt — a string intended for a human, already separated from the
model’s raw output.
What a recorded approval proves
It proves that a named authenticated principal, holding a named role, consumed a one-use challenge bound to this exact effect preview at a recorded time. It does not prove that the human understood the preview, that the preview was a good summary, or that the decision was correct. Threat model row TM-05 states this explicitly: human misunderstanding of an accurate preview remains possible.Approval integration guide
Building the operator-facing flow, including what not to render.
Customer refunds use case
A complete worked example with an irreversible effect behind an approval gate.