Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions docs/CLAIMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -549,12 +549,11 @@ Evidence

Scope, stated plainly:

- **Not merged or deployed.** The change is in the working tree of branch `feat/approval-required-everywhere`, not committed, on 2026-09-30.
- **Production needs policy approvals.** Production runs the version most recently approved for each name (2.43). After a deploy, and until `github-pr-read` 1.1.0, `hubspot-deal-read` 1.0.0, `hubspot-deal-update` 1.1.0 and `slack-post-message` 1.1.0 are approved through maker checker, the versions in effect fail to load, so GitHub reads, HubSpot reads and updates and Slack posts are refused. Nothing runs without a person in the meantime. CI's `verify-policy-approvals` job also fails until every new policy file has an approval record.
- **In production since 2026-09-30.** Merged (PR #87, `e18ddae`) and deployed on 2026-09-30, after all 13 new policy versions were approved through maker checker (proposed by `charak1987`, approved by `reviewer-charak1987`, two credentials held by one person). Checked after the deploy: `hubspot:deal-fetch` reports `hubspot-deal-read` 1.0.0 in effect, `/ready` is READY, `/execute` without a key returns `401`. Production runs the version most recently approved for each name (2.43).
- **An approval covers the action and the resource, not every parameter.** A Slack approval does not fix the message text; a HubSpot approval does not fix the new stage or amount. Payment, expense and refund approvals do cover the amount.
- **Superseded versions stay in `policies/` as history** (for example `github-pr-read` 1.0.0, `hubspot-deal-update` 1.0.0, `slack-post-message` 1.0.0, `customer-refund` 1.0.0 and 1.1.0, `vendor-payment` 2.0.0). Each fails to load.
- **No automatic path.** An action cannot be authorized by server checks alone. That is the rule, not a missing feature (G-80).
- **Who approves is still limited to the trusted approver list** (2.42, 2.45). Today that is one approver held by the operator, so in practice one person approves every agent action.
- **Who approves is still limited to the trusted approver list** (2.42, 2.45). Today that is one approver, `manager-charak1987`, held by the operator (key `manager-charak1987-key-2` since 2026-09-30, added through maker checker), so in practice one person approves every agent action.
- Holds for actions routed through Parmana (3.1).

Verification
Expand Down
11 changes: 5 additions & 6 deletions docs/CURRENT-STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,16 @@ deployment. The route by route mapping is `docs/site/sdks/api-coverage.mdx`.

Merged to `main` and deployed to production on 2026-09-27 (PR #46, merge `4eebd5f`).

**Every action needs a signed human approval, reads included (2026-09-30, not
committed, branch `feat/approval-required-everywhere`, `docs/CLAIMS.md` 2.47,
G-80).** `PolicyValidator` refuses any policy whose approve rule does not
**Every action needs a signed human approval, reads included (2026-09-30,
merged in PR #87 and deployed, `docs/CLAIMS.md` 2.47, G-80).** `PolicyValidator` refuses any policy whose approve rule does not
require an `approvalSignals` fact with `is_true` at its top level, on load and
on proposal, and `RuntimeEngine` refuses an approval with no approval verifier
configured. New versions: `github-pr-read` 1.1.0, `hubspot-deal-read` 1.0.0
(new, for `hubspot:deal-fetch`), `hubspot-deal-update` 1.1.0,
`slack-post-message` 1.1.0, and approval backed versions of every reference
policy. In production, GitHub reads, HubSpot and Slack are refused until those
versions are approved through maker checker. The rest of this section
describes the state before that change.
policy. All of them were approved in production through maker checker on
2026-09-30 and are in effect. The rest of this section describes the state
before that change.

- A policy declares in `approvalSignals` which of its signals need a
person's signed approval, and where the resource (a `parameters` path or
Expand Down
26 changes: 13 additions & 13 deletions docs/REMAINING-WORK.md

Large diffs are not rendered by default.

15 changes: 9 additions & 6 deletions docs/VERIFICATION-GAPS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1228,9 +1228,11 @@ every policy under `policies/`, `CANONICAL_CAPABILITY_POLICY_BINDINGS`, `PolicyV
`createApplication` and `pending-policy-changes.ts`.

**G-80. Most actions were authorized with no human approval at all. FOUND 2026-09-30, `blocks-pilot`
against the stated rule. FIXED in the working tree the same day on branch
`feat/approval-required-everywhere`, not committed; takes effect in production when the change is
deployed and the new policy versions are approved.**
against the stated rule. FIXED the same day (PR #87, merge `e18ddae`). CLOSED in production
2026-09-30: all 13 new policy versions approved through maker checker (proposed by `charak1987`,
approved by `reviewer-charak1987`, two credentials held by one person), then merged and deployed.
After the deploy `hubspot:deal-fetch` reported `hubspot-deal-read` 1.0.0 in effect, `/ready` was
READY and `/execute` without a key returned `401`.**
Human approval was a property of each policy, not of the product. Only three policies required it:
`customer-refund` 1.2.0, `github-pr-approval` 1.1.0 and `llm-tool-call` 1.1.0. Every other policy
approved on facts the agent declares or on nothing:
Expand Down Expand Up @@ -1279,9 +1281,10 @@ approved on facts the agent declares or on nothing:
sends a refund with that manager's signed approval: 14 of 14 passed on 2026-09-30. The Python SDK
suite (135 tests, including three that start a real server) passed.
- **Not done, stated plainly:**
- **Production.** Until the new versions are approved through maker checker, the versions in effect
for GitHub reads, HubSpot and Slack fail to load, so those actions are refused (fails closed). CI's
`verify-policy-approvals` job fails until every new policy file has an approval record (G-79).
- **Production: done 2026-09-30.** The 13 versions are approved and deployed. `connector-capability`
1.1.0 was approved twice: the first proposal, read with Windows PowerShell 5.1 `Get-Content -Raw`,
changed an em dash in the description, so CI `verify-policy-approvals` (G-79) found the approved
hash different from the file and refused the merge until the file's exact content was approved.
- **An approval covers the action and the resource, not every parameter.** A Slack approval does not
fix the text; a HubSpot approval does not fix the new stage or amount. Binding those would need the
approval scope to carry them.
Expand Down
2 changes: 1 addition & 1 deletion docs/connectors/PAYTM_CONNECTOR.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> **Update (2026-09-27):** `paytm:refund` is now bound to `customer-refund` 1.1.0: automatic up to 10000, a verified signed manager approval above 10000 and up to 100000, refused above 100000. This page describes the connector as built with 1.0.0. See `docs/site/concepts/human-approval.mdx` and `docs/CLAIMS.md` 2.42.

> **Update (2026-09-28, G-75):** the binding now names `customer-refund` 1.2.0: every refund needs a verified signed manager approval, because `refundEligible` and `fraudCheckPassed` are declared by the agent and nothing checks them. 0 or less and above 100000 are refused. It takes effect in production when 1.2.0 is approved through maker checker; until then 1.1.0 applies. See `docs/CLAIMS.md` 2.44.
> **Update (2026-09-28, G-75):** the binding now names `customer-refund` 1.2.0: every refund needs a verified signed manager approval, because `refundEligible` and `fraudCheckPassed` are declared by the agent and nothing checks them. 0 or less and above 100000 are refused. Approved in production through maker checker on 2026-09-28 and in effect since: no refund of any amount runs without a signed manager approval. See `docs/CLAIMS.md` 2.44.

> **Update (2026-09-28):** the connector service's other endpoint, `/agent/refunds`, called Paytm itself after Parmana had already released the refund through this connector, so an approved refund could be paid twice (G-70). Fixed and deployed in `parmana-paytm-agent` PR #6: Parmana, through this connector, is the only path to Paytm. Also found and fixed the same day (G-71): an optional `refundReference` makes the refId per refund instead of per transaction, and `refundReason` now reaches Paytm; see "Idempotency and replay protection".

Expand Down
41 changes: 35 additions & 6 deletions docs/site/agents/integrate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,41 @@ background to interpret. If your situation is not covered, **stop and ask the op

## Inputs you need before you start

| Input | Where it comes from | How to check it |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `PARMANA_URL` | The operator. The base URL of the Parmana server, without a trailing slash. | It must start with `https://`, except for a local server, which uses `http://localhost:3000`. |
| `PARMANA_API_KEY` | The operator. A secret string issued for you. | It is non empty. Never print it, log it or put it in a URL. |
| `APPROVAL_SIGNALS` | The operator. The signals that need a person's signed approval for this action, for example `managerApproved`, or none. | Ask. If the operator says none, the action never needs one. |
| `ACTION` | The operator. The capability name, for example `paytm:refund`. | Step 2 checks your key may use it. |
| Input | Where it comes from | How to check it |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| `PARMANA_URL` | The operator. The base URL of the Parmana server, without a trailing slash. | It must start with `https://`, except for a local server, which uses `http://localhost:3000`. |
| `PARMANA_API_KEY` | The operator. A secret string issued for you. | It is non empty. Never print it, log it or put it in a URL. |
| `APPROVAL_SIGNALS` | The table in [Every action needs a signed approval](#every-action-needs-a-signed-approval), or the operator for an action not in it. | It is never empty. Every action needs one, reads included. If the operator says none, stop: that is not possible on a current server. |
| `ACTION` | The operator. The capability name, for example `paytm:refund`. | Step 2 checks your key may use it. |

Do not ask for a policy version. Step 3 reads the version in effect from the server, because an approved new version
replaces the old one at once and a request naming an old version is refused.

## Every action needs a signed approval

No action is authorized without a signed approval from a trusted person, for that action and that resource. This holds
for reads as well as writes, and for every policy: a server refuses to load a policy that could approve without one.
So plan for it from the start: **your first request for an action on a new resource will be refused** until a person
signs an approval for it.

For the actions with a connector, the approval signal and the resource it names are:

| `ACTION` | Policy in effect (step 3 confirms) | Approval signal | Resource the approval names | Other signals the policy reads |
| --------------------- | ---------------------------------- | -------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `paytm:refund` | `customer-refund` 1.2.0 | `managerApproved` | `intent.parameters.orderId`, up to `intent.parameters.amount` | `refundEligible`, `fraudCheckPassed`, `refundAmount` (equal to `intent.parameters.amount`) |
| `github:pr-merge` | `github-pr-approval` 1.1.0 | `mergeApproved` | `intent.target` | `branchProtected`, `repositoryAuthorized`, `requiredReviewsCompleted`, `riskScore`, `statusChecksPassed` |
| `github:pr-fetch` | `github-pr-read` 1.1.0 | `readApproved` | `intent.target` | none |
| `hubspot:deal-update` | `hubspot-deal-update` 1.1.0 | `dealUpdateApproved` | `intent.parameters.dealId` | `dealStageChangeRequested`, `dealStageTransitionAllowed`; `proposedDealStage` and `proposedAmount` equal to `intent.parameters.dealstage` and `intent.parameters.amount` |
| `hubspot:deal-fetch` | `hubspot-deal-read` 1.0.0 | `readApproved` | `intent.parameters.dealId` | none |
| `slack:post-message` | `slack-post-message` 1.1.0 | `postApproved` | `intent.target` (the channel id) | `channelAuthorized`, `contentApproved`; `channelId` equal to `intent.target` |

For any other action, the operator gives you the policy's `approvalSignals` entry: the signal name, and the request path
of the resource (and of the amount, if there is one). The source is `policies/<name>/<version>/policy.json` on that
server. The server does not publish it through the API today.

An approval covers the action and the resource, and the amount where the table names one. It does not fix other
parameters: a Slack approval does not fix the message text, and a HubSpot approval does not fix the new stage.

Every request below carries this header: `Authorization: Bearer <PARMANA_API_KEY>`.

## Step 1: check the server is reachable and safe
Expand Down Expand Up @@ -185,6 +210,10 @@ with the current time.
}
```

Sent as it is, this example is refused with `403 POLICY_DENIED`, because `managerApproved` is `false` and every refund
needs a signed manager approval. That refusal is the normal first step: it is what tells a person to approve. The
version with the approval is below.

**Never set a signal to `true` unless you have checked it is true.** A policy trusts the signals you send for some
facts, so a false `true` produces an authorization that should not exist.

Expand Down
Loading
Loading