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:
+10
-3
@@ -23,7 +23,7 @@ from typing import Any
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from . import auth, cache, chat as chat_layer, db, entry as entry_mod, models_resolver
|
||||
from . import auth, cache, chat as chat_layer, db, entry as entry_mod, funder, models_resolver
|
||||
from .bot import Bot
|
||||
from .config import Config
|
||||
from .gitea import Gitea, GiteaError
|
||||
@@ -92,6 +92,7 @@ def make_router(
|
||||
chat_messages = _branch_chat_excerpt(slug, branch)
|
||||
rfc_default_model = models_resolver.default_model_for_rfc(slug, providers)
|
||||
title, description = _draft_with_provider(
|
||||
slug=slug,
|
||||
providers=providers,
|
||||
default_model=rfc_default_model,
|
||||
rfc_title=rfc["title"],
|
||||
@@ -786,6 +787,7 @@ def _branch_chat_excerpt(slug: str, branch: str, limit: int = 40) -> list[dict]:
|
||||
|
||||
def _draft_with_provider(
|
||||
*,
|
||||
slug: str,
|
||||
providers: dict[str, BaseProvider],
|
||||
default_model: str,
|
||||
rfc_title: str,
|
||||
@@ -799,11 +801,16 @@ def _draft_with_provider(
|
||||
When no provider is configured — or per §6.6 the RFC's resolved
|
||||
list is empty (operator universe empty, frontmatter opt-out, or
|
||||
intersection empty) — we fall back to a deterministic stub. The
|
||||
surface still works; the contributor edits the text.
|
||||
surface still works; the contributor edits the text. Per §6.7,
|
||||
when a consenting funder is in effect, the provider instance is
|
||||
built from funder credentials; if the funder cannot serve the
|
||||
default model, we also fall back to the stub.
|
||||
"""
|
||||
if not providers or not default_model:
|
||||
return _stub_draft(rfc_title=rfc_title, main_body=main_body, branch_body=branch_body)
|
||||
provider = providers.get(default_model) or next(iter(providers.values()))
|
||||
provider = funder.provider_for_rfc(slug, default_model, providers)
|
||||
if provider is None:
|
||||
return _stub_draft(rfc_title=rfc_title, main_body=main_body, branch_body=branch_body)
|
||||
system = (
|
||||
"You are summarizing a contributor's proposed change to an RFC for an arbiter audience. "
|
||||
"Output exactly two sections in this order: 'TITLE: <one line, structural, spec-voice>' "
|
||||
|
||||
Reference in New Issue
Block a user