Files
rfc-app/docs/DEV.md
T
Ben Stull 779ba6db59 Slice 1: scaffolding + propose-to-super-draft vertical
Brings the §1 bot wrapper, the §4 cache (webhook + reconciler), the
§5 schema (six numbered migrations), Gitea OAuth + §6 user
provisioning, the §7 catalog left pane, and the propose-to-merge
vertical: propose modal opens an idea PR against the meta repo, an
owner merges from the pending-idea view, the cache picks it up via
webhook or reconciler sweep, and the catalog renders the new
super-draft.

Per §1 the bot is the only Git writer; every commit, branch
creation, and PR merge carries the §6.5 On-behalf-of: trailer and
an `actions` audit row. Per §4 the cache is never written from a
user action — it's webhook+reconciler only.

Covered by `backend/tests/test_propose_vertical.py` against an
in-process Gitea simulator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 04:31:11 -07:00

154 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Build notes
The slicing plan for the v1 build, the current state of the codebase,
and the next slice's brief.
## The slicing plan
Eight slices carry §§115 of [`SPEC.md`](../SPEC.md) end-to-end. The
build does not extend the spec; spec corrections during the build are
rare and surgical and live in the appropriate numbered section per
§19.3's working agreement.
1. **Repository scaffolding + propose-to-super-draft vertical.** The
chokepoint that every Git operation flows through (§1 bot wrapper),
the §4 cache machinery (webhook + reconciler), the §5 schema, Gitea
OAuth + user provisioning, the minimal §7 catalog, and one
end-to-end vertical: propose → idea PR → merge → super-draft view.
2. **The active-RFC view per §8 in full.** Editor, branch creation,
per-branch chat with AI participation (the §18 `<change>` protocol),
the change-card panel, accept/decline/edit, manual-edit flushes,
sub-threads, flags, DiffView.
3. **The PR flow per §10.** Open, review surface (diff + compressed
chat), the §10.3 seen-cursor, §10.4 review threads, merge,
post-merge, §10.9 conflict resolution.
4. **Super-draft body editing per §9.5 + §9.6.** Meta-repo edit
branches as the unit of work; everything from §8 inherits.
5. **Graduation per §13.** The dialog, the five-step transactional
sequence, rollback, the pre-graduation history affordance.
6. **Notifications per §15.** Last, because every other surface
produces signals the inbox receives — notification correctness
depends on the producers being in place first.
7. **The §14 chrome.** Landing page polish, the `/philosophy` route,
the persistent About link.
8. **Hardening.** End-to-end tests, dev/prod deployment shape,
the §12 30/90 branch-hygiene timers.
## State of the codebase
### Slice 1 — shipped
The repository scaffolding (`backend/`, `frontend/`, `scripts/`,
`docs/`), the §5 schema as numbered migrations under
`backend/migrations/`, the §1 bot wrapper (`app/bot.py`) that is the
single chokepoint every Git write flows through, Gitea OAuth and the
§6.1 user-provisioning row in `users`, the §4.1 webhook receiver and
the §4.1 periodic reconciler (both writing to the cache; user actions
never do), the §7 left pane (catalog list, search, sort, state-filter
chips, pending-ideas disclosure), and one end-to-end vertical: propose
→ idea PR opens → owner merges → super-draft appears in the catalog →
super-draft view renders the body.
The §17 endpoints exercised so far:
| Method | Path | § |
| ------ | -------------------------------------- | ------- |
| GET | `/api/auth/me` | §6 |
| GET | `/api/rfcs` | §7, §17 |
| GET | `/api/rfcs/{slug}` | §17 |
| GET | `/api/proposals` | §17 |
| GET | `/api/proposals/{pr_number}` | §17 |
| POST | `/api/rfcs/propose` | §9.1 |
| POST | `/api/proposals/{pr_number}/merge` | §9.3 |
| POST | `/api/proposals/{pr_number}/decline` | §9.3 |
| POST | `/api/proposals/{pr_number}/withdraw` | §9.3 |
| POST | `/api/webhooks/gitea` | §4.1 |
| GET | `/auth/login` / `/auth/callback` / `/auth/logout` | §18 |
### What's deferred from slice 1
These were on the §9.1 spec but pushed to Slice 2 because they belong
with surfaces that haven't been built yet:
- The propose modal's **AI-suggested tags** (§9.1) — the AI surface
lands with Slice 2's chat wiring. The tag chip input works manually
in the meantime.
- The propose modal's **AI-drafted PR description** (§9.2) — same
reason. The PR description is the pitch text for now.
- The decline ceremony's **two-step composer-then-preview dialog**
(§9.3) — the single-step required-comment input is in place; the
preview-and-confirm beat is the kind of UX polish that the §19.2
topic "pending-idea view's interaction design (remainder)" should
pick up alongside the merge-confirmation ceremony.
- The §9.3 **pre-merge chat thread on a pending-idea view** and the
migration of those threads to the super-draft on merge — depends
on Slice 2's chat infrastructure.
These are deferred in the build's working sense — surfaces exist in
the spec, but they share infrastructure that's wired in a later slice
and would otherwise have to be wired twice.
## Environment notes
- **Python 3.13.** Earlier 3.11+ should also work; 3.13 is what the
build session ran on.
- **Node 20+** for the frontend.
- **Local Gitea on port 3000.** Anything that exposes the Gitea v1
REST API works. If you tunnel Gitea elsewhere (e.g. a container,
a Codespace), re-run `scripts/seed_meta_repo.py` so the webhook
re-registers against the right `APP_URL`.
## Conventions
- **Bot writes only via `app/bot.py`.** If a module wants to call
`app/gitea.py`'s write methods directly, the spec is right and
the module is wrong — the wrapper is the chokepoint that makes
the §6.5 `On-behalf-of:` trailer and the §6 authorization both
consistent.
- **Cache writes only from `app/cache.py`.** User actions trigger
Git operations via the bot; the cache learns about them when the
webhook arrives (or the next reconciler sweep), and never before.
This invariant is what makes §4's "Git is truth" claim hold
operationally.
- **Spec corrections during the build are rare and surgical.** When
running code reveals the spec was wrong at a structural level (per
§19.3's working agreement), the correction lands in the appropriate
numbered section with a brief note explaining what running code
revealed. Spec extensions during the build are not in scope —
they accumulate in §19.2.
- **§16 stays deferred.** Body full-text search, per-RFC model
picker, funder role, persistent accepted-change markup, slug
renames — these are not shipped in any slice. They earn their own
topic sessions when use surfaces evidence they matter.
## Next slice
**Slice 2: the active-RFC view per §8.**
The active-RFC view inherits the three-column shape (§8.1), opens
on `main` in discuss mode by default (§8.2), supports the §8.3
discuss-vs-contribute mode flip on non-main branches, hosts §8.4's
per-branch chat with AI participation (§18's `<change>` protocol
parsing into `changes` rows per §8.6), the §8.8 change-card panel
with §8.9's accept / decline / edit-before-accept resolution, the
§8.10 tracked-change markup and DiffView toggle, the §8.11 manual-
edit flushes, the §8.12 range and paragraph sub-threads, the §8.13
flag affordance, and the §8.14 discuss-mode buffer.
The carryover assets that belong to Slice 2 are in the prototype
under `/Users/benstull/projects/wiggleverse/rfc-app-prototype/`:
- `frontend/src/components/Editor.jsx`, `ChatPanel.jsx`,
`ChangePanel.jsx`, `PromptBar.jsx`, `SelectionTooltip.jsx`,
`DiffView.jsx`, `ModelPicker.jsx` — Tiptap config, the
`<change>` parser, the selection-quote machinery, the
model-picker UX.
- `backend/providers.py`, `backend/chat.py` — the multi-provider
abstraction and the SSE-streaming chat layer.
These are §18 carryovers; reuse the working code rather than
rewriting. The prototype's *data model* and *permission shape* do
not carry; this codebase's `threads`, `thread_messages`, `changes`,
`changes.thread_id`, the §6 four-role model, and the per-branch
chat thread are the canonical shape for Slice 2 to wire against.