What is proven,
and what is enforced
n0de is attribute-based access control for compartmented workloads. One identity holds every compartment it has been granted, and the decision is taken per access rather than per account. The policy is a machine-checked Lean 4 proof, and every enforcement layer is differentially tested against that proof rather than merely written to agree with it.
This page is the map: what the theorems say, what the gates check, and what is outside both. The last part is the reason to trust the first two.
01The problem it retires
In compartmented environments one engineer is routinely cleared into several programs at once. The common workaround is one account per compartment: separate logins, separate desktops, separate credentials, and a human keeping them apart. That arrangement is expensive, it puts the isolation property in the operator's discipline rather than in the system, and it fails at exactly the moment it matters most, which is de-accession. Disabling an account does not touch labelled bytes already on a shared workstation.
n0de takes the other route. Authority derives from current attributes and nothing else, and every access is decided against them. One identity carries ALP and BRA at the same time and reads both. A compartment the identity does not hold is not merely denied, it is invisible: objects in it do not appear, and their existence does not leak through a name collision. De-accession is one attribute change, after which every object carrying that compartment is denied on the next decision, residue on the machine included.
The system runs on ordinary open components. Lean 4.31.0 with mathlib for the proof, Cedar 4.11.2 for the policy decision point, PostgreSQL 18 with row-level security for the store, Node 22 using only its standard library for the identity and file API, and SELinux MCS as the operating-system reference monitor, on Fedora.
02The label, and the one decision function
A label has four axes: level, compartments,
need-to-know, and releasability. Levels and compartments
map onto SELinux MLS sensitivity and categories. Need-to-know is a first-class dimension
rather than a convention. Releasability is the set of countries an object may be released to,
with NOFORN being the singleton set containing the United States, and each
subject carrying a citizenship. Dominance over that axis is reversed set inclusion, so a
narrower release is more restrictive.
Those four axes form a lattice, and dominance over the lattice is the whole of the read rule:
a read is permitted when the subject's effective label dominates the object's on all four
axes at once. A write must dominate in the other direction, which is the Bell-LaPadula
star-property, and it may not widen releasability. Both directions are theorems rather than
code review notes: read_permit_sound and write_permit_sound, with
transfer_deny recording that the decision point never authorizes a cross-domain
transfer at all.
There is one proven decision function, decide, defined in the Lean model. There
are then several independent implementations of that policy in the running system: the Cedar
policy set, the Postgres row predicates, and the JavaScript decision mirror in the API. They
can drift, which is the entire reason the gates exist. Each is differentially checked to
agree with decide rather than assumed to encode it, and the same compiled proof
function is available as a command-line oracle, so the running engine's verdict can be put
beside the proven one on any input.
The distributed agent is a different case and is worth separating, since it is easy to read the gate list as one long equivalence check. The agent's decision path reduces to the same function, but most of the gates around it are operational rather than decision-equivalence tests: they exercise fail-closed behaviour on partition, replication, key handling, revocation, failover and clock trust. Those are properties of the deployment, checked by running it, not statements derived from the model.
03What is proven
The theorems live in model/Pl4Abac/. The keystone is
Pl4Abac.noninterference: writes by a high or foreign-compartment subject never
change what a low observer sees. Because the label carries all four axes, that statement
ranges over all four, including releasability.
| theorem | what it establishes | file |
|---|---|---|
| noninterference | high and foreign-compartment writes never change a low observer's view | NonInterference.lean |
| compartment_isolation | an identity holding N compartments has zero cross-compartment flow | MultiTenancy.lean |
| read_permit_sound | a permitted read implies the object is dominated on level, compartments, need-to-know and releasability | Soundness.lean |
| write_permit_sound | a permitted write implies the object dominates the subject, with no releasability widening | Soundness.lean |
| transfer_deny | the decision point never authorizes a transfer | Soundness.lean |
| naive_create_leaks | a shared-namespace create leaks object existence: the threat, stated as a theorem | Existence.lean |
| poly_create_ni | polyinstantiation closes that existence channel | Existence.lean |
| deaccess_revokes_read | removing a compartment denies every object carrying it | Deaccession.lean |
| deaccess_residue_invisible | on-disk residue cannot influence a de-accessed subject's view | Deaccession.lean |
| temporal_deaccess_blind | over any trace, a de-accessed subject stays blind to that compartment | TemporalDeaccession.lean |
| revoked_then_blind | blindness persists after revocation until an explicit re-grant | Reaccession.lean |
| read_permit_iff / rls_read_refines | the row-level-security read predicate is decide's read decision, both directions | Refinement.lean |
| write_permit_iff / rls_write_refines | the row-level-security insert predicate is decide's write decision | Refinement.lean |
| low_obs_determinism | a subject's view depends only on data it may read | CovertChannel.lean |
| no_uncontrolled_declassification | absent reviewer authorization, no high writer affects a low observer | Guard.lean |
| only_authorized_flows | with the guard, a run is low-equivalent to running only its authorized releases | Intransitive.lean |
| lease_expired_denies / lease_expired_blind | past the lease expiry the agent denies every access and sees nothing | Lease.lean |
| lease_revoked_blind | once the renewed lease drops a compartment, the agent is blind to every object carrying it | Lease.lean |
| naive_compilation_leaks | a memoryless decision function provably cannot enforce compilation rules: the aggregation attack, stated as a theorem | Aggregation.lean |
| agg_knowledge_bounded | with the knowledge gate, no trace of reads accumulates facets that fire a compilation rule above the subject's label | Aggregation.lean |
| agg_no_tipping_delivery | a denied tipping read delivers nothing and absorbs nothing | Aggregation.lean |
| marked_deny_leaks / suppress_eq_absent | a visible deny marker leaks undelivered facets; the shipped suppression contributes nothing to the subject's view - equal to the object never existing | AggregationObs.lean |
| stale_knowledge_never_overdenies | a lease-carried knowledge snapshot never denies what fresh knowledge permits; staleness exposure is one-directional and TTL-bounded | AggregationObs.lean |
| verdictOk_binds / authorized_within_ceiling | the engine's verdict check as a predicate: a passing cross-domain verdict is bound to its request on every identifying field and carries an output label under the destination ceiling | Verdict.lean |
| verdict_flows | composed with only_authorized_flows: a low observer's view of a guarded run depends only on the verdict-authorized releases, each ceiling-bounded | Verdict.lean |
| le_jointAuth_iff / coalOk_anti | a coalition's joint authorization is the meet of its members' labels, so a compilation is authorized iff every member may hold it; sub-coalitions of a safe coalition are safe | Coalition.lean |
| coalRun_inv | with the coalition gate, no trace of reads by anyone lets a declared coalition hold knowledge that fires a rule above its joint authorization | CoalitionObs.lean |
| coalition_reads_interfere / deny_forever / verdicts_independent_of_content | a coalition-mate's read can flip a verdict (the observable, stated as a theorem); per subject and object the verdict is then constant over time, and no verdict depends on any object's content | CoalitionObs.lean |
Not the full index, and every name above appears verbatim in
docs/THEOREMS.md, which maps each theorem to the attack it stops.
Two results worth reading together
naive_create_leaks and poly_create_ni are a pair, and the first is
the unusual one. Rather than assuming the existence channel is a problem, the model proves
that a shared namespace leaks the existence of an object a subject may not read, then proves
that polyinstantiation closes it. Stating the attack as a theorem is what makes the fix
checkable rather than asserted.
The de-accession group is the other one. Three separate statements are needed because a
single-step result is not the property anyone actually wants:
deaccess_revokes_read covers the next decision,
deaccess_residue_invisible covers bytes already on the machine, and
temporal_deaccess_blind covers arbitrary traces, so blindness is not a claim
about one moment. revoked_then_blind then says it persists until an explicit
re-grant, which is what stops a re-accession race from quietly restoring access.
Axiom footprint
No sorry in the model. The proof compiles under the Lean
kernel with no admitted goals, and model/check.sh fails if
sorry or admit appears. Be precise about that scan's reach: it
covers model/Pl4Abac/*.lean, the proof files, and it is not a statement about
any other file in the repository. It then prints
#print axioms for 25 headline theorems. The footprint is
[propext, Quot.sound], with Classical.choice appearing in the
ones that reason over finite sets, and never sorryAx. A reader who wants to check that claim runs one script and
reads the output rather than taking this paragraph's word for it.
04Proven, then pinned
A proof of a policy says nothing about the code that runs. The bridge is
engine/ci.sh, which re-runs every differential gate that pins an enforcement
layer to the model and prints one verdict. It builds the Lean oracle and the Cedar policy
decision point first, then runs each gate under a 180 second timeout, standing up an
ephemeral Postgres where a gate needs one.
There are 42 gate invocations. One is a regression gate over known attacks; the other 41 are the E-numbered gates, which carry labels E1 through E41 because E4 and E5 share a line, E24 is unassigned, and E29 and E34 each run as two lines. The full inventory, read out of the file:
| gate | what it checks |
|---|---|
REGRESSION known-attacks denied | the known-attack corpus stays denied |
E1 cedar==lean (5000 cases) | Cedar decision point against the Lean decide, 5,000 random cases at seed 42 |
E2 rls polyinstantiation+diff | row-level security: polyinstantiation, and the predicate differential |
E3 file api == lean | the label-filtered file API against the Lean decision |
E4/E5 identity read+write+escalation | one invocation covering both labels: identity-bound read and write, escalation blocked |
E6 lifecycle primitives | against an ephemeral Postgres: attribute set, principal listing, audit read |
E7 server routes + SPA | server routes and the single-page app, carrying the existence-mask regression |
E8 why engine==oracle | the why path: the running engine's verdict against the compiled oracle |
E9 access provider (offline) | the pluggable access provider, offline |
E10 lease fail-closed + bounded-staleness revoke | reads die at the TTL on partition; revocation bounded by that TTL |
E11 live replication authority->agent | objects and keys reaching the agent from the authority |
E12 key-in-lease + at-rest encryption | content is ciphertext at rest; the key arrives with it and lives in memory |
E13 signed immediate revocation (hard-kill) | a verified signed revocation latches the agent dark |
E14 content-key rotation | rotation by epoch invalidates old key material |
E15 authority HA: replicas + agent failover | interchangeable replicas, and an agent that fails over between them |
E16 DB HA: pg streaming replication + failover | Postgres streaming replication, and failover to a promoted standby |
E17 sync replication: zero-RPO durable de-access | a confirmed de-access survives an instantaneous primary loss |
E18 clock trust: monotonic lease expiry + anti-replay | winding the wall clock back, and replaying an older signed token, both rejected |
E19 label derivation: JS join == proven deriveLabel | the JavaScript label join against the proven derivation |
E20 crypto/lease adversarial (forge/tamper/replay/cross-object) | forged, tampered, replayed and cross-object material all fail closed |
E21 decision-mirror differential fuzz (8000 cases) | the JavaScript decision mirror fuzzed against decide, 8,000 cases |
E22 oracle-domain integrity (no silent coercion) | out-of-domain input to the oracle is rejected rather than coerced |
E23 marking conformance (CAPCO country axis + REL TO grammar) | the country axis and the REL TO banner grammar computed from data |
E25 aggregation-mirror differential fuzz (9200 verdicts) | the knowledge-gate mirror against the proven aggDecide: 6,000 single cases plus 400 stateful traces |
E26 compilation-attack corpus denied (agg gate == oracle) | the compilation attack in every order, elevation on each axis, deny absorbs nothing, and a cleared subject is not over-denied |
E27 aggregation enforced end-to-end (absorb+suppress == oracle) | through the HTTP API: suppression generic and persistent, knowledge durable before delivery, verdicts equal to the compiled oracle |
E28 aggregation at the edge (K-in-lease, offline gate, report-merge) | knowledge rides the signed lease; the offline agent suppresses without marker, absorbs durably, reports upstream, and a wiped machine inherits the suppression from the lease alone |
E29 S3 codec round-trip == oracle printLabel / E29 S3 bucket-policy compiler + simulated read == oracle | labels as S3 object keys round-trip through the oracle's printer; the generated bucket policy, simulated, returns the proven read verdict |
E30 S3 store adapter under moto (placement, relabel order) | the S3 store adapter against a local S3 emulator: object placement by label, relabel ordering |
E31 S3 LIVE: real-account GetObject == Lean decide (enforced) | a real AWS account: S3 itself returns the proven read verdict under the generated bucket policy. Skipped, not passed, without the account environment |
E32 guard: monotone rule == oracle lattice order, routes fail closed, two-person rule | the cross-domain guard's routing rule against the proven lattice order; unknown routes fail closed; two-person release |
E33 guard: verdict binding adversarial (forge/substitute/replay/ceiling/hash/state/expiry) | forged, substituted, replayed, over-ceiling, hash-mismatched, wrong-state and expired verdicts all refused |
E34 guard: cross-domain release end to end (two stacks + mock CDS) / E34 guard: s3 sink LIVE (real bucket, tagged sessions) | a release across two running stacks through a mock cross-domain solution; the second line lands it in a real bucket and is skipped, not passed, without the account environment |
E35 guard: verifyVerdict == proven verdictOk (5000 cases, real signatures) | the engine's verdict check against the Lean predicate verdictOk, 5,000 cases with real signatures |
E36 identity: OIDC verifier adversarial (none/HMAC/confusion/forge/iss/aud/exp/kid) | the token verifier refuses the algorithm-none, key-confusion, forged, wrong-issuer, wrong-audience, expired and unknown-key cases |
E37 identity: claim sync (tombstone blocks re-grant, revoked never cleared) | identity-provider claims synced into principals; a tombstoned principal cannot be silently re-granted |
E38 identity: LIVE Keycloak (verified identity, attributable officer, sink SA) | against a running Keycloak: verified identity, officer actions attributed to a named human, a service account for the sink |
E39 guard: LIVE release end to end into an s3-sinked domain (bucket, codec key, receipt) | a release landing in a real bucket under the codec key with a signed receipt. Skipped, not passed, without the account environment |
E40 guard: receipt-verified ingest (token authenticates, verdict authorizes) | the destination authorizes delivery on the guard's signed verdict alone, verified against a key it registered itself; its ingest credential authenticates the caller and authorizes nothing |
E41 guard: delivery exactly-once under concurrent retries (delivering claim + reclaim) | concurrent officer retries of one release claim delivery through a delivering state and land exactly once |
Read directly from engine/ci.sh. Each row names a script in the repository, so
the mapping from claim to executable check is one file lookup rather than a matter of trust.
Three lines need a real cloud account (E31, the live half of E34, and E39); without it the
script reports them as skipped, and it says in its own summary that a skip is not a pass.
Two of these deserve their own sentence. E22 exists because a differential harness can be
fooled by its own oracle: the Lean oracle's string parsing silently coerced an
out-of-domain field rather than failing, which would have let a differential run compare a
verdict on an input neither side actually received. A gate that checks the gate is the
unglamorous kind of assurance work that only gets written after somebody looks for it. E21
fuzzes the JavaScript decision mirror against decide over 8,000 cases, because
the mirror is the piece most likely to drift and least likely to be noticed when it does.
The kernel gate runs separately, and its scope is narrower
The SELinux differential is not part of ci.sh. It lives in reality/
and is run on its own, because it needs a live kernel with the right policy loaded rather
than an ephemeral container. It queries the loaded policy through libselinux
for a constrained domain pair, which computes the real kernel access decision including the
MCS constraint.
The recorded run is 2026-06-29, on Fedora with the targeted policy, enforcing, MLS enabled:
8 cases, model and kernel agree on all 8. The repository is explicit about
what that does not cover, and so is this page. It exercises categories, which are our
compartments, and not the sensitivity hierarchy, because the targeted policy fixes
sensitivity at s0. It covers the read direction only; the star-property is
proven in Lean but was not differentially tested against the kernel. And it is valid only
for confined domains, since unconfined_t is exempt from MCS and reads across
categories freely, which was observed directly rather than assumed.
05The distributed increment
The single-host arrangement assumes the decision point is reachable. The distributed layer answers the harder question: what does a machine do when it is offline, stolen, or has just been de-accessed and does not know it yet.
An authority mints short-lived signed leases carrying a subject's attributes. A local agent serves reads from its own replica and enforces them against the held lease, contacting the authority only on the renew tick. When it cannot renew, because the network is partitioned or because the authority has revoked the principal, the lease passes its expiry and the agent denies unconditionally. The exposure window is bounded by the lease TTL, and there is no path in the state machine that opens access without a fresh valid lease.
Three theorems in Lease.lean state exactly that.
lease_expired_denies is the decision form: once the lease has expired, every
access is denied, any object, any action, without consulting the policy at all.
lease_expired_blind is the observation form: the agent sees nothing, residue on
the box included. lease_revoked_blind is bounded-staleness revocation: once the
renewed lease no longer carries a compartment, the agent is blind to every object carrying
it, whether or not the lease is currently valid.
The model gates on expiry, not on the signature. The Lean statement is
about time: agentDecide consults the policy only while now < exp
and denies otherwise, so lease_expired_denies is a real statement about the
clock rather than about an opaque validity flag. The other half of lease validity, the
signature check, lives in engine/agent/lease.cjs and is exercised by gate E10
and attacked by E20. It is deliberately outside the model, and a reader assessing the
distributed layer should treat the crypto as tested rather than proven.
The aggregation gate crosses the same boundary the same way. Knowledge and the
compilation rules ride in the signed lease, so the offline agent enforces the gate
against the authority's last-known view plus what this machine has itself absorbed -
recorded durably before delivery, reported upstream on renew, carried back in the
next lease. A stale snapshot is proven never to over-deny
(stale_knowledge_never_overdenies); the exposure direction, a
tipping fact delivered inside one TTL of a cross-channel absorption, is the same
bounded-staleness statement as revocation, and E28 exercises the whole loop
including a wiped machine inheriting suppression from the lease alone.
Around that core the gates cover the operational failures rather than the policy ones: content encrypted at rest under per-object keys that the agent holds only in memory (E12), signed revocation as a hard kill that latches until restart (E13), key rotation by epoch (E14), authority replicas with agent failover (E15), Postgres streaming replication with failover (E16), and synchronous replication so that a confirmed de-access survives an instantaneous primary loss with zero RPO (E17). E18 covers clock trust, using a monotonic clock and anti-replay so that moving the wall clock backwards does not resurrect an expired lease.
The cross-domain increment
Release across domains is the one place the model lets information flow down, and it does
so only through a guard. only_authorized_flows already said that a guarded run
is low-equivalent to running only its authorized releases, with the authorization bit as
an input. The increment replaced that input with a predicate. The engine's release check is
five steps over an ECDSA-signed verdict tuple, and Verdict.lean states those
steps as the predicate verdictOk, with the signature result as the one input
that remains: verdictOk_binds says a passing
verdict is bound to its request on every identifying field and carries an output label
under the destination ceiling, authorized_within_ceiling says a guard cannot
lift that ceiling, and verdict_flows composes with the intransitive result so
that a low observer's view depends only on verdict-authorized, ceiling-bounded releases.
E35 pins the engine's check to the predicate over 5,000 real-signature cases, E33 attacks
it, and E32 and E34 run the release path end to end.
The bound is on the authorization ticket, not the delivered bytes. The signature result enters the predicate as a boolean, so the cryptography is tested (E33, E35) rather than proven, the same stance as the lease. The theorems bound the verdict's output label; that the delivered write lands at that label is enforced by the engine's ceiling re-check at delivery and at ingest, and tested (E34), not proven.
Around the guard, three further increments are pinned rather than proven. Identity: a real OpenID Connect provider verifies tokens and syncs claims into principals, so officer actions attribute to a named human (E36 to E38). Ingest: a destination authorizes delivery solely on the guard's signed verdict, verified against a key it registered itself, so the ingest credential authenticates and authorizes nothing (E40), and concurrent retries of one release land exactly once (E41). Storage: labels become S3 object keys and a bucket policy generated from the label universes makes S3 itself return the proven read verdict; the real account is the gate that earns the word enforced (E31), and the two offline lines (E29, E30) check the codec and the adapter.
06What is not claimed
This is the section that makes the rest of the page worth reading. What is proven is the confidentiality decision logic over all four label axes, including releasability, plus its refinement to the row-level-security predicate, plus kernel agreement on the compartment dimension. The disclosed frontiers, stated as the repository states them and not softened here:
- The trusted-desktop surface. Display, clipboard, peripherals and timing channels are outside the single-machine model. This is where a trusted access tier belongs; the access layer is pluggable, with a no-op provider and a Kasm provider, and the gate for it (E9) runs offline.
- Object and exhaust labelling. The decision point governs known objects, not the per-artifact exhaust a workstation produces: temp files, swap, logs, clipboard, print, network. Enforcing at the application layer while exhaust lands on unlabelled storage is a spill path around the proof. Closing it needs born-labelled artifacts under SELinux MLS with single-label confined sessions, encrypted swap and labelled networking. The data tier itself is already ciphertext at rest. This one is worth reading against the residue claim in section 01: a de-accessed subject is provably blind to labelled residue, and that says nothing about bytes which were never labelled.
- Label reclassification, and label origination generally: the first marking of a new document is a human legal act, out of scope by design.
-
Aggregation and inference - split, because half of it moved. The
rule-based half, classification by compilation, is no longer a frontier: objects
carry content facets, compilation rules elevate combinations, each subject's
absorbed facets persist, and a read that would complete a compilation above the
subject's label is suppressed - absent from the response, indistinguishable from
ordinary non-visibility. That is proven (
naive_compilation_leaks,agg_knowledge_bounded,agg_no_tipping_delivery) and enforced through the running API, pinned by gates E25-E27. The suppression itself is proven silent for the subject's own view: a suppressed object contributes exactly what a nonexistent one does (suppress_eq_absent), and the alternative - a visible deny - is proven to be an aggregation oracle (marked_deny_leaks), which is why the engine ships silence. What remains unclaimed: statistical inference with no written rule, and the fidelity of rule and facet authoring: the guard is exactly as good as the guide it encodes. -
Coalitions - proven in the model, not enforced. Two subjects each
below every trigger, pooling what they read outside the system, defeat the
per-subject gate. A coalition gate now exists in
Coalition.leanandCoalitionObs.lean: a coalition's joint authorization is the meet of its members' labels, so a compilation is authorized only if every member may hold it (le_jointAuth_iff); no trace of reads by anyone lets a declared coalition exceed it (coalRun_inv); and what denial reveals is stated rather than hoped - a coalition-mate's read can flip a verdict (coalition_reads_interfere), after which the verdict for that subject and object is constant over time (deny_forever) and never depends on content (verdicts_independent_of_content). None of it runs: there is no engine mirror and no gate, and this page's rule is that a claim means proven and enforced. Until it ships, the running engine controls compilation by a subject, not by a conspiracy, and comparing views out of band remains the only way to observe a suppression. Open on the model side: a bound on what denial bits reveal across many objects, locality across overlapping coalitions, and the over-denial cost of the meet measured on real rule sets. - Attribute-source integrity. The proof assumes the attributes are honest. It does not verify the pipeline that sets a person's clearance or compartments.
- De-access TOCTOU and replay at the boundaries of the enforcement path.
- Full mechanized refinement to SQL and OS semantics. What exists is predicate-level refinement, which is a weaker statement than a mechanized model of the database.
- Dual citizenship and per-session releasability contexts. Multi-country REL TO objects are seeded-only in v1. Authoring them is the foreign-disclosure-officer increment, and it is not built.
One precision on the releasability axis, because it is easy to overstate. The subject side is a citizenship singleton by construction, so every theorem is exercised on that axis at exactly one element. Generalising the subject side to an authorized-disclosure set re-opens the proof obligations on that axis, in particular the write star-property, which must be re-established to still mean "a write may not widen releasability" when the subject's set is a disclosure authority rather than a nationality. The axis is proven, and it is proven over singletons.
Two further limits worth naming in the same breath. The kernel differential covers the compartment dimension, so full sensitivity-hierarchy enforcement end to end is not demonstrated against a live kernel, and closing it needs an MLS-policy host rather than new research. And timing, termination and probabilistic covert channels need a quantitative model, which this is not.
Separately from the proof: an implementation security review answers a different question from the gates, which is whether anything can get around the enforcement rather than whether the enforcement matches the policy. That review found no injection or authentication bypass and hardened three defense-in-depth gaps, and empirical probing found one real existence leak through a duplicate-key status oracle on the write path, since fixed by masking with a regression added under E7. A full external penetration test against a real deployment is still owed and is not substituted for by any of this.
07Check it rather than believe it
Everything above is re-runnable by someone with the repository in front of them. The proof
rebuilds and kernel-checks with lake build, and model/check.sh
scans for admitted goals and prints the axiom footprint of the headline theorems. The
pinning suite is engine/ci.sh, one command, one verdict, ephemeral Postgres per
gate as required.
The demo is the same check made interactive: an engineer workspace where one identity spans two compartments and a third stays invisible, a security console that grants and de-accesses live, and a decision probe where a reader types a hostile case and sees the running engine's verdict beside the verdict of the compiled Lean oracle on that same case.
Being exact about what that comparison shows, because it is the point where a demo invites the wrong conclusion. A theorem does not agree or disagree with a case; it is a universally quantified statement, already checked by the Lean kernel, that no input can exercise. What the probe compares is two executions, the engine's and the compiled oracle's, and what it detects is drift between the implementation and the proven function. The theorem is named alongside because it is the property that function was proven to have. Agreement on a case is evidence the implementation tracks the model; the guarantee itself comes from the proof, not from the case.
The releasability case is the one worth trying first: a foreign liaison reading a
NOFORN object is denied, and the same read against an object marked
REL TO that liaison's country is permitted.
The repository is private today, so this is what an evaluator with access runs rather than something a reader can clone from this page. The demo is one command and about ten seconds to a browser, and it is available on request.
n0de / access control, proven, then built / mike@0pon.com