From aaf7b09bbecbd791fbb956f68675d20e376f4435 Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Fri, 5 Jun 2026 08:31:43 -0700 Subject: [PATCH] =?UTF-8?q?=C2=A722=20S1:=20release=20v0.40.0=20=E2=80=94?= =?UTF-8?q?=20three-tier=20collection=20grain=20(breaking=20URL=20+=20migr?= =?UTF-8?q?ation=20029)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 80 +++++++++++++++++++++++++++++++++++++++++++ VERSION | 2 +- frontend/package.json | 2 +- 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46325b2..74bd6b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,86 @@ skip versions are the composition of each intervening adjacent release's steps in order — no A-to-B path is pre-computed beyond that. +## 0.40.0 — 2026-06-05 + +**Minor (breaking URL) — §22 three-tier refactor, slice S1: the *collection* +grain. A deployment now hosts N projects, each owning one content repo and +holding N RFC *collections*, each collection a typed corpus. S1 inserts the +collection grain beneath today's project as the invisible default: the +deployment runs exactly as before, now with a real collection layer and one +extra `/c//` URL segment. Per-corpus configuration (`type`, +`initial_state`), entry keys, and membership move to the collection grain; +no operator action is required beyond deploying.** + +See [`docs/design/2026-06-05-three-tier-projects-collections.md`](./docs/design/2026-06-05-three-tier-projects-collections.md) +(Part A model, Part E / §A.6 migration strategy). The structural model (Parts +A–D) is unaffected; the SPEC.md merge itself rides slice S6. + +Added: + +- **Migration `029_collections.sql`** — (1) a `collections` table + `(id, project_id, type, subfolder, initial_state, visibility, name, + registry_sha)` beneath `projects`; (2) the per-corpus fields (`type`, + `initial_state`) move **down** off `projects` onto the collection; (3) one + **default collection** per project (`id='default'` for the standard + single-project deployment, `subfolder` = repo root), inheriting the project's + type / initial_state / visibility; (4) the 13 entry-corpus tables re-key + `(project_id, slug)` → `(collection_id, slug)` via the migration-028 rebuild + pattern, each row mapped to its project's default collection; (5) + `project_members` generalises into **`memberships(scope_type ∈ {project, + collection}, scope_id, user_id, role, …)`** with the role enum collapsed to + `{owner, contributor}` (M2's `project_admin`→`owner`, + `project_contributor`→`contributor`; `project_viewer` folded into + `contributor` this pass — the read-only tier is deferred). +- **`app/collections.py`** — collection resolution helpers + (`default_collection_id`, `collection_type`, `collection_initial_state`, + `project_of_collection`). +- **`/c//` URL segment** — the canonical entry route is now + `/p//c//e/`. The project landing + `/p//` redirects into the project's single (default) collection + (C3.7); the deployment root `/` continues to redirect into the sole project + (C3.8). + +Changed: + +- **The registry mirror** writes a project's grouping-tier fields (name, + content_repo, visibility, config) to `projects` and the per-corpus fields + (`type`, `initial_state`) to its default collection; §22.4a type-immutability + is now enforced on the collection. +- **Backend threading** — `auth.project_of_rfc` recovers a project by joining + `collections`; `auth.project_member_role` reads `memberships`; + `cache`/`api_*`/`funder` writers + readers key the 13 entry-corpus tables by + `collection_id` (the denormalised `project_id` tags on + `cached_prs`/`threads`/`changes`/`notifications`/`actions`/`pr_resolution_branches` + are unchanged). Serving stays project-scoped (collection = default); the + registry `.collection.yaml` reader and collection-aware serving land in S2. + +Breaking: + +- **`/p//e/` URLs gain a `/c//` segment.** The + shipped v0.35.0 `/p//e/` form is preserved by a client-side + redirect into the default collection; the pre-multi-project `/rfc/` and + `/proposals/` server 308s now target `/p//c//…`. + +> ### Upgrade steps (0.39.0 → 0.40.0) +> +> - A deployment **MUST** deploy this version with its migrations applied (the +> standard startup path runs `029_collections.sql` automatically); the +> migration seeds the default collection and re-keys existing entries with no +> data loss. No configuration change is required. +> - Operators **SHOULD** be aware that the canonical entry URL is now +> `/p//c/default/e/`. Existing `/p//e/`, +> `/rfc/`, and `/proposals/` links keep working (client redirect / +> server 308). External systems that hardcoded the old form **SHOULD** be +> updated to the collection-scoped form at their convenience. +> - Deployments that pin the framework version **MUST** bump their version pin +> to `0.40.0`. + +Deferred (later slices): creating + navigating a second collection and the +registry `.collection.yaml` reader (S2); the four-layer scope-role resolver and +the `viewer` read tier (S3); invitation surfaces (S4); in-app create-project +(S5); per-type surfaces, membership lifecycle, and the SPEC.md merge (S6). + ## 0.39.0 — 2026-06-04 **Minor — §22.13 step 1: the default-project-id re-stamp. A deployment can diff --git a/VERSION b/VERSION index 4ef2eb0..9b0025a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.39.0 +0.40.0 diff --git a/frontend/package.json b/frontend/package.json index 3a523eb..c417a57 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "rfc-app-frontend", "private": true, - "version": "0.39.0", + "version": "0.40.0", "type": "module", "scripts": { "dev": "vite",