779ba6db59
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>
154 lines
7.4 KiB
Markdown
154 lines
7.4 KiB
Markdown
# 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 §§1–15 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.
|