---
title: 'ADR 0001: Scope boundaries'
description: Veefore is identity, authority, policy and enforcement. The adjacent products it deliberately is not, and the build gate that keeps it that way.
label: '0001 Scope boundaries'
---

## Context

An agent authorization layer sits next to several much larger product
categories. If an agent can be authorized to issue a refund, it is a short step
to holding the balance, a shorter step to processing the payment, and a shorter
one still to recording the transaction.

Each step is individually reasonable and collectively fatal. A product that is
an authorization layer *and* a wallet *and* a ledger is not better at either; it
is a different, larger, more regulated product with a confused security model —
and it inherits custody obligations that have nothing to do with deciding
whether an agent may act.

The pressure is real: "we already evaluate the amount, we may as well record the
transaction" is a sentence somebody will say.

## Decision

Veefore is identity, authority, policy and enforcement infrastructure. The
following do not exist, as code, schema, routes, services or UI:

wallet · marketplace · agent commerce · payment processing · settlement ·
payouts · disbursement · financial transaction ledger · smart contracts ·
merchant acquiring · agent purchasing · marketplace reviews

`amount` exists in exactly two roles: a **policy input** (a rule tests it, a
delegation caps it, a risk signal compares it against history) and **recorded
decision context** (the action record keeps what the agent asked to do).

The list is published, unauthenticated, at `GET /v1/meta/info` under
`out_of_scope`, so an integrator can check it against the deployment they are
talking to rather than against a document.

And it is **enforced in CI**. `npm run scope:audit` is a stage of
`npm run verify`.

## Alternatives

**Document the boundary and rely on review.** This is what most products do, and
it fails on a long enough timeline. A reviewer who has not read the boundary
document approves a `settlements` table because the PR it arrived in was about
something else.

**Enforce only by naming.** A keyword scan catches `WalletService` and
`/v1/payments`. It does not catch a wallet implemented without the word, which
is exactly what someone would build after the first rejection.

**Allow it behind a feature flag.** A flag means the code exists, the schema
exists, and the tests exist. The scope boundary would then be a runtime setting,
and runtime settings get turned on.

**Keep it out and allow amounts nowhere.** Then a policy cannot express "refunds
above ₹1,000 need a human", which is the single most useful rule anyone writes.
The product becomes unable to do its job in order to prove a point.

## Consequences

**The audit has two independent checks**, because naming alone is evadable.

*Naming:* table names, service classes, route paths, identifiers, nav labels.
Comments and prose that state the boundary are allowed — a negated mention is
documentation, not an implementation — which is how
[the scope page](/scope) can exist.

*Shape:* no migration may declare `balance`, `available_balance`,
`ledger_balance` or `funds`. And any table with an `amount` column must be on an
explicit allow-list of policy and decision tables — `actions`, `approvals`,
`delegations`, `delegation_constraints`, `policy_versions`,
`policy_test_cases`, `risk_events`, plus Veefore's own `plans`,
`subscriptions`, `usage_records`.

An amount column on a table that is not a policy or decision table fails the
build **with that table named**. A wallet could be written without the word
"wallet"; it could not be written without somewhere to put a balance.

**Customers build the excluded parts themselves**, and register them as tools.
That is the intended shape: your refund service is a tool, your ledger is yours,
your payment provider is yours. Veefore decides whether the agent may call them
and records what it decided.

**The division of labour has to be explained repeatedly**, because "it evaluates
amounts but moves no money" is a distinction people have to be walked through
once. The published exclusion list exists partly to shorten that conversation.

**The audit occasionally flags something legitimate.** The allow-list of
amount-bearing tables has to be extended when a genuine policy or decision table
needs one. That is a deliberate friction point — extending it is a decision
someone makes explicitly rather than a column someone adds in passing.

## Related

- [What Veefore is not](/scope)
- [Data model](/architecture/data-model)
- [Testing strategy](/architecture/testing-strategy)
