# 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).