diff --git a/decisions.md b/decisions.md index 6ae932d..a54c81e 100644 --- a/decisions.md +++ b/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.