Governance · read-only by construction

Policy is code.
Not a prompt.

SQAI treats the model as what it is: an untrusted client. Allow-lists are fixed in code when the tool is constructed, checked in-process before anything executes, and absent from the model's protocol. There is nothing to talk the system out of.

4,574capabilities the contract exposes — every one read-only
6grants in one app's policy
1typed request that runs

IIThe narrowing, in full

Three layers. Each may only remove.

Every answer passes the same containment. A hash-pinned contract defines what exists. Your policy narrows it to what is allowed. One typed request must fit inside both.

  1. 01

    The contract

    4,778 capabilities in the pinned runtime; 4,574 exposed to agents, every one read-only. The other 204 are excluded outright — for a model, they do not exist.

  2. 02

    Your policy

    Three allow-lists — allowedSources, allowedFields per source, allowedFunctions — fixed at createSQAI() time. Functions default to "all-readonly".

  3. 03

    One request

    A typed plan, validated against the contract, then checked against policy in-process — before execution, never after.

Layer 01 · The contract4,574 exposed · read-only
Layer 02 · Your policy6 grants
allowedSourcesorders
allowedFieldsregionrevenueunit_price
allowedFunctionsstats.medianfinance.npv
Layer 03 · One request1 typed plan

QuerySpec v1 · median(revenue) by region · policy ✓

contract_hash sha256:79f1c5a6c7164e7e9e1750e70a5c03292fa87eb52d8148a740c06695924be9a1

Narrow only.

A policy can shrink the surface; nothing can grow it. Name a capability the contract does not expose and createSQAI() throws unsupported_operation at construction — the app fails before an agent ever connects.

And the model's tool input carries no allowed* field. The policy is not in the protocol, so there is nothing for a prompt — or an injection — to widen.

IIIThe policy, in code

Written once. Checked every time.

Most governance tooling sits beside the data path and observes it. SQAI's policy sits inside the path: three allow-lists in the constructor, enforced in-process before every execution.

const sqai = createSQAI({
  sources: { orders },

  // policy — fixed here, invisible to the model
  allowedSources: ['orders'],
  allowedFields: {
    orders: ['region', 'revenue', 'unit_price'],
  },
  // functions default: 'all-readonly'
  allowedFunctions: [
    'stats.median', 'finance.npv',
  ],
});
allowedSources
The registered sources a plan may name. Anything else returns policy_denied_source.
allowedFields
Columns, per source. A plan that touches any other column returns policy_denied_field.
allowedFunctions
The read-only functions a plan may call — default "all-readonly". Anything outside returns policy_denied_function.
tool input
Carries no allowed* field. The model never sees the policy, so it can never send a wider one.

The denial ledger

Denials are data, not exceptions. Each carries a stable code an agent can read — and none is retryable, so a loop cannot wear the policy down.

at construction

unsupported_operation

The policy names a capability the contract does not expose. Construction throws; the app fails before any agent connects.

at request time

policy_denied_source

The plan names a source outside allowedSources.

policy_denied_field

The plan touches a column outside that source's allowedFields.

policy_denied_function

The plan calls a function outside allowedFunctions.

source: "sqai"every policy denial arrives as a structured, non-retryable result. The tools never throw.

IVCustody

Results are held, not kept.

A full result set never lands in the model's context. It is parked in a governed store and referenced by id; the model receives a declared sample.

The result store

Governed store · TTL 15 min

result_id
16 random bytes, base64url. Unguessable, never sequential.
authorization
Tenant-bound. A wrong tenant reads result_not_found — the store never confirms existence.
ttl
15 minutes. Then the entry is gone.
capacity
At most 256 results — 64 MB total, 16 MB per tenant.

The store holds the result. The model reads a sample and says so.

Model-context caps

defaultLimit100row limit applied when a plan does not set one
maxExecutionRows1,000hard ceiling on rows any execution returns
maxRowsToModel25the most rows a model context ever receives
maxCellsToModel250the most cells a model context ever receives
maxBytesToModel32,000the most bytes of result data a model ever receives

Truncation is always declared in the result. Partial rows are never shown — a row arrives whole or not at all.

The audit angle

17%of organizations can reconstruct an agent's full tool-call sequence after the fact

GDPR Article 30 and SOC 2 CC7.2 expect exactly those records.

Every SQAI answer already carries its own reconstruction:

plan_hash · invocation_hash · computation_hash · contract_hash

Replay is a lookup, not an investigation. How replay works

VIQuestions

Governance, asked directly

Can the model widen its own access?

No. Policy is fixed at createSQAI() time and checked in-process before execution. The model's tool input carries no allowed* field, so there is nothing in the protocol to widen — a request outside policy returns a structured policy_denied result.

Is read-only a flag that something could bypass?

It is not a flag. The exposed contract holds 4,574 read-only capabilities; a write path is absent by construction, not disabled. Prompt injection can change what a model asks for — it cannot add capabilities to a pinned contract.

What records exist for a GDPR Article 30 or SOC 2 CC7.2 review?

Every result carries plan_hash, invocation_hash, computation_hash and contract_hash. The exact computation can be replayed and verified against those hashes long after the fact.

Where does result data live after a query?

In a tenant-authorized result store: ids are 16 random bytes, entries expire after 15 minutes, and the store is capped at 64 MB total and 16 MB per tenant. The model context receives at most 25 rows, 250 cells and 32,000 bytes — truncation always declared.

VIINext

Govern the answer.

Bring a schema and a compliance question. We will show you the policy that answers it.