| 1 | # 0009 — The index holds a ref snapshot, not a diff |
| 2 | |
| 3 | **Status:** adopted |
| 4 | |
| 5 | ## Decision |
| 6 | |
| 7 | `WalIndex.refs` is the complete current ref map. Entries hold the *transitions* |
| 8 | (`oldOid → newOid`); the index holds the *result |
| 9 | |
| 10 | ## Why store both |
| 11 | |
| 12 | They answer different questions and both are needed: |
| 13 | |
| 14 | - **The index's snapshot** answers "what does |
| 15 | GET, with no history folding. This is the hot path: every `info/refs` |
| 16 | advertisement and every materialization needs it. |
| 17 | - **The entries' transitions** answer "what did |
| 18 | Replaying them reconstructs ref state at any point in history — reflog, audit, |
| 19 | and point-in-time restore, none of which a snapshot alone can provide. |
| 20 | |
| 21 | Storing only transitions makes every read O(history). Storing only the snapshot |
| 22 | throws away the capability that motivated the log. |
| 23 | |
| 24 | ## Where each field comes from |
| 25 | |
| 26 | Every field has exactly one source, which is what makes the format defensible: |
| 27 | |
| 28 | | Field | Source | |
| 29 | |---|---| |
| 30 | | `transitions` | ** |
| 31 | | `packSha`, `size` |
| 32 | | `ulid`, `createdAt`, |
| 33 | | `seq` | ** |
| 34 | | `refs` | ** |
| 35 | | `layers` | ** |
| 36 | | `compactedThroughSeq` | ** |
| 37 | |
| 38 | Nothing is invented. The client supplies *what* changed, the server assigns |
| 39 | *when/who/which-number*, and * |
| 40 | |
| 41 | ## Deletes |
| 42 | |
| 43 | A transition whose `newOid` is all zeroes is a ref deletion. |
| 44 | `applyTransitions` removes the key rather than storing a zero oid, so a deleted |
| 45 | ref is absent from the snapshot while the deletion remains visible in history. |