Veefore docs

ADR 0001: Scope boundaries

Veefore is identity, authority, policy and enforcement. The adjacent products it deliberately is not, and the build gate that keeps it that way.

#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 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.

Identity, authority, policy and enforcement for autonomous AI agents.