Grover FS Architecture

Grover
Filesystem Architecture
v0.1.0

## Component Map

How UnifiedFileSystem routes through MountRegistry to LocalFileSystem and DatabaseFileSystem backends, with shared logic in BaseFileSystem.

100%
graph TD Caller["Caller (Grover facade)"] subgraph UnifiedFileSystem UFS["UnifiedFileSystem"] UFS_perm["_check_writable()"] UFS_route["resolve path → mount + rel_path"] UFS_emit["_emit(FileEvent)"] end subgraph Mounts MR["MountRegistry"] MC_proj["MountConfig /project"] MC_grover["MountConfig /.grover"] Perm["Permission (RW / RO)"] end subgraph Backends Proto["StorageBackend (Protocol)"] subgraph BaseFileSystem BFS["BaseFileSystem (ABC)"] BFS_read["read / write / edit / delete"] BFS_ver["_save_version / restore_version"] BFS_dir["mkdir / list_dir / move / copy"] BFS_trash["soft delete / list_trash / restore"] BFS_fmt["_format_read_output"] end subgraph LocalFileSystem LFS["LocalFileSystem"] LFS_disk["_resolve_path → disk I/O"] LFS_db["SQLite at ~/.grover/{slug}/"] LFS_override["overrides: read, list_dir, mkdir"] end subgraph DatabaseFileSystem DFS["DatabaseFileSystem"] DFS_content["content in GroverFile.content column"] end end subgraph Models GF["GroverFile"] FV["FileVersion"] end subgraph Support Dialect["dialect.py (upsert_file)"] Utils["utils.py (normalize, validate, replace)"] Types["types.py (ReadResult, WriteResult, ...)"] EB["EventBus"] end Caller --> UFS UFS --> UFS_perm --> Perm UFS --> UFS_route --> MR MR --> MC_proj MR --> MC_grover MC_proj -->|"local mode"| LFS MC_grover -->|"local mode"| LFS MC_proj -->|"database mode"| DFS UFS --> UFS_emit --> EB LFS -->|inherits| BFS DFS -->|inherits| BFS LFS -.implements.-> Proto DFS -.implements.-> Proto BFS --> BFS_read BFS --> BFS_ver BFS --> BFS_dir BFS --> BFS_trash BFS --> BFS_fmt BFS_read --> Utils BFS_read --> Types BFS_ver --> GF BFS_ver --> FV BFS_dir --> Dialect LFS --> LFS_disk LFS --> LFS_db LFS --> LFS_override
sequenceDiagram participant C as Caller participant UFS as UnifiedFileSystem participant MR as MountRegistry participant P as Permission participant EB as EventBus participant LFS as LocalFileSystem participant BFS as BaseFileSystem participant DB as SQLite participant Disk as Disk I/O C->>UFS: write("/project/hello.py", content) UFS->>P: _check_writable("/project/hello.py") P-->>UFS: OK UFS->>MR: resolve("/project/hello.py") MR-->>UFS: (MountConfig /project, "/hello.py") UFS->>LFS: write("/hello.py", content) LFS->>BFS: write("/hello.py", content) Note over BFS: validate_path + normalize_path Note over BFS: is_text_file check BFS->>DB: _get_session() BFS->>DB: SELECT existing file alt new file BFS->>DB: _ensure_parent_dirs (upsert) BFS->>DB: INSERT GroverFile BFS->>DB: INSERT FileVersion (snapshot) else existing file BFS->>DB: UPDATE GroverFile (version++) BFS->>LFS: _read_content (old content) LFS->>Disk: read old bytes BFS->>DB: INSERT FileVersion (diff or snapshot) end BFS->>DB: COMMIT BFS->>LFS: _write_content("/hello.py", content) LFS->>Disk: atomic write (tmpfile + rename) LFS-->>UFS: WriteResult(success=True) UFS->>EB: emit(FILE_WRITTEN, path, content) Note over EB: handlers update graph + search UFS-->>C: WriteResult(success=True)
graph LR subgraph Version_Chain["Version Chain — SNAPSHOT_INTERVAL = 20"] V1["v1: SNAPSHOT\n(full content)"] V2["v2: forward diff"] V3["v3: forward diff"] V4["v4: forward diff"] V5["..."] V20["v20: SNAPSHOT"] V21["v21: forward diff"] end V1 --> V2 --> V3 --> V4 --> V5 --> V20 --> V21 subgraph Reconstruct_v3["Reconstruct v3"] R1["Start from v1 snapshot"] R2["Apply v2 diff"] R3["Apply v3 diff → result"] end R1 --> R2 --> R3
graph LR Path["/project/src/app.py"] subgraph MountRegistry M1["/.grover → LocalFileSystem\n(internal storage)"] M2["/project → LocalFileSystem\n(workspace)"] end Path -->|"longest prefix match"| M2 M2 -->|"strip mount prefix"| Rel["/src/app.py"] Rel -->|"_resolve_path"| Disk["~/workspace/src/app.py"]
Component