Files
rfc-app/docs/superpowers/specs/2026-06-06-corpus-tree-design.md
T
Ben Stull dc5345cef4 docs(spec): Corpus Tree — universal directory-tree left pane (Solution Design)
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) <noreply@anthropic.com>
2026-06-06 17:47:24 -07:00

29 KiB
Raw Blame History

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.

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.

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.

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.

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.

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.

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 modesstructure (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.

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
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
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
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
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
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
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
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
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
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
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
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

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 PerProduct-Use-Case design

PUC-1 — Browse the tree (realizes BUC-1; honors INV-2, INV-7)

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)

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