How do userset rewrites let a relation-tuple store grant every component of an airframe to its inspectors without one tuple per component?
answer
- stored facts versus derived grants
- the schema states the rule once
- same object, or follow a tuple
- one write when a part moves
- read work replaces write amplification
basics
~20 sThe schema declares a component's signoff relation as the inspector relation of the airframe its own tuple names. Derived grants are computed during the check, so fitting or moving a component costs one tuple write.
solid answer
~50 sA rewrite is a rule in the schema that says a relation is satisfied by other relations rather than only by stored tuples. Two shapes cover almost everything. A **computed userset** stays on the same object: `signoff` on an airframe is satisfied by anyone holding `inspector` on that same airframe. A **tuple-to-userset** rewrite hops: a component's `signoff` is satisfied by the `inspector` relation of whatever object its `airframe` tuple points at. So the only stored facts are the ones your domain actually produces — a component is fitted to an airframe, an engineer is an inspector on it — and every derived grant is computed during the check. The payoff is that moving a pump to another airframe is one tuple write and its authority follows immediately; the cost is that the check now traverses at read time, so every rewrite you add is a level the traversal must walk.
code
json · 27 lines{
"types": [
{
"type": "organisation",
"relations": { "member": { "direct": true } }
},
{
"type": "airframe",
"relations": {
"holder": { "direct": true },
"inspector": {
"union": [
{ "direct": true },
{ "tupleToUserset": { "follow": "holder", "thenRelation": "member" } }
]
}
}
},
{
"type": "component",
"relations": {
"airframe": { "direct": true },
"signoff": { "tupleToUserset": { "follow": "airframe", "thenRelation": "inspector" } }
}
}
]
}go deeper
Learn the distinction between a stored tuple and a derived grant. Only the facts your domain produces are written; everything the schema implies is worked out while the check runs.
Be able to write both rewrite shapes for one concrete rule and say which tuples remain stored. The tuple-to-userset hop — follow a relation to another object, take a relation there — is the piece interviewers probe.
Show that you know the trade you made: write amplification became read work, and each rewrite is a level the traversal walks. Name the relation on your hottest path and say how deep it goes.
A rewrite is a security rule written once and enforced everywhere, so review it as one. The judgment is which rules belong in the graph at all, and where a chain through a meaningless intermediate object has made revocation unreasonable.
## The problem a rewrite solves In an aviation maintenance record system the rule is short to say and expensive to store: *anyone who may sign off an airframe may sign off the components fitted to it*. An airframe carries thousands of components, an organisation holds dozens of airframes, and components are removed, overhauled and refitted to different airframes constantly. If derived grants had to be stored, fitting one pump would mean writing a grant for every current inspector, and removing one inspector would mean deleting a row for every component on the airframe. The write amplification is the whole problem, and it gets worse: those derived rows can drift out of step with the facts that produced them, and you now have two sources of truth about the same authority. A **userset rewrite** removes the derived rows entirely. The schema states the rule once; the stored tuples stay at the size of your real domain facts; the derivation happens during the check. ## Two rewrite shapes | shape | what it says | example in this setting | |---|---|---| | computed userset | this relation on this object is also satisfied by that relation on the **same** object | `signoff` on an airframe is satisfied by `inspector` on that airframe | | tuple-to-userset | follow this object's tuples of relation X to another object, then take relation Y **there** | a component's `signoff` is the `inspector` of the airframe its `airframe` tuple names | The two compose. An airframe's `inspector` can itself be a union of *directly granted inspectors* and *a tuple-to-userset rewrite through the airframe's `holder` tuple to the holding organisation's `member` relation*. Now three facts — the organisation holds the airframe, the engineer is a member, the pump is fitted — produce authority over the pump with nothing derived stored anywhere. ## What is stored and what is computed - **Stored:** custody (`airframe#holder@org`), membership (`org#member@user`), fitting (`component#airframe@airframe`), and direct exceptions (`airframe#inspector@user`). - **Computed at check time:** every grant that follows from those, at whatever depth the schema's rules imply. The union in a rewrite is important: declaring `inspector` as *direct tuples* **or** *the holder's members* means an engineer can be an inspector by either route, and losing one route does not necessarily remove the authority. That matters for revocation, and it is the thing candidates most often get wrong — removing the membership does not revoke an engineer who also holds a direct tuple. ## The payoff: a component moves When the pump is removed and fitted to a different airframe, the correct migration of authority is: 1. delete `component:hyd-pump-77#airframe@airframe:G-ABCD`; 2. write `component:hyd-pump-77#airframe@airframe:G-EFGH`. Two writes, and the set of engineers who may sign off that pump changes wholesale, because it was never stored in the first place. With materialised grants the same move is a bulk rewrite whose failure halfway through leaves a component signable by inspectors of an airframe it is no longer on. ## What a rewrite costs Every rewrite you add is a level the check has to walk, and a tuple-to-userset rewrite multiplies: the store must read the tupleset, then ask the same question again at each object it reaches. A rule that reads as one English sentence can be four lookups deep once `holder` and parent organisations are in the path. You are trading write amplification for read work, deliberately, and you should know which relations in your schema are on the hot path of an ordinary request. ## Where rewrites go wrong - **Too broad.** Declaring `signoff` as satisfied by *any* relation on the airframe hands sign-off to whoever holds a purely administrative relation such as `viewer`. The rewrite is the security rule; a sloppy one grants silently and nothing in the stored tuples looks wrong. - **A chain through a meaningless intermediate.** If an object exists in the path only to make the traversal work, every rule that passes through it becomes hard to reason about and hard to revoke. - **Cycles.** Two relations that rewrite to each other can loop; the store bounds this, but the schema is still wrong and it will surface as a depth error rather than as a denial. - **Rewrites doing conditions' work.** *Only during a scheduled maintenance window* is not a relationship, and forcing it into the graph as a synthetic object is how a tuple schema becomes unreadable. ## How to review one Read each relation aloud as a sentence starting with *anyone who…* and check that the sentence is the rule you actually meant. Then ask the opposite question for each: if this relationship ends, what authority ends with it, and what survives because it was granted by another arm of the union?
- An engineer is removed from the holding organisation but can still sign off the airframe's components. What happened?The airframe's `inspector` relation is a union, and the engineer also holds a direct `inspector` tuple on that airframe. Removing one arm of a union removes only the authority that came through it. Revocation in this model means finding every arm that grants, which is precisely what an expand-style query is for.
- When would you materialise a derived grant as a stored tuple anyway?When a specific rewrite is measurably too deep or too wide on a hot path and the staleness of a background writer is acceptable for that relation. It is a deliberate exception: you now have two sources of truth for that authority and must own the lag and the repair job.
- Does a rewrite let you express `everyone except the engineer who performed the work`?Not as a rewrite in the basic model — the union of relations has no negation, and a rule of that shape is a condition on the decision rather than a relationship. Some schemas add an exclusion operator for exactly this, but reaching for one is a signal that the rule may not be relationship-shaped at all.
A tuple-to-userset rewrite is like a maintenance authority that reads whoever is signed as inspector on the airframe this part is fitted to. The paperwork never lists the engineers by name, so refitting the part to another airframe changes who may sign it without reissuing a single document.
saying these in an interview costs you the question
- Thinks inherited grants must be written out as stored tuples
- Believes a rewrite changes what is stored rather than what is computed
- Cannot say which relations are read at check time
- Assumes removing one arm of a union revokes the authority
- Treats a time window or an attribute test as a relationship