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