Skip to content
Open
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
10 changes: 10 additions & 0 deletions dashboard/src/__tests__/policy-tab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ describe("PolicyTab — rendering (Issue #47)", () => {
render(<PolicyTab {...buildProps()} />);
expect(screen.getByText(/Rosa Garcia/)).toBeTruthy();
});

it("renders the accurate server-side enforcement copy", () => {
const { container } = render(<PolicyTab {...buildProps()} />);
const policyCopy = screen.getByText(/Enforced server-side by the agent/i);

expect(policyCopy.textContent).toMatchInlineSnapshot(
`"Enforced server-side by the agent before every payment. See docs/SPENDING-POLICY.md for how."`,
);
expect(container.textContent).not.toMatch(/Soroban smart contracts/i);
});
});

describe("PolicyTab — form interaction (Issue #47)", () => {
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/components/tabs/policy-tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ export function PolicyTab({
Spending Policy for {recipient.name}
</h2>
<p className="text-xs text-slate-500 mb-6">
These limits are enforced by Soroban smart contracts on Stellar. The
agent cannot exceed them.
Enforced server-side by the agent before every payment. See
docs/SPENDING-POLICY.md for how.
</p>
<form
noValidate
Expand Down
25 changes: 25 additions & 0 deletions docs/SPENDING-POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ CareGuard enforces five limits on every payment the agent makes:
| `billMonthlyBudget` | $500 | Monthly cap for bill payments only |
| `approvalThreshold` | $75 | Payments above this amount require explicit caregiver approval |

## Enforcement Model

The spending policy is enforced server-side by the agent before every payment. It is not enforced by a Soroban smart contract.

Before `payForMedication` or `payBill` submits a payment, `checkSpendingPolicy` in `agent/tools.ts` reads the current policy, compares the proposed payment with the daily, monthly, category, and approval-threshold limits, and returns an allow/deny decision. The dashboard Policy tab updates that server-side policy; it does not create an on-chain rule.

If a payment is denied, the agent should stop before submitting the payment request. If a payment needs approval, the agent should hold the payment until the caregiver approves it through the normal approval flow.

## Threat Model

This model protects against normal agent workflows accidentally or intentionally exceeding configured caregiver limits. It assumes the CareGuard server and its persisted policy/transaction data are trusted inputs to the payment decision.

It does not protect against:

- direct database or filesystem writes that alter the stored policy or transaction history
- a compromised server process or deployment environment
- direct use of the underlying wallet outside the CareGuard agent
- a future service that submits payments without calling `checkSpendingPolicy`

Any future on-chain spending-policy contract should be tracked as a separate design and implementation issue.

## Daily Limit and Timezones

The daily limit resets at **local midnight** in the caregiver's timezone, not UTC midnight.
Expand Down Expand Up @@ -47,3 +68,7 @@ Limits are validated client-side and server-side:
- `dailyLimit` must not exceed `monthlyLimit`
- `medicationMonthlyBudget + billMonthlyBudget` must not exceed `monthlyLimit`
- `approvalThreshold` must not exceed the smallest of `dailyLimit`, `medicationMonthlyBudget`, and `billMonthlyBudget`

## Limits of Enforcement

Policy checks are only as accurate as the stored policy and transaction history available to the agent. Restart-safe persistence and transaction logging are therefore part of the enforcement boundary, but they are still application-level controls rather than blockchain-level controls.