| 1 | # 0004 — Object storage is the source of truth, local disk is a cache |
| 2 | |
| 3 | **Status:** adopted |
| 4 | |
| 5 | ## Decision |
| 6 | |
| 7 | Every repository's authoritative state lives in S3 as a write-ahead log. The |
| 8 | bare repositories on disk are a **cache keyed by `(repoId, seq) |
| 9 | deleted at any time without data loss. |
| 10 | |
| 11 | ``` |
| 12 | repos/<repoId>/index the only mutable object |
| 13 | repos/<repoId>/entries/<ulid>.pack immutable: header + packfile bytes |
| 14 | ``` |
| 15 | |
| 16 | ## Why |
| 17 | |
| 18 | Holding every repository on local disk does not survive a crash, does not |
| 19 | survive a node being replaced, and does not scale past one machine. A node that |
| 20 | has never seen a repository must be able to serve it, and a node that dies |
| 21 | mid-push must not leave the repository in a state no other node can interpret. |
| 22 | |
| 23 | The log makes that possible: any node can reconstruct any repository at any |
| 24 | point in its history by replaying entries in the order the index records. |
| 25 | |
| 26 | ## The rule that keeps it honest |
| 27 | |
| 28 | The instant local disk becomes authoritative for anything, there is split brain |
| 29 | across nodes. So: |
| 30 | |
| 31 | - A push commits to the log **before** the local repository is touched |
| 32 | (`GitService.receivePack`). |
| 33 | - Serving a fetch materializes forward from the log when the local cache's |
| 34 | recorded seq is behind the index. |
| 35 | - A crash between the commit and the local write leaves the cache *behind* the |
| 36 | log, which the next materialization repairs. |
| 37 | |
| 38 | Reversing those two steps is unrecoverable: a failed commit would leave a |
| 39 | locally visible ref for a push that never happened. |
| 40 | |
| 41 | ## Consequences |
| 42 | |
| 43 | - `RepositoryStorageService` currently writes to `os.tmpdir()` and auto-creates |
| 44 | any repository anyone names. That is a prototype stand-in and is why pushing |
| 45 | to a non-existent repository silently succeeds instead of returning 404. |
| 46 | See [0011](0011-deferred.md |
| 47 | - Local disk can be wiped as an operational action, not an incident. |