1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2024-present, fjall-rs
// Copyright (c) 2026-present, Dmitry Prudnikov
/// Block / SST disk format version.
///
/// This enum tracks the on-disk layout of Blocks and SST files: block
/// header layout, filter wire format, range-tombstone encoding, ECC
/// trailer geometry. It is the version persisted in the manifest's
/// `format_version` section and gated at `Tree::open`.
///
/// ## Relationship to the manifest layout version
///
/// `FormatVersion` and [`crate::manifest_blocks::MANIFEST_LAYOUT_VERSION_V1`]
/// evolve at **independent cadences**:
///
/// | Concept | Type | Tracks |
/// |---------|------|--------|
/// | `FormatVersion` | This enum (V1..V5) | Block / SST on-disk layout |
/// | `manifest_layout_version` | `u8` in manifest Footer Block | Manifest file structure (footer fields, TOC encoding, head-mirror geometry) |
///
/// A block format bump does NOT force a manifest layout bump and
/// vice versa. The CURRENT pointer's canonical digest binds the
/// manifest layout version (so a manifest-only break is detected
/// at recovery), and the manifest's `format_version` section binds
/// this enum (so a block-format-only break is detected at
/// `Tree::open`).
///
/// ## Amendment policy
///
/// Once a value is **published to crates.io** (any released binary
/// writes that value to disk), **any** subsequent change to the
/// on-disk bytes under that value is a breaking change that MUST
/// bump to a new variant. This applies regardless of whether the
/// change is otherwise additive: a reader running the old code is
/// not free to interpret unknown bytes.
///
/// The amendment window is the **pre-release period**: while a
/// `FormatVersion` is being actively developed and no published
/// binary writes it, the on-disk bytes under that version MAY be
/// amended in place (no enum bump required). The release that
/// crystallises the variant ends this window.
///
/// Same rule applies to `manifest_layout_version` independently:
/// pre-publication amendments are free; post-publication changes
/// require a new layout-version constant.
///
/// **Practical checklist for any PR that touches on-disk bytes:**
///
/// 1. Identify which layer the change touches (Block/SST → this
/// enum; manifest framing → `manifest_layout_version`).
/// 2. If that layer's current value has shipped to crates.io,
/// add a new variant / constant instead of amending in place.
/// 3. The OTHER layer's value stays unless its layer also changed.
/// ## Supported versions
///
/// **V5 is the ONLY supported on-disk format.** The engine neither reads
/// nor migrates pre-V5 layouts: there are no legacy decode paths, no
/// upgrade tooling, and no backward-compat variations anywhere in the
/// codebase. Discriminants 1–4 are reserved history: opening a tree that
/// carries one always fails, at whichever gate notices first, and which error
/// comes back depends on which that is. A V1 directory is caught by its
/// `version` marker file in `Tree::open` before any manifest is read. Later
/// pre-V5 manifests are usually caught earlier still, by the Blocks manifest
/// reader: their framing is not the one it decodes, so they fail at the
/// footer rather than at a version field. This `TryFrom` is the gate for the
/// remaining shape: a manifest that frames like the current one but declares
/// a version this engine does not write, which fails with
/// [`crate::Error::InvalidVersion`]. The same single-format rule
/// applies to every subsidiary format (blob frames, manifest layout): each has
/// exactly one readable shape, the one the current writer emits.
///
/// The retired discriminants are reserved as NUMBERS, not as names: this enum
/// carries no `V1`–`V4` variants. Keeping them as deprecated stubs would add
/// four public names that no file can ever decode into and that exist only to
/// keep a downstream exhaustive `match` compiling — a compatibility shim for a
/// layout the engine deliberately cannot read. A caller matching on this enum
/// should be matching what the writer emits, and that is one shape.
///
/// This crate offers no upgrade path and plans none: a pre-V5 database is not
/// adopted, converted or repaired here — it fails at the format gate above and
/// stays that way. That is a statement about THIS engine, not about the data:
/// the store is still readable by the engine that wrote it, which is where a
/// conversion would have to happen.
///
/// What the refusal buys is that recovery, salvage, patrol scrub and verify
/// have no second layout to reason about: every one of them can assume the
/// shape the current writer emits, with no branch for a shape it might also
/// have to accept.