From dc5345cef49d807e5828857f17d3a9d33761e14d Mon Sep 17 00:00:00 2001 From: Ben Stull Date: Sat, 6 Jun 2026 17:47:24 -0700 Subject: [PATCH] =?UTF-8?q?docs(spec):=20Corpus=20Tree=20=E2=80=94=20unive?= =?UTF-8?q?rsal=20directory-tree=20left=20pane=20(Solution=20Design)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Solution Design for making the left pane a universal git-directory tree: host existing documentation repos as path-addressed corpora, full governance lifecycle per file, dual-mode (structure/flat) pane replacing the §7 Catalog, zero-migration onboarding ("no record = active"). Discovery output of ohm session 0081.0. Conforms to handbook §3.3 Solution Design standard. Sliced SLICE-1..4 in §7. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../specs/2026-06-06-corpus-tree-design.md | 627 ++++++++++++++++++ 1 file changed, 627 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-06-corpus-tree-design.md diff --git a/docs/superpowers/specs/2026-06-06-corpus-tree-design.md b/docs/superpowers/specs/2026-06-06-corpus-tree-design.md new file mode 100644 index 0000000..fb1f7e1 --- /dev/null +++ b/docs/superpowers/specs/2026-06-06-corpus-tree-design.md @@ -0,0 +1,627 @@ +# Solution Design: Corpus Tree — universal directory-tree left pane + +| | | +| --- | --- | +| **Author(s)** | Ben Stull | +| **Reviewers / approvers** | Ben Stull | +| **Status** | `draft` | +| **Version** | v0.2.0 | +| **Source artifacts** | BDD corpus: §§1.9/4 below (this doc) · Prototype: brainstorm mockups, session 0081.0 (`.superpowers/brainstorm/`, not committed) · Reference: current `rfc-app` §7 Catalog + §22 three-tier + `DocsLayout` flyout nav · Supersedes: — | + +**Change log** + +| Date | Version | Change | By | +| --- | --- | --- | --- | +| 2026-06-06 | v0.1.0 | Initial draft (discovery session ohm 0081.0) | Ben Stull | +| 2026-06-06 | v0.2.0 | Reworked to the restructured Solution Design standard (two-part front; Pain Points; Business Actors vs Product Personas; renumbered) | Ben Stull | + +--- + +## 1. Business Context + +*The business lens — solution-agnostic throughout. No mechanism is proposed until §2.* + +### 1.1 Executive Summary + +Organizations keep large, living bodies of documentation, and the value in them +depends on people being able to find what they need and trust that it is current +and collectively maintained. This design targets two outcomes: readers can locate +any document by where it sits in a documentation body's own organization, and an +organization can bring an existing body of documentation under collaborative, +reviewed governance without disrupting how that documentation is already +arranged. The benefit accrues to readers (faster, more confident access), +contributors (a reviewed way to improve the docs), and the organization (a +governed, trustworthy knowledge base). + +### 1.2 Background + +The platform already governs collaboratively-edited documents organized as a +single shallow list within a body. Real organizational documentation — handbooks, +runbooks, design libraries — is instead deeply structured, and most of it already +exists as finished, authoritative content rather than passing through a +proposal-to-acceptance flow. There is currently no way to bring such a body onto +the platform's governance without flattening its structure, which is why +structured documentation bodies stay off-platform today. + +### 1.3 Business Actors / Roles + +Real-world roles, independent of any product. + +| Role | Responsible for (in the business) | +| --- | --- | +| Reader | Finds and reads documents to do their work; needs current, authoritative content | +| Contributor | Proposes new documents and changes to existing ones | +| Maintainer | Reviews proposed changes and decides what becomes authoritative | +| Documentation steward | Owns an existing body of documentation and decides to bring it under collaborative governance | + +### 1.4 Problem Statement + +A reader cannot navigate a documentation body by its own structure, and an +organization cannot place an existing structured body under collaborative +governance without reorganizing it. The governance model assumes every document +is one entry in a single flat list and passes through a proposal flow — neither +of which holds for an established, deeply-organized documentation body whose +documents already exist as authoritative content. + +### 1.5 Pain Points + +| # | Pain | Who feels it | Cost / frequency today | +| --- | --- | --- | --- | +| PP-1 | In a large body presented as one flat list, a reader can't tell where a document sits or browse by area | Reader | Every lookup in a sizeable body; slow, error-prone, gives up | +| PP-2 | An existing structured body can't be brought under governance without rearranging its documents into a flat scheme | Documentation steward | Blocks adoption entirely for any living body — a rearrange is a non-starter | +| PP-3 | Contributors to an existing body have no governed, reviewed way to propose changes tied to where each document lives | Contributor, Maintainer | Changes happen outside review, or not at all; no shared record of why | +| PP-4 | When the documentation is briefly unreachable, the reader is left with nothing to orient by | Reader | Intermittent; erodes trust in the body as a dependable source | + +### 1.6 Targeted Business Outcomes + +| Outcome | Success metric | Baseline → Target | Guardrail (must not regress) | How / when measured | +| --- | --- | --- | --- | --- | +| Structured documentation bodies adopt the platform's governance | bodies of documentation hosted | 0 → ≥1 | existing bodies' usability unaffected | inspection at first onboarding | +| Bringing a body under governance is a decision, not a project | preparatory rearrangement / setup required | a flatten/rework → none | — | inspection at onboarding (PP-2) | +| Readers reliably reach documents in a large body | reader reaches the intended document | not feasible for structured bodies → routine | flat-body access unchanged | manual walkthrough (PP-1) | + +> These are threshold/qualitative targets, not funnel metrics: this enables a new +> class of hosted documentation rather than tuning a conversion surface. + +### 1.7 Scope (business) + +- **In scope:** readers navigating a body by its own organization; contributors + proposing additions and changes anywhere in a body under review; stewards + bringing an existing body under governance without rearranging it. +- **Out of scope:** authoring tools beyond proposing/reviewing text documents; + governance policy changes (who may review/accept) — unchanged. +- **Non-goals:** becoming a general file store for non-document assets — the value + is governed *documents*, not arbitrary binaries. + +### 1.8 Assumptions · Constraints · Dependencies + +- **Assumptions:** bodies brought under governance are predominantly prose + documents (risk: a body that is mostly non-document assets gains little). +- **Constraints:** the existing collaborative-governance model (proposal → + review → acceptance) is reused, not redefined. +- **Dependencies:** the steward can grant the platform access to the existing + documentation body. + +### 1.9 Business Use Cases + +Solution-agnostic; no product, no technology. + +**BUC-1 — As a reader, I can find and read a document by where it sits in the body, so that I get authoritative content without knowing an internal name.** + +```gherkin +Scenario: BUC-1 — A reader finds and reads a document in a structured body + Given a body of documentation organized into sections + When a reader looks for a particular document + Then they can locate it by where it sits in that organization + And read its current content +``` +- **BUC-1 acceptance criteria:** the reader reaches the intended document and + reads its current authoritative content. + +**BUC-1a — As a reader, when the body is briefly unavailable, I am still oriented and never hit a dead end.** + +```gherkin +Scenario: BUC-1a — The documentation is temporarily unavailable + Given the documentation cannot be reached for a moment + When a reader tries to access it + Then they are still shown what was last known to exist, or told clearly how to try again + And are never left at an empty, unexplained dead end +``` + +**BUC-2 — As a contributor, I can propose a change to a document, so that improvements are reviewed before they become authoritative.** + +```gherkin +Scenario: BUC-2 — A contributor proposes a change to a document + Given a contributor authorized to change the documentation + When they propose a change to an existing document + Then the change enters review before it can become authoritative + And the document is shown as having a change under review +``` +- **BUC-2 acceptance criteria:** a reviewable proposal exists against that + document; until accepted, the authoritative content is unchanged. + +**BUC-2a — As a contributor, when my proposal can't be accepted as placed, I'm told why and nothing is half-done.** + +```gherkin +Scenario: BUC-2a — A proposed change cannot be accepted as placed + Given a contributor proposing a document + When the chosen placement conflicts with an existing document, or is not allowed + Then the proposal is refused with a clear, specific reason + And nothing is partially recorded +``` + +**BUC-3 — As a contributor, I can introduce a new document anywhere in the body, so that the body grows where the content belongs.** + +```gherkin +Scenario: BUC-3 — A contributor introduces a new document anywhere in the body + Given a contributor authorized to add documentation + When they propose a new document at a place within the body + Then it enters review as a draft in that place + And on acceptance it becomes the authoritative document there +``` +- **BUC-3 acceptance criteria:** a draft appears at the chosen place and is + reviewable; on acceptance it is the authoritative document there. + +**BUC-4 — As a documentation steward, I can bring an existing body under collaborative governance, so that it gains review and shared maintenance without disruption.** + +```gherkin +Scenario: BUC-4 — A steward brings an existing doc body under governance + Given an organization with an existing body of documentation + When that documentation is brought under collaborative governance + Then all of its existing documents are immediately readable as authoritative + And none of them had to be rearranged to make that possible +``` +- **BUC-4 acceptance criteria:** every existing document is readable and treated + as authoritative, with no rearrangement and no preparatory data entry. + +--- + +## 2. Solution Proposal + +Build software: make the platform's left-pane navigation a **universal +directory-tree** that mirrors a content repository's own git directory structure, +and address every document by its **path** rather than a flat slug — so a +documentation body is navigated by its real structure while keeping the existing +propose → review → accept governance on every file. The flat list becomes the +degenerate "one folder" case of the tree; a deep body is the general case. A new +`CorpusTree` left-pane component replaces the flat §7 Catalog as the *universal* +idiom (one navigation model for every project type), with **two display modes** — +*structure* (the directory tree) and *flat* (today's ranked list, engaged on +search or a non-path sort) — so the four affordances the flat list provides +(search, lifecycle state, sort, the contribution surface) all survive. + +An existing body is onboarded as an ordinary registry project pointed at its +repository, with **no content migration and no state backfill**: a document +present with no lifecycle record is treated as authoritative ("no record = +active"). + +**Why this approach, over the alternatives:** +- *Do nothing / keep flat + rearrange repos* — rejected: PP-2 makes a rearrange a + non-starter for a living body. +- *A read-only documentation viewer* — rejected: delivers PP-1 but not PP-3 + (no governed contribution). +- *A second, separate tree view beside the flat catalog* — rejected: forks the + navigation idiom and doubles the surface; the tree generalizes the flat list + rather than sitting beside it. + +**Solution-specific scope / non-goals:** +- *In:* path-addressed documents; a directory-tree read surface; the dual-mode + pane; lifecycle by path; propose/edit/review at any path; zero-migration + onboarding; legacy slug→path URL compatibility. +- *Out:* lazy per-folder tree loading (a scale follow-on; v1 serves the full + document tree from cache); a rich renderer for non-document files (listed but + inert); changes to graduation / integer-ID assignment. +- *Non-goals:* merging folders with collections (kept distinct — INV-3); a new + project *type* (existing types render via the tree — D5). + +--- + +## 3. Product Personas + +| Product persona | In rfc-app | Maps to business role(s) | +| --- | --- | --- | +| Reader | Browses a project's corpus and opens documents | Reader | +| Contributor | Holds collection `can_contribute`; proposes/edits docs at any path | Contributor, Maintainer | +| Deployment operator | Registers a content repo as a project and flips the cutover flag | Documentation steward | + +## 4. Product Use Cases + +UX-level; steps are about the Product Personas (§3). Each links to the Business UC +it realizes. + +```gherkin +Scenario: PUC-1 — Browse the directory tree in structure mode (realizes BUC-1) + Given the left pane is in structure mode + When the reader opens the project + Then folders and files are shown in path order + And each markdown file shows its lifecycle-state badge + And folders expand and collapse, with expansion persisted across visits +``` + +```gherkin +Scenario: PUC-2 — Search or non-path sort flips to flat mode (realizes BUC-1) + Given the pane is in structure mode + When the reader types a search query or picks a non-path sort + Then folders are hidden and a ranked flat list of matches is shown + And clearing the search with a path sort returns the tree with folders restored +``` + +```gherkin +Scenario: PUC-3 — Open a document by its path (realizes BUC-1) + When the reader selects a file in the tree + Then the main column renders that document + And the tree highlights the corresponding node + And the document's lifecycle state is visible +``` + +```gherkin +Scenario: PUC-4 — Propose a new doc at a path (realizes BUC-3) + Given a contributor with contribute capability + When they choose "Propose new doc" and give a path like deploy/runbooks/rollback.md + Then intermediate folders are created in the proposal branch + And a PR is opened via the bot + And a super-draft entry appears at that path +``` + +```gherkin +Scenario: PUC-5 — Propose an edit to an existing doc (realizes BUC-2) + Given a contributor viewing an existing document + When they propose an edit + Then an edit PR is opened against that document's path + And the file's node shows the in-review badge with the open PR reference +``` + +```gherkin +Scenario: PUC-6 — Filter and see lifecycle state (realizes BUC-1, BUC-2) + Given files exist in active, in-review, and super-draft states + When the reader enables the "in review" state filter + Then only files with an open edit PR are listed +``` + +```gherkin +Scenario: PUC-7 — Star a doc; starred pins in flat mode (product-only) + Given the reader has starred a file + When the pane is in flat mode + Then the starred file is pinned above the ranked results +``` + +```gherkin +Scenario: PUC-8 — Legacy slug URL redirects to its path (product-only, compat) + When the reader navigates to a legacy /p/:pid/c/:cid/e/:slug URL + Then they are redirected to the path-addressed URL for that entry + And the document renders +``` + +```gherkin +Scenario: PUC-9 — Operator onboards an existing repo (realizes BUC-4) + Given an existing doc repo and bot read+write access + When the operator registers it as a project's content repo and flips the cutover flag + Then every pre-existing file renders as active in the tree + And no content was moved and no state was backfilled +``` + +```gherkin +Scenario: PUC-10 — Tree fetch fails (realizes BUC-1a) + Given a previously cached tree exists + When the tree-listing fetch to gitea fails + Then the last good tree is served from cache + And when no cache exists, a graceful empty state with a retry action is shown +``` + +```gherkin +Scenario: PUC-11 — Propose at an invalid path (realizes BUC-2a) + When a contributor proposes a doc at an existing or out-of-repo path + Then the proposal is rejected with a clear validation error + And no branch or PR is left behind +``` + +```gherkin +Scenario: PUC-12 — Non-markdown files are listed but inert (product detail) + Given the repo contains schemas/app.json + When the tree is listed + Then schemas/app.json appears in the tree + But it has no lifecycle badge and opens no entry view +``` + +## 5. UX Layout + +### 5.1 Left pane — `CorpusTree` (serves PUC-1..PUC-7, PUC-12) + +- **Purpose:** navigate a project's corpus and reach any document; surface + lifecycle state and the contribution affordances. +- **Layout (top → bottom):** + - **Toolbar:** search input; lifecycle state filter-chips; sort selector + (path · recent · title · id · state); `+ Propose new doc` action. + - **Body — structure mode (default):** indented directory tree; folders with + expand/collapse in path order; file rows show a state dot + (active / in-review / super-draft) and a star marker; the active file is + highlighted. Non-markdown files render dimmed and inert. + - **Body — flat mode (search / non-path sort):** folders hidden; a ranked flat + list of file rows (path as secondary text); starred pinned to top; pending + super-drafts grouped. +- **States:** happy: tree/list rendered · empty: "No documents yet" + propose CTA + if permitted · loading: skeleton rows · error: stale tree if cached, else an + empty state with Retry · permission: propose control hidden without + `can_contribute`. +- **Notifications:** inline validation error on invalid propose (PUC-11); existing + PR/discussion notifications unchanged. + +### 5.2 Main column (serves PUC-3, PUC-5) + +Unchanged — rendered markdown + discussion + PR/contribution affordances — +addressed by path instead of slug. + +## 6. Technical Design + +### 6.1 Invariants + +- **INV-1:** An entry is addressed by its repo `path` within a + `(project, collection)`. Slug addressing exists only as a legacy redirect. +- **INV-2:** A markdown file present on `main` with no explicit lifecycle record + is `active`. Onboarding requires no state backfill. +- **INV-3:** Folders are organizational only. Access control is the collection's; + a folder never carries permissions. +- **INV-4:** Lifecycle records are keyed by `(collection, path)` and follow file + renames on merge — no orphaned records survive a `git mv`. +- **INV-5:** The framework names no deployment. The backing repo is supplied via + the registry (`CLAUDE.md` separation-of-concerns). +- **INV-6:** Non-markdown files are listed but carry no lifecycle and open no + entry view. +- **INV-7:** The tree pane never renders blank — stale cache or an explicit + empty/retry state on fetch failure. + +### 6.2 High-level architecture + +```mermaid +flowchart LR + CT[CorpusTree pane] -->|GET tree / entry by path| API[API service] + CT -->|propose / edit at path| API + API --> CACHE[(TTL cache)] + CACHE --> GT[Gitea git-trees / raw] + API -->|branch / PR writes| BOT[Bot account] + BOT --> GT + API --> DB[(App DB: lifecycle, stars)] + REG[rfc-registry] -->|project to content-repo| API + WH[Gitea webhooks] -->|invalidate / reconcile| CACHE +``` + +- **CorpusTree** — owns left-pane rendering and mode state; owns no source of + truth; must never assume a flat namespace. +- **API service** — owns the tree-listing and path-addressed entry/contribution + endpoints; derives lifecycle state; must never write content except via the bot. +- **App DB** — owns lifecycle records, stars, reviewed-marks keyed by + `(collection, path)`; system of record for collaboration state. +- **Gitea** — system of record for document content and PRs. +- **Cache** — holds the materialized tree + per-path metadata; invalidated by the + webhook/PR-merge signals used today (§4.1 reconciler pattern). + +### 6.3 Data model & ownership + +| Entity | Owned by | Key fields | System of record | +| --- | --- | --- | --- | +| Document (entry) | Gitea | `(project, collection, path)`, body | Gitea repo `main` | +| Lifecycle record | App DB | `(collection, path)`, state, reviewed-by | App DB | +| Star | App DB | `(user, collection, path)` | App DB | +| Open-PR mapping | Gitea | `path` → PR number | Gitea | +| Tree node (materialized) | Cache | `path`, type, `last_commit_at`, state, `open_pr`, `starred_by_me` | derived (cache) | + +### 6.4 Interfaces & contracts + +- **`GET /api/projects/{pid}/collections/{cid}/tree`** — in: pid, cid, viewer · + out: nodes `{path, type, last_commit_at, lifecycle_state, open_pr, + starred_by_me}` (full markdown tree) · errors: `404` unknown project/collection; + gitea failure → stale cache or `503` with a retriable marker (INV-7). +- **Path-addressed entry read** — generalize `…/rfcs/{slug}` to a path + (`…/entries/{path}`); out: existing entry payload; errors: `404`. +- **Propose-at-path / edit / discussion** — generalize existing contribution/PR/ + discussion endpoints from `slug` to `path`; propose-new in: target path, body; + out: PR ref; errors: `409` path exists, `422` invalid/out-of-repo path + (PUC-11), `403` no `can_contribute`. + +### 6.5 Per–Product-Use-Case design + +#### PUC-1 — Browse the tree (realizes BUC-1; honors INV-2, INV-7) + +```mermaid +sequenceDiagram + actor R as Reader + participant CT as CorpusTree + participant A as API + participant C as Cache + participant G as Gitea + R->>CT: open project + CT->>A: GET …/tree + A->>C: get materialized tree + alt cache hit + C-->>A: tree + else miss + A->>G: git trees + last-commit + G-->>A: entries + A->>A: derive state (no record = active, INV-2) + A->>C: store + end + A-->>CT: nodes + CT-->>R: structure-mode tree (or stale/empty per INV-7) +``` + +- **Implementation:** materialize the markdown tree once per cache cycle; join + per-path lifecycle/star records; "no record = active." Folder expansion is + client state (localStorage keyed by project/collection). + +#### PUC-4 — Propose a new doc at a path (realizes BUC-3; honors INV-1, INV-3) + +```mermaid +sequenceDiagram + actor Cn as Contributor + participant CT as CorpusTree + participant A as API + participant B as Bot + participant G as Gitea + Cn->>CT: + Propose new doc (path) + CT->>A: propose-at-path(path, body) + A->>A: validate path (unique, in-repo) else 409/422 + A->>B: create branch + file (mkdir -p path) + B->>G: commit + open PR + G-->>A: PR ref + A-->>CT: super-draft at path +``` + +- **Implementation:** reuse the existing bot/branch/PR flow; only the target path + and intermediate-folder creation change. PUC-5 (edit), PUC-6 (filter), PUC-8 + (redirect) reuse existing flows with `slug`→`path` substitution and need no new + sequence. + +### 6.6 Non-functional requirements & cross-cutting concerns + +- **Security & privacy:** read follows existing project/collection visibility; + propose gated by `can_contribute` (INV-3); all writes via the bot; secrets stay + references, never bytes (§6.3-handbook). No new PII. +- **Performance & scale:** v1 returns the full markdown tree from the TTL cache; + cold build is one git-trees call + a last-commit join. Lazy per-folder loading + is the scale follow-on if a body's tree is large enough to hurt cold-build + latency. +- **Availability & resilience:** stale-cache fallback + empty/retry state + (INV-7); no new hard dependency beyond what the corpus already needs. +- **Observability:** log tree cold-builds, cache hit/miss, gitea-failure + fallbacks; reuse existing health signals. +- **Accessibility:** the tree uses ARIA `tree`/`treeitem` roles with keyboard + expand/collapse and roving focus; state conveyed by text/label, not color alone. + +### 6.7 Key decisions & alternatives considered + +| Decision | Chosen | Alternatives considered | Why chosen | +| --- | --- | --- | --- | +| D1 Interaction model | Full governance lifecycle on any file | read-only viewer; read + light comments | operator intent; reuses existing machinery | +| D2 Topology | Tree becomes universal | tree as a second view; tree only for a new type | one navigation model; no idiom fork | +| D3 Entry identity | Path-addressed | keep slug + side table of paths | path is the natural key for a real body | +| D4 Folders vs collections | Distinct | merge folders into collections | collections are access-control, folders are structure | +| D5 Project type | No new type | a `tree`/`docs` type | "universal" means all types render via tree | +| D6 Build approach | New `CorpusTree`, port flat mode, retire Catalog | evolve Catalog in place; promote DocsLayout flyout | clean dual-mode boundary; safe staged cutover | +| D7 Existing files | "No record = active" | backfill a record per file at onboard | zero-migration onboarding | +| D8 Affordances | Keep all four via dual mode | drop sort/pending on a tree | operator marked all non-negotiable | +| D9 Routing | `e/*` splat + `?pr=` + legacy shim | encode path in slug; new `/f/` segment | least collision; reuses redirect pattern | + +### 6.8 Testing strategy + +Tests are part of each slice (not a follow-up). + +- **Unit (vitest):** `CorpusTree` mode-switching (search→flat, sort→flat, + clear→structure), badge rendering, expand/collapse persistence, starred-pin, + flat-mode parity with the retired Catalog. +- **Backend (DI at boundaries):** tree endpoint state derivation (INV-2), open-PR + detection, path-addressed read/contribution, slug→path migration, rename + reconciliation (INV-4). +- **Two-tier:** Tier-1 local-Docker gitea for branch/PR flows; Tier-2 PPE for the + onboard-a-real-repo path (SLICE-4). e2e: browse → open; propose-at-path → PR → + merge → state transitions; search flatten; legacy redirect. + +### 6.9 Failure modes, rollback & flags + +- **Failure:** gitea unavailable → **behavior:** stale cache or empty/retry + (INV-7) → **rollback:** none needed. +- **Failure:** a project regresses on the new pane → **behavior/rollback:** flip + the **per-project-type cutover flag** off; the Catalog renders again (not + deleted until parity is proven). +- **Feature flag:** per-project-type cutover flag, default **off**; deployments + enable per project after validating parity. + +## 7. Delivery Plan + +### 7.1 Approach / strategy + +Riskiest-foundation-first: land the path/state model and tree read behind the +existing flat UI (no user-visible change), then the dual-mode UI behind a flag, +then contribution-at-path, then onboard a real body. Per the handbook execution +convention, **each slice is its own coding session** — plan just-in-time → +execute → verify → ship → merge + version bump — in dependency order; this design +pass happens once and is amended only if a slice proves it wrong. The flag keeps +every intermediate state shippable. + +### 7.2 Slicing plan + +#### SLICE-1 — Backend foundation → completes (no user-visible PUC) +- **Depends on:** — +- **DoD:** path-keyed lifecycle + slug→path migration + "no record = active" + (INV-2) + tree endpoint + path-addressed reads; Catalog still renders; backend + tests green. + +#### SLICE-2 — `CorpusTree` frontend → completes PUC-1, PUC-2, PUC-3, PUC-6, PUC-7, PUC-8, PUC-10, PUC-12 +- **Depends on:** SLICE-1 +- **DoD:** dual-mode pane behind the cutover flag; path routing + legacy shim; + flat-mode parity; Catalog retired once a project is flipped; unit + e2e green. + +#### SLICE-3 — Contribution-at-path → completes PUC-4, PUC-5, PUC-11 +- **Depends on:** SLICE-1 +- **DoD:** propose/edit/discussion at arbitrary paths; rename reconciliation + (INV-4); validation (BUC-2a); tests green. + +#### SLICE-4 — Onboard an existing doc body → completes PUC-9 (BUC-4) +- **Depends on:** SLICE-2, SLICE-3 +- **DoD:** a real external repo registered + bot access + flag flipped; all + pre-existing files render active with zero migration; Tier-2 PPE validation. + +### 7.3 Rollout / launch plan + +Pre-v1, single-prod: each slice ships to prod on merge with its CHANGELOG upgrade +steps; the per-project-type flag defaults off, so deployments opt in per project. +Rollback trigger: flag off → Catalog returns (§6.9). + +### 7.4 Risks & mitigations + +| Risk | Likelihood / impact | Mitigation | +| --- | --- | --- | +| Full-tree fetch slow on a large body | M / M | TTL cache; lazy per-folder loading as a defined follow-on | +| Catalog flat-mode parity gaps after cutover | M / H | port logic verbatim; flag-gated per project; keep Catalog until parity proven | +| Rename leaves orphan state records | M / M | webhook reconciliation (INV-4) + test | +| slug→path migration mis-maps non-`document` entry folders | L / M | resolve entry folder per project type, not hardcoded; migration test | + +## 8. Traceability matrix + +| Pain | Business UC | Product UC | Slice | Tests | +| --- | --- | --- | --- | --- | +| PP-1 | BUC-1 | PUC-1, PUC-2, PUC-3, PUC-6, PUC-7 | SLICE-2 | `test_tree_*`, `corpustree.*.test` | +| PP-4 | BUC-1a | PUC-10 | SLICE-2 | `test_tree_fallback_*` | +| PP-3 | BUC-2 | PUC-5, PUC-6 | SLICE-3 | `test_edit_at_path_*` | +| PP-3 | BUC-2a | PUC-11 | SLICE-3 | `test_propose_validation_*` | +| PP-3 | BUC-3 | PUC-4 | SLICE-3 | `test_propose_at_path_*` | +| PP-2 | BUC-4 | PUC-9 | SLICE-4 | e2e `onboard_repo_*` | +| PP-1 | (compat) | PUC-8 | SLICE-2 | `test_legacy_redirect_*` | +| PP-1 | (detail) | PUC-12 | SLICE-2 | `test_tree_non_markdown_*` | + +## 9. Open Questions & Decisions log + +**Open** + +| # | Question | Owner | Blocks | +| --- | --- | --- | --- | +| — | none outstanding | — | — | + +**Resolved** + +| # | Decision | Resolution | Date | +| --- | --- | --- | --- | +| D1 | Interaction model | Full governance lifecycle on any file | 2026-06-06 | +| D2 | Topology | Tree becomes the universal left pane | 2026-06-06 | +| D3 | Entry identity | Path-addressed; slug is legacy-redirect-only | 2026-06-06 | +| D4 | Folders vs collections | Kept distinct | 2026-06-06 | +| D5 | Project type | No new type; existing types render via tree | 2026-06-06 | +| D6 | Build approach | New `CorpusTree`; port flat mode; retire Catalog | 2026-06-06 | +| D7 | Pre-existing files | "No record = active"; zero-migration onboarding | 2026-06-06 | +| D8 | Affordances | Keep all four via dual display mode | 2026-06-06 | +| D9 | Routing | `e/*` splat + `?pr=` + legacy shim | 2026-06-06 | + +Deferred (not open): lazy per-folder tree loading; raw/preview view for +non-markdown files. + +## 10. Glossary & References + +- **Structure mode** — left pane showing the directory tree in path order. +- **Flat mode** — left pane showing a ranked flat list (search/non-path sort); + the retired Catalog's behavior. +- **Entry** — a markdown document, addressed by its repo path within a + `(project, collection)`. +- **Lifecycle record** — app-DB row keyed by `(collection, path)` carrying + non-default state; absence means `active`. +- **References:** `SPEC.md` §7 (catalog), §22 (three-tier), §8 (revision), §13 + (graduation), §20 (versioning); `CLAUDE.md` (separation-of-concerns); + handbook `solution-design/GUIDE.md` (this doc's standard).