Repository navigation
feat(storage): v8 page format — meta pages, verified page headers, atomic save (v8 PR 2, refs #374 #388) - #444
Merged
Merged
Conversation
…terim fact pages The meta slot formula is (generation - 1) % 2 so generation 1 lands in page 0, matching the migration section. New files get an empty generation-1 meta. v7 migration moves into PR 2 because PR 2 replaces page 0. Refs #374 #388 #434 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
…and atomic save Every non-meta page now carries a 24-byte header (type, count, CRC32, page id, generation) that the page cache verifies on every load. Two alternating meta pages are the only commit point: save() writes only pages the active meta does not reference (its free list first, then appended), syncs, then writes the other meta slot and syncs. A crash or torn write at any point leaves the previous checkpoint intact, so the index checksum and the rebuild-on-open path are gone. - Meta selection on open per spec 4.1.1, using the new WAL v2 base_generation and a search for pages of the next generation. - Free list (0x81 pages), rewritten in full each save for now. - v7 migration appends the new layout and commits through page 0 with a backup meta in the last page. - FileBackend no longer parses page 0; page count is the file length. - MAX_FACT_BYTES is 4052 so every index key fits in an internal node; page encoders now reject overflow instead of corrupting the page. - New codes STG-029..STG-035. Refs #374 #388 #434 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
Also refine the spec's meta-selection table: a WAL whose base generation is at or below the valid meta's means open there and replay, and a v2.x (version 1) WAL reads as base generation 1. INT-053 stays in use for a damaged v7 header. Refs #374 #388 #434 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This was referenced Oct 6, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 2 of 5 for the v8 storage format (spec:
docs/superpowers/specs/2026-10-05-v8-storage-format-design.md; plan:docs/superpowers/plans/2026-10-05-v8-storage-format.md, PR 2 section).What changes
save()writes only pages the active meta does not reference (its free list first, then appended), syncs, writes the other meta page and syncs again. The whole-file index checksum,fact_prefix_crcand the rebuild-on-open path are removed.base_generation, and searches for pages of the next generation on the free list and pastpage_count. If a later commit existed, open fails with STG-033 instead of rolling back silently. Unknown feature bits fail with STG-034. A file with no valid meta fails with STG-032; one with no magic still gets STG-002.is_newis removed fromStorageBackend.stream_allkeeps insertion order.Bug found and fixed
An index key can be nearly as large as its fact (
key ≤ fact − 1), and an internal node needs room for one separator beside the header and child pointers. With the larger header, a maximum-size value overflowed an internal node silently:max_size_value_at_exact_boundary_checkpoint_and_read_backreturned 1 of 2 facts. Fixes:MAX_FACT_BYTESis now 4052 (was 4080).v2.x is not affected. Its index keys have no value bytes, and the parser caps attribute keywords at 1,024 bytes, so its keys stay far below the internal-node limit. I checked this end-to-end on
main. The overflow became possible only when the v3 branch added value bytes to keys (#287) and was never released.Tests
1,225 passing, 8 ignored.
page_countevidence cases. Each failed open is checked to leave the file unmodified.Performance
checkpoint/after_1_fact: 10k from about 3.7 ms to about 11.5 ms; 100k from about 33 ms to about 63 ms. Every save now frees all old tree pages and rewrites the whole free-list chain. This interim cost goes away in PR 4 (copy-on-write insert, O(change) free list).Not covered
.wiki/Architecture.mdand the size and cost benchmarks are in PR 5.Refs #374 #388 #434
🤖 Generated with Claude Code
https://claude.ai/code/session_015GgLEs8YozJjYhwPEYgTUn