- Feature Name: `write-tiers` (the bar for a write scales with how
permanent the write is; a tier that costs less may ask less)
- Start Date: 2026-09-12
- Status: Draft; its three open questions are settled (see the last
three sections). Implementation follows teams (ticket 8318bd2819ca),
by decision: teams ships against the store tier first, and the
companion half of its membership floor arrives with this RFC.
- Depends on: RFC 0004 (capability letters are the native model); RFC
0001 §8 (the OLTP tier is forge-local state, the DAG is truth); RFC
0015 (companions — this RFC amends §"What the parent keeps"); RFC 0008
(roles as the interface over the letters)
- Amends: RFC 0015, which says the companion's name never reaches a
gate. It reaches one here, for writes only.
- Precedent: local tickets already exist as a lower tier
(`docs/local-tickets.md`, `local_ticket`, `ticket.intake`), with the
explicit rationale that an append-only artifact history "has no answer
but 'it is in there now'". This RFC states the rule that tier was an
instance of.
## Summary
quarry stores writes in three places with wildly different costs, and
asks the same price for all of them.
A check-in, a ticket artifact, a wiki page and a forum post in the
repository's own store are permanent, synchronized to every clone, and
unsayable-again. A post in a **companion** store is permanent but
separable — it is not in the store anybody clones for the code. A
**local** ticket is in the forge's database: mutable, deletable, and
carried by nobody.
Those are not the same act, and requiring the same authority for all
three has a visible consequence: a project that wants to take outside
contribution has to choose between letting strangers write its DAG and
letting them do nothing at all.
This RFC states one rule — **the bar may differ per tier, and a tier
that costs less may ask less** — and applies it to the two tiers that
exist. It introduces no new capability letter.
## The tiers, and what a write costs in each
| tier | where | permanence | who carries it |
|---|---|---|---|
| **store** | the repository's own DAG | permanent, unsayable | everyone who clones |
| **companion** | a bound store (RFC 0015) | permanent, separable | whoever clones *that* |
| **local** | forge OLTP | mutable, deletable | nobody |
The ordering is the whole RFC. A store write is the most expensive thing
a stranger can do to a project, because it is the one nobody can undo
and everybody downloads. A companion write is permanent but costs the
code store nothing: it does not enter the repository people clone to
build, it does not grow the artifact history CI walks, and it can be
detached. A local write costs almost nothing and can be discarded.
**So the bar should follow the cost.** Anything else is either too
generous at the top — strangers writing the DAG — or too mean at the
bottom, which is where quarry is today.
## Rule
> An authority that governs writes MAY be set per tier. A lower tier MAY
> hold a lower bar than the tier above it. A lower tier MUST NOT be able
> to raise the bar of the tier above it, and MUST NOT be able to grant
> anything the tier above it denies about *visibility*.
Two halves, and the second is what keeps it safe.
**Writes may relax downward.** A companion may let more people post than
the parent lets push. The local tier may let more people file than the
store lets mint.
**Visibility never relaxes.** Whether a reader may know a repository
exists, and read it, stays the parent's answer in every tier. Otherwise
a private repository's companion becomes a side door: bind a forum,
grant a stranger, and they learn the repository exists and can read
discussion of code they cannot see. RFC 0015 already says the parent
answers "a name they may not see", and that does not change.
The rule is a **union**, like every other authority in quarry (RFC
0004): a tier adds letters, never subtracts them. A relaxed companion
cannot take posting away from somebody the parent already granted it to.
## What changes in RFC 0015
0015 §"What the parent keeps" currently says every forum question — may
this account post, reply, moderate, announce — is answered by the
parent's capability set, and that the companion's name never reaches the
gate. That is amended to split the question:
- **Read and visibility** stay exactly as specified: answered by the
parent, through the parent's name, including its not-found answer.
- **Write letters** — posting, replying, attaching, and posting without
moderation — become the union of the parent's and the companion's own.
Moderation itself does not; see §"Which letters a companion may
relax" for the exact split and why judgement stays with the parent.
So the companion gains what 0015 §"What the companion gets" does not
currently list: **its own grants, for writes only.** It still has no
identity model of its own; accounts remain forge-global, and the
companion's People surface is a section on the parent's settings page
rather than a page on a store that has no page.
This is the point of a companion that 0015 did not state. 0015 justifies
the separation on lease contention and store size — "a busy thread never
waits on a push". The other reason is **policy**: it is a lower burden
to take outside contribution somewhere that is not the store holding the
code, and until a companion can hold a lower bar, that reason is
unavailable.
`forum.bind` therefore becomes an access decision and not only an
operational one, and must say so where it is offered.
## What changes for local tickets
`ticket.intake` (local) and `ticket.new` (store) both gate on `n`, so
the local tier cannot be more relaxed than the store today. The letter
`n` means "file tickets", and fossil had one tier to file into.
`n` becomes the **store** door and only the store door. `ticket.intake`
gates on `r` — read tickets — on the reasoning that quarry's local tier
is deletable and promotable, so the bar for filing into it should be
"you can see the tracker", not "you may write the DAG".
Practically this changes little for existing deployments: fossil's stock
`nobody` category holds `r`, so anonymous intake on a public project
behaves as before. What it makes possible is a repository that takes
tickets from anyone while minting nothing in its store until an admin
promotes one — which is what the local tier was built for and could not
express.
## No new capability letter
The tempting shape is a new letter meaning "may mint a permanent object
in this store", gating `ticket.new`, `forum.post` and wiki creation.
quarry has invented a letter before — `8`, for CI, on the grounds that
fossil has no CI and an unused digit cannot collide with an imported
user table.
It is rejected here. Every existing grant holding `3` or `n` would lose
thread and ticket creation until backfilled, and Reader — which holds
`3` — would silently become reply-only. A migration that changes what
an existing role means is a poor trade for a distinction the tiers
already draw structurally: a write's tier is a property of *where it
lands*, which the forge knows without asking the letters.
## What this does not propose
- A separate identity model for any tier. Accounts stay forge-global.
- Any relaxation of **read** or visibility anywhere.
- A companion for anything but the forum. 0015 defines one feature and
this RFC adds none.
- Moving existing artifacts between tiers. Promotion (local → store)
exists; demotion does not and is not proposed.
- Letting a tier restrict. Every tier adds.
## Consequences to state plainly
**Three routes to one authority.** A person may hold a letter directly,
through a category, or through a lower tier's own grant. Any page that
answers "who may do this" must name the route, not just the result —
the same obligation the union rule already creates elsewhere.
**Binding a forum widens who may post.** That is the feature, and it
must be said at the moment of binding rather than discovered afterwards.
**A relaxed companion is still permanent.** Separable is not deletable:
a companion's history is a DAG like any other, and shunning is the only
removal. The local tier is the one that forgets.
## Which letters a companion may relax
Posting relaxes. Judgement does not.
| letter | what it is | relaxes? |
|---|---|---|
| `3` | post in the forum | yes |
| `B` | attach files to forum posts | yes |
| `4` | post without moderation | **yes** |
| `5` | moderate the forum | no |
| `6` | grant moderation exemptions | no |
`4` relaxes because it is about the *contributor*: a companion exists to
take outside contribution, and a queue nobody can clear is not an open
door. Deciding what gets removed (`5`) and who is trusted to skip the
queue (`6`) is judgement about the project, and judgement stays with
people who hold something on the parent.
The consequence, stated rather than discovered: a companion can be
relaxed to the point where anybody may post unmoderated, and only
somebody with standing on the parent can then take a post down. A
project that wants community moderation of a community forum cannot have
it under this rule. That is deliberate — a moderator who holds nothing
on the parent can shape what the project's forum says about the project
— and it is the one place this RFC chooses the cautious side.
## Unbinding drops the relaxed grants
When a companion is unbound it becomes a repository in its own right,
and the grants it held as a companion are **removed**, not inherited.
The argument for inheriting them is that nothing is lost and nobody is
surprised. It was rejected: a grant made in the context of "this is X's
forum, and the bar here is low because it is not X's code" does not
obviously mean the same thing once the store is a repository of its own.
Carrying it over would silently turn a relaxed forum grant into a
standing grant on a new repository.
Dropping them is the safe direction — it removes access rather than
creating it — but it is not a quiet operation, and the surface must not
treat it as one. **Unbinding MUST name who loses access before it
happens.** The forge knows exactly who: the accounts holding a write
grant on that store. A confirmation that lists them is the difference
between a decision and an accident.
## The wiki stays whole, for now
RFC 0015 declined to split the wiki because nobody had asked. The policy
argument in this RFC is new evidence rather than a request, so the scope
does not change: **`forum` remains the only companion feature.**
Recorded so the next person does not have to rediscover it: the wiki
*could* be split on exactly these grounds, and the reason not to is that
the demand is hypothetical, not that the rule fails to reach it. The
wiki's tabs, search and embedded-docs surfaces all assume one store, so
the work is larger than the forum split was and should be paid for by a
real want.
## Open questions
None outstanding. Three questions this RFC opened were settled above:
which letters relax, what unbinding does, and whether the wiki follows.