Post-v1: per-RFC credential delegation (funder role) folded into §6.7

Second §19.2 settlement after v1. New §6.7 alongside §6.6: optional
`funder:` frontmatter field names a single gitea_login; a
`funder_consents` app-db row records funder-side opt-in; both halves
required for the binding to activate (two-key rule). Funder universe
replaces — does not augment — the operator universe per-RFC for
attribution-clean resolution. Funder role grants zero §6.1/§6.3
authority. Three revocation paths each restore the operator-credentials
status quo.

§19.2's credential-delegation entry is split: lighter half marked
settled with a pointer to §6.7; operational-realities half (mid-call
failure, rotation, billing, rate-limit attribution) lives on as its
own entry. Test suite is 125/125 green (106 prior + 19 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ben Stull
2026-05-25 06:08:43 -07:00
parent a255429e57
commit 55a8be051a
12 changed files with 1437 additions and 43 deletions
+144 -21
View File
@@ -80,6 +80,9 @@ tags: [identity, schema]
# models: # optional per-§6.6 — absent inherits the
# - claude # operator universe; [] opts the RFC out of AI
# - gemini # entirely; populated narrows the picker
# funder: alice # optional per-§6.7 — names whose registered
# API credentials pay for AI calls. Inert until
# the named user consents from /settings/funder.
---
## Why this RFC is needed
@@ -453,11 +456,93 @@ commitment here is the field, the resolution rule, and the
configuration capability, not the click path.
This section names *which* models are permitted on a given RFC. It
does not name *whose API resources pay for them* — credentials
remain operator-supplied per §18. Credential delegation and the
funder role are a separate topic (§19.2) whose settlement will
attach a parallel "credential set" notion alongside this one
without changing the availability surface.
does not name *whose API resources pay for them* the credential-
delegation half settles in §6.7, where the operator-credentials
default is preserved and a per-RFC `funder:` field optionally points
the calls at a contributor-supplied credential set.
---
### 6.7 Per-RFC credential delegation — the funder role
§6.6 settles *which* AI models are permitted on a given RFC. This
section settles *whose* API credentials pay for them. The two halves
are parallel — both live in the meta-repo entry's frontmatter, both
follow the same edit-authority rules as `owners:` and `arbiters:`,
both mirror through the §4 cache.
A new optional `funder:` frontmatter field names a single
`gitea_login` — the user whose registered API credentials pay for AI
calls on this RFC. Absent means the operator-supplied credentials per
§18 are used; this is the v1 default and the status quo for every
RFC without an explicit funder.
The funder role is **purely credential-binding**. It confers none of
the §6.3 owner/arbiter authority and none of the §6.1 admin/owner
authority. The funder gains exactly one capability — withdraw consent
— and gains no new read access beyond what their underlying role
already affords.
**Frontmatter + consent hybrid.** The frontmatter names the funder
(RFC-side approval, via the standard meta-repo PR flow). A
`funder_consents` app-db record records the funder-side approval —
the user explicitly opts in per-slug from `/settings/funder`. The
frontmatter can name a user who has not consented; the binding stays
operationally inert until both halves match. Both sides have a veto.
**The funder universe replaces the operator universe.** When a
funder is in effect for an RFC — frontmatter names them and they
have consented — the picker for that RFC resolves to the
intersection of:
- the §6.6 `models:` list (or the implicit "all permitted" when
absent), and
- the funder's registered universe — the picker keys the operator
has enabled and for which the funder has supplied a provider-family
API key.
If the intersection is empty the RFC falls into the §6.6 opt-out
shape and the AI surfaces refuse honestly. The operator universe is
**not** augmented; the resolution is deterministic and attribution-
clean — a call on an RFC with a consenting funder is paid entirely
from the funder's credentials. If the funder cannot satisfy a
requested model, the model is unavailable for this RFC. The "fall
back to operator credentials when a funder call fails" semantics
belong to the operational-realities half (§19.2); the lighter half
deliberately does not blend funders and operators per-call.
A funder cannot expand the operator universe through registration —
registering an Anthropic key on a deployment whose operator has not
enabled `claude` does not make `claude` available on RFCs the funder
funds. The operator's enabled set bounds the picker; the funder
narrows it further.
**Three revocation paths, each restoring the operator-credentials
status quo.** First — the funder withdraws consent. Instant; the
next AI call resolves through the operator universe. Second — an
RFC owner, arbiter, or app admin edits the frontmatter to remove
the field or name a different funder. Flows through the standard
meta-repo PR. Third — the named user's account is disabled per §6.1.
Their consent rows are treated as inactive; the resolution flips
back without an explicit revocation gesture.
**Editing the funder field.** Same authority as editing `models:`
(or `owners:` / `arbiters:`). Super-draft entries: the claimed
owners and app-wide admins. Active RFCs: the RFC's owners and
arbiters per §6.3, plus app-wide admins. The dedicated chrome for
the edit is downstream — clustered with the §19.2 metadata-pane UX
topic for super-drafts and with whatever surface admins use for
active-RFC frontmatter edits.
**Explicitly deferred to the operational-realities half (§19.2).**
Mid-conversation credential failure handling; retry-with-fallback to
operator credentials when a funder call fails; per-RFC billing
surface and cost visibility; per-funder rate-limit attribution and
quota-exhaustion behavior; the key-rotation ceremony for a funder
swapping in a fresh key without dropping in-flight conversations.
The lighter half ships the structural shape — frontmatter, consent,
resolution, revocation. The heavier half ships the runtime
hardening.
---
@@ -2485,6 +2570,27 @@ The follow-up session will refine this. A minimal starting set:
user is acting in an admin/owner authority capacity or as an
arbiter on an RFC where the muted user is also active.
- `DELETE /api/users/<id>/notification-mute` — remove it.
- `GET /api/users/me/funder` — read the signed-in user's funder
surface per §6.7: the list of provider families for which they
have registered credentials (without the keys themselves) and the
list of RFC slugs they have consented to fund.
- `POST /api/users/me/funder/credentials` — register or replace an
API key for a provider family (`anthropic`, `google`, `openai`).
Body: `provider`, `api_key`. The provider name must match one the
operator has enabled; registering for a provider the operator has
not enabled is refused since per §6.7 a funder cannot expand the
operator universe.
- `DELETE /api/users/me/funder/credentials/<provider>` — remove the
registered key for a provider family. Idempotent. Existing consent
rows survive; the resolved funder universe for affected RFCs
simply shrinks.
- `POST /api/rfcs/<slug>/funder/consent` — the signed-in user opts
in to fund this RFC per §6.7. Idempotent. Refused if the signed-in
user has no registered credentials at all (a consent without any
registered universe would be inert).
- `DELETE /api/rfcs/<slug>/funder/consent` — withdraw consent per
§6.7's first revocation path. Restores the operator-credentials
status quo on the next AI call.
- `GET /api/email/unsubscribe` — one-click per-category
unsubscribe per §15.4. Signed URL; idempotent; redirects to a
short confirmation page.
@@ -2517,8 +2623,12 @@ them:
GitHub Copilot. `ENABLED_MODELS` and per-provider API keys via env —
these now define the operator's *universe* of available models, the
set the deployment is provisioned to run. Per-RFC selection from
that universe is settled in §6.6; credential delegation and the
funder role remain a §19.2 candidate.
that universe is settled in §6.6; per-RFC credential delegation
(whose keys pay for the call) is settled in §6.7. Either the
operator's keys or, when a consenting funder is named, the funder's
registered keys — never blended per-call. The operational
hardening (mid-call failure handling, retry, rotation, billing
attribution) remains a §19.2 candidate.
- The discuss-vs-contribute distinction inside an RFC view (to be
fully specified in the follow-up session).
- Gitea OAuth for user authentication. The OAuth identity is the basis
@@ -2702,20 +2812,33 @@ binding.
downstream — clustered with the metadata-pane UX candidate
below for super-drafts, and with whatever surface admins use
for active-RFC frontmatter edits.*
- **Per-RFC credential delegation and the funder role.** The
heavier half of the original per-RFC-model topic — who supplies
the API resources behind the models a given RFC permits. The
availability half (§6.6) names *which* models are allowed;
credential delegation names *whose keys pay for the calls*.
Touches security (delegation grant shape, revocation), billing
(per-RFC spend, attribution), abuse mitigation (rate limits per
funder, quota exhaustion), key rotation (mid-conversation
failure handling, retry-with-fallback), and a possible
`funder` role distinct from owner/arbiter that scopes credential
authority without conferring frontmatter authority. Load-bearing
once the framework runs past single-operator deployment; the v1
shape — operator-supplied keys per §18 — is the right default
until a real multi-operator scenario surfaces.
- **Per-RFC credential delegation funder role + grant shape.**
*Settled in the post-v1 session that picked it. The meta-repo
entry frontmatter grew an optional `funder:` field per §6.7,
parallel in shape to `owners:` / `arbiters:` / `models:`. The
frontmatter names the funder (RFC-side approval, via the meta-repo
PR flow); a `funder_consents` app-db record records funder-side
approval (the user opts in per-slug from `/settings/funder`); both
halves are required for the binding to be operationally active.
When in effect, the funder universe replaces — not augments — the
operator universe for the RFC's picker. The funder role is purely
credential-binding (no §6.3 / §6.1 authority granted). Three
revocation paths each restore the operator-credentials status quo.
The operational hardening — retry/fallback, mid-call failure,
rotation, billing — lives on as the entry below.*
- **Per-RFC credential delegation — operational realities.** The
heavier half of the original credential-delegation topic, split
out when §6.7 settled the structural shape. What happens at
runtime when funder credentials fail mid-conversation; whether
failed funder calls fall back to operator credentials (and how
that interacts with §6.7's attribution-clean rule); per-RFC
billing surface and cost visibility; per-funder rate-limit
attribution and quota-exhaustion behavior; the key-rotation
ceremony for a funder swapping in a fresh key without dropping
in-flight conversations. Earns its session once a real
multi-operator scenario surfaces and the structural §6.7 shape
meets enough load to expose where the runtime path needs
hardening.
- **Admin surfaces.** Where role management, muting, audit-log
views, the graduation-readiness queue, and Topic 13's
notification-preferences settings (email categories per §15.4,