> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parmanasystems.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Approved what, exactly? Binding approval to content

A refund agent asks for ₹500 back on a cancelled order. The agent's request says "refund amount: ₹500". The store
manager reads it and signs an approval. Every check passes.

Then the action that actually reaches the payment system says ₹50,000.

Nobody approved ₹50,000. But if the system checked only a label the agent wrote, not the request itself, the
approval for ₹500 just paid out ₹50,000. This is an old bug with a clumsy name: time of check to
time of use. You check one thing, then you act on another.

## Where the gap hides

With agents, the gap shows up in at least four places:

* **The facts and the action disagree.** The agent says "amount 500" in the facts the policy reads, and puts 50,000
  in the parameters that get executed.
* **The content changes after approval.** The decision is made on one payload and a different one is sent under the
  same transaction id.
* **The rules change after approval.** The policy is edited between the decision and the release.
* **The world changes after approval.** The approval expires, the approver's key is revoked, the deal moves to
  another stage, the agent's authority is withdrawn.

An approval that names only an id cannot catch any of these. It has to be bound to the content, the rules and the
facts it rested on, and those bindings have to be re-checked at the moment of release.

## How Parmana binds it

**The facts must describe the action.** A policy can bind a fact to a field of the request. The refund policy binds
the refund amount the policy reads to the amount parameter that will be executed. This check runs before the policy
is evaluated, so the ₹500 versus ₹50,000 request above is refused before any rule runs, and the refund service is
never called. An integration test covers that case. The mechanism came out of an external adversarial exercise; 28
regression tests reproduce the exploits it found.

The signed human approval is bound the same way: it counts only for the action and resource it names (and the
amount, where the policy names one), and it is used once. Every agent action needs one, reads included.

**The content is hashed into the signature.** When Parmana signs the execution authorization, it includes a
canonical hash of the executable content: action, target and parameters. At release the gateway recomputes that
hash from the exact content it is about to forward, with the same hashing code the signer used, and refuses on any
mismatch. After that the content is frozen, and the request handed to the connector is copied from the frozen
content, not rebuilt.

**The rules are hashed too.** The authorization carries a hash of the exact policy content. At release the gateway
recomputes the live policy's hash, and it must match both the signed one and the policy's most recent signed checker
approval. A missing hash is a failure, not a skip.

**The facts are re-checked at release.** The default server re-runs some checks just before release: the human
approval (still unexpired, approver key still trusted), the live HubSpot deal state for deal updates, and the Slack
channel against an allowlist.

**What the decision rests on travels with it.** Since 11 October, when a policy names the business system that owns
a fact, each answer is signed into the authorization with a "valid until" time, and so is the agent's authority
grant if the policy requires one. The gateway checks them again before release. If a fact has expired, or the grant
has expired or been revoked, nothing is sent: the request gets a 409 saying the authorization is no longer valid,
the action is recorded as not executed, and the single-use nonce is not consumed.

An external system connected to Parmana receives those facts as signed conditions in its release, and the release
expires no later than the earliest of them. An endpoint that checks them in the same transaction as the action can
decline with "conditions not met", which is recorded as not acted on.

## Honest about timing

In the default server, decision and release happen in the same request, seconds apart. So the release check catches
what changes in those seconds, such as an approval that just expired. It matters most when an authorization is
carried to a separate system and released later. For the same reason an HTTP client cannot provoke a content hash
mismatch through the public API; the tamper case is demonstrated at the library level, in runnable tutorials.

## What it does not do

* **Binding covers only what the policy author binds.** A fact that is not bound to the request, or sourced from a
  business system, is the caller's word. In the refund policy, refund eligibility and the fraud check are still
  declared by the agent; they can only cause a refusal.
* **No real business system is connected as a source yet**, and no shipped policy declares a source or requires a
  grant. The release re-check of facts and grants is deployed and passed live checks with a test policy and a demo
  source, but it does not yet decide any real action.
* **A refusal at release has not been seen in production**, and there is no end to end test of it through the API.
  Each part is tested separately; timing it needs a test hook.
* **"Execute only if still valid" at the target system is the endpoint's job.** Parmana signs the conditions; it
  cannot make an endpoint check them. Built-in connectors (Paytm, HubSpot, GitHub, Slack) get the gateway re-check
  only.
* **A request refused at release leaves its Execution Intent in an errored state** until a person closes it as not
  executed. There is no separate "not released" state.
* **None of this proves the policy is right.** It proves the approved policy, content and facts are the ones that
  were acted on.
* **It covers only actions routed through the gateway.**

## Takeaway

"Approved" is meaningless until you can say what was approved. Bind the facts to the request, hash the content and
the rules into the signature, carry what the decision rested on with an expiry, and look again at the last moment
before acting. The approval for ₹500 should be useless for anything except that ₹500.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.