Slice 4: super-draft body editing per §9.5 + §9.6
The §17 routing-collapse rule lands in api_branches.py and api_prs.py — every branches/<branch>/... and prs/<n>/... route dispatches on the entry's state to pick the right Gitea repo, and the body extracted from the entry's frontmatter envelope is what the editor and the diff see. The bot grows open_metadata_pr; cache grows refresh_meta_branches. Two §17 routes added: start-edit-branch and metadata. The §9.4 super-draft view replaces RFCView.jsx's Slice 2 placeholder; a metadata pane modal opens from the breadcrumb. Branch naming uses edit-<slug>-<6hex> to dodge the §19.2 path-routing candidate while preserving §9.5's structural shape. Covered by tests/test_super_draft_vertical.py (10 tests). The full Slices 1-4 suite is 35/35 green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+115
-42
@@ -186,6 +186,63 @@ posting, arbiter-only merge, contributor withdraw with the
|
||||
of a public PR, and the full §10.9 conflict-replay path including
|
||||
the auto-close of the original PR on the resolution PR's merge.
|
||||
|
||||
### Slice 4 — shipped
|
||||
|
||||
Super-draft body editing per §9.5 + §9.6 + §9.7. The §17 routing-collapse
|
||||
rule landed in `backend/app/api_branches.py` and `backend/app/api_prs.py`
|
||||
— every `branches/<branch>/...` and `prs/<n>/...` route now dispatches
|
||||
on the entry's state to pick the right Gitea repo, and the body
|
||||
extracted from the entry's frontmatter envelope is what the editor and
|
||||
the diff see. The bot wrapper grew `open_metadata_pr`; the rest of the
|
||||
bot's methods already accepted owner/repo arguments and worked against
|
||||
the meta repo without change. The §4 cache learned about meta-repo edit
|
||||
branches via a new `refresh_meta_branches` pass that mirrors
|
||||
`edit-<slug>-<6hex>` branches into `cached_branches` and synthesizes a
|
||||
per-slug `main` row so the §10.1 has-commits-ahead check works
|
||||
uniformly across active and super-draft surfaces. The §5 schema needed
|
||||
no migration — the super-draft scoping note already settled that the
|
||||
existing tables carry both cases.
|
||||
|
||||
The two §17 routes Slice 4 added:
|
||||
|
||||
| Method | Path | § |
|
||||
| ------ | -------------------------------------- | ------- |
|
||||
| POST | `/api/rfcs/{slug}/start-edit-branch` | §9.5 |
|
||||
| POST | `/api/rfcs/{slug}/metadata` | §9.5 |
|
||||
|
||||
Everything else from the §8 vertical (chat, accept, decline, manual
|
||||
flush, threads, flags, visibility, grants, the SSE chat stream) and the
|
||||
§10 PR flow (open, draft, review, merge, withdraw, conflict-replay)
|
||||
reaches super-drafts through the same routes Slices 2 and 3 shipped —
|
||||
no per-state forks at the API surface.
|
||||
|
||||
The branch-naming choice: §9.5 names the structural shape
|
||||
`edit/<slug>/<auto-name>`, but FastAPI's default `{branch}` path matcher
|
||||
refuses slashes (the §19.2 path-routing candidate). Slice 4 picked
|
||||
`edit-<slug>-<6hex>` — same dash-separated shape Slice 2 used for
|
||||
`<login>-draft-<6hex>`. Metadata-pane PRs use the parallel
|
||||
`metadata-<slug>-<6hex>` form. The cache parsers in `app/cache.py`
|
||||
recognize both the dashed and slashed prefixes so a future routing-fix
|
||||
slice can flip back without a data migration.
|
||||
|
||||
On the frontend, `RFCView.jsx`'s super-draft placeholder was replaced
|
||||
by the full editor surface — same component, dispatched on
|
||||
`entry.state`. The `BranchDropdown` renders `canonical body` as the
|
||||
first position when the entry is a super-draft, per §9.4. A new
|
||||
`MetadataPaneModal` opens from the breadcrumb actions when the viewer
|
||||
holds super-draft edit authority per §9.5 (until §13.1's claim runs,
|
||||
that's app admins/owners only).
|
||||
|
||||
Slice 4 ships covered by `backend/tests/test_super_draft_vertical.py` —
|
||||
ten integration tests against the FakeGitea, covering main-view read,
|
||||
start-edit-branch, body extraction from the envelope on read, accept
|
||||
preserving the frontmatter on write, manual flush through the envelope,
|
||||
the body-edit PR's `pr_kind='meta_body_edit'` shape, the full
|
||||
cut-accept-open-merge loop with the §9.5 unclaimed-merge gate
|
||||
(admin/owner only), the metadata pane PR cycle, the canonical-body
|
||||
branch (`main` for super-drafts) being read-only, and the metadata pane
|
||||
permission gate.
|
||||
|
||||
### What's deferred from Slice 2
|
||||
|
||||
These were in the §8 spec but lean on infrastructure later slices
|
||||
@@ -259,51 +316,67 @@ spec:
|
||||
|
||||
## Next slice
|
||||
|
||||
**Slice 4: super-draft body editing per §9.5 + §9.6.**
|
||||
**Slice 5: graduation per §13.**
|
||||
|
||||
The §8 within-branch surface and the §10 bridge to main now ship for
|
||||
active RFCs; the same mechanics still need to reach super-draft
|
||||
entries on the meta repo. Slice 4's unit of work is the meta-repo
|
||||
edit branch — `edit/<slug>/<auto-name>` per §9.5 — and the
|
||||
structural claim is that almost everything from §8 falls out
|
||||
unchanged once `<slug>` resolves to a super-draft entry and
|
||||
`<branch>` names a meta-repo branch rather than a per-RFC-repo
|
||||
branch (see the §5 super-draft scoping note).
|
||||
A super-draft becomes an active RFC through the §13 graduation
|
||||
sequence — the dialog (§13.2), the five-step transactional sequence
|
||||
with rollback (§13.3), the chat-follows-the-work migration (§13.4),
|
||||
the pre-graduation history affordance for the new RFC view (§9.8),
|
||||
and the precondition gate that refuses to graduate while body-edit
|
||||
PRs are open (§9.8 / §13.3).
|
||||
|
||||
What Slice 4 owns specifically:
|
||||
Slice 4 left this clean: the §9.5 metadata pane, the body-edit PR
|
||||
flow, and the active-RFC PR flow all converge on the same dispatch.
|
||||
Graduation is the act that flips an entry's state from `super-draft`
|
||||
to `active`, creates the per-RFC repo via `bot.ensure_rfc_repo_seed`
|
||||
(which Slice 2 added as a forward-looking seam), copies the body
|
||||
from the frontmatter envelope into the new repo's `RFC.md`, strips
|
||||
the body field from the meta-repo entry, mints the integer ID and
|
||||
fills the `repo`/`graduated_at`/`graduated_by` fields, and migrates
|
||||
the whole-doc main thread's chat to the new RFC's `branch_name=null`
|
||||
thread per §13.4.
|
||||
|
||||
- §9.5's `Start Contributing` on a super-draft cutting an
|
||||
`edit/<slug>/<auto-name>` branch on the meta repo via the bot,
|
||||
re-anchoring pending `changes` rows from `main` to the new branch
|
||||
the way `promote-to-branch` does for active RFCs.
|
||||
- §9.6's chat-and-threads surface scoped to the super-draft and to
|
||||
edit branches, sharing the §5 `threads`/`thread_messages` shape.
|
||||
- §9.7's visibility and contribute grants on edit branches — the
|
||||
same `branch_visibility` / `branch_contribute_grants` machinery
|
||||
that Slice 2 wired, now keyed on the meta repo.
|
||||
- The metadata pane from §9.5 — title and tag edits as small
|
||||
meta-repo PRs via `POST /api/rfcs/{slug}/metadata`. Slug renames
|
||||
remain deferred per §9.5 / §19.2.
|
||||
- The §17 routing collapse the spec calls for: the
|
||||
`branches/<branch>/...` endpoint family already exists; Slice 4's
|
||||
job is the dispatch in `api_branches.py` that recognizes a
|
||||
super-draft slug and routes to the meta repo on every read and
|
||||
write. `RFCView.jsx`'s super-draft placeholder is replaced by the
|
||||
full editor surface.
|
||||
What Slice 5 owns specifically:
|
||||
|
||||
What Slice 4 does NOT own: the §10 PR flow against the meta repo's
|
||||
super-draft edits is structurally identical to the active-RFC PR
|
||||
flow Slice 3 just shipped, and falls out from the same dispatch.
|
||||
The graduation flow from §13 stays deferred to Slice 5.
|
||||
- The §13.2 Graduate dialog — three fields (integer ID, repo name,
|
||||
initial owners), the inline-validation endpoint
|
||||
`GET /api/rfcs/{slug}/graduate/check`, the blocking-PRs popover
|
||||
via `GET /api/rfcs/{slug}/blocking-prs`, and the merge-actor set
|
||||
per §13's authority rules.
|
||||
- The §13.3 transactional sequence — five steps emitted as an SSE
|
||||
stream via `GET /api/rfcs/{slug}/graduate/progress`, with each
|
||||
step's `pending → running → done/failed` transitions surfacing in
|
||||
the dialog, and a trailing `rollback` step if any earlier step
|
||||
fails. The bot grows `graduate` plus the rollback primitives the
|
||||
sequence needs.
|
||||
- The §13.4 chat migration — the whole-doc main thread on the
|
||||
super-draft (`rfc_slug=<slug>`, `branch_name='main'`) re-anchors
|
||||
onto the new RFC's main thread; range and paragraph sub-threads
|
||||
on the canonical-body view migrate too per §9.8's clarification.
|
||||
Edit-branch chats stay attached to their original `branch_name`
|
||||
on the meta repo per §9.8 — no data movement, surfaced by the
|
||||
pre-graduation history affordance.
|
||||
- The §9.8 pre-graduation history affordance on the new RFC view —
|
||||
the slug remains the canonical key per §2.3, so the query is a
|
||||
straightforward lookup of `threads` and `changes` rows where
|
||||
`rfc_slug = <slug>` and `branch_name` begins with the meta-repo
|
||||
edit prefix.
|
||||
|
||||
The carryovers Slice 4 inherits — none new from the prototype;
|
||||
every §8 / §10 surface already exists. The work is dispatch glue
|
||||
plus a small number of routes that need the meta-repo path
|
||||
(`branches/edit/<slug>/<auto-name>` cuts).
|
||||
What Slice 5 does NOT own:
|
||||
|
||||
The next build session should read `SPEC.md`, `README.md`, and
|
||||
`docs/DEV.md` and pick up Slice 4 cleanly without re-briefing. The
|
||||
working agreement in §19.3 continues to apply: implement the slice,
|
||||
correct the spec only where running code reveals it was wrong at a
|
||||
structural level, accumulate new candidate topics in §19.2, do not
|
||||
extend the spec beyond what the slice requires.
|
||||
- The §15 notification surface (still Slice 6).
|
||||
- The §14 chrome polish (still Slice 7).
|
||||
- The §12 30/90 branch-hygiene timers (still Slice 8).
|
||||
|
||||
The carryovers Slice 5 inherits — the `ensure_rfc_repo_seed`
|
||||
primitive Slice 2 added, the body-edit-PR precondition gate
|
||||
(checked against the same `cached_prs` shape Slice 4 wired), and
|
||||
the existing `actions` audit-log shape for the rollback record.
|
||||
|
||||
The next build session should read `SPEC.md`, `README.md`,
|
||||
`docs/DEV.md`, and `SPEC.md`'s §19.1 and pick up Slice 5 cleanly
|
||||
without re-briefing. The working agreement in §19.3 continues to
|
||||
apply: implement the slice, correct the spec only where running
|
||||
code reveals it was wrong at a structural level, accumulate new
|
||||
candidate topics in §19.2, do not extend the spec beyond what the
|
||||
slice requires.
|
||||
|
||||
Reference in New Issue
Block a user