feat: object store, typed object layer, work-tree scanner, and vcs CLI #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "changes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Builds the four layers needed to turn the reference store into a
commit-capable VCS, plus one recovery-path perf fix and a scan
progress indicator.
What's in it
Object-segment storage (SPEC.md §3.8-§3.9, §4.4; FORMAT.md §7b)
ObjectSegmentpayload with a BLAKE3-addressed locator index.SegmentFootergainsobject_index_offsetand anOBJECT_SEGMENTfeature flag (FORMAT.md footer tail, still withinthe frozen 256B window).
ref-segment and object-segment sequences. v1 manifests still
decode.
put_object,get_object,flush_object_segment.segments (RECOVERY.md §C1).
Typed object layer (
include/vcs/objects.hpp)vcs::varintandvcs::crc32c. Tree entries are validated forname legality, sort order, and duplicate rejection.
Staging and work-tree composition (
include/vcs/workdir.hpp)Index(sorted, unique, CRC32C-framed) with D1-styleatomic save (create-tmp + fsync + rename + fsync_dir per
RECOVERY.md §D1).
IFileSystem, hashes everyregular file through
Store::put_object, and upserts the Index.build_tree_from_index,put_commit,stage_commit_from_indexcompose a tree graph from the Index andstage a ref CAS through the writer protocol (SPEC.md §3.2, §3.4).
IFileSystem::is_dirprimitive;MemoryFs::list_dirnowreturns immediate children including subdir names (POSIX
readdirsemantics).CLI (
cli/main.cpp, newbuild/bin/vcs)vcs init,vcs commit -m <message>,vcs log.workdir::scan_into_index+stage_commit_from_index+the writer's flush/publish sequence.
line; non-TTY: one line per tick). Suppressed for sub-250ms
scans.
Recovery perf fix (RECOVERY.md §C1)
verify_segmentno longer slurps and rehashes the whole segmentbody; it reads the fixed 256B footer via
VFile::read_atandvalidates the header+footer pair. Body integrity remains the
reader's job via per-block CRCs (FORMAT.md §2).
What's deliberately not in it
vcs add,vcs status,vcs diff,vcs cat-file,vcs ls-tree,vcs show, branches, checkout, merge. All additive on top ofthis base.
TreeMode::Regular..vcsignore; the CLI's hardcoded ignore set is{".vcs"}.every path.
nobody <nobody@example>; noconfig file yet.
feature flag, manifest v2 parallel to v1). No bytes in any
existing layout have moved.
Invariants relied on
§3.8-§3.9 (object put/get), §4.4 (object segment recovery).
rename + fsync_dir), §D2 (manifest durability).
frozen 256B footer.
compacted.
Testing
./build/bin/vcs_tests).test_objects.cpp(239 lines), new workdircoverage in
test_store.cpp(+475 lines), manifest/publishtests updated for the v2 manifest and footer-only recovery.
tree build + commit + publish + reopen + log walk.
scan ~560ms; 500 × 200 KiB files — ~1.5s end-to-end, scan ~620ms.
New files only; no existing behavior touched. SPEC.md §1 places object typing outside the content-addressed store, so this layer sits on top of put_object/get_object (SPEC.md §3.8, §4.4) and hashes its own framed bytes with BLAKE3 unchanged. Framing (include/vcs/objects.hpp): [magic:4]['TREE'|'COMT'][version:1=1][payload][crc32c:4] tree payload : varint(count) + sorted entries of (varint mode, varint name_len, name, 32B oid) commit payload: 32B tree_oid + varint(parent_count) + parent_oids + author sig + committer sig + varint(msg_len) + msg signature : varint name, varint email, i64 LE ts_ns, i16 LE tz_min Encoder enforces: entries sorted and unique by name, non-empty names free of NUL/'/'/'.'/'..', modes in {0100644, 0100755, 0040000}, tz_offset_min in [-1439, 1439]. Decoder checks magic, version, CRC, varint framing, sort order, name and mode validity, tz range, and rejects trailing bytes. test/test_objects.cpp: 11 cases covering tree sort/round-trip, order invariance (permutations hash identically), empty tree, invalid names/modes/duplicates, bad framing (truncated, bad magic, bad version, bad CRC), root/merge commits, tz bounds, and format-drift hash smoke check. 282/282 tests pass.Phase 3 staging area. Three concepts sit above SPEC.md's byte-store interface: * Index: persistent (path, mode, oid) list at <store_dir>/index, framed by 'VCSINDX\0' + version + varint entries + CRC32C. Saved via the D1-style tmp+fsync+rename+fsync_dir pattern used by publish.cpp; load() treats a missing file as an empty index and surfaces decode failures as errors (callers can clear+rebuild). * workdir::scan_into_index: recursive IFileSystem walk that hashes every regular file through Store::put_object (SPEC.md \u00a73.8) and upserts an IndexEntry{TreeMode::Regular, ...}. Names validated via objects::is_valid_name per segment; optional ignore set for the store directory when it lives inside the work tree. * workdir::build_tree_from_index / put_commit / stage_commit_from_index: compose Tree objects by grouping entries on each '/' boundary, put_object each synthesized subtree, encode a Commit, and stage the ref CAS via Store::stage_write (SPEC.md \u00a73.2). Path collisions (file and subtree at the same name) fall out as encode_tree's duplicate-name rejection. MemoryFs::list_dir now returns immediate children including implicit subdirectory names, matching POSIX readdir. The previous 'flat namespace' filter was adequate for flat manifest directories but blocked the recursive scanner. Updated the matching test case in test/test_memory_fs.cpp.Exercises the full Phase 3 pipeline against a MemoryFs-backed store: 1. Scan initial work tree -> Index -> stage_commit_from_index -> flush_object_segment + flush_segment + publish. Save Index. 2. Mutate the work tree (edit README, add src/util/u.hpp), load the Index back, re-scan, stage a second commit with parent=c1 under a CAS pre-image of Direct{c1} (SPEC.md \u00a73.4), publish. After the second publish: * store.version() == 2 and HEAD resolves to c2. * decode_commit(c2).parents == [c1] and message == 'v2'. * Walking c2's tree reaches the post-mutation blobs via Store::get_object, and the README blob's bytes match the v2 contents, confirming the content-addressed round trip through put_object/get_object (SPEC.md \u00a73.8, \u00a74.4). 291/291 tests pass.View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.