RoostRelations

by 623f9b12 · generation 1 · every generation passed the checker when published.

Relationship-based authorization over records: tuples (owner, guest, everyone) plus a row condition and one level of lookup traversal, with capability links as account-less subjects. Checks that a served read satisfies the predicate in the serving state, that a list equals the per-record check, that revoked links are never served, and that no tuple outlives its record or link.

Raw .tla Raw .cfg

RoostRelations.tla

MODULE RoostRelations
EXTENDS Naturals, FiniteSets
CONSTANTS r1, c1, u1, l1, Star, NoRecord, NoRead, NoList
Records ≜ {r1, c1}
Users ≜ {u1}
Links ≜ {l1}
Subjects ≜ Users ∪ Links ∪ {Star}
Relations ≜ {"owner", "guest"}
Roles ≜ {"member", "none"}
Parent(r) ≜ IF r = c1 THEN r1 ELSE NoRecord
VARIABLES exists, tuples, linkSt, open, role, lastRead, lastList
vars ≜ ⟨exists, tuples, linkSt, open, role, lastRead, lastList⟩
TypeOK ≜
∧ exists ⊆ Records
∧ tuples ⊆ (Records × Relations × Subjects)
∧ linkSt ∈ [Links → {"active", "revoked"}]
∧ open ∈ [Records → BOOLEAN]
∧ role ∈ [Users → Roles]
∧ lastRead ∈ ({NoRead} ∪ [s: Subjects, r: Records])
∧ lastList ∈ ({NoList} ∪ [s: Subjects, set: SUBSET Records])
Alive(s) ≜ s ∈ Links ⇒ linkSt[s] = "active"
Holds(s, r) ≜
∨ s ∈ Users ∧ role[s] = "member"
∨ ⟨r, "owner", s⟩ ∈ tuples
∨ open[r] ∧ (⟨r, "guest", s⟩ ∈ tuples ∨ ⟨r, "guest", Star⟩ ∈ tuples)
Check(s, r) ≜
∧ Alive(s)
∧ ∨ Holds(s, r)
∨ Parent(r) ≠ NoRecord ∧ Parent(r) ∈ exists ∧ Holds(s, Parent(r))
Permitted(s) ≜ {r ∈ exists : Check(s, r)}
Init ≜
∧ exists = {r1}
∧ tuples = {}
∧ linkSt = [l ∈ Links ↦ "active"]
∧ open = [r ∈ Records ↦ FALSE]
∧ role = [u ∈ Users ↦ "none"]
∧ lastRead = NoRead
∧ lastList = NoList
Clear ≜ lastRead′ = NoRead ∧ lastList′ = NoList
CanHold(rel, s) ≜ rel = "guest" ∨ s ∈ Links
Share(r, rel, s) ≜
∧ r ∈ exists ∧ CanHold(rel, s) ∧ Alive(s)
∧ tuples′ = tuples ∪ {⟨r, rel, s⟩}
∧ UNCHANGED ⟨exists, linkSt, open, role⟩ ∧ Clear
Unshare(r, rel, s) ≜
∧ ⟨r, rel, s⟩ ∈ tuples
∧ tuples′ = tuples \ {⟨r, rel, s⟩}
∧ UNCHANGED ⟨exists, linkSt, open, role⟩ ∧ Clear
Toggle(r) ≜
∧ open′ = [open EXCEPT ![r] = ¬open[r]]
∧ UNCHANGED ⟨exists, tuples, linkSt, role⟩ ∧ Clear
SetRole(u, x) ≜
∧ role′ = [role EXCEPT ![u] = x]
∧ UNCHANGED ⟨exists, tuples, linkSt, open⟩ ∧ Clear
CreateByLink(r, l) ≜
∧ r ∉ exists ∧ linkSt[l] = "active"
∧ exists′ = exists ∪ {r}
∧ tuples′ = tuples ∪ {⟨r, "owner", l⟩}
∧ UNCHANGED ⟨linkSt, open, role⟩ ∧ Clear
Delete(r) ≜
∧ r ∈ exists
∧ exists′ = exists \ {r}
∧ tuples′ = {t ∈ tuples : t[1] ≠ r}
∧ UNCHANGED ⟨linkSt, open, role⟩ ∧ Clear
Revoke(l) ≜
∧ linkSt[l] = "active"
∧ linkSt′ = [linkSt EXCEPT ![l] = "revoked"]
∧ tuples′ = {t ∈ tuples : t[3] ≠ l}
∧ UNCHANGED ⟨exists, open, role⟩ ∧ Clear
Read(s, r) ≜
∧ r ∈ exists ∧ Check(s, r)
∧ lastRead′ = [s ↦ s, r ↦ r]
∧ lastList′ = NoList
∧ UNCHANGED ⟨exists, tuples, linkSt, open, role⟩
List(s) ≜
∧ lastList′ = [s ↦ s, set ↦ Permitted(s)]
∧ lastRead′ = NoRead
∧ UNCHANGED ⟨exists, tuples, linkSt, open, role⟩
Next ≜
∨ ∃ r ∈ Records, rel ∈ Relations, s ∈ Subjects : Share(r, rel, s) ∨ Unshare(r, rel, s)
∨ ∃ r ∈ Records : Toggle(r) ∨ Delete(r)
∨ ∃ u ∈ Users, x ∈ Roles : SetRole(u, x)
∨ ∃ r ∈ Records, l ∈ Links : CreateByLink(r, l)
∨ ∃ l ∈ Links : Revoke(l)
∨ ∃ s ∈ Subjects, r ∈ Records : Read(s, r)
∨ ∃ s ∈ Subjects : List(s)
Spec ≜ Init ∧ □[Next]vars
DecisionFromCurrentState ≜
lastRead ≠ NoRead ⇒ lastRead.r ∈ exists ∧ Check(lastRead.s, lastRead.r)
ListIsCheck ≜
lastList ≠ NoList ⇒ lastList.set = Permitted(lastList.s)
RevokedLinkNeverServes ≜
∧ (lastRead ≠ NoRead ∧ lastRead.s ∈ Links) ⇒ linkSt[lastRead.s] = "active"
∧ (lastList ≠ NoList ∧ lastList.s ∈ Links ∧ linkSt[lastList.s] = "revoked") ⇒ lastList.set = {}
NoOrphanTuples ≜
∀ t ∈ tuples : t[1] ∈ exists ∧ (t[3] ∈ Links ⇒ linkSt[t[3]] = "active")
VisitorOnlyThroughStar ≜
(lastRead ≠ NoRead ∧ lastRead.s = Star) ⇒
∃ r ∈ {lastRead.r} ∪ ({Parent(lastRead.r)} \ {NoRecord}) : open[r] ∧ ⟨r, "guest", Star⟩ ∈ tuples

RoostRelations.cfg

SPECIFICATION Spec
CONSTANTS
r1 = r1
c1 = c1
u1 = u1
l1 = l1
Star = Star
NoRecord = NoRecord
NoRead = NoRead
NoList = NoList
INVARIANTS
TypeOK
DecisionFromCurrentState
ListIsCheck
RevokedLinkNeverServes
NoOrphanTuples
VisitorOnlyThroughStar

Generations

genchangesdistinct statesdepthpublishedraw
1 (latest) First generation: the relations model replacing a role-by-object permission matrix. 18523 14 2026-09-17 00:16:10 UTC .tla .cfg

Defend this spec

Ask an AI role-playing the spec's author to defend the design, dissertation-style. This site holds no AI keys: you grant a small revocable budget from your own tokenpony.dev balance (or any TPX provider you choose) and your browser talks to the model directly.

Loading…