Post-v1: per-RFC model availability (UX half) folded into §6.6
First §19.2 candidate settled after v1. The heavier per-RFC-model
topic subdivided into UX (this) and credential delegation + funder
role (still §19.2). New §6.6 carries the rule: an optional `models:`
frontmatter field on the meta-repo RFC entry; absent inherits the
operator universe, populated narrows the picker to the intersection
with provisioned providers, `[]` opts the RFC out of AI entirely.
The first resolved entry is the RFC default. §18's ENABLED_MODELS is
reframed as the operator universe.
Code: migration 009 adds nullable cached_rfcs.models_json (NULL ≠ []
is load-bearing); entry.py grows the optional field with absent-vs-
empty round-tripping in parse/serialize; new models_resolver module
holds the rule; api_branches replaces /api/models with the slug-aware
/api/rfcs/{slug}/models and threads the chat + reask paths through
the resolver; api_prs §10.2 uses the resolver and extends the stub
fallback to the opt-out case; frontend passes slug to listModels.
Tests 106/106 green (96 prior + 10 in test_per_rfc_models.py). No
behavioral change for entries without `models:` — operator universe
preserved as default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,9 @@ graduated_by: null
|
||||
owners: [] # contributors elevated for this RFC
|
||||
arbiters: [ben] # contributors with merge authority for this RFC
|
||||
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
|
||||
---
|
||||
|
||||
## Why this RFC is needed
|
||||
@@ -395,6 +398,67 @@ the acting user. Gitea's commit log is for code archaeology; the
|
||||
`actions` and `permission_events` tables are the real accountability
|
||||
record.
|
||||
|
||||
### 6.6 Per-RFC model availability
|
||||
|
||||
Which AI models contributors can pick from is configurable per RFC.
|
||||
The configuration lives in the meta-repo entry's frontmatter as an
|
||||
optional `models:` list of model identifiers (see §2.1), in the same
|
||||
shape as `owners:` and `arbiters:` — frontmatter-native, edited via
|
||||
the meta-repo PR flow that already governs the rest of the entry's
|
||||
canonical state, mirrored into the §4 cache for read-without-roundtrip.
|
||||
The field is structurally
|
||||
*optional* and the absent/empty distinction is load-bearing:
|
||||
|
||||
- **Absent** (`models:` key omitted) — the RFC inherits the operator's
|
||||
universe. The operator's universe is the set of models the
|
||||
deployment is provisioned to run, configured at the process level
|
||||
per §18. A freshly proposed super-draft and any RFC whose
|
||||
contributors haven't expressed a preference fall here.
|
||||
- **Present and non-empty** — the RFC opts into a specific subset.
|
||||
The picker's option list, at every AI surface scoped to this RFC,
|
||||
is the intersection of this list with the operator's currently
|
||||
provisioned models. Models the RFC names but the operator no
|
||||
longer provisions are silently hidden from the picker; the
|
||||
frontmatter list is preserved so a later operator change can
|
||||
restore them.
|
||||
- **Present and empty** (`models: []`) — the RFC opts out of AI
|
||||
participation entirely. Every AI surface on the RFC honors the
|
||||
refusal honestly: the chat composer's AI affordances are absent,
|
||||
flag-resolution's "Ask Claude to propose a fix" is absent, the
|
||||
§10.2 PR-draft falls back to its deterministic stub, the §9.1
|
||||
AI-suggested tags surface is absent. A contributor who tries to
|
||||
invoke the AI sees the refusal in the surface, not a mid-turn
|
||||
failure.
|
||||
|
||||
The **RFC default model** is the first entry in the resolved list
|
||||
(intersection with the operator's provisioned set; or the operator
|
||||
universe when the field is absent). Where a deterministic single
|
||||
model must be chosen and the contributor has not picked one — the
|
||||
§10.2 PR-draft, the §9.1 tag suggestions, the §8.13 "Ask Claude to
|
||||
propose a fix" invocation from an empty thread — that's the model
|
||||
used. Per-message picker grain inside a chat thread (the §18
|
||||
prototype carryover) is preserved: each message can name a different
|
||||
model from the resolved list, and the picker's currently-selected
|
||||
entry persists across messages within a session.
|
||||
|
||||
Editing the field — adding a model, removing one, switching to the
|
||||
empty-list opt-out — follows the same authority rules as editing
|
||||
`owners:` or `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 (the
|
||||
metadata pane equivalent that the §19.2 metadata-pane UX topic will
|
||||
settle for super-drafts, and whatever surface admins use for active-
|
||||
RFC frontmatter edits) is a downstream concern — the structural
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 7. The left pane
|
||||
@@ -783,6 +847,15 @@ the scroll-to-editor binding. Resolved and stale threads stay in the
|
||||
data; the chat feed's filter affordances surface or hide them on
|
||||
demand.
|
||||
|
||||
The chat's model picker (the §18 prototype carryover) draws its
|
||||
option list from the resolved per-RFC set per §6.6 — the
|
||||
intersection of the entry's optional `models:` frontmatter (or the
|
||||
operator universe when absent) with the operator's currently
|
||||
provisioned providers. An RFC whose resolved list is empty surfaces
|
||||
the AI affordances as absent rather than disabled-but-present, so
|
||||
the refusal reads as a property of the RFC, not as a transient
|
||||
error.
|
||||
|
||||
### 8.13 Flags
|
||||
|
||||
A flag is the lightweight "I'm pointing at this, it's a problem"
|
||||
@@ -1290,8 +1363,13 @@ branch chat, both editable inline before submit:
|
||||
to consider.
|
||||
|
||||
The model is told the audience is *an arbiter*, not Ben specifically —
|
||||
the framework has to scale past one person. Title and description remain
|
||||
editable post-open by the contributor or any of the RFC's arbiters.
|
||||
the framework has to scale past one person. The model used for the
|
||||
draft is the RFC's default per §6.6 — the first entry in the
|
||||
resolved per-RFC list. When that list is empty (the RFC opts out of
|
||||
AI per §6.6), the draft falls back to a deterministic stub naming
|
||||
the RFC title; the contributor edits the prefilled text as usual.
|
||||
Title and description remain editable post-open by the contributor
|
||||
or any of the RFC's arbiters.
|
||||
|
||||
There is no reviewer picker. The RFC's arbiters (§6.3) are the implicit
|
||||
reviewer set; surfacing a per-PR picker would either duplicate that or
|
||||
@@ -2202,7 +2280,9 @@ specified* and what is intentionally out of scope for v1.
|
||||
rich markdown, headings, links, code blocks.
|
||||
- **The per-RFC and per-branch chat UX.** Threading model, AI
|
||||
participation, the discuss-vs-contribute mode distinction from the
|
||||
prototype, the selection tooltip, the prompt bar, model picker.
|
||||
prototype, the selection tooltip, the prompt bar, the model picker
|
||||
chrome (its option-list source is settled in §6.6 / §8.12; the
|
||||
visual treatment and per-thread persistence remain).
|
||||
- **The revision flow.** How proposed changes from AI or contributors
|
||||
appear, the change-card panel, accept/decline/edit, tracked
|
||||
insertions/deletions in the editor.
|
||||
@@ -2434,7 +2514,11 @@ them:
|
||||
- The structured `<change>` / `<original>` / `<proposed>` / `<reason>`
|
||||
protocol for AI-proposed edits.
|
||||
- Multi-provider LLM support: Anthropic Claude, Google Gemini, OpenAI /
|
||||
GitHub Copilot. `ENABLED_MODELS` and per-provider API keys via env.
|
||||
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.
|
||||
- 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
|
||||
@@ -2604,24 +2688,34 @@ build surfaces evidence for which one matters next. Topics are
|
||||
listed roughly in order of expected weight; the order is not
|
||||
binding.
|
||||
|
||||
- **Per-RFC model availability and credential delegation.** Which
|
||||
AI models contributors can pick from when chatting on a given
|
||||
RFC, and who supplies the API resources for those models.
|
||||
Replaces §18's app-level `ENABLED_MODELS` and env-supplied keys
|
||||
with per-RFC-scoped configuration. Touches every AI surface —
|
||||
every chat thread (§8.12), every change-proposal turn (§8.9,
|
||||
§8.11), every flag-resolution invocation (§8.13), the AI-drafted
|
||||
PR title and description (§10.2), and the propose modal's
|
||||
AI-suggested tags (§9.1). Touches §5 (schema for model config
|
||||
and credentials), §6 (possibly a `funder` role, or a per-RFC
|
||||
capability extension along the lines of §6.2's per-user
|
||||
overrides), and §18 (carryover supersession). Subdividable into
|
||||
"model availability" (lighter, UX-shaped) and "credential
|
||||
delegation and the funder role" (heavier — security, billing,
|
||||
abuse mitigation, rotation, mid-conversation key failure) if the
|
||||
session driver judges the combined scope too large. Load-bearing
|
||||
once the framework runs past single-operator deployment;
|
||||
defer-able until then.
|
||||
- **Per-RFC model availability — UX half.** *Settled in the
|
||||
post-v1 session that picked it. The meta-repo entry frontmatter
|
||||
now carries an optional `models:` list per §6.6; the resolution
|
||||
rule (absent inherits the operator universe, populated narrows
|
||||
the picker by intersection, `[]` opts the RFC out of AI
|
||||
entirely) is uniform across every AI surface — §8.12 chat
|
||||
picker, §8.9 / §8.11 change-proposal turns, §8.13 flag
|
||||
resolution, §10.2 PR draft, §9.1 tag suggestions. The §18
|
||||
`ENABLED_MODELS` env contract is reframed as the operator's
|
||||
universe of provisioned models; the per-RFC list picks from
|
||||
within it. The dedicated chrome for editing the field is
|
||||
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.
|
||||
- **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,
|
||||
@@ -2763,12 +2857,12 @@ binding.
|
||||
- **The §10.2 modal's AI-drafted text when no provider is
|
||||
configured.** Slice 3 falls back to a deterministic stub
|
||||
(`Edits to <RFC title>` plus a character-count line) when the
|
||||
app has no LLM provider. The fallback is functional but does
|
||||
not produce spec-voice text. Per-RFC model availability (the
|
||||
first §19.2 candidate, on the funder-role topic) will need to
|
||||
settle the credential-delegation shape before this earns its
|
||||
own topic; until then, the stub is the right shape for the
|
||||
no-credential-available case.
|
||||
app has no LLM provider. The §6.6 settlement extends the same
|
||||
fallback to the case where the RFC's resolved model list is
|
||||
empty — the RFC has opted out of AI entirely. The fallback is
|
||||
functional but does not produce spec-voice text; improving the
|
||||
no-credential-available render remains its own future topic,
|
||||
defer-able until evidence shows the stub bites.
|
||||
- **§10.9 replay AI participation.** Slice 3 implements the
|
||||
structural §10.9 path — fresh resolution branch off main, replay
|
||||
the accepted changes whose `original` text still locates exactly
|
||||
|
||||
Reference in New Issue
Block a user