Slice 2: the §8 active-RFC view in full
Per the §19.1 brief: the three-column shape (§8.1) opens on main
in discuss mode (§8.2), supports the §8.3 discuss-vs-contribute
flip on non-main branches, hosts §8.4's per-branch chat with AI
participation (§18's <change> protocol → §8.14 changes rows), the
§8.8 change-card panel with §8.9 accept/decline/edit-before-accept,
the §8.10 tracked-change markup + DiffView toggle, the §8.11
manual-edit flushes with the stale-change mechanic, the §8.12
range and paragraph sub-threads, the §8.13 flag affordance, and
the §8.14 discuss-mode buffer.
Backend: bot.py grew per-RFC-repo write ops (cut_branch_from_main,
commit_accepted_change with the structured original/proposed/reason
body and Change-Id + Source-Message-Id + On-behalf-of trailers,
commit_manual_flush, ensure_rfc_repo_seed). cache.py grew
refresh_rfc_repo and the webhook dispatches on repository.full_name.
providers.py and chat.py port the §18 carryovers — multi-provider
LLM abstraction and SSE-streaming chat against the §5 threads /
thread_messages / changes schema. api_branches.py mounts the §17
branches/<branch>/* and threads/<thread_id>/* routes with the §6
/ §11 permission checks inline.
Frontend: RFCView.jsx rebuilt as the §8 surface; Editor.jsx,
ChatPanel.jsx, ChangePanel.jsx, PromptBar.jsx, SelectionTooltip.jsx,
DiffView.jsx, ModelPicker.jsx, modelStyles.js lifted from the
prototype and adapted to the canonical schema.
Covered by `backend/tests/test_rfc_view_vertical.py` — eleven new
integration tests against an extended FakeGitea (PUT contents,
POST orgs/{org}/repos, seed_rfc_repo): main-view read,
promote-to-branch, accept (with and without edit-before-accept),
decline, manual flush + system message, flag creation, visibility
flip, anonymous read-but-no-contribute, stale-change refusal, and
the chat-streaming path with a fake provider injected. The 5
Slice 1 tests continue to pass alongside.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-2
@@ -17,10 +17,11 @@ from typing import Any
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from . import auth, db, entry as entry_mod, cache
|
||||
from . import api_branches, auth, db, entry as entry_mod, cache
|
||||
from .bot import Bot
|
||||
from .config import Config
|
||||
from .gitea import Gitea, GiteaError
|
||||
from .providers import BaseProvider
|
||||
|
||||
|
||||
class ProposeBody(BaseModel):
|
||||
@@ -34,8 +35,22 @@ class DeclineBody(BaseModel):
|
||||
comment: str = Field(min_length=1, max_length=4000)
|
||||
|
||||
|
||||
def make_router(config: Config, gitea: Gitea, bot: Bot) -> APIRouter:
|
||||
def make_router(
|
||||
config: Config,
|
||||
gitea: Gitea,
|
||||
bot: Bot,
|
||||
providers: dict[str, BaseProvider] | None = None,
|
||||
) -> APIRouter:
|
||||
# Use `is None` rather than `providers or {}` — an empty dict is
|
||||
# falsy, and the test harness mutates the dict the closure holds to
|
||||
# inject a fake provider; substituting a fresh `{}` here would
|
||||
# silently drop those mutations.
|
||||
if providers is None:
|
||||
providers = {}
|
||||
router = APIRouter()
|
||||
# Slice 2: the §8 active-RFC view's endpoints live in api_branches.
|
||||
# Mounting them on the same router keeps the §17 layout flat.
|
||||
router.include_router(api_branches.make_router(config, gitea, bot, providers))
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Auth surface — extends the prototype's pattern but reads role
|
||||
|
||||
Reference in New Issue
Block a user