Skip to main content

CACHE_VERSION

Constant CACHE_VERSION 

Source
pub const CACHE_VERSION: u32 = 29;
Expand description

Cache version - increment when format changes.

v1: Initial release with string-based Decimal/NaiveDate v2: Binary Decimal (16 bytes) and NaiveDate (i32 days) v3: Fixed account type defaults in CachedOptions v4: Hash algorithm switched from SHA-256 to BLAKE3 — same 32-byte output so the header layout is unchanged, but old hashes won’t match new files. Bumping the version short-circuits stale caches at the header check instead of paying the rkyv deserialize cost only to fail the hash compare. v5: Transaction.postings: Vec<Posting> became Vec<Spanned<Posting>> (#1151). The inner posting bytes gained a Span + file_id per entry, so old cache files would rkyv-deserialize into the new type as junk. Header check forces a rebuild instead. v6: The #1163 newtype slices (#1169 Currency, #1171 Account, #1172 Tag, #1173 Link, #1174 MetaValue) swapped variant payload types from InternedStr/String to typed newtypes. The archived layout coincidentally matches AsInternedStr in most cases, but MetaValue::{Account,Currency,Tag,Link} and Transaction.tags/links (plus the parallel Document fields) changed their archive wrappers. Bumping the version forces regeneration so we don’t risk rkyv reading old bytes into a structurally-different ArchivedMetaValue. v7: PriceAnnotation refactored from 6-variant enum to { kind: PriceKind, amount: Option<IncompleteAmount> } (#1167). Old cache bytes for the enum’s discriminant would deserialize as nonsense in the new struct layout. v8: CostSpec.{number_per,number_total}: Option<Decimal> collapsed into CostSpec.number: Option<CostNumber> where CostNumber is a 3-variant enum (PerUnit, Total, PerUnitFromTotal) (#1164). The archived layout is structurally different (Option<Decimal> + Option<Decimal>Option<discriminant + payload>); reading v7 bytes into the v8 layout would produce garbage cost numbers. Bumping forces regeneration. Subsequent #1164 follow-up commits converted CostNumber’s variants from tuple form (PerUnit(Decimal)) to struct form (PerUnit { value: Decimal }) so serde could apply tag = "kind" for cross-boundary wire unification. The rkyv- archived layout for a single-field struct variant is byte- identical to the tuple variant (both pack Archived<Decimal> positionally) — verified against rkyv 0.8.16 — so this change does NOT require a separate version bump. If a future rkyv version changes that encoding, OR if CostNumber gains additional fields, bump CACHE_VERSION to the next value. v13: CostNumber gained the Compound { per_unit, total } variant (#1700) and the parser now emits it for {a # b} cost specs — exactly the “gains additional fields” case the v12 note calls out. Without the bump, a cache written by a pre-#1700 binary serves the old misparse (Total{b} / PerUnit{b}) to fixed binaries, resurrecting the bug for any previously-loaded ledger. v14: green compound-cost conversion now retries past unparsable pre-/post-hash NUMBER tokens like red (#1713); inputs with garbage around {a # b} parse to different CostNumber values than v13 cached them as. v15: EOF now terminates a line in the parser’s error-recovery walkers, so a malformed FINAL line without a trailing newline emits its diagnostic (#1884). Previously such a file parsed to zero errors and rledger check exited 0 on it. The cached errors differ, and a cache written by a pre-fix binary would serve the silent-pass result to a fixed one — resurrecting exactly the bug for every ledger already in the cache, which is the worst case since the symptom is “no error reported”. v16: a sign separated from its operand is no longer dropped. - 7.50 USD (valid beancount) parsed as +7.50, and -,123.00 USD (malformed) parsed as +123.00 with no diagnostic, because the sign landed outside the AMOUNT node where nothing read it. Cached postings from a pre-fix binary therefore hold the WRONG SIGN, and the malformed case also holds an empty errors list. Serving either to a fixed binary reproduces the original bug on every ledger already in the cache — and a flipped sign is silent, so nothing downstream would flag it. v17: balance / price values are no longer read as “the first NUMBER token”. Parenthesized arithmetic evaluated to the leading operand ((1 + 5) / 2.1 USD asserted against 1, not 2.857…), and a split numeral did the same (1,23,4.50 USD -> 1, a thousandfold error). Cached directives from a pre-fix binary therefore hold those wrong VALUES, and the malformed cases also hold an empty errors list — both silent, so nothing downstream would flag them. v9: CachedOptions gained a set_options: Vec<String> field (#1340). It was previously dropped, so a cache hit lost the record of which options the file explicitly set — making resolve_effective_booking_method re-book FIFO/LIFO ledgers as STRICT. The new trailing field changes the archived layout, so old bytes must be regenerated. v10: String literals are now escape-decoded at parse (\"->", etc.); the stored narration/payee/meta/etc. bytes differ from the old raw form, so a cache hit would serve stale, still-escaped strings. v11: MetaValue gained an Int(i64) variant (appended last). Integer metadata literals (key: 42) now archive as Int rather than Number, and the new discriminant changes the enum’s archived layout, so old bytes must be regenerated. v12: CachedOptions gained display_precision, use_precise_interpolation, and plugin_processing_mode — previously dropped, so a cache hit silently ignored option "display_precision" "USD:0.0001" (formatting fell back to inferred precision) and the other two settings. New fields change the archived layout, so old bytes must be regenerated. v18: arithmetic in a COST SPEC is now evaluated rather than truncated to its first operand (#1939). {10.00 * 3 USD} previously archived a cost of 10.00; it now archives 30.00. The layout is unchanged, so nothing here would REJECT the old bytes — which is exactly why the bump is required: a stale cache would keep serving the truncated cost basis, and the file would keep failing to balance, on a build that has the fix. Verified by hitting precisely that during development. v19: arithmetic is now evaluated in METADATA values and BALANCE TOLERANCES as well as cost specs (#1944). key: 2 * 3 archives 6 not 2, and ~ 0.005 * 2 archives 0.010 not 0.005. Values again, not layout — and again the reason the bump is mandatory: a stale cache would keep serving the truncated tolerance and keep rejecting a file the fixed build accepts. v20: account names accept any NON-ASCII character inside a component (#1930). A ledger that previously failed to parse now yields directives, and one that parsed may gain account names it did not have. Layout unchanged, so old bytes would be accepted and a cached PARSE FAILURE served on a build that can read the file. v21: a #tag / ^link on a directive that does not take one is now a parse error (#1949). A file that previously loaded clean can now carry errors, so a stale cache would serve the old clean parse on a build that objects. v22: a metadata key now needs at least two characters, as in beancount (#1955). A file using k: 42 previously loaded clean and now carries a parse error, so a stale cache would serve the old clean parse on a build that objects. v23: a ^link is no longer accepted as a metadata VALUE (#1954), so a file using ref: ^x moves from clean to erroring. A stale cache would serve the old clean parse. v24: tags and links are no longer accepted as custom / pushmeta values (#1958), so a file using them moves from clean to erroring and a stale cache would serve the old clean parse. v25: transaction headers beancount’s grammar rejects are now parse errors (#2008) - a third header string, a string after a tag/link, or junk after the narration. Same reasoning as v24: those files move from clean to erroring, and this was observed for real - the first rledger check run against the fixtures after the change reported only the old downstream E1001s, because the cache still held the permissive parse. v26: malformed cost-spec component lists are now parse errors (#2008 cases 1 and 2) - an empty comma-delimited component, or a token after a component is already complete. Same clean-to-erroring move as v25, and a separate version because a cache written between the two lands is stale for this change even though it carries v25. v27: a cost spec with no number the author wrote now archives number: None instead of an invented zero (#2008). { # CCY} used to become Compound { per_unit: 0, total: 0 }, and a malformed spec had a number scraped out of it. Both changed the ARCHIVED CostSpec, so a stale cache would serve the invented number to a build that no longer produces one.

v28: a literal -0.00 now parses to an UNSIGNED zero (matching beancount, whose parser yields Decimal('0.00')), where the green path’s bare -n previously archived a signed zero. That is parser OUTPUT, so a stale cache would keep serving -0.00 from a build that no longer produces one.

v29: Posting::cost and Posting::price are boxed. rkyv mirrors the in-memory layout, so ArchivedPosting changed shape — a v28 file read as v29 would interpret an inline CostSpec as a relative pointer. This is a layout change rather than a content change, so unlike the entries above nothing about the ledger’s meaning moved.

Public so rustledger-wasm can pin its own cache version against this one. Both caches archive the same Vec<Directive>, so a parser change that alters PARSER OUTPUT has to bump both — and on #1942 only this one was bumped, which review caught rather than any test. See loader_cache_version_is_pinned in rustledger-wasm/src/cache.rs.