1558cc3a8b
Documentation-only minor. The guide had drifted since it was first written; brought back in sync with v0.7.0–v0.29.0: - "Signing in" rewritten: email + one-time-code, optional passcode, trust-device 30d, optional Turnstile, and the beta-request → pending → admin-grant gate, plus admin-create + invite-claim. The vestigial email allowlist is no longer described as the gate. - "Proposing a new RFC": four → five fields (optional use-case #26) + AI tag-suggestion disclosure (#27). - "Roles & permissions": documents the pending state. - New "Invitations, cross-references, and contribution requests" section (#12 owner invites; #28 auto-link / create-RFC / ask-to- contribute). - New "Privacy and cookies" section (#11/#13). No code/schema/API/config/overlay/secret change — DOCS.md is served verbatim by /api/docs. VERSION + frontend/package.json bumped to 0.30.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
699 lines
28 KiB
Markdown
699 lines
28 KiB
Markdown
# Using the RFC app
|
|
|
|
This is the user-facing guide to the Wiggleverse RFC framework — how to
|
|
read what's here, propose a new RFC, contribute to one that already
|
|
exists, and understand who is allowed to do what.
|
|
|
|
This guide describes the framework. Individual deployments brand and
|
|
configure themselves independently — the name in the header and the
|
|
corpus the RFCs are about belong to the deployment, not to this
|
|
document.
|
|
|
|
For the *why* of the framework, read the [philosophy](/philosophy).
|
|
For the binding technical contract, see `SPEC.md` in the repository.
|
|
|
|
---
|
|
|
|
## Reading without signing in
|
|
|
|
You can read the catalog and every public RFC without an account.
|
|
Anonymous visitors can:
|
|
|
|
- Browse the catalog of super-drafts and active RFCs.
|
|
- Open any RFC and read its canonical body.
|
|
- Read any public branch — its diff and its chat thread.
|
|
- Read any pull request — its diff, its conversation, its review
|
|
comments.
|
|
- Read the discussion that has accumulated on an RFC's main view.
|
|
|
|
Reading is open by design. The framework's claim is that the *argument
|
|
behind a definition* is the evidence that the definition was earned,
|
|
and an argument that disappears behind a sign-in wall stops carrying
|
|
that evidence.
|
|
|
|
What you cannot do without an account: chat, propose a new RFC,
|
|
create a branch, open a PR, drop a flag, or post on a discussion
|
|
thread. Every write affordance is replaced with a sign-in prompt.
|
|
|
|
---
|
|
|
|
## Signing in
|
|
|
|
Anyone can start the sign-in flow with their own email address — there
|
|
is no invite-only allowlist. Sign-in is passwordless:
|
|
|
|
1. **Enter your email.** If the deployment has human verification
|
|
enabled (a Cloudflare Turnstile challenge), you complete it here.
|
|
2. **Enter the one-time code.** The app emails you a short numeric
|
|
code; entering it signs you in. Codes expire after a few minutes,
|
|
and repeated wrong entries briefly lock the email.
|
|
3. **Set a passcode (optional).** After your first code sign-in you
|
|
can set a passcode. On later visits you sign in with email +
|
|
passcode, with the one-time code as the forgot-passcode fallback.
|
|
4. **Trust this device (optional).** You can mark a device trusted for
|
|
30 days to skip the code/passcode step on it. Trusted devices are
|
|
listed in your settings and can be revoked individually or all at
|
|
once.
|
|
|
|
### Getting write access
|
|
|
|
Signing in gives you an account, but write access is gated. The first
|
|
time you sign in you're asked for your first name, last name, and a
|
|
short note on why you'd like access; you then land on a "request in
|
|
review" page. While your account is **pending**, you can read
|
|
everything an anonymous visitor can but cannot write — no chat,
|
|
propose, branch, PR, or discussion post. Once an admin **grants** your
|
|
account you become a **contributor**, the role that carries every
|
|
write affordance the app exposes, scoped by the per-RFC and per-branch
|
|
rules described below.
|
|
|
|
An admin can also create your account ahead of time and email you an
|
|
invite link. Clicking it claims the account and signs you in with the
|
|
role the admin assigned, skipping the one-time-code step.
|
|
|
|
---
|
|
|
|
## Proposing a new RFC
|
|
|
|
A new RFC begins as a proposal. The "+ Propose new RFC" button at
|
|
the bottom of the catalog opens a small modal that collects five
|
|
things:
|
|
|
|
- **Title.** The word, concept, or topic this RFC would define.
|
|
- **Slug.** A kebab-cased identifier derived from the title. It is
|
|
the entry's stable handle from this moment until it graduates;
|
|
collisions with existing entries or open proposals are caught
|
|
inline.
|
|
- **Pitch.** One or two paragraphs answering *why this RFC is
|
|
needed*. This becomes the body of the entry.
|
|
- **Use case.** Optional. *What will you be using this RFC for?* —
|
|
the concrete application driving the proposal, as distinct from the
|
|
abstract case for it. Leaving it blank is fine.
|
|
- **Tags.** Optional. If the deployment has AI tag suggestion
|
|
enabled, suggested tags appear as you fill the form (with an inline
|
|
note that the text you've entered is sent to the model that
|
|
generates them); you can accept, dismiss, or type your own.
|
|
|
|
Submitting the modal does one concrete thing: it opens a pull
|
|
request against the framework's meta repository, adding one new
|
|
file under `rfcs/`. There is no other Git artifact and no other
|
|
side-effect. You are returned to the **pending-idea view** for the
|
|
new proposal.
|
|
|
|
A pending idea is publicly readable but not yet a super-draft. The
|
|
catalog surfaces it in a "Pending ideas" disclosure at the bottom
|
|
of the list. A conversation can accumulate on the pending-idea view
|
|
before it is admitted — contributors can argue, in public, about
|
|
whether the entry belongs in the catalog at all.
|
|
|
|
Three outcomes are possible:
|
|
|
|
- **Merge.** An admin or owner merges the proposal PR. The entry
|
|
becomes a super-draft and graduates from the "Pending ideas"
|
|
section into the main catalog. Any conversation that accumulated
|
|
on the pending-idea view migrates with it.
|
|
- **Decline.** An admin or owner declines, attaching a written
|
|
comment. You see the comment on your next visit, along with a
|
|
one-click affordance to revise and re-propose.
|
|
- **Withdraw.** You can withdraw your own proposal at any time. The
|
|
entry will not appear in any default view; the conversation that
|
|
accumulated stays attached to the closed PR as historical record.
|
|
|
|
You are automatically the first owner of any RFC you propose. The
|
|
claim flow described under [Roles & permissions](#roles--permissions)
|
|
is for *other* contributors to add themselves as owners later, not
|
|
for the proposer.
|
|
|
|
---
|
|
|
|
## What a super-draft is
|
|
|
|
A super-draft is an entry that has been admitted to the catalog but
|
|
does not yet have its own dedicated repository. Most of the
|
|
argument that shapes a definition happens here. The framework
|
|
assumes — and the philosophy explicitly invites — that many
|
|
super-drafts will not survive the argument, and that is fine. The
|
|
entries that do survive earn their place in the catalog by being
|
|
defensible in public.
|
|
|
|
Opening a super-draft from the catalog gives you the same surface
|
|
an active RFC uses:
|
|
|
|
- The canonical body in the centre, read-only by default.
|
|
- A chat thread on the right where the public conversation lives.
|
|
- A breadcrumb dropdown listing any in-flight edit branches and
|
|
any open body-edit PRs against this entry.
|
|
- A "Start Contributing" affordance that cuts a fresh edit branch
|
|
and lands you in contribute mode.
|
|
|
|
Edits to a super-draft body propagate through pull requests against
|
|
the meta repository — there is no dedicated RFC repository yet.
|
|
|
|
---
|
|
|
|
## What an active RFC is
|
|
|
|
An active RFC is an entry that has been **graduated**. It has its
|
|
own dedicated repository, an integer `RFC-NNNN` identifier, and a
|
|
canonical body file (`RFC.md`) inside that repository. The catalog
|
|
distinguishes super-drafts and active RFCs at a glance.
|
|
|
|
Opening an active RFC gives you:
|
|
|
|
- `main` — the canonical body, always read-only. Changes to `main`
|
|
arrive exclusively through pull requests.
|
|
- A breadcrumb listing every open branch and pull request on this
|
|
RFC.
|
|
- A per-branch chat thread on the right. Each branch has its own
|
|
conversation, including `main` itself.
|
|
- A "Start Contributing" affordance: on `main` it cuts a new branch
|
|
and lands you on it in contribute mode; on any other branch you
|
|
already have push access to, it flips that branch into
|
|
contribute mode.
|
|
|
|
---
|
|
|
|
## Discussion vs contribution
|
|
|
|
The framework draws an explicit distinction between two surfaces
|
|
that other tools tend to conflate:
|
|
|
|
- **Discussion** is what the RFC is *for*. The chat thread on an
|
|
RFC's main view is the place for "what about this part?" or
|
|
"have we considered…?" questions that don't yet warrant proposing
|
|
a specific edit. Posting on a discussion thread does not create
|
|
any Git artifact; the conversation lives in the app database.
|
|
- **Contribution** is how an RFC *changes*. Editing the canonical
|
|
body requires opening a branch and, eventually, a pull request.
|
|
The pull request is the place a specific proposed change is
|
|
reviewed and merged.
|
|
|
|
Reading both surfaces is open to anonymous visitors. Posting on
|
|
either requires a contributor account.
|
|
|
|
---
|
|
|
|
## Invitations, cross-references, and contribution requests
|
|
|
|
Three connected surfaces help the right people find and join the
|
|
right RFC.
|
|
|
|
### Owner invitations
|
|
|
|
An RFC's owner (or an app-wide admin or owner) can invite a specific
|
|
person to that RFC from the "Invitations" control in the RFC header.
|
|
The invite names an email and a role for *this RFC*:
|
|
|
|
- **contributor** — can open PRs and join the discussion;
|
|
- **discussant** — can join the discussion only.
|
|
|
|
The invitee gets an email with an accept link; accepting adds them as
|
|
a collaborator on that RFC. The invitations panel lists every invite
|
|
with its status (pending / accepted / expired / revoked); pending
|
|
invites can be revoked. An invitation is per-RFC — it does not change
|
|
the invitee's app-wide role, and it cannot lift the pending gate: the
|
|
invitee still needs a granted account to write.
|
|
|
|
### RFC cross-links in PRs and comments
|
|
|
|
When a PR description or a comment mentions an existing active RFC —
|
|
by its ID, its multi-word title, or its slug — the framework renders
|
|
that mention as a link to the RFC. The matching is conservative by
|
|
design (single common words are never auto-linked), and the links are
|
|
computed at read time, so nothing is rewritten in what you typed.
|
|
|
|
### "Create" and "ask to contribute" offers
|
|
|
|
The same scan surfaces two affordances inline:
|
|
|
|
- If a term looks like it should have an RFC but none exists yet, a
|
|
reader who has create rights sees a **"create RFC for '<term>'"**
|
|
link that opens the propose modal with the title pre-filled.
|
|
- If a term matches a *pending* RFC (a super-draft someone already
|
|
owns), a signed-in reader sees an **"ask to contribute"** offer
|
|
naming the owner. It opens a short request form — who you are, why
|
|
you're asking, and optionally what you'd use the RFC for. The
|
|
request lands in the owner's inbox; the owner can **accept** (which
|
|
sends you an owner invitation) or **decline** (which notifies you).
|
|
|
|
---
|
|
|
|
## Working on a branch
|
|
|
|
Contribute mode flips one branch into edit-enabled. The centre
|
|
column splits: a markdown source pane on the left, a live-rendered
|
|
preview on the right. Fenced `mermaid` blocks render as diagrams in
|
|
the preview.
|
|
|
|
Two kinds of edits accumulate on a branch:
|
|
|
|
- **AI-proposed changes.** You ask the AI a question or request a
|
|
revision in the branch's chat. When the AI proposes a concrete
|
|
edit, that edit appears as a *change card* in a panel below the
|
|
chat — not yet applied to the document. You can **accept**,
|
|
**decline**, or **edit before accepting**. Accepting produces
|
|
one commit on the branch with the original text, the proposed
|
|
text, and the AI's reason recorded in the commit body.
|
|
- **Manual edits.** Typing directly into the source pane buffers
|
|
locally and flushes as a single commit on an idle window, a
|
|
branch switch, or an explicit "Save now" button. Manual edits
|
|
also appear as change cards in the same panel — same evidence
|
|
shape, different author.
|
|
|
|
Every accepted change is one commit. The framework does not
|
|
support squash-merges or fixup-style cleanups: the per-change
|
|
commit granularity is the framework's evidence unit, and
|
|
collapsing it would erase what was earned.
|
|
|
|
### Discuss mode vs contribute mode
|
|
|
|
A branch defaults to discuss mode — read-only, with chat enabled.
|
|
AI proposals still appear in chat, but they are *buffered* rather
|
|
than applied; a single CTA invites you to flip the branch into
|
|
contribute mode if you want to act on them. The toggle is an
|
|
*intent* affordance, not a permission one. If you don't have push
|
|
access to the branch, the toggle is disabled with a sign-in or
|
|
request-access path.
|
|
|
|
`main` is special: contribute mode is never available there. The
|
|
"Start Contributing" button on `main` always cuts a new branch.
|
|
|
|
### Flags
|
|
|
|
Anywhere you can read, you can drop a flag. A flag is the
|
|
lightweight "I'm pointing at this, it's a problem" gesture — a
|
|
single short declarative statement anchored to a passage. Creating
|
|
a flag requires a contributor account but does not require push
|
|
access to the branch: any signed-in contributor who can read a
|
|
passage can point at it and say it's wrong.
|
|
|
|
Flags don't block PR merges by design — making them a merge gate
|
|
would re-create the failure mode where contributors hastily "resolve"
|
|
threads to unblock a button. Flags are prominent on PR headers but
|
|
non-blocking.
|
|
|
|
### Branch visibility
|
|
|
|
A new branch is publicly readable by default. The branch creator
|
|
can flip a branch to private, in which case only the creator, any
|
|
explicit grantees, and the RFC's per-RFC owners and arbiters can
|
|
read it. Owners and arbiters can flip it back.
|
|
|
|
**Opening a PR makes the branch fully public.** If your branch is
|
|
currently private, the "Open PR" affordance asks you to confirm
|
|
this before submitting. There is no concept of a private PR — the
|
|
framework's evidence claim depends on the argument being readable.
|
|
|
|
### Who can push to a branch
|
|
|
|
Every branch has one of three contribute modes:
|
|
|
|
- **`just-me`** (default) — only the branch creator can push.
|
|
- **`specific`** — only the branch creator and explicitly granted
|
|
contributors can push.
|
|
- **`any-contributor`** — any signed-in contributor can push.
|
|
|
|
The branch creator and the RFC's per-RFC owners and arbiters can
|
|
change this setting at any time.
|
|
|
|
### Branch hygiene
|
|
|
|
A branch with no associated PR auto-closes after 30 days of
|
|
inactivity. A closed branch is deleted from the Git host 60 days
|
|
later. Closed branches remain in the catalog under a "show closed"
|
|
filter — closing is a state, not a censorship event. The chat
|
|
attached to a closed or deleted branch is preserved as historical
|
|
record.
|
|
|
|
Owners and arbiters can *pin* a branch to disable the auto-close
|
|
timer if the work is paused but legitimately ongoing.
|
|
|
|
---
|
|
|
|
## Opening and reviewing a pull request
|
|
|
|
A pull request is the deliberate "ready for review" gesture for
|
|
work that has accumulated on a branch. The "Open PR" affordance is
|
|
available on any branch with at least one commit ahead of `main`.
|
|
|
|
The PR creation modal collects two AI-drafted fields, both editable
|
|
before submit:
|
|
|
|
- **Title.** A one-line description of the change, in spec voice.
|
|
- **Description.** Two to four sentences pulling from the branch
|
|
chat, written for an arbiter.
|
|
|
|
There is no reviewer picker. The RFC's arbiters are the implicit
|
|
reviewer set.
|
|
|
|
### The PR review page
|
|
|
|
The review page shows the diff, the branch's compressed chat
|
|
(messages that produced accepted changes are expanded, the rest is
|
|
behind a "Show full conversation" toggle), and the review-comment
|
|
surface inline below the chat.
|
|
|
|
Review comments are not a separate concept from chat — they live in
|
|
the same thread, anchored to a range in the diff. The framework's
|
|
claim is that the disagreement an arbiter raises about a proposed
|
|
change is the same *kind* of thing as the disagreement that
|
|
produced the proposed change in the first place, and the two should
|
|
share a surface.
|
|
|
|
Each PR records a per-user seen-cursor. New diff hunks and new
|
|
conversation messages since your last visit render with a subtle
|
|
accent. The cursor advances on view; you do not have to mark
|
|
anything as read.
|
|
|
|
### Merging a PR
|
|
|
|
Per-RFC owners and arbiters can merge; app-wide admins and owners
|
|
also retain this capability. The merge produces a no-fast-forward
|
|
commit on `main`, preserving every per-acceptance commit as an
|
|
individually reachable node in `main`'s history.
|
|
|
|
Merge is hard-blocked **only** by Git-level conflicts with `main`.
|
|
Open review threads, pending change-cards, unresolved chat threads,
|
|
and open flags do not block merge by design.
|
|
|
|
### Conflicts with main
|
|
|
|
A conflict surfaces on the PR page as a read-only banner. A "Start
|
|
resolution branch" affordance cuts a fresh branch off `main`'s
|
|
current tip, replays the work into it (asking the AI to resolve
|
|
unambiguous conflicts, surfacing the rest for you), and opens a new
|
|
PR. The original PR auto-closes when the resolution PR merges.
|
|
|
|
Fixup commits on the existing branch are not supported. Per-change
|
|
commit granularity is the framework's evidence unit; admitting
|
|
"fix merge conflict with main" commits would dilute it.
|
|
|
|
---
|
|
|
|
## Graduation: super-draft → active RFC
|
|
|
|
Graduation is the moment a super-draft becomes a canonical entry
|
|
in the catalog. It is initiated by an app-wide admin, an app-wide
|
|
owner, or one of the RFC's per-RFC owners or arbiters from the
|
|
super-draft's page.
|
|
|
|
Two preconditions block the action:
|
|
|
|
- **The super-draft must have at least one owner.** The proposer
|
|
is automatically the first owner; if they have stepped away, any
|
|
contributor can use the "Claim ownership" affordance to add
|
|
themselves.
|
|
- **No open body-edit PRs against the super-draft's entry.** An
|
|
open body-edit PR would attempt to re-introduce a body to a
|
|
frontmatter-only entry after graduation runs. Merge or withdraw
|
|
them first.
|
|
|
|
When the dialog confirms, the framework runs a transactional
|
|
sequence: create a fresh Git repository for the RFC, seed it with
|
|
the super-draft's body as `RFC.md`, update the meta-repo entry to
|
|
`state: active` with the integer ID and the new repository's URL,
|
|
auto-merge that update. If any step fails partway, the sequence
|
|
rolls back — the half-created repository is deleted and the
|
|
unmerged update is abandoned. The dialog shows each step in flight
|
|
and tells you exactly what happened.
|
|
|
|
The chat thread on the super-draft moves to the new repository's
|
|
`main` chat at graduation. Edit-branch chats from the super-draft
|
|
phase stay attached to their original branches on the meta repo
|
|
and surface from the new RFC view under a "Pre-graduation history"
|
|
section.
|
|
|
|
Graduation is not reversible. The path forward from an active RFC
|
|
is withdrawal, not back to super-draft.
|
|
|
|
---
|
|
|
|
## Withdrawing and reopening
|
|
|
|
An active RFC or a super-draft can be withdrawn by the proposer
|
|
(for a super-draft they proposed) or by an admin or owner. A
|
|
withdrawn entry stays in the catalog as a historical record but is
|
|
hidden from default views. The entry is filterable back in.
|
|
|
|
An admin or owner can reopen a withdrawn entry back into the
|
|
super-draft state. The history is preserved across the transition.
|
|
|
|
---
|
|
|
|
## AI in the chat
|
|
|
|
The chat on every RFC, super-draft, branch, and PR has an AI
|
|
participant by default. The framework treats the AI as one voice
|
|
among many in a public argument — not an oracle, and not a
|
|
co-author whose name lands on commits.
|
|
|
|
You invoke the AI by writing into the chat composer and submitting.
|
|
Each message can pick a model from the picker (the option list is
|
|
configurable per RFC). The AI responds in the chat; when its
|
|
response includes a concrete change to the document, that change
|
|
appears as a card you can accept, decline, or edit.
|
|
|
|
When you accept an AI's proposed change, the commit's
|
|
`On-behalf-of:` trailer names *you*, not the AI. The AI's authorship
|
|
survives only as evidence — the original proposal in the commit body
|
|
and the message that produced it in the chat record. The framework
|
|
is explicit about this: AI participation produces evidence; it does
|
|
not produce authorship.
|
|
|
|
Two configuration knobs scope AI participation per RFC:
|
|
|
|
- **Which models are available.** The meta-repo entry's frontmatter
|
|
carries an optional `models:` list. Absent means the RFC inherits
|
|
whatever models the deployment is provisioned to run. An empty
|
|
list (`models: []`) opts the RFC out of AI entirely — every AI
|
|
surface is absent rather than disabled-but-present.
|
|
- **Whose credentials pay.** By default the deployment operator's
|
|
API credentials cover AI calls on every RFC. A `funder:`
|
|
frontmatter field can name a single contributor whose registered
|
|
credentials pay for AI calls on this RFC instead. The named
|
|
contributor must explicitly consent from their settings page;
|
|
either side can revoke at any time.
|
|
|
|
Per-RFC AI configuration is edited through the meta-repo PR flow
|
|
that governs the rest of the entry's frontmatter — by the RFC's
|
|
per-RFC owners and arbiters, or by app-wide admins or owners.
|
|
|
|
---
|
|
|
|
## Notifications
|
|
|
|
The framework's public-async work model produces signals that
|
|
shouldn't all reach you the same way. Five surfaces compose:
|
|
|
|
- **In-app inbox.** The durable triage surface. One mental space
|
|
across every RFC you have any relationship to, with per-RFC and
|
|
per-category filters. Reachable from the inbox icon in the
|
|
header.
|
|
- **Badges.** Ambient pull-ins. A single integer beside the inbox
|
|
icon (count of unread notifications). A small binary dot on
|
|
individual catalog rows for watched RFCs with unseen activity.
|
|
No per-row counts and no per-section counts.
|
|
- **Toasts.** Transient mid-session signals. Used only for your own
|
|
actions completing, and for events arriving on the view you're
|
|
currently looking at.
|
|
- **Email.** The single channel that escapes the app. Opt-in per
|
|
category, conservative defaults. One-click unsubscribe per
|
|
category.
|
|
- **Digest.** Aggregation for activity on watched RFCs you haven't
|
|
triaged through any other channel.
|
|
|
|
### Watch states
|
|
|
|
Every RFC has one of three implicit relationship states for you:
|
|
|
|
- **Watching.** You receive structural signals for the RFC.
|
|
- **Following.** You receive only churn-grade signals (new
|
|
commits, new chat messages on threads you didn't participate
|
|
in). This is a lighter relationship than watching.
|
|
- **Muted.** You receive no signals for the RFC. The mute is
|
|
per-RFC and self-imposed; it does not affect what others see
|
|
or what reaches you on *other* RFCs.
|
|
|
|
Watch states transition automatically based on your participation,
|
|
with explicit overrides available from each RFC's header and from
|
|
the notification settings page.
|
|
|
|
### Email categories
|
|
|
|
Four categories with distinct defaults:
|
|
|
|
- **Personal-direct events** — default on. Signals where you are
|
|
the named subject. The contract is that when your name is on the
|
|
action, the framework reaches out of band.
|
|
- **Watched-RFC structural events** — default off. PR opened on a
|
|
watched RFC, PR merged, graduation, withdrawal. Inbox and badges
|
|
carry these by default; the email toggle is opt-in.
|
|
- **Watched-RFC churn** — permanently off, by design. Per-commit
|
|
and per-message email is intentionally not offered. The digest
|
|
aggregates this activity weekly.
|
|
- **Admin-actionable events** — default on for admins and owners,
|
|
unused for contributors.
|
|
|
|
### Quiet hours
|
|
|
|
You can set a daily window during which email notifications are
|
|
held. Messages held during the window are released at window end —
|
|
bundled into a single "Activity while you were away" email if a
|
|
threshold accumulated, otherwise sent individually.
|
|
|
|
---
|
|
|
|
## Roles & permissions
|
|
|
|
Authorization in this framework is owned by the app itself, not by
|
|
the Git host. The Git host sees only a single bot account — every
|
|
commit, every PR, every merge passes through it on a user's behalf
|
|
— and the *app* decides which users are authorized to ask the bot
|
|
to do which things.
|
|
|
|
### The four app-wide roles
|
|
|
|
Each role is a strict superset of the one below it.
|
|
|
|
1. **Anonymous.** Anyone who has not signed in. Can read public
|
|
RFCs, public branches, and public PRs; cannot chat, propose,
|
|
create branches, or open PRs.
|
|
|
|
2. **Contributor.** The default role for any authenticated
|
|
account. Adds everything anonymous can do, plus: propose new
|
|
RFCs, create branches on any RFC repository, open PRs from
|
|
branches they have push access to, post on chat anywhere they
|
|
can read, claim ownership of unclaimed super-drafts.
|
|
|
|
3. **Admin.** Adds the ability to act on any RFC, anywhere in the
|
|
framework. Concretely: merge any PR on any RFC, graduate any
|
|
super-draft, set branch visibility on anyone's behalf, withdraw
|
|
or reopen any entry, write-mute or restore any contributor,
|
|
grant or revoke the **admin** role.
|
|
|
|
4. **Owner.** Adds two capabilities admin does not have: grant or
|
|
revoke the **owner** role itself, and disable an account
|
|
entirely. The framework names a single "owner zero" at
|
|
bootstrap.
|
|
|
|
Between anonymous and contributor sits one transient state:
|
|
**pending**. A freshly signed-in account that hasn't been granted
|
|
access yet (see [Signing in](#signing-in)) reads everything an
|
|
anonymous visitor can, but no write affordance unlocks until an admin
|
|
grants it. Granting promotes the account to contributor; an admin can
|
|
also revoke a granted account back to a no-write state. These
|
|
transitions are recorded in the `permission_events` log.
|
|
|
|
The practical difference between admin and owner is narrow but
|
|
load-bearing: admin is the operational tier — it does the day-to-
|
|
day moderation and stewardship work; owner is the tier that
|
|
controls the admin tier. Disabling an account and creating other
|
|
owners are owner-only because they affect the framework's chain of
|
|
authority itself.
|
|
|
|
The app refuses to let the last owner demote themselves silently —
|
|
losing the last owner would leave nobody able to grant the role
|
|
back. Role changes are recorded in an append-only `permission_events`
|
|
log; an admin's own admin/users page shows the log of who promoted,
|
|
demoted, or muted whom.
|
|
|
|
### Per-RFC delegated authority
|
|
|
|
The four roles above are framework-wide. Within an individual RFC,
|
|
the meta-repo entry's frontmatter names two additional groups:
|
|
|
|
- **`owners:`** — contributors elevated for this RFC. They can
|
|
grant push access on any branch in the RFC, merge any PR on the
|
|
RFC, change branch visibility, and withdraw the RFC.
|
|
- **`arbiters:`** — contributors with merge authority for this RFC.
|
|
Functionally similar to per-RFC owners for merge decisions; the
|
|
distinction matters in some configuration paths.
|
|
|
|
Per-RFC owners and arbiters are **not** app-wide admins. Their
|
|
elevated powers are scoped strictly to the RFC named in the
|
|
frontmatter. This is what lets the framework distribute work
|
|
without putting one person on the hook for every action.
|
|
|
|
The proposer of an RFC is automatically the first per-RFC owner.
|
|
Additional per-RFC owners are added through a "Claim ownership"
|
|
PR against the meta repository; app-wide admins or owners merge
|
|
it.
|
|
|
|
### Per-branch contribute grants
|
|
|
|
Within an RFC, the branch creator and the RFC's per-RFC owners
|
|
and arbiters can grant push access to specific contributors on a
|
|
specific branch — `specific` contribute mode, described under
|
|
"Working on a branch."
|
|
|
|
### The write-mute
|
|
|
|
An app-wide admin or owner can **mute** a contributor. A muted
|
|
account retains read access and keeps its existing branches, but
|
|
cannot create new branches, open new PRs, propose new RFCs, or
|
|
post chat. This is a moderation tool, distinct from removing the
|
|
account; restoring is the reverse gesture.
|
|
|
|
The write-mute applies only to contributors. Promoting a user to
|
|
admin or owner is the way to remove a user's write-restriction in
|
|
the structural sense; the write-mute is for *retaining* an account
|
|
while removing its ability to act.
|
|
|
|
Every mute and every restore is recorded in `permission_events`.
|
|
|
|
### Three different "mutes"
|
|
|
|
The word "mute" appears in three structurally distinct places.
|
|
They share a word and nothing else.
|
|
|
|
- **Write-mute.** Admin-imposed. Removes a contributor's ability
|
|
to post or push. Described above.
|
|
- **Per-RFC notification mute.** Self-imposed. Sets your watch
|
|
state on a specific RFC to *muted* — you stop receiving signals
|
|
for that RFC, in inbox, badges, and email. Does not affect what
|
|
others see.
|
|
- **Per-user notification mute.** Self-imposed. Suppresses
|
|
notifications produced by a specific other user, anywhere in
|
|
the framework. Notification-volume only — it does not affect
|
|
what you can read.
|
|
|
|
A write-muted contributor continues to receive notifications
|
|
normally, so they can triage what they can't act on, and so a
|
|
restore lands cleanly.
|
|
|
|
### Audit trail
|
|
|
|
Every gesture that changes app state — role changes, mutes,
|
|
graduations, withdrawals, grant changes — is recorded in
|
|
append-only logs the app maintains. Git commit history is for
|
|
code archaeology; the app's audit log is the accountability
|
|
record. An admin's page surfaces both `permission_events` (the
|
|
role/mute log) and `actions` (the state-transition log) for
|
|
review.
|
|
|
|
---
|
|
|
|
## Privacy and cookies
|
|
|
|
A consent banner appears on your first visit and lets you choose
|
|
which cookie categories to allow — essential always, with analytics
|
|
and other categories opt-in. The choice is remembered and can be
|
|
changed any time from the privacy/cookies controls in settings.
|
|
|
|
Analytics only load if you opt in: the framework defers the analytics
|
|
SDK behind your consent, so declining means it is never initialized.
|
|
The `/privacy` and `/cookies` pages describe what's collected and
|
|
why; a deployment can point those pages at its own fuller policy.
|
|
|
|
---
|
|
|
|
## Where to learn more
|
|
|
|
- The framework's *why* lives in [the philosophy
|
|
document](/philosophy).
|
|
- The binding technical contract — section numbers (`§n.n`)
|
|
referenced throughout this guide — is in `SPEC.md` in the
|
|
framework's source repository.
|
|
- Deployment operators have their own recipe in
|
|
`docs/DEPLOYMENTS.md`.
|