Skip to content

feat(lattice): parametrise Typing and Noninterference over a Lattice record (LNT-01 sibling) #9

Closed

Description

@hyperpolymath

Summary

PROOF-STATUS (at 833715c) lists under Open: "Arbitrary lattices (parametric in a Lattice record, with the census in N-6 then certifiable the way resource-algebra's is)". This issue is that step. It has a first customer waiting.

metadatastician/lintel#2 (LNT-01) adds a privacy lattice whose laws typecheck under --safe --without-K --no-libraries --double-check (Agda 2.6.4.3), in src/Lintel/Lattice.agda:

  • Carrier: reader sets over the oblivious-DNS roles {client, proxy, target}, with eight labels.
  • Operations: ⊑ is reverse inclusion, ⊔ is intersection, ⊓ is union, ⊥ = anyone and ⊤ = no-one.
  • Shape: joins and meets are proved for every pair, so it is a lattice, not a poset completed by hand.

By owner decision (2026-10-14), Lintel proves the laws as lemmas and holds no copy of the record. The record is defined once, here, and Lintel instantiates it by pin. Lintel's tini instance, and with it its "self-defeating compositions are unconstructible" claim, waits on this issue.

Proof work that applies now

ID Claim Status Artefact
N-1 TINI over the two-point lattice PROVEN Noninterference.tini (re-checked by Lintel's gate at 833715c)
N-6 laws census: only ⊔-L₁, ⊔-L₂, H ⊔ y = H ASSUMED by inspection nothing parametric to certify against yet
— the same census stated at Lintel's lattice PROVEN Lintel ⊔-anyone₁, ⊔-anyone₂, no-one-⊔, anyone-⊔
— parametric Lattice record OPEN this issue

Census by inspection (to be certified, not trusted)

This is a reading of Noninterference.agda at 833715c. Each two-point step is listed with the general law it appears to need once the low observer becomes an observer level o, with s ≈ₒ s' meaning the stores agree on every variable x with label x ⊑ o:

Where Two-point use General form From
eval-low (plus) ⊔-L₁, ⊔-L₂ x ⊔ y ⊑ o → x ⊑ o and → y ⊑ o ⊔ upper bounds + ⊑-trans
eval-low (lit) lab (lit _) = L ⊥ ⊑ o a least element
tini (assign to the observed variable) low-pc : x ⊑ L → x ≡ L pc ⊔ lab e ⊑ label x ⊑ o → lab e ⊑ o upper bound + trans
tiniIf / tiniW case split ℓ ∈ {L, H} by pattern Dec (ℓ ⊑ o) decidable order
confine (secret pc) H ⊔ y = H pc ⋢ o → pc ⊔ y ⋢ o, and an assignment under pc ⋢ o only reaches variables with label x ⋢ o upper bound + trans

The candidate minimal record is: a carrier, ⊑ with transitivity, ⊔ with both upper-bound laws, ⊥ with ⊥ ⊑ x, and decidable ⊑. By this reading, the proof would not use antisymmetry, leastness of ⊔ or a top. Whether that reading is right is exactly what minimal-laws.sh should settle.

Proposed work

  1. Record. Add a Lattice record (in SecretTypes/Lattice.agda or a new module) and keep the two-point lattice as its first instance, so Witness and tests/reject stay as they are.
  2. Parametrise. Make Typing and Noninterference take the record, an observer level and a label : Var → Carrier instead of the fixed L/H. Lintel's labels are per field, so lo/hi become two fields whose labels are parameters.
  3. N-6 ASSUMED → TESTED. Add scripts/minimal-laws.sh, following the choreographic-types K-4 pattern: check Noninterference against a record carrying only the named laws.
  4. Proofs CI. proofs.yml is DESIGNED in PROOF-STATUS. The Debian 13 / agda-bin=2.6.4.3-1+b2 recipe that choreographic-types and Lintel use would close it.

Acceptance criteria

  • Lattice record defined once in this repo; the two-point lattice is an instance and N-1…N-5 still hold at it.
  • tini stated and proved over the record (observer level and variable labelling as parameters).
  • minimal-laws.sh passes against a record with only the census laws (N-6 → TESTED), and fails if one of them is removed.
  • The commit that lands this is announced on LNT-01 so Lintel can re-pin and instantiate.

Out of scope

TSNI, declassification and multiple variables are each already Open in PROOF-STATUS. Lintel's lattice itself stays in Lintel.

As this lands

Lintel re-pins scripts/fetch-siblings.sh to the landing commit, packages its lemmas as one record value, instantiates tini once per role observer (observer client|proxy|target), and moves its README row from OPEN to PROVEN. Note for that re-pin: Lintel.Lattice declares its own Dec, because SecretTypes.Prelude has none at 833715c. If this work adds Dec to the Prelude, Lintel drops its copy.

Activity

  1. hyperpolymath commented on Oct 19, 2026

    @hyperpolymath
    OwnerAuthor

    Landed in #10 as ccdcb3ec42792337a9ab6047e1f99de9d20a4f96, a squash commit signed by GitHub. Its tree is identical to the PR head 9bd1e94, where the Agda proofs job passed in CI.

    Against the acceptance criteria:

    • The Lattice record is defined once, and the two-point lattice is an instance. The record is in SecretTypes.Lattice.Record and the instance is SecretTypes.Lattice.two-point. N-1 to N-5 still hold at it: Noninterference.tini, eval-low and confine keep their original statements, and Witness and tests/reject are unchanged.
    • tini is stated and proved over the record. It is Noninterference.Generic.tini : (V : Observer 𝓛) → TINI (Observer.sees V), with the labelling label : Var → Carrier as a module parameter. Observers are down-closed sets of labels; principal o is the "level o" observer.
    • minimal-laws.sh passes with only the census laws and fails if one is removed. N-6 moved ASSUMED → TESTED. The census differs from the hypothesis here:
      • generic TINI uses ⊔-upper₁, ⊔-upper₂ and observer down-closure;
      • ⊑-trans is needed only to build principal;
      • neither ⊥ ⊑ x nor decidable ⊑ is used.
      • SecretTypes.Countermodels shows each law is necessary (N-8).
    • Announced on LNT-01. That is LNT-01: instantiate secret-types' generic TINI at the reader-set lattice (L-6) metadatastician/lintel#11, which carries the re-pin, drops Lintel's local Dec (now a hard Multiple definitions error) and adds a checked instance snippet. A coalition-observer follow-up is Coalition observers: state TINI for colluding roles and narrow assumption A-1 metadatastician/lintel#12.

    The Prelude gained ⊥-elim, Dec, _≟_, dec-stable and ¬¬-dec; Lintel must drop its own Dec when it re-pins.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew capability or improvement to existing behaviour

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions