TLDR
- A context compiler turns a decision request into a typed evidence plan before retrieval, so the model never decides which identities, purposes, policies or source classes it is allowed to use.
- Its mechanism is a sequence of deterministic passes: parse, resolve, type-check, admit, plan and attest. Learned ranking can operate inside the admitted universe, but cannot widen it.
- The output is a context intermediate representation that names required propositions, authorised resources, applicable versions, retrieval routes, token budgets, omissions and the dependencies that invalidate the plan.
- Compilation does not repair bad identity data, stale entitlements or weak source governance. A precisely executed wrong policy can still produce a defensible-looking but incorrect evidence packet.
- Use a compiler when authority, applicability or evidential force varies across users and decisions. For a public, single-version, low-consequence corpus, ordinary retrieval may be the better design.
The answer that a good retriever should refuse to assemble
Maya is reviewing Atlas Fasteners, a fictional commercial customer. She asks a familiar question: “Can Atlas keep its overdraft while the annual review is open?” A hybrid retriever has plenty to work with. It finds the current group credit manual, the almost identical manual it replaced, a local transition addendum, the facility record, an expired covenant waiver, a relationship manager’s note saying renewal was requested, and a restricted investigation note that mentions the same customer and covenant.
Every item is relevant. That is the problem. Maya may read the facility record but not the investigation note. The new group manual is current, yet the local addendum preserves one provision for renewals until quarter end. The manager’s note is permitted and recent, but it does not prove that a waiver was approved. The expired waiver is authoritative for its historical interval and useless for today’s entitlement. A reranker can arrange these passages beautifully and still hand the model the wrong decision substrate.
The usual repair is to add more instructions: use only authorised data, prefer current policy, cite reliable sources, abstain when uncertain. Those instructions arrive too late. They ask the same probabilistic component that reads the evidence to decide which evidence it had authority to receive. They also compress different questions into one vague score: permission, applicability, source force, contradiction and coverage.
The core answer is to move evidence selection out of prompt craft and into compilation. A context compiler accepts a typed decision request, resolves its principal and resource scope, evaluates authorisation and applicability, opens the propositions that must be established, chooses retrieval routes and emits a bounded context intermediate representation. Search engines execute that representation. They may rank within it; they may not broaden it. The model receives admitted evidence, explicit gaps and an attestation of how the packet was produced.
This is a composite scenario, not a reported bank deployment. Its purpose is to expose a systems distinction. Retrieval asks, “Which items resemble the query?” Compilation asks, “Which items may participate in this decision, in what evidential role, under which budget and dependencies?” Those are not competing rankers. They are different layers of responsibility.
Part IThe wrong optimisation target
Retrieval-augmented generation gave language models an explicit non-parametric memory and a route to provenance and updateable knowledge. The original RAG work joined a sequence model to a dense index and showed gains on knowledge-intensive tasks.1 That mechanism answers an important question: how can a model condition generation on external material? It does not, by itself, answer who may see each resource, which version governs a particular decision or what evidence is sufficient to establish a proposition.
Longer context windows do not remove the need to select. In controlled multi-document and key-value tasks, Liu and colleagues found that performance could change sharply with the position of relevant material, often deteriorating when it appeared in the middle of a long context.2 More context therefore expands capacity without guaranteeing dependable use. In a consequential workflow, indiscriminately filling that capacity also increases exposure, contradiction and review cost.
A useful context item must pass three tests that ordinary similarity ranking tends to blur:
| Test | Question | Typical authority | Failure if collapsed into relevance |
|---|---|---|---|
| Permission and purpose | May this principal use this resource for this task? | Identity, entitlement and policy services | A highly similar protected item enters candidate generation. |
| Applicability | Does this version govern this entity, product, action and time? | Policy registry, source state and precedence rules | A current but inapplicable rule displaces the governing one. |
| Evidential force | Can this source class support this proposition? | Decision schema and evidence contract | A note, slide or email is treated as proof of approval. |
Relevance is useful only after the admissible universe exists. A score can order two authorised, applicable policy clauses. It cannot turn an email into an approval, a global policy into a local rule or a service account into the end user whose purpose justified the read.
Thought experiment: the identical query, a different caller
Freeze the words, time, customer and corpus. Maya asks about Atlas. Then an employee from an unrelated unit submits the identical sentence. A text retriever should produce the same similarity scores because the query and documents have not changed. A decision system should not produce the same candidate universe because the principal, case assignment and approved purpose have changed.
This single variation reveals why authorisation cannot be a prompt preference or a reranking feature. If “permission score” merely lowers a protected document rather than excluding it, the document can still enter traces, caches or model context when the candidate budget grows. NIST’s attribute-based access-control definition makes subject, object, action and environment attributes part of the access decision.3 Zero-trust guidance similarly centres explicit decisions about resources rather than ambient trust from network location.4 Neither source defines a context compiler, but both support the architectural boundary: permission is evaluated as policy, not inferred from semantic similarity.
The strongest objection: “Is this only access control plus RAG?”
Access control is necessary and insufficient. It can answer whether Maya may read a document. It does not usually say that an approved waiver object may support waiver_valid while a case note may only support waiver_requested. Retrieval can find both. A context compiler composes access, applicability, decision schema, evidence typing, budgets and replay dependencies into one executable plan.
The original contribution is therefore a systems separation, not a claim to have invented authorisation, provenance or query planning. Cedar, Zanzibar, XACML and Open Policy Agent each address policy or relationship evaluation at different layers.56 A compiler uses those capabilities as inputs and preserves their decisions while lowering a decision request into backend-specific reads. It becomes valuable when no single index, policy engine or prompt can carry the whole decision contract.
flowchart TD A["The answer that a good<br/>retriever should refuse to<br/>assemble"] --> B["Part I The wrong optimisation<br/>target"] B --> C["Part II Compile the evidence<br/>boundary"] C --> D["Part III Emit a<br/>decision-specific packet"] D -. "re-test" .-> A classDef first fill:#0a1424,stroke:#5B5CF6,stroke-width:2px,color:#e6f3ff classDef step fill:#0a1424,stroke:#3f7da0,stroke-width:1px,color:#e6f3ff class A first class B,C,D step
Part IICompile the evidence boundary
A conventional compiler translates a source programme into an executable representation while preserving meaning. The analogy is useful if its limits remain explicit. A context compiler does not prove arbitrary natural-language truth. It translates a governed decision request into a constrained acquisition and assembly plan. Its semantics are the authorised resource set, applicable rule set, accepted evidence classes, required proposition slots and release invariants.
Open Policy Agent can compile policy queries into an intermediate representation containing planned evaluation paths.7 That is an implementation precedent for separating a declarative request from its executable plan. The context intermediate representation proposed here is broader practitioner synthesis. It carries policy results, but also entity roots, evidence obligations, retrieval routes, budgets, omissions, provenance and invalidation dependencies.
A small formal model
Let S be the raw source estate, p the principal chain, d the decision request, t the decision time and q a required proposition. Three predicates decide whether a resource may enter the candidate universe: A for authorisation, G for governing applicability and E for accepted evidential class.
The planner then selects a packet C contained in U. It tries to cover required propositions, preserve decisive contradictions and minimise tokens and retrieval cost under budget B. Changing B can alter which secondary evidence is included. It cannot admit a resource outside U. If a critical proposition has no acceptable resource, its state remains unknown. This is the operational meaning of “do not search first and justify later”.
The model is untrusted with respect to boundary expansion. It may suggest an alias, query paraphrase or likely evidence class. Those suggestions become typed input to deterministic validation. It may not create a principal, change purpose, remove a deny, invent an effective date or substitute a weaker source class for a required one.
Six passes, six distinct error owners
The passes matter because a single “retrieval failed” status hides where repair belongs. Parsing failures belong to the interaction contract. Resolution failures belong to identity or entity services. Type errors belong to the decision catalogue. Admission failures belong to authorisation, applicability or source governance. Planning failures belong to adapters and budgets. Attestation failures belong to release and cryptographic dependency handling.
Pass 1, parse. Convert the interaction into a DecisionRequest. The natural-language question is preserved as query material, while control fields arrive from authenticated workflow state. “Summarise this case” and “recommend continuation” are different decision types. A request that silently combines advice, approval and execution should not become one broad retrieval instruction.
Pass 2, resolve. Map names, pronouns and aliases to stable identifiers. The compiler can use a model to propose candidates, but canonical selection must be verified through an authorised interface or deterministic relationship. The phrase “the customer” cannot become whichever customer has the closest embedding.
Pass 3, type-check. Confirm that the decision type exists, that the workflow permits it and that its required proposition schema is known. A type error is preferable to a plausible context packet for an undefined action. Fine-grained structured authorisation requests, such as those represented by RFC 9396, illustrate why machine-readable purpose and resource detail are more expressive than a coarse scope string.8
Pass 4, admit. Intersect authorisation, resource roots, purpose, applicability, deny conditions and evidence-class rules. Deny must dominate across joins. If Maya can read a customer file and the service can search annual reviews, neither fact should erase a specific prohibition on investigation material. Predicate pushdown should constrain candidate generation where the backend supports it; an independent validator must still check each returned item before the model boundary.
Pass 5, plan. Choose one route per proposition. Exact identifiers and structured APIs suit facility state. Filtered lexical and semantic search suit policy clauses. Graph traversal may establish customer-facility relationships. The optimiser may trade latency, token use and redundancy only inside the admitted semantics. Post-filtering a broad top-k result can preserve secrecy if done inside a trusted boundary, yet it can destroy recall because forbidden high-scoring items occupy the candidate budget.
Pass 6, attest. Emit a versioned plan with policy hashes, index or source versions, query routes, evidence slots, rejected reason classes, expiry and invalidation dependencies. OAuth token exchange provides standard vocabulary for delegation and impersonation, although it does not design the domain entitlements themselves.9 Provenance can draw on W3C PROV-O’s distinction among entities, activities and agents.10 The attestation should carry stable references and reason codes, not replicate sensitive group memberships or denied content into an audit leak.
The context intermediate representation
The intermediate representation is the contract between governance and retrieval implementation. It is deliberately backend-neutral. A SQL adapter, graph adapter and vector adapter can all lower the same proposition and policy constraints into different queries. Conformance tests then ask whether each adapter preserves the admitted set, not whether its query text looks similar.
Worked example: a four-source refund desk
Consider a smaller decision: “May order 481 receive a refund without manager approval?” The corpus contains refund policy version 3, superseded version 2, the order record and a customer email asking for an exception. The caller is a support agent assigned to order 481. The evidence contract requires three propositions: delivery date from the order system, ordinary refund rule from the current policy and any approved exception from an approval object.
Parse identifies refund.eligibility. Resolve binds order 481 and its customer. Type-check opens the three proposition slots. Admit excludes policy version 2 because it is superseded. The email is permitted and may support exception_requested, but its source class cannot support exception_approved. Plan uses a structured order lookup and a filtered policy read. Emit marks delivery date and ordinary rule as supported, while manager approval remains unknown.
A plain retriever might produce the same final answer in this tiny case. The value of compilation is that its correctness does not depend on the email being ranked below the policy. Add a phrase such as “manager already approved this” to the email and semantic confidence may rise. The evidence type does not change. The compiler still refuses the substitution.
Part IIIEmit a decision-specific packet
A packet is not complete because it fills the context window. It is complete when every required proposition has a visible evidential state. The minimum useful states are supported, contradicted and unknown. Some domains need finer distinctions such as not_applicable, temporarily_unavailable or reserved_for_human. The crucial property is that absence does not silently become false and weak evidence does not silently become proof.
An evidence contract names the proposition, accepted source classes, precedence rules, contradiction treatment and whether a gap blocks the decision. For Atlas, a facility-system record can establish the approved limit. A signed approval may corroborate it. An email summary cannot establish it alone. A valid waiver object can establish waiver status. A relationship-manager note can explain that renewal was requested, but it cannot promote the waiver slot from unknown to supported.
Decision-specific evidence beats a generic top-k budget. A context window is a scarce common resource. Without proposition budgets, five passages repeating a popular policy clause can displace the one workflow event needed to establish review status. The compiler allocates capacity by evidential obligation, then permits ranking within each slot.
Thought experiment: move the decision by one day
Keep Maya, Atlas, the question and every document unchanged. Move the decision time from the last day of the quarter to the first day of the next. The local transition addendum expires at midnight. Similarity scores do not notice. File modification times may not change. Yet the governing policy set changes because applicability is a function of decision class and valid time, not merely document recency.
This thought experiment isolates a second causal feature. The correct packet can change even when text and identity remain constant. A compiler represents effective intervals, supersession and transition rules as plan dependencies. When the clock or relevant event crosses a boundary, the old plan becomes invalid and must be recompiled. Paper 110’s deeper problem is reconstructing what was knowable and applicable at a historical decision moment; Paper 111 treats freshness and supersession in detail. Here the narrower point is that time belongs in the IR rather than in a “prefer recent” prompt.
Worked example: walk the Atlas case through the packet
The annual-review workspace supplies Maya’s verified identity, service identity, case assignment, entity and purpose. The compiler does not infer those fields from chat history. It parses the request as a continuation assessment, not an approval or account action. Resolution confirms that facility F-102 belongs to Atlas and the case concerns the same booking entity.
Admission permits the facility record, annual-review events, applicable credit policy and approved waiver objects. It excludes the investigation note. The interaction receives a bounded denial reason, not a disclosure that such a record exists. Applicability selects the group manual and the local transition provision; it rejects the superseded general wording. The planner opens slots for facility limit, review status, waiver validity, continuation rule and any authorised hard stop.
The facility and workflow reads support their slots. The current policy supports the continuation rule. The waiver fails. The last approved object expired two days earlier. The manager’s note says renewal was requested, which is relevant to the narrative and insufficient for the required source class. The resulting packet states waiver_valid: unknown. The model may explain that continued availability cannot be established from admitted evidence and point to the approved resolution route. It may not convert a pending request into an approval.
The compiler has not made a credit judgement. It has changed the decision surface. Maya sees the exact unresolved proposition rather than a fluent synthesis of mixed-authority text. If an authorised officer later approves a waiver, the new source event invalidates the old packet. The request is compiled again against the changed state.
A controlled synthetic comparison
The accompanying executable artefact builds a deliberately contaminated eight-item corpus. Four high-scoring candidates are unsafe or unusable: another entity’s facility record, a superseded policy, an email masquerading as approval and a restricted waiver. Four lower-scoring candidates satisfy the evidence contract. Plain top-5 retrieval passes five items, of which four are unsafe under the test policy, and covers three of four proposition names only because weak or forbidden sources happen to mention them. Filtering those five after retrieval removes the unsafe items but leaves one proposition covered. Compiling before ranking returns four admitted items and covers all four.
These numbers are synthetic, not a general performance claim. They demonstrate a structural failure: post-filtering cannot recover evidence that never entered the original top-k set. A recent controlled study of multitenant agentic retrieval reached a related result under its own assumptions. Attribute-based gating reduced cross-tenant leakage to zero in its synthetic testbed, while post-retrieval filtering suffered severe recall loss as corpus size grew; the authors explicitly excluded compromised servers, side channels and model prior knowledge from their guarantee.11 The study supports pre-retrieval enforcement, not every detail of the compiler proposed here.
Negative control: when the compiler adds little
Take a public help-centre bot over one openly licensed appliance manual. There is one product version, no per-user access variation, no conflicting policy authority, no private case data and low consequence if a passage is omitted. The requested output is explanatory, not an approval or action. A well-tested lexical or hybrid retriever with citations may be enough. The compiler would repeat fixed predicates, add operational dependencies and create a misleading impression of assurance without changing the admissible set.
This negative control matters because “compile everything” can become architecture theatre. A context compiler earns its cost only when at least one of three dimensions varies materially: who may use a resource and for what purpose, which rule or state applies to the decision, or what source class can establish the required claim. If those dimensions are invariant and consequence is low, simpler retrieval is easier to test and operate.
stateDiagram-v2 [*] --> Claim state "Thought experiment: the<br/>identical query, a different<br/>caller" as Claim state "The strongest objection: “Is<br/>this only access control plus<br/>RAG?”" as Test state "A small formal model" as Revision Claim --> Test: expose mechanism Test --> Decision: evidence survives Test --> Revision: rival survives Revision --> Claim: narrow or rebuild Decision --> [*]
Part IVBuild, break and operate it
The compiler belongs on the trusted side of the model boundary. It should receive verified workflow fields directly, call authoritative identity and policy services, and emit a plan that retrieval adapters cannot widen. The model may generate candidate query terms inside a restricted grammar. Retrieved documents are data. Instructions embedded in them cannot change the principal, purpose, tool set, output destination or action authority.
Indirect prompt injection remains a residual risk because admitted content can contain adversarial instructions. OWASP identifies external content as a route for prompt injection and recommends layered controls.12 Compilation contributes a hard containment property: content cannot acquire permission or alter the plan. It does not guarantee that a model will interpret every admitted passage correctly. Output claim checking, tool authorisation and action controls still sit downstream.
Cloud retrieval products expose useful primitives. Amazon Bedrock Knowledge Bases documents metadata filters, and Azure AI Search documents document-level security trimming patterns.1314 Those features are adapters, not the compiler. The application still has to decide which identity attributes, purpose, legal entity, effective interval, evidence class and denial rules belong in the plan. It must also test that each backend preserves them.
The failure boundary
The most dangerous failure is deterministic wrongness. Suppose a policy owner forgets to add “approved committee record” to the evidence classes for waiver validity. The compiler consistently returns unknown even when valid evidence exists. That is an availability and decision-quality defect. Reverse the mistake and accept “case note” as proof; the compiler consistently promotes requests into approvals. The system may look more auditable precisely because it is wrong in the same way every time.
Determinism transfers the burden from model behaviour to contract quality. Release evidence must therefore cover source-to-index metadata, policy fixtures, decision schemas and adapter equivalence. A model benchmark cannot substitute for these tests.
Test the authorised set before answer quality
Begin with deterministic fixtures. For each principal, purpose, resource root and decision time, enumerate the expected admitted set. Include nested groups, revoked delegation, information barriers, cross-entity assignments, policy transitions, deletion and unknown classification. Mutate one predicate at a time. Remove an entity constraint, reorder policy rules, replay an expired plan or relabel a chunk. Any unapproved widening should block release.
Then test the evidence contract. Hide one authoritative source. Insert a highly similar but inapplicable policy. Supply only secondary evidence. Add a contradiction from a higher-precedence source. The expected output should be unknown, contradicted or refused, not a lower confidence score attached to a complete-sounding answer. Finally test every adapter against the same IR fixtures. A graph traversal and a vector query may be operationally different while remaining semantically equivalent.
Only after these controls pass should the team measure retrieval recall, reranking quality and answer usefulness. The order matters. A fluent answer can hide a forbidden read. A highly cited answer can still rely on an inapplicable version. A low acceptance rate can be caused by missing metadata rather than model weakness.
| Test family | Primary question | Release evidence | Safe failure |
|---|---|---|---|
| Admission soundness | Did any forbidden resource cross the model boundary? | Zero false admissions in deterministic security fixtures | Block affected plan or adapter |
| Admission completeness | Were legitimate resources denied? | False-denial rate by role, case and source class | Route to source or policy owner |
| Applicability | Was the governing version selected? | Golden transitions and precedence cases | Expose conflict, do not rank through it |
| Evidence typing | Does every supported claim have an accepted source class? | No unsupported critical proposition | Mark unknown or contradicted |
| Adapter equivalence | Did every backend preserve the same semantics? | Expected set equality plus rejection reasons | Disable non-conforming adapter |
| Replay resistance | Can a stale plan survive changed dependencies? | All revocation and expiry tests pass | Invalidate and recompile |
Operate dependencies, not only latency
A plan cache keyed by query text is unsafe. The key or dependency graph must include principal and delegation version, purpose, resource roots, policy bundle, relevant entitlement state, case state, applicable time and source or index versions. A cache miss costs time. A stale permit can disclose data. When revocation propagation is uncertain, high-sensitivity reads should re-evaluate or stop rather than “permit on error”.
Operational telemetry should be pass-specific: parse rejection, entity ambiguity, policy conflict, unsafe admission, permission mismatch at independent validation, evidence-slot coverage, unsupported proposition, compilation latency, invalidation lag and manual fallback. Preserve denominators and distinguish unknown from system failure. A rise in unknown waiver status may reflect missing approval objects, not a weaker language model.
Logs are another source boundary. A trace that captures rejected snippets, user group memberships or deny-rule bodies can recreate the leak that compilation prevented. Routine receipts should carry stable resource identifiers, policy and content hashes, reason classes and dependency versions. Privileged investigation can resolve those references through a separately authorised path.
Executable artefact: a minimal Context IR compiler
The Python laboratory below uses only the standard library. It defines a typed request, evidence requirements, resources and a compiler. The positive case admits a facility record, workflow event and current policy. The negative cases exclude a restricted note, superseded policy and wrong evidence class. Assertions enforce the token budget and require every admitted resource to be authorised, applicable and relevant to an evidence slot.
unknown. The synthetic benchmark records 100% proposition coverage and zero unsafe items for compilation before ranking, compared with 25% coverage after filtering the original top-five candidates. These are fixture results, not production estimates.
Open the complete runnable Python artefact
from __future__ import annotations
from dataclasses import asdict, dataclass
from datetime import date
from enum import Enum
import hashlib
import json
from typing import Iterable
class EvidenceState(str, Enum):
SUPPORTED = "supported"
CONTRADICTED = "contradicted"
UNKNOWN = "unknown"
@dataclass(frozen=True)
class DecisionRequest:
decision_type: str
principal: str
roles: frozenset[str]
purpose: str
entity_id: str
decision_date: date
token_budget: int
@dataclass(frozen=True)
class EvidenceRequirement:
proposition: str
accepted_classes: tuple[str, ...]
required: bool = True
@dataclass(frozen=True)
class Resource:
resource_id: str
entity_id: str
allowed_roles: frozenset[str]
allowed_purposes: frozenset[str]
evidence_class: str
supports: frozenset[str]
contradicts: frozenset[str]
valid_from: date
valid_to: date | None
superseded: bool
tokens: int
relevance: float
content: str
@dataclass(frozen=True)
class EvidenceSlot:
proposition: str
state: EvidenceState
resource_ids: tuple[str, ...]
reason: str
@dataclass(frozen=True)
class ContextIR:
plan_id: str
decision_type: str
principal: str
purpose: str
entity_id: str
decision_date: str
token_budget: int
tokens_used: int
admitted_resource_ids: tuple[str, ...]
rejected: tuple[tuple[str, str], ...]
evidence_slots: tuple[EvidenceSlot, ...]
def authorised(req: DecisionRequest, resource: Resource) -> bool:
return bool(req.roles & resource.allowed_roles) and req.purpose in resource.allowed_purposes
def applicable(req: DecisionRequest, resource: Resource) -> bool:
within_time = resource.valid_from <= req.decision_date and (
resource.valid_to is None or req.decision_date <= resource.valid_to
)
return resource.entity_id == req.entity_id and within_time and not resource.superseded
def compile_context(
req: DecisionRequest,
requirements: Iterable[EvidenceRequirement],
resources: Iterable[Resource],
) -> ContextIR:
"""Compile a request into a bounded, typed context intermediate representation."""
required = tuple(requirements)
accepted_by_prop = {r.proposition: set(r.accepted_classes) for r in required}
candidates: list[Resource] = []
rejected: list[tuple[str, str]] = []
for item in resources:
if not authorised(req, item):
rejected.append((item.resource_id, "not_authorised"))
continue
if not applicable(req, item):
rejected.append((item.resource_id, "not_applicable"))
continue
typed_props = {
p for p in item.supports | item.contradicts
if p in accepted_by_prop and item.evidence_class in accepted_by_prop[p]
}
if not typed_props:
rejected.append((item.resource_id, "wrong_evidence_class"))
continue
candidates.append(item)
# Prefer resources that cover required propositions, then higher relevance,
# while never exceeding the deterministic token budget.
uncovered = {r.proposition for r in required}
admitted: list[Resource] = []
tokens_used = 0
remaining = candidates[:]
while remaining and uncovered:
remaining.sort(
key=lambda x: (
len((x.supports | x.contradicts) & uncovered),
x.relevance,
-x.tokens,
x.resource_id,
),
reverse=True,
)
item = remaining.pop(0)
covered = (item.supports | item.contradicts) & uncovered
if not covered:
break
if tokens_used + item.tokens > req.token_budget:
rejected.append((item.resource_id, "budget_exceeded"))
continue
admitted.append(item)
tokens_used += item.tokens
uncovered -= covered
# Any remaining typed candidates are omitted rather than filling the window.
admitted_ids = {x.resource_id for x in admitted}
for item in remaining:
if item.resource_id not in admitted_ids:
rejected.append((item.resource_id, "not_needed_for_contract"))
slots: list[EvidenceSlot] = []
for requirement in required:
support_ids = tuple(
x.resource_id for x in admitted
if requirement.proposition in x.supports
and x.evidence_class in requirement.accepted_classes
)
contradiction_ids = tuple(
x.resource_id for x in admitted
if requirement.proposition in x.contradicts
and x.evidence_class in requirement.accepted_classes
)
if support_ids and contradiction_ids:
slots.append(EvidenceSlot(
requirement.proposition,
EvidenceState.CONTRADICTED,
support_ids + contradiction_ids,
"admissible sources disagree",
))
elif contradiction_ids:
slots.append(EvidenceSlot(
requirement.proposition,
EvidenceState.CONTRADICTED,
contradiction_ids,
"admissible evidence contradicts the proposition",
))
elif support_ids:
slots.append(EvidenceSlot(
requirement.proposition,
EvidenceState.SUPPORTED,
support_ids,
"supported by an accepted evidence class",
))
else:
slots.append(EvidenceSlot(
requirement.proposition,
EvidenceState.UNKNOWN,
(),
"no admitted resource satisfies the evidence contract",
))
fingerprint = {
"request": {
"decision_type": req.decision_type,
"principal": req.principal,
"purpose": req.purpose,
"entity_id": req.entity_id,
"decision_date": req.decision_date.isoformat(),
},
"admitted": sorted(x.resource_id for x in admitted),
"slots": [(s.proposition, s.state.value, s.resource_ids) for s in slots],
}
plan_id = hashlib.sha256(
json.dumps(fingerprint, sort_keys=True).encode("utf-8")
).hexdigest()[:12]
ir = ContextIR(
plan_id=plan_id,
decision_type=req.decision_type,
principal=req.principal,
purpose=req.purpose,
entity_id=req.entity_id,
decision_date=req.decision_date.isoformat(),
token_budget=req.token_budget,
tokens_used=tokens_used,
admitted_resource_ids=tuple(x.resource_id for x in admitted),
rejected=tuple(sorted(set(rejected))),
evidence_slots=tuple(slots),
)
# Release invariants: the model cannot waive these checks.
assert ir.tokens_used <= ir.token_budget
assert all(authorised(req, x) and applicable(req, x) for x in admitted)
assert all(
any(
slot.proposition in x.supports | x.contradicts
and x.evidence_class in accepted_by_prop[slot.proposition]
for slot in ir.evidence_slots
)
for x in admitted
)
return ir
def synthetic_benchmark() -> dict[str, dict[str, float | int]]:
"""Compare three retrieval orders on a deliberately contaminated corpus."""
req = DecisionRequest(
"credit.review.continuation", "maya", frozenset({"credit_analyst"}),
"annual_credit_review", "ATLAS-IN-01", date(2026, 8, 30), 1000,
)
requirements = (
EvidenceRequirement("facility_limit", ("facility_record",)),
EvidenceRequirement("review_open", ("workflow_event",)),
EvidenceRequirement("waiver_valid", ("approved_waiver",)),
EvidenceRequirement("continuation_rule", ("policy_clause",)),
)
resources = (
Resource("other-tenant-limit", "OTHER", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "facility_record", frozenset({"facility_limit"}), frozenset(), date(2025,1,1), None, False, 100, 1.00, "other tenant"),
Resource("old-policy", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "policy_clause", frozenset({"continuation_rule"}), frozenset(), date(2025,1,1), None, True, 100, 0.99, "old policy"),
Resource("email-waiver", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "case_note", frozenset({"waiver_valid"}), frozenset(), date(2026,8,1), None, False, 100, 0.98, "email says approved"),
Resource("restricted-waiver", "ATLAS-IN-01", frozenset({"financial_crime"}), frozenset({"investigation"}), "approved_waiver", frozenset({"waiver_valid"}), frozenset(), date(2026,8,1), None, False, 100, 0.97, "restricted"),
Resource("facility", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "facility_record", frozenset({"facility_limit"}), frozenset(), date(2025,1,1), None, False, 100, 0.96, "facility"),
Resource("workflow", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "workflow_event", frozenset({"review_open"}), frozenset(), date(2026,8,1), None, False, 100, 0.80, "workflow"),
Resource("current-policy", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "policy_clause", frozenset({"continuation_rule"}), frozenset(), date(2026,7,22), None, False, 100, 0.79, "current policy"),
Resource("approved-waiver", "ATLAS-IN-01", frozenset({"credit_analyst"}), frozenset({"annual_credit_review"}), "approved_waiver", frozenset({"waiver_valid"}), frozenset(), date(2026,8,1), date(2026,9,30), False, 100, 0.78, "approved waiver"),
)
accepted = {r.proposition: set(r.accepted_classes) for r in requirements}
def is_typed(item: Resource) -> bool:
return any(
p in accepted and item.evidence_class in accepted[p]
for p in item.supports | item.contradicts
)
def metrics(items: list[Resource]) -> dict[str, float | int]:
covered = set().union(*(x.supports | x.contradicts for x in items)) if items else set()
unsafe = sum(not (authorised(req, x) and applicable(req, x) and is_typed(x)) for x in items)
return {
"items_passed": len(items),
"unsafe_items": unsafe,
"coverage_percent": round(100 * len(covered & set(accepted)) / len(accepted)),
}
top_five = sorted(resources, key=lambda x: x.relevance, reverse=True)[:5]
post_filtered = [x for x in top_five if authorised(req, x) and applicable(req, x) and is_typed(x)]
compiled_ids = set(compile_context(req, requirements, resources).admitted_resource_ids)
pre_filtered = [x for x in resources if x.resource_id in compiled_ids]
return {
"plain_top_k": metrics(top_five),
"post_filter_top_k": metrics(post_filtered),
"compiled_pre_filter": metrics(pre_filtered),
}
def demo() -> ContextIR:
req = DecisionRequest(
decision_type="credit.review.continuation",
principal="maya",
roles=frozenset({"credit_analyst"}),
purpose="annual_credit_review",
entity_id="ATLAS-IN-01",
decision_date=date(2026, 8, 30),
token_budget=760,
)
requirements = (
EvidenceRequirement("facility_limit", ("facility_record",)),
EvidenceRequirement("review_open", ("workflow_event",)),
EvidenceRequirement("waiver_valid", ("approved_waiver", "committee_record")),
EvidenceRequirement("continuation_rule", ("policy_clause",)),
)
resources = (
Resource(
"facility-F102", "ATLAS-IN-01", frozenset({"credit_analyst"}),
frozenset({"annual_credit_review"}), "facility_record",
frozenset({"facility_limit"}), frozenset(), date(2025, 1, 1), None,
False, 180, 0.78, "Approved overdraft limit: 2.0m.",
),
Resource(
"workflow-E88", "ATLAS-IN-01", frozenset({"credit_analyst"}),
frozenset({"annual_credit_review"}), "workflow_event",
frozenset({"review_open"}), frozenset(), date(2026, 8, 1), None,
False, 90, 0.69, "Annual review status: OPEN.",
),
Resource(
"policy-P3", "ATLAS-IN-01", frozenset({"credit_analyst"}),
frozenset({"annual_credit_review"}), "policy_clause",
frozenset({"continuation_rule"}), frozenset(), date(2026, 7, 22), None,
False, 260, 0.74, "Continuation requires a valid waiver when covenant breach persists.",
),
Resource(
"policy-P2", "ATLAS-IN-01", frozenset({"credit_analyst"}),
frozenset({"annual_credit_review"}), "policy_clause",
frozenset({"continuation_rule"}), frozenset(), date(2025, 1, 1), None,
True, 240, 0.99, "Superseded continuation wording.",
),
Resource(
"rm-note-N7", "ATLAS-IN-01", frozenset({"credit_analyst"}),
frozenset({"annual_credit_review"}), "case_note",
frozenset({"waiver_valid"}), frozenset(), date(2026, 8, 29), None,
False, 120, 0.96, "The relationship manager says renewal was requested.",
),
Resource(
"investigation-X9", "ATLAS-IN-01", frozenset({"financial_crime"}),
frozenset({"investigation"}), "investigation_note",
frozenset({"waiver_valid"}), frozenset(), date(2026, 8, 20), None,
False, 150, 1.00, "Restricted investigation note.",
),
)
ir = compile_context(req, requirements, resources)
# Positive and negative cases.
assert set(ir.admitted_resource_ids) == {"facility-F102", "workflow-E88", "policy-P3"}
assert "investigation-X9" not in ir.admitted_resource_ids
assert "policy-P2" not in ir.admitted_resource_ids
waiver = next(s for s in ir.evidence_slots if s.proposition == "waiver_valid")
assert waiver.state is EvidenceState.UNKNOWN
return ir
if __name__ == "__main__":
result = demo()
payload = asdict(result)
payload["evidence_slots"] = [
{**asdict(slot), "state": slot.state.value} for slot in result.evidence_slots
]
payload["synthetic_benchmark"] = synthetic_benchmark()
print(json.dumps(payload, indent=2, sort_keys=True))
Open the deterministic output
{
"admitted_resource_ids": [
"facility-F102",
"policy-P3",
"workflow-E88"
],
"decision_date": "2026-08-30",
"decision_type": "credit.review.continuation",
"entity_id": "ATLAS-IN-01",
"evidence_slots": [
{
"proposition": "facility_limit",
"reason": "supported by an accepted evidence class",
"resource_ids": [
"facility-F102"
],
"state": "supported"
},
{
"proposition": "review_open",
"reason": "supported by an accepted evidence class",
"resource_ids": [
"workflow-E88"
],
"state": "supported"
},
{
"proposition": "waiver_valid",
"reason": "no admitted resource satisfies the evidence contract",
"resource_ids": [],
"state": "unknown"
},
{
"proposition": "continuation_rule",
"reason": "supported by an accepted evidence class",
"resource_ids": [
"policy-P3"
],
"state": "supported"
}
],
"plan_id": "8fa9f7452d5d",
"principal": "maya",
"purpose": "annual_credit_review",
"rejected": [
[
"investigation-X9",
"not_authorised"
],
[
"policy-P2",
"not_applicable"
],
[
"rm-note-N7",
"wrong_evidence_class"
]
],
"synthetic_benchmark": {
"compiled_pre_filter": {
"coverage_percent": 100,
"items_passed": 4,
"unsafe_items": 0
},
"plain_top_k": {
"coverage_percent": 75,
"items_passed": 5,
"unsafe_items": 4
},
"post_filter_top_k": {
"coverage_percent": 25,
"items_passed": 1,
"unsafe_items": 0
}
},
"token_budget": 760,
"tokens_used": 530
}
Decision instrument: when compilation earns its cost
Use two axes for the first architecture decision. The vertical axis is consequence if the wrong source enters or the right source is omitted. The horizontal axis is heterogeneity in authority, applicability and evidence force. Ordinary retrieval is strongest in the lower-left. A compiler becomes the default as either dimension rises, and becomes difficult to avoid when both are high.
Five-question architecture record
- Can two authorised users asking the same words have different permitted source sets?
- Can the governing source change by entity, product, action, event or valid time?
- Can two equally relevant source classes have different authority to establish the same claim?
- Would post-filtering a broad candidate set create leakage, recall loss or sensitive traces?
- Must a reviewer reconstruct why each source entered and what dependency later invalidated it?
If three or more answers are yes, prototype a context IR and compare it with a simpler pre-filtered retrieval baseline. If all are no, retain the simpler design unless failure injection changes the evidence.
Compact glossary
- Decision request
- A typed envelope containing the intended task, principal chain, purpose, resource roots, decision time and output mode.
- Evidence contract
- The propositions a decision needs, the source classes that may support them and the treatment of gaps or contradictions.
- Context IR
- A backend-neutral intermediate representation of admitted resources, evidence slots, retrieval routes, budgets and dependencies.
- Admitted universe
- The resources that pass authorisation, applicability and evidence-class checks before relevance ranking.
- Decision receipt
- A replayable record of the request, policy and source versions, admitted evidence, omissions and compilation outcome.
- Deterministic wrongness
- A reproducible but incorrect packet caused by bad metadata, policy encoding or an incomplete evidence contract.
sequenceDiagram participant Q as Question participant M as Mechanism participant E as Evidence participant D as Decision Q->>M: The answer that a good retriever should refuse to assemble M->>E: Thought experiment: the identical query, a different caller E-->>M: compare rival explanations E->>D: Compile the boundary, then let the model reason D-->>Q: revise scope or act
Compile the boundary, then let the model reason
The context compiler changes one architecture decision: retrieval is no longer the first authority-bearing step. A typed decision request is parsed, resolved and checked before any candidate set exists. Authorisation and applicability define the universe. Evidence contracts define what can prove each proposition. Planning allocates routes and budget without changing those semantics. Attestation makes the packet replayable and revocable.
This arrangement does not make a language model truthful, a source correct or an organisation’s policies coherent. It does something narrower and operationally important. It prevents the model from deciding which evidence it was entitled to see, which rule governed and which informal statement counted as approval. It turns missing evidence into a visible state rather than pressure to complete the narrative.
The decision to adopt a compiler should be falsifiable. Build the simplest pre-filtered retrieval baseline. Add a negative control where identities, versions and evidence classes are invariant. Then inject principal changes, policy transitions, superseded documents, weak source substitutions, revoked delegations and top-k contamination. The compiler earns its place only when it preserves an evidence boundary that the simpler design cannot preserve without hidden coupling.
For Atlas, the changed outcome is modest: the system says it cannot establish a valid waiver. That answer is less fluent than a stitched narrative and more useful than a false approval. It tells the analyst what is known, what is missing, why the missing item matters and which authorised path can resolve it. That is the compiler’s proper contribution: not more context, but a defensible reason for every item that became context.
References
- Lewis, P. et al. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks. NeurIPS, 2020.
- Liu, N. F. et al. Lost in the Middle: How Language Models Use Long Contexts. Transactions of the Association for Computational Linguistics, 2024.
- NIST. SP 800-162: Guide to Attribute Based Access Control Definition and Considerations.
- NIST. SP 800-207: Zero Trust Architecture.
- Cutler, G. et al. Cedar: A New Language for Expressive, Fast, Safe, and Analyzable Authorization. 2024.
- Pang, R. et al. Zanzibar: Google’s Consistent, Global Authorization System. USENIX ATC, 2019.
- Open Policy Agent. Intermediate Representation.
- IETF. RFC 9396: OAuth 2.0 Rich Authorization Requests.
- IETF. RFC 8693: OAuth 2.0 Token Exchange.
- W3C. PROV-O: The PROV Ontology.
- Arceo, F. J. and Narsing, V. P. Securing the Agent: Vendor-Neutral, Multitenant Enterprise Retrieval and Tool Use. ACM CAIS, 2026.
- OWASP. LLM01: Prompt Injection.
- Amazon Web Services. RetrievalFilter API reference.
- Microsoft. Document-level access control and security trimming for Azure AI Search.
Source ledger. Primary research: references 1, 2, 5, 6 and 11. Official standards and guidance: references 3, 4, 8, 9, 10 and 12. Official implementation documentation: references 7, 13 and 14. The Context IR, evidence contract composition, six-pass compiler and decision instrument are practitioner synthesis presented for testing, not established standards.