EDR 0016 Status: accepted Implementation: none
Compile a written delegation, and have the human sign the compilation
A delegation may be written in plain language. A model compiles it into a structured scope, the grantor reads and signs the compiled form, and enforcement runs entirely on the compilation — never on the sentence.
TL;DR
You can write a delegation as a sentence:
Sam can always update the
settingsfield onaccounts, for sandbox accounts, up to 100 rows.
A model compiles it into the structured scope of EDR-0007. The grantor is then shown the compilation, not their sentence, and signs that. From then on, nothing about enforcement involves a model or the original text: the compiled scope is what is checked, fenced and asserted.
Three rules make this safe:
- The signature is over the compilation. The sentence is provenance, kept in the logbook. The compiled scope is the authority.
- The compiler must refuse to guess. Anything it cannot express as a structured scope is reported as unexpressible, and the grantor either rewrites the sentence or accepts a narrower compilation. A partial compilation is never silently completed.
- An unbounded compilation is refused. A scope with no row fence and no
max_rowson a table above a configured size cannot be signed — the grantor must supply a bound. "Update status on orders" is four million rows if nobody asks.
Context
EDR-0007 gives a sound, enforceable delegation
model — and it is written in JSON with table names, column lists and SQL predicates. That is a fine
format for a machine and a poor one for the person who actually knows what Sam should be allowed to
do. The people best placed to scope a delegation are frequently not the people who will write a
correct fence expression, and the gap between them is where delegations either do not get created
at all or get created too wide.
The obvious fix is to accept the sentence and have a model interpret it at request time, for every request. That puts a model in the authorisation path permanently, and makes every future authorisation decision depend on the model reading the same sentence the same way — which it will not reliably do, and which nobody can audit after the fact.
Compiling once inverts that. The model does the part it is genuinely good at — turning intent into structure — at the moment a human is present to check the result. The output is a static artefact. Every subsequent decision is deterministic, reproducible, and inspectable, and re-running the compiler tomorrow cannot change what Sam is allowed to do today.
This is the same shape as ZFN-26: a model may draft, and a human co-signs what goes out under their name. Here the co-signature is literal.
Decision
The compile step. Given a sentence, a target and a role, the compiler emits a candidate delegation plus a per-clause account of how it got there:
{
"source": "Sam can always update the settings field on accounts, for sandbox accounts, up to 100 rows.",
"compiled": {
"to": "sam@acme.example", "target": "prod-primary", "role": "settings_writer",
"operations": ["update"],
"objects": [ { "schema": "public", "relation": "accounts", "columns": ["settings"] } ],
"fence": ["tier = 'sandbox'"],
"max_rows": 100,
"not_after": "2026-11-30T00:00:00Z",
"issued_at": "…", "roster_epoch": 47 // the grantor signature resolves against this epoch
},
"derivation": [
{ "clause": "update … settings … on accounts", "became": "UPDATE on public.accounts(settings)",
"confidence": "exact", "schema_evidence": "column public.accounts.settings exists" },
{ "clause": "for sandbox accounts", "became": "tier = 'sandbox'",
"confidence": "inferred", "schema_evidence": "public.accounts.tier has values sandbox|trial|production" },
{ "clause": "always", "became": "not_after defaulted to 90 days",
"confidence": "policy_default", "note": "delegations cannot be perpetual" }
],
"unexpressible": []
}
Signed artefacts carry their moment. A compiled delegation records a signed issued_at and
roster_epoch, and its grantor signature resolves against that epoch on exactly the rule a marque's
does (EDR-0030). Without them a long-lived
artefact verified against roster keys has no stated answer to "was this key live when this was
signed" — the question roster_epoch was added to settle for marques and which applies with more
force here, because these artefacts outlive them.
The grantor signs the compilation. The console and CLI show the compiled scope first and the
sentence second, with every inferred clause flagged. marque delegate --from-text prints the
compiled form and requires explicit confirmation of it. The signed payload covers the compilation;
the sentence and the derivation are recorded in the logbook as evidence of intent
(EDR-0012).
"Always" never means perpetual. Every delegation carries not_after
(ZFN-37). A sentence saying "always" compiles to the
deployment's default period with the substitution shown, and the grantor may extend it up to what
policy permits — never beyond.
Refusals are explicit, and are the interesting output. The compiler reports rather than resolves:
| Situation | Result |
|---|---|
| A named table or column does not exist | Refused, naming what was not found |
| A clause has no structured equivalent ("fix obvious typos") | Listed in unexpressible; see EDR-0017 |
| The scope has no row bound on a table above the size threshold | Refused; the grantor must supply one |
| The sentence is ambiguous between two readings | Refused, with both readings shown, rather than a choice made silently |
| The compilation exceeds the grantor's own authority | Refused; attenuation is checked against the grantor, not the sentence |
Attenuation is checked on the compilation. A grantor cannot compile their way to more than they hold. The check in EDR-0007 runs against the compiled scope exactly as if it had been written by hand.
Schema evidence is required for an inference. The compiler is given the target's schema through
the Pilot, read-only. An inference with no schema evidence behind it (tier = 'sandbox' where no
tier column exists) is a refusal, not a guess.
Distinct values are sent only for columns classified non-sensitive. This is the only path by which production data reaches a model whose output becomes a candidate authority artefact, so it is gated rather than merely bounded by cardinality:
- A column must be explicitly classified non-sensitive in target configuration (EDR-0015) before its distinct values are sent.
- Everywhere else the compiler receives names and types only, cannot ground a value inference, and refuses — the grantor writes the predicate themselves.
- A low-cardinality column is not automatically harmless: a status naming a legal hold, or a tier naming one customer, is disclosure. Cardinality is a performance heuristic, not a privacy one.
Compilation quality therefore degrades exactly where the data is sensitive, which is the right place for it to degrade.
Schema evidence is untrusted input, on the same terms as statement text. Column names and values come from a database that operators and customers write to. They are passed as a length-bounded, escaped data block, never in an instruction position, and the compiler's output is constrained rather than its input trusted:
- every literal in an emitted fence conjunct must come from the supplied distinct-value set;
- every named column must exist in the supplied schema, and belong to the target relation (EDR-0007 rule 5);
- each conjunct must satisfy the shape rules in EDR-0041 — it parses standalone as a boolean expression, and carries no comment token, newline, control character or parameter reference. An earlier version of this list said "the predicate must parse under EDR-0007's grammar", which is a statement grammar; no expression subset for a fence exists yet, and that gap is issue #25.
A compilation failing any of those is refused. What those constraints actually buy is narrower than
it first reads: they make a compilation ungroundable in fabricated evidence — a literal it did not
receive, a column that does not exist, a predicate that will not parse. They do not bound its
meaning. Injected schema evidence can still steer the compiler toward a wider but perfectly
well-formed predicate — tier <> 'production' in place of tier = 'sandbox'. What bounds that is
the grantor's signature on the compiled form and attenuation against the grantor's own
authority, which is why the human reads the compilation and not the sentence.
Recompilation is a new delegation. Editing the sentence produces a new compilation requiring a new signature. An existing delegation is never re-derived, so improving the compiler cannot change what someone is already permitted to do.
Consequences
Easier.
- The people who understand the domain can write delegations, which is the difference between this feature existing and not.
- The review is on the compiled form, so it is precise, diffable and short — usually easier to check than the sentence.
- The derivation makes the model's reasoning inspectable at exactly the moment a human can correct it.
Harder.
- A grantor may sign a compilation they did not read carefully. This is the central risk, and it is the same one as EDR-0009: a plausible summary invites trust. Flagging inferred clauses and refusing unbounded scopes reduces it; nothing removes it.
- The refusal rate will be annoying at first. Ambiguity refusals in particular will feel pedantic when the intent seems obvious. Resolving ambiguity silently is the alternative, and it is worse.
- Schema access for the compiler is a new read path from the control plane's analyser through the Pilot, and a new place where column names and sample values are handled.
- Compilation quality varies with the model, so the compiler is versioned and covered by a regression suite over known sentences (EDR-0009 sets the precedent).
New obligations.
- The compiler's test suite includes adversarial sentences — ones that try to compile to more than they appear to say, and ones with injected instructions in the text — and adversarial schema evidence: a column value containing an instruction, a column named to read as one, and evidence that steers the compiler to a wider but well-formed predicate — the case the output constraints do not catch. A failure to refuse is a build failure.
- Compiled delegations are reviewed at renewal against their sentence, which is when a drifted compilation is caught.
References
- ZFN-26 — a human co-signs what a model drafts.
- ZFN-37 — "always" is still a lease.
- EDR-0007 — what a compilation compiles to.
- EDR-0017 — what happens to the clauses that will not compile.
Changelog
- 2026-08-15: Accepted.
- 2026-08-15: Amended after review: the signed compilation supplies the approver limb of a marque minted by a delegation match, and travels with it so a Pilot can verify offline that a human signed the scope (EDR-0029).
- 2026-08-16: Amended after the expert panel's should-fix pass: gated distinct values to columns classified non-sensitive — this is the only path by which production data reaches a model whose output becomes a candidate authority artefact — and declared schema evidence untrusted input with the compiler's output constrained rather than its input trusted.
- 2026-08-16: Amended in the second panel's should-fix pass: added
issued_atandroster_epoch; and corrected an overclaim — the output constraints make a compilation ungroundable in fabricated evidence, they do not bound its meaning, so a steered-but-well-formed predicate is bounded by the grantor's signature and attenuation instead. - 2026-08-19: Amended for the artefact spelling (EDR-0041): the compiled delegation's
fenceis an array of conjuncts, its relation is two fields, and its operations are lowercase. Thederivationentries stay prose — they are an account for a human of how a clause was compiled, not a copy of the compiled field. The compiler's output constraints also required an emitted fence to "parse under EDR-0007's grammar", which is a statement grammar — the mirror of the false attribution removed from EDR-0007 in this change: each record pointed at the other for a rule neither states. They are now stated per conjunct, against EDR-0041's shape rules and EDR-0007 rule 5's target-relation requirement, with what a conjunct may do left open as issue #25. The cost lands here rather than anywhere else: the grantor now signs a list where they used to sign a predicate.