docs(decisions): document validated editor architecture and workspace model
This commit is contained in:
parent
2c923c245a
commit
7d4538d8c1
1 changed files with 383 additions and 0 deletions
383
decisions.md
383
decisions.md
|
|
@ -395,3 +395,386 @@ Negative:
|
|||
- The editor abstraction must prevent the rest of the app from depending directly on NSTextView or UITextView.
|
||||
- A future custom editor engine may still be required if line replacement or overlay rendering cannot preserve cursor correctness.
|
||||
- Native adapter updates must isolate user-originated selection changes from programmatic text, selection, and attribute changes to avoid SwiftUI/TextKit feedback loops.
|
||||
|
||||
---
|
||||
|
||||
# D-014 — Hybrid Editor Architecture Validated
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Date
|
||||
|
||||
2026-06-02
|
||||
|
||||
## Context
|
||||
|
||||
Sapling's core user experience depends on a hybrid editing model:
|
||||
|
||||
* active content is displayed as Markdown source
|
||||
* inactive content is displayed as rendered output
|
||||
|
||||
This model combines advantages of:
|
||||
|
||||
* plain-text Markdown editors
|
||||
* live preview editors
|
||||
* rendered document editors
|
||||
|
||||
However, early in development there was uncertainty regarding:
|
||||
|
||||
* editor performance
|
||||
* large-document scalability
|
||||
* rendering determinism
|
||||
* active-line tracking
|
||||
* viewport stability
|
||||
* TextKit suitability
|
||||
* code block rendering
|
||||
* interactive rendered elements
|
||||
|
||||
A significant portion of Milestones 1–3 was dedicated to validating the feasibility of this architecture before proceeding with workspace and Git functionality.
|
||||
|
||||
## Decision
|
||||
|
||||
Sapling adopts a hybrid rendered/source editing architecture as its primary editing model.
|
||||
|
||||
The architecture is considered validated and will remain the foundation of the application.
|
||||
|
||||
The editor will not be rewritten and no custom text engine is planned at this time.
|
||||
|
||||
## Validated Properties
|
||||
|
||||
The following properties have been demonstrated through implementation, profiling, and real-world testing.
|
||||
|
||||
### Large Document Scalability
|
||||
|
||||
Documents exceeding:
|
||||
|
||||
* 50,000 lines
|
||||
* 5 MB of Markdown content
|
||||
|
||||
remain usable.
|
||||
|
||||
Profiling identified document-wide operations and replaced them with incremental approaches.
|
||||
|
||||
### Incremental Editing
|
||||
|
||||
Sapling maintains:
|
||||
|
||||
* incremental line indexing
|
||||
* incremental invalidation
|
||||
* incremental rendering updates
|
||||
|
||||
Editor interactions scale with the edited region rather than total document size.
|
||||
|
||||
### Rendering Determinism
|
||||
|
||||
Rendering output is derived from document state rather than interaction history.
|
||||
|
||||
Rendered content behaves consistently across:
|
||||
|
||||
* scrolling
|
||||
* focus changes
|
||||
* selection changes
|
||||
* document reloads
|
||||
|
||||
### Editable Regions
|
||||
|
||||
The editor supports:
|
||||
|
||||
* single-line editing
|
||||
* multi-line editing
|
||||
* block editing
|
||||
|
||||
Rendered content transitions into source mode when actively edited.
|
||||
|
||||
### Rendered Elements
|
||||
|
||||
The editor supports first-class rendered elements including:
|
||||
|
||||
* headings
|
||||
* task lists
|
||||
* links
|
||||
* code blocks
|
||||
|
||||
The architecture supports future rendered elements without fundamental redesign.
|
||||
|
||||
### Code Blocks
|
||||
|
||||
Code blocks are treated as semantic block elements rather than styled text.
|
||||
|
||||
They support:
|
||||
|
||||
* rendered containers
|
||||
* syntax highlighting
|
||||
* editable source transitions
|
||||
|
||||
### Viewport Stability
|
||||
|
||||
Rendered/source transitions preserve user context and do not require disruptive viewport repositioning.
|
||||
|
||||
## Technology Choice
|
||||
|
||||
The editor continues to use:
|
||||
|
||||
* NSTextView
|
||||
* NSTextStorage
|
||||
* NSLayoutManager
|
||||
* TextKit
|
||||
|
||||
Investigation determined that observed performance bottlenecks originated primarily from Sapling's own document-wide algorithms rather than AppKit itself.
|
||||
|
||||
After introducing:
|
||||
|
||||
* incremental line indexing
|
||||
* incremental invalidation
|
||||
* region-based rendering
|
||||
|
||||
TextKit remained sufficiently performant for the project's requirements.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
### Custom Text Engine
|
||||
|
||||
Rejected.
|
||||
|
||||
Reasons:
|
||||
|
||||
* significantly higher complexity
|
||||
* increased maintenance burden
|
||||
* no demonstrated need
|
||||
* current architecture satisfies project requirements
|
||||
|
||||
### Split Editor / Preview Model
|
||||
|
||||
Rejected.
|
||||
|
||||
Reasons:
|
||||
|
||||
* interrupts writing flow
|
||||
* increases cognitive overhead
|
||||
* conflicts with Sapling's editing philosophy
|
||||
|
||||
### Full WYSIWYG Editor
|
||||
|
||||
Rejected.
|
||||
|
||||
Reasons:
|
||||
|
||||
* obscures Markdown source
|
||||
* reduces portability
|
||||
* conflicts with project goals
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
* Markdown remains the source of truth.
|
||||
* Editing remains fast on large documents.
|
||||
* Rendered content improves readability.
|
||||
* The editor architecture is stable enough for future feature development.
|
||||
* Workspace and Git functionality can now be built on top of a proven editor foundation.
|
||||
|
||||
### Negative
|
||||
|
||||
* Hybrid editing introduces presentation complexity.
|
||||
* Rendered/source transitions require ongoing testing.
|
||||
* Some presentation-layer edge cases may continue to require refinement.
|
||||
|
||||
## Rationale
|
||||
|
||||
The editor is the core product experience.
|
||||
|
||||
Milestones 1–3 demonstrated that a hybrid rendered/source architecture can provide:
|
||||
|
||||
* Markdown transparency
|
||||
* pleasant reading experience
|
||||
* scalable performance
|
||||
* future extensibility
|
||||
|
||||
without requiring a custom editor implementation.
|
||||
|
||||
Future development should build upon this foundation rather than revisit the editor architecture unless substantial new evidence emerges.
|
||||
|
||||
---
|
||||
|
||||
# D-015 — Filesystem Is The Source Of Truth
|
||||
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Date
|
||||
|
||||
2026-06-02
|
||||
|
||||
## Context
|
||||
|
||||
Sapling introduces a distinction between:
|
||||
|
||||
* ordinary folders
|
||||
* versioned projects
|
||||
* Git subprojects
|
||||
|
||||
A key architectural decision is determining where workspace state lives.
|
||||
|
||||
Two approaches were considered:
|
||||
|
||||
### Option A — Sapling-Owned Workspace Metadata
|
||||
|
||||
Sapling maintains a manifest or database describing:
|
||||
|
||||
* folders
|
||||
* files
|
||||
* projects
|
||||
* attachments
|
||||
* hierarchy
|
||||
|
||||
The filesystem becomes an implementation detail.
|
||||
|
||||
Advantages:
|
||||
|
||||
* complete control
|
||||
* fast metadata access
|
||||
* custom workspace structures
|
||||
|
||||
Disadvantages:
|
||||
|
||||
* duplicates filesystem state
|
||||
* requires synchronization
|
||||
* external modifications become difficult
|
||||
* introduces risk of workspace corruption
|
||||
* reduces interoperability with other tools
|
||||
|
||||
### Option B — Filesystem-Native Workspace
|
||||
|
||||
The workspace is a normal directory on disk.
|
||||
|
||||
Sapling scans and interprets the filesystem directly.
|
||||
|
||||
Advantages:
|
||||
|
||||
* simple mental model
|
||||
* interoperability with external tools
|
||||
* no synchronization layer
|
||||
* naturally compatible with Git
|
||||
* resilient to external modifications
|
||||
|
||||
Disadvantages:
|
||||
|
||||
* requires filesystem scanning
|
||||
* metadata must be derived rather than stored
|
||||
|
||||
## Decision
|
||||
|
||||
Sapling adopts a filesystem-native architecture.
|
||||
|
||||
The filesystem is the authoritative source of truth.
|
||||
|
||||
Sapling does not maintain an authoritative database or manifest describing workspace contents.
|
||||
|
||||
Workspace contents are derived directly from the filesystem.
|
||||
|
||||
Projects are discovered through Git metadata.
|
||||
|
||||
Subprojects are discovered through Git submodules.
|
||||
|
||||
Files and folders remain ordinary filesystem objects.
|
||||
|
||||
## Workspace Model
|
||||
|
||||
Workspace:
|
||||
|
||||
```text
|
||||
Workspace/
|
||||
├── Notes/
|
||||
├── Research/
|
||||
├── Project-A/
|
||||
└── Project-B/
|
||||
```
|
||||
|
||||
Sapling scans the workspace root and builds its tree model from the current filesystem state.
|
||||
|
||||
Changes made through:
|
||||
|
||||
* Finder
|
||||
* Terminal
|
||||
* VS Code
|
||||
* Cursor
|
||||
* Xcode
|
||||
* Photoshop
|
||||
* external scripts
|
||||
|
||||
must appear naturally inside Sapling.
|
||||
|
||||
No import or synchronization step should be required.
|
||||
|
||||
## Project Detection
|
||||
|
||||
A directory containing:
|
||||
|
||||
```text
|
||||
.git/
|
||||
```
|
||||
|
||||
is considered a project.
|
||||
|
||||
Projects receive additional capabilities:
|
||||
|
||||
* Git status
|
||||
* commits
|
||||
* branches
|
||||
* remotes
|
||||
* history
|
||||
* Git LFS
|
||||
* submodules
|
||||
|
||||
Folders without Git metadata remain ordinary folders.
|
||||
|
||||
## Subproject Detection
|
||||
|
||||
Git submodules are treated as first-class Sapling subprojects.
|
||||
|
||||
Subproject discovery is derived from Git configuration rather than Sapling metadata.
|
||||
|
||||
## Persistence
|
||||
|
||||
Sapling may persist application state separately.
|
||||
|
||||
Examples:
|
||||
|
||||
* recent workspaces
|
||||
* window state
|
||||
* open tabs
|
||||
* sidebar width
|
||||
* editor preferences
|
||||
* UI configuration
|
||||
|
||||
This data must never become the authoritative representation of workspace contents.
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
* Workspace remains human-readable.
|
||||
* Workspace remains tool-agnostic.
|
||||
* Users can manipulate files outside Sapling.
|
||||
* Git integration remains natural.
|
||||
* Cloud synchronization solutions work without special support.
|
||||
* Workspaces remain usable even if Sapling is uninstalled.
|
||||
|
||||
### Negative
|
||||
|
||||
* Workspace state must be derived from filesystem scans.
|
||||
* File watching becomes important.
|
||||
* Some metadata may need caching for performance.
|
||||
|
||||
## Rationale
|
||||
|
||||
One of Sapling's core values is ownership.
|
||||
|
||||
Users should own their notes, projects, attachments, and repositories without depending on Sapling-specific storage formats.
|
||||
|
||||
A workspace should remain a normal directory that can be understood and manipulated using standard operating system tools.
|
||||
|
||||
Sapling should adapt to the filesystem rather than requiring the filesystem to adapt to Sapling.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue