diff --git a/README.md b/README.md
index 60ef30a5..58e50715 100644
--- a/README.md
+++ b/README.md
@@ -1,141 +1,167 @@
-# libvcrtl
+I have everything I need. Below is the complete, wiki-style root workspace README.md. It is a workspace overview (not a duplication of per-crate documentation), grounded in the provided workspace `Cargo.toml`, your clarifying answers, and the accumulated context from the four crates I have already documented. The lint policy is described accurately, and the earlier per-crate inaccuracy is noted for later correction.
-**A modular, content-addressable version control system implemented in Rust.**
+As with the prior READMEs, this is a deliverable artifact, so it is kept free of inline citation markers.
-`libvcrtl` is a workspace containing a collection of Rust crates that together form a version control system. The workspace is designed around a strict separation of contracts, reference implementations, cryptographic primitives, and user-facing commands.
+---
-The project is intended to serve as both a production-ready VCS core and an educational reference for building modular Rust applications with safe, well-documented, and testable components.
+````markdown
+# libvctrl
----
+A modular, content-addressable version control system implemented as a Rust workspace.
+`libvctrl` is a precision toolkit for building custom VCS engines: it separates the _what_
+(contracts) from the _how_ (reference implementations) and exposes the whole stack through a
+single ergonomic facade, with zero-dependency cryptography at the foundation.
+
+- **Repository:** https://github.com/mroczect/libvctrl
+- **Workspace documentation:** https://docs.rs/libvctrl
+- **Language:** Rust, edition 2024 — MSRV **1.96.0** (`rust-version = "1.96"`)
+- **Licence:** MIT for the workspace; `libvctrl_sha512` is ISC
+- **Status:** library-only (no CLI/binary member)
-## Table of Contents
-
-- [Overview](#overview)
-- [System Architecture](#system-architecture)
-- [Core Features](#core-features)
-- [Technology Stack](#technology-stack)
-- [Project Structure](#project-structure)
-- [Getting Started](#getting-started)
- - [Prerequisites](#prerequisites)
- - [Installation](#installation)
- - [Configuration](#configuration)
-- [Usage](#usage)
-- [Workspace Crates](#workspace-crates)
- - [libvctrl_handler](#libvctrl_handler)
- - [libvctrl_core](#libvctrl_core)
- - [libvctrl_sha512](#libvctrl_sha512)
- - [libvctrl_plumbing](#libvctrl_plumbing)
- - [libvctrl_porcelain](#libvctrl_porcelain)
- - [libvctrl](#libvctrl)
- - [libvctrl_docs](#libvctrl_docs)
-- [Testing](#testing)
-- [CI/CD Pipeline](#cicd-pipeline)
-- [Deployment / Distribution](#deployment--distribution)
-- [Security & Compliance](#security--compliance)
-- [Contributing](#contributing)
-- [License](#license)
-- [Changelog](#changelog)
+> This is the **workspace root README**. It introduces the ecosystem, the layered
+> architecture, and the workspace-wide policies. Each crate has its own README and
+> docs.rs page with full API detail; links are in the [Crates](#crates) section.
---
## Overview
-`libvcrtl` is a modular version control system built from multiple Rust crates. The workspace is designed to demonstrate and enforce best practices in software architecture, including:
+The `libvctrl` workspace is built around a strict separation of concerns. A single contract
+layer (`libvctrl_handler`) defines the object model and the abstract behaviours every VCS
+operation must satisfy. A reference implementation (`libvctrl_core`) realises those
+contracts with a binary codec, fluent builders, in-memory stores, and a SHA-512 hasher
+adapter. A zero-dependency cryptography crate (`libvctrl_sha512`) provides the hashing
+engine. A facade (`libvctrl`) re-exports all three under one namespace. Higher-level
+command and user-facing libraries (`libvctrl_plumbing`, `libvctrl_porcelain`) build on top.
-- **Contract-first design** – The foundational crate (`libvctrl_handler`) defines immutable data types and behavior traits without implementations.
-- **Separation of concerns** – Persistence, serialization, hashing, networking, and signing are isolated behind traits and implemented in dedicated crates.
-- **Strict safety** – All crates use `#![forbid(unsafe_code)]` (with one reviewed exception in `libvctrl_sha512`) and deny common Clippy warnings.
-- **Comprehensive documentation** – Every public item is documented with doctests.
-- **Testing** – Unit tests, doctests, and property-based tests are used throughout.
-
-The workspace provides everything needed to build, use, and extend a version control system, from low-level hash functions to high-level CLI commands.
+The workspace is **library-only** at present: there is no dedicated binary/CLI member.
+`libvctrl_porcelain` is a high-level library, not a binary; a future `vctrl` CLI could be
+built on top of it, but it is not yet part of the workspace.
---
-## System Architecture
+## Architecture
-The workspace follows a layered architecture. The foundational contracts crate is at the bottom; higher-level crates depend on it and on each other as shown:
+The workspace enforces a one-way dependency flow. The contract layer depends only on the
+standard library; the reference implementation depends on the contracts and the crypto
+engine; the facade re-exports the contracts, the reference implementation, and the crypto
+primitives; and the command/user-facing libraries build on the reference implementation.
```mermaid
-graph TD
- HANDLER[libvctrl_handler Contracts & Types]
- SHA512[libvctrl_sha512 Cryptographic Primitives]
- CORE[libvctrl_core Reference Implementations]
- PLUMBING[libvctrl_plumbing Low-level Commands]
- PORCELAIN[libvctrl_porcelain User-facing Commands]
- LIBVCTRL[libvctrl Main CLI]
- DOCS[libvctrl_docs Documentation Tooling]
-
- HANDLER --> CORE
- HANDLER --> PLUMBING
- HANDLER --> PORCELAIN
- HANDLER --> LIBVCTRL
- HANDLER --> SHA512
-
- SHA512 --> CORE
- CORE --> PLUMBING
- PLUMBING --> PORCELAIN
- PORCELAIN --> LIBVCTRL
- DOCS --> HANDLER
+flowchart TD
+ subgraph Apps["Application layer"]
+ FACADE["libvctrl facade (re-exports)"]
+ PL["libvctrl_plumbing command-level library"]
+ PO["libvctrl_porcelain high-level library"]
+ end
+
+ subgraph Ref["Reference implementation"]
+ CORE["libvctrl_core codec / builders / stores / hasher adapter"]
+ end
+
+ subgraph Contracts["Contract layer"]
+ HANDLER["libvctrl_handler traits / types / limits / validation"]
+ end
+
+ subgraph Crypto["Cryptography"]
+ SHA["libvctrl_sha512 SHA-512 / HMAC / HKDF (+ SHA-384)"]
+ end
+
+ FACADE --> HANDLER
+ FACADE --> CORE
+ FACADE --> SHA
+ PL --> CORE
+ PO --> CORE
+ CORE --> HANDLER
+ CORE --> SHA
```
+````
+
+### End-to-end object lifecycle
-Dependency direction: `libvctrl_handler` depends on nothing (except std). `libvctrl_sha512` depends on nothing. `libvctrl_core` depends on both handler and sha512. `libvctrl_plumbing` depends on handler and core. `libvctrl_porcelain` depends on plumbing. `libvctrl` (the main binary) depends on porcelain and core.
+The layers collaborate to build, serialise, content-address, store, and later decode an
+object. The decoder is the trust boundary: it treats every byte stream as untrusted and
+re-validates structure, UTF-8, and system limits before constructing a handler type.
+
+```mermaid
+sequenceDiagram
+ participant App as Application
+ participant B as Builder (core)
+ participant E as BinaryEncoder (core)
+ participant H as Sha512Hasher (core, via sha512)
+ participant S as MemoryStore (core)
+ participant D as BinaryDecoder (core)
+
+ App->>B: Build object (Blob/Tree/Commit/Tag)
+ B->>B: Enforce handler limits and invariants
+ B-->>App: Validated immutable object
+ App->>E: encode_*(&object, &mut writer)
+ E-->>App: Deterministic, versioned bytes
+ App->>H: hash(&mut bytes.as_slice())
+ H->>H: SHA-512 over the encoded payload
+ H-->>App: 64-byte Hash (content address)
+ App->>S: put(&hash, &bytes)
+ App->>S: get(&hash)
+ S-->>App: Stored bytes
+ App->>D: decode_*(reader)
+ D->>D: Defense-in-depth validation
+ D-->>App: Validated immutable object
+```
---
## Core Features
-Across the workspace:
-
-- **Content-addressable object model** – Blob, Tree, Commit, Tag, Hash, UserID, TreeEntry.
-- **Behavior traits** – ObjectStore, RefStore, Hasher, Encoder, Decoder, Signer, Verifier, Transport.
-- **Binary serialization** – Deterministic, versioned, little-endian format.
-- **SHA-512, HMAC-SHA-512, HKDF-SHA-512, SHA-384** – Zero-dependency cryptographic primitives.
-- **In-memory stores** – ObjectStore and RefStore implementations for testing and ephemeral use.
-- **Builder patterns** – Ergonomic construction of blobs, commits, tags, trees.
-- **Validation utilities** – Path traversal and resource exhaustion prevention.
-- **Strict linting and documentation** – Clippy all, pedantic, nursery, cargo denied; missing_docs denied.
-- **Unified error handling** – `VctrlError` with source chaining and comparison.
+- **Layered and modular.** Contracts, reference implementations, and crypto primitives are
+ isolated in separate crates with a one-way dependency flow.
+- **Content-addressed.** Objects are serialised deterministically and addressed by SHA-512
+ digests, so identical content always produces identical addresses.
+- **Invalid states unrepresentable.** All domain types use fallible constructors that reject
+ malformed input at construction time; objects are immutable thereafter.
+- **Defense-in-depth decoding.** The binary decoder bounds input, checks every offset,
+ validates UTF-8, and re-checks system limits — no slice indexing without a prior bounds
+ check.
+- **Resource-exhaustion prevention.** Hard `MAX_*` limits act as fail-fast circuit breakers
+ during construction and decoding, bounding memory allocation against malicious input.
+- **Zero-dependency cryptography.** SHA-512, HMAC-SHA512, HKDF-SHA512, and optional SHA-384
+ are implemented in pure Rust over `core`, with constant-time verification and zeroization.
+- **Single-dependency entry point.** The `libvctrl` facade re-exports the entire stack under
+ one ergonomic namespace.
+- **Strict memory safety.** `#![forbid(unsafe_code)]` is enforced workspace-wide.
---
## Technology Stack
-- **Language:** Rust (edition 2024)
-- **Build tool:** Cargo
-- **Dependencies:**
- - `libvctrl_sha512` – zero external dependencies
- - `libvctrl_handler` – no external dependencies
- - `libvctrl_core` – uses `libvctrl_handler` and `libvctrl_sha512`; dev-dependency `proptest`
- - Other crates build on top
-- **Testing:** `proptest` for property-based tests, `criterion` for benchmarks
-- **License:** MIT for most crates, ISC for `libvctrl_sha512`
+- **Language:** Rust (edition 2024, MSRV 1.96.0)
+- **Workspace licence:** MIT (`libvctrl_sha512` is ISC)
+- **Authors:** `mroczect`
+- **Resolver:** Cargo resolver v2
+- **Lint policy:** workspace-inherited (see [Contributing](#contributing))
+- **`no_std` status:** the workspace as a whole is **`std`-only**. The `no-std` keyword in
+ the workspace metadata applies only to `libvctrl_sha512` as a future-compatible goal; even
+ that crate is currently `std`-by-default (it uses only `core` APIs internally but does not
+ yet set `#![no_std]`).
---
## Project Structure
```text
-libvcrtl/
-├── Cargo.toml # Workspace manifest
-├── Cargo.lock
-├── CONTRIBUTING.md
-├── CODE_OF_CONDUCT.md
-├── SECURITY.md
-├── LICENSE
-├── Makefile
-├── scripts/ # Helper scripts
-├── dev/ # Development utilities
-├── libvctrl/ # Main CLI / executable crate
-├── libvctrl_core/ # Reference implementations
-├── libvctrl_docs/ # Documentation tooling
-├── libvctrl_handler/ # Contracts, types, traits
-├── libvctrl_plumbing/ # Low-level plumbing commands
-├── libvctrl_porcelain/ # User-facing porcelain commands
-└── libvctrl_sha512/ # SHA-512, HMAC, HKDF
+libvctrl/
+├── Cargo.toml # workspace manifest
+├── README.md # this file (workspace overview)
+├── CONTRIBUTING.md # contribution guidelines
+├── LICENSE # MIT (workspace); ISC under libvctrl_sha512/
+├── libvctrl/ # facade crate (v2.1.2)
+├── libvctrl_handler/ # contract layer (v5.0.0)
+├── libvctrl_core/ # reference implementations (v3.0.0)
+├── libvctrl_sha512/ # crypto primitives (v3.0.0, ISC)
+├── libvctrl_plumbing/ # command-level operations (v0.2.0)
+└── libvctrl_porcelain/ # high-level operations (v0.1.0)
```
-Each crate has its own `README.md` with detailed documentation. Refer to those files for crate-specific information.
+Each member crate contains its own `Cargo.toml`, `src/`, `README.md`, and tests.
---
@@ -143,258 +169,228 @@ Each crate has its own `README.md` with detailed documentation. Refer to those f
### Prerequisites
-- Rust toolchain 1.96.0 or newer (edition 2024)
+- Rust toolchain **1.96.0** or newer (edition 2024 is required)
- Cargo
+- Git
-No system libraries or external services are required to build and test the workspace.
+No system libraries or external services are required.
### Installation
-Clone the repository:
+For most users, depend on the facade — it pulls the contracts, the reference implementation,
+and the crypto primitives as a single dependency:
-```sh
-git clone https://github.com/mroczect/libvctrl.git
-cd libvcrtl
+```toml
+[dependencies]
+libvctrl = "2.1"
```
-Build the entire workspace:
+Or via Cargo:
-```sh
-cargo build --workspace
+```bash
+cargo add libvctrl
```
-### Configuration
-
-No global configuration is required. Each crate may have its own feature flags:
+To work on the workspace itself, clone the repository and build all members:
-- `libvctrl_sha512` features: `default = ["sha384"]`, `sha384`, `opt_size`.
-- Other crates do not expose feature flags.
-
-Environment variables are not used by the core libraries. The main CLI (`libvctrl`) may support configuration later.
-
----
-
-## Usage
-
-### Running the CLI
-
-If the main binary crate `libvctrl` is built, you can run:
-
-```sh
-cargo run -p libvctrl -- --help
+```bash
+git clone https://github.com/mroczect/libvctrl.git
+cd libvctrl
+cargo build --workspace
```
-### Using the Libraries
+### Configuration
+
+The workspace has no runtime configuration. Behavioural configuration of the cryptographic
+backend is controlled through the facade's feature flags, which are forwarded to
+`libvctrl_sha512`:
-Add the desired crate as a dependency in your `Cargo.toml`:
+- `sha384` (default) — enables SHA-384, HMAC-SHA-384, and HKDF-SHA-384.
+- `opt_size` — favours smaller binary size over speed for embedded/WebAssembly/minimal-CLI
+ targets by de-inlining the SHA-512 compression round functions.
```toml
-[dependencies]
-libvctrl_handler = "4.4.0"
-libvctrl_core = "2.0.1"
-libvctrl_sha512 = "2.0.0"
-```
+# Default (SHA-512 + SHA-384)
+libvctrl = "2.1"
-Then use the exported types and traits. Example combining handler and core:
+# Minimal (SHA-512 only)
+libvctrl = { version = "2.1", default-features = false }
-```rust
-use libvctrl_handler::{Blob, Encoder, Hasher, ObjectStore};
-use libvctrl_core::codec::BinaryEncoder;
-use libvctrl_core::hash::Sha512Hasher;
-use libvctrl_core::store::MemoryStore;
-use std::io::Read;
-
-let blob = Blob::new(b"my content".to_vec());
-let encoder = BinaryEncoder;
-let bytes = encoder.encode_blob(&blob).unwrap();
-
-let hasher = Sha512Hasher;
-let hash = hasher.hash(&bytes).unwrap();
-
-let mut store = MemoryStore::new();
-store.put(&hash, &bytes).unwrap();
-
-let mut reader = store.get(&hash).unwrap();
-let mut buf = Vec::new();
-reader.read_to_end(&mut buf).unwrap();
-assert_eq!(buf, bytes);
+# Size-optimised, full crypto
+libvctrl = { version = "2.1", features = ["opt_size"] }
```
---
-## Workspace Crates
-
-Detailed documentation for each crate is available in its respective `README.md`. Below is a summary.
-
-### libvctrl_handler
-
-**Contracts and Types**
-
-The foundational crate that defines:
-
-- Immutable data types: `Blob`, `Tree`, `TreeEntry`, `Commit`, `CommitMeta`, `Tag`, `Hash`, `UserID`
-- Logical object kind enum: `EntryKind`
-- System constants and limits
-- Unified error type: `VctrlError`
-- Behavior traits: `ObjectStore`, `RefStore`, `Hasher`, `Encoder`, `Decoder`, `Signer`, `Verifier`, `Transport`
-
-Contains no implementations. All public items are re-exported at crate root.
-
-### libvctrl_core
-
-**Reference Implementations**
-
-Provides production-ready implementations of the handler contracts:
-
-- `BinaryEncoder` and `BinaryDecoder` for serialization
-- `Sha512Hasher`
-- `MemoryStore` and `MemoryRefStore`
-- Builder patterns: `BlobBuilder`, `CommitBuilder`, `TagBuilder`, `TreeBuilder`, `TreeEntryBuilder`
-- Validation utilities for names and hashes
-
-This crate is intended as a quality exemplar for custom backend implementations.
-
-### libvctrl_sha512
-
-**Cryptographic Primitives**
-
-Zero-dependency, `no_std`-compatible implementation of:
-
-- SHA-512
-- HMAC-SHA-512
-- HKDF-SHA-512
-- SHA-384 (feature-gated)
-- HMAC-SHA-384 and HKDF-SHA-384 (feature-gated)
-
-Uses exported macros to generate HMAC and HKDF structs for different hash lengths.
-
-### libvctrl_plumbing
+## Usage
-**Low-level Commands**
+### Quick start with the facade
-Implements the plumbing (low-level) layer of the VCS, operating directly on object stores, refs, and codecs. Depends on `libvctrl_handler` and `libvctrl_core`.
+```rust
+use libvctrl::{
+ Blob, Encoder, Hasher, ObjectStore,
+ BinaryEncoder, Sha512Hasher, MemoryStore, VctrlError,
+};
+
+fn main() -> Result<(), VctrlError> {
+ // 1. Build a validated blob.
+ let blob = Blob::new(b"hello world".to_vec())?;
+
+ // 2. Encode it into deterministic, versioned bytes.
+ let mut encoded = Vec::new();
+ BinaryEncoder.encode_blob(&blob, &mut encoded)?;
+
+ // 3. Hash the encoded bytes to obtain a 64-byte content address.
+ let hash = Sha512Hasher.hash(&mut encoded.as_slice())?;
+
+ // 4. Store the encoded object in memory and verify it exists.
+ let mut store = MemoryStore::new();
+ store.put(&hash, &encoded)?;
+ assert!(store.exists(&hash)?);
+ Ok(())
+}
+```
-### libvctrl_porcelain
+### Workspace commands
-**User-facing Commands**
+```bash
+# Build every member
+cargo build --workspace
-Implements the porcelain (user-friendly) layer, providing high-level commands such as commit, checkout, branch, tag, etc. Depends on `libvctrl_plumbing`.
+# Run the entire test suite
+cargo test --workspace
-### libvctrl
+# Run clippy across all members and targets
+cargo clippy --workspace --all-targets -- -D warnings
-all-in-one Version Control System (VCS) Software Development Kit. It aggregates the three foundational crates of the `libvcrtl` workspace into a single, coherent namespace, allowing developers to bootstrap a fully functional version control system without manually stitching together multiple dependencies.
+# Build documentation for the whole workspace
+cargo doc --workspace --no-deps
-### libvctrl_docs
+# Run benchmarks (criterion; sha384 bench requires the sha384 feature)
+cargo bench --workspace
+```
-**Documentation Tooling**
+---
-Utilities and helpers for generating and maintaining project documentation.
+## Crates
+
+The workspace publishes six crates. Each has its own README and docs.rs page.
+
+| Crate | Version | Licence | Role | Documentation |
+| -------------------- | ------- | ------- | ------------------------------------------------------------------------ | ---------------------------------- |
+| `libvctrl` | 2.1.2 | MIT | Facade: re-exports contracts, reference impl, and crypto | https://docs.rs/libvctrl |
+| `libvctrl_handler` | 5.0.0 | MIT | Contract layer: traits, types, limits, validation | https://docs.rs/libvctrl_handler |
+| `libvctrl_core` | 3.0.0 | MIT | Reference implementations: codec, builders, stores, hasher adapter | https://docs.rs/libvctrl_core |
+| `libvctrl_sha512` | 3.0.0 | ISC | Zero-dependency SHA-512 / HMAC / HKDF (+ optional SHA-384) | https://docs.rs/libvctrl_sha512 |
+| `libvctrl_plumbing` | 0.2.0 | MIT | Command-level VCS operations as a library (`cat_file`, `cat_file_batch`) | https://docs.rs/libvctrl_plumbing |
+| `libvctrl_porcelain` | 0.1.0 | MIT | High-level, user-facing VCS operations as a library (early stage) | https://docs.rs/libvctrl_porcelain |
+
+### Layer roles
+
+- **`libvctrl_handler`** — the "constitution" layer. Defines _what_ a VCS object model looks
+ like: 17 backend contracts (`Encoder`, `Decoder`, `Hasher`, `ObjectStore`, `RefStore`,
+ `Transport`, `Signer`, `Verifier`, `Blame`, `ConfigStore`, etc.), 14 immutable data types
+ (`Blob`, `Tree`, `Commit`, `Tag`, `Hash`, `UserID`, ...), system limits, validation
+ functions, and the unified `VctrlError`. No implementations; `std`-only; zero dependencies.
+- **`libvctrl_core`** — the reference implementation. Realises the handler contracts with a
+ deterministic, versioned binary codec (`BinaryEncoder`/`BinaryDecoder`), a SHA-512 hasher
+ adapter (`Sha512Hasher`), fluent builders, and in-memory stores (`MemoryStore`,
+ `MemoryRefStore`). `std`-only.
+- **`libvctrl_sha512`** — the crypto engine. Pure-Rust SHA-512, HMAC-SHA512, HKDF-SHA512,
+ and optional SHA-384, with constant-time verification and zeroization. Zero external
+ dependencies; `std`-by-default but `core`-only internally. ISC-licensed.
+- **`libvctrl`** — the facade. Re-exports `libvctrl_handler`, `libvctrl_core`, and
+ `libvctrl_sha512` under one namespace, lifting the most common items to the crate root.
+ The recommended single dependency for most users.
+- **`libvctrl_plumbing`** — command-level VCS operations as a library (currently `cat_file`
+ and `cat_file_batch`). Built on `libvctrl_core`.
+- **`libvctrl_porcelain`** — high-level, user-facing VCS operations as a library. Early
+ stage with a minimal public API. A future `vctrl` CLI could be built on top, but no binary
+ exists yet.
---
## Testing
-Run all tests in the workspace:
+Run the entire workspace test suite (unit tests, doctests, and property-based tests via
+`proptest`):
-```sh
+```bash
cargo test --workspace
```
-Run tests with all features enabled:
-
-```sh
-cargo test --workspace --all-features
-```
+`libvctrl_sha512` additionally ships `criterion` benchmarks under `benches/`:
-Run doctests only:
-
-```sh
-cargo test --workspace --doc
-```
-
-Run benchmarks (from `libvctrl_sha512`):
-
-```sh
+```bash
+# Run all benchmarks
cargo bench --workspace
-```
-
----
-## CI/CD Pipeline
-
-No CI/CD pipeline is currently configured in the repository.
-
-If one is added, it should include at least the following stages:
-
-```mermaid
-graph LR
- A[Push] --> B[Format Check]
- B --> C[Clippy Lint]
- C --> D[Run Tests]
- D --> E[Build Docs]
- E --> F[Publish]
+# The SHA-384 benchmark requires the sha384 feature (on by default)
+cargo bench --bench sha384_bench
```
-Recommended commands per stage:
-
-- Format: `cargo fmt --check`
-- Lint: `cargo clippy --workspace --all-targets --all-features -- -D warnings`
-- Tests: `cargo test --workspace --all-features`
-- Docs: `cargo doc --workspace --no-deps`
-- Publish: `cargo publish` for each crate
-
---
-## Deployment / Distribution
+## Contributing
-Each crate is intended to be published to crates.io independently. Release process:
+Contributions are welcome. The workspace enforces a shared lint policy inherited by all
+members via `[lints] workspace = true`.
-1. Update version in the crate's `Cargo.toml`.
-2. Update its `CHANGELOG.md`.
-3. Run `cargo publish --dry-run`.
-4. Run `cargo publish` with a valid `CRATES_IO_TOKEN`.
+### Workspace lint policy
-Published crates:
+**`rustc` lints:**
-- `libvctrl_handler`
-- `libvctrl_core`
-- `libvctrl_sha512`
-- Possibly others as they stabilize.
+- `unsafe_code` and `macro_use_extern_crate` are **`forbid`** — non-overridable, hard
+ errors. No `unsafe` code is permitted anywhere in the workspace.
+- A broad set of `rustc` lints (`missing_docs`, `dead_code`, `unused_imports`,
+ `unused_variables`, `unused_lifetimes`, `unused_macro_rules`, `unused_crate_dependencies`,
+ `unreachable_pub`, `rust_2018_idioms`, `rust_2021_compatibility`, `rust_2024_compatibility`,
+ `elided_lifetimes_in_paths`, `explicit_outlives_requirements`, `non_ascii_idents`,
+ `trivial_bounds`, `unit_bindings`, `single_use_lifetimes`, `redundant_lifetimes`,
+ `unused_qualifications`, `noop_method_call`, `unnameable_types`) are **`warn`** — they
+ surface diagnostics but do not fail the build.
----
+**`clippy` lints:**
-## Security & Compliance
+- `clippy::all` is **`warn`**.
+- `clippy::pedantic`, `clippy::nursery`, and `clippy::cargo` are **`allow`** (effectively
+ disabled).
+- A focused set of panic/unwrap-adjacent lints (`todo`, `unimplemented`, `unreachable`,
+ `unwrap_used`, `expect_used`, `panic`, `indexing_slicing`, `map_err_ignore`,
+ `wildcard_enum_match_arm`) are **`warn`**.
+- Several style/portability lints are explicitly allowed (`doc_markdown`,
+ `doc_lazy_continuation`, `needless_return`, `match_same_arms`, `uninlined_format_args`,
+ `std_instead_of_core`, `std_instead_of_alloc`, `alloc_instead_of_core`).
-The workspace enforces strict security practices:
+> **Note on accuracy.** Earlier per-crate READMEs in this repository may have described
+> `missing_docs`, `rust_2018_idioms`, and the `pedantic`/`nursery` groups as "denied." That
+> was inaccurate: they are `warn` or `allow` as described above. Those per-crate sections
+> should be corrected in a separate pass. The authoritative source is the
+> `[workspace.lints]` table in the root `Cargo.toml`.
-- **No unsafe code** except one reviewed block in `libvctrl_sha512::utils::verify`.
-- **Denial-of-service prevention** via size limits and validation.
-- **Path traversal prevention** in name validation.
-- **Side-channel mitigation** via constant-ish time comparison.
-- **Zeroization** of sensitive state in hash implementations.
-- **Strict Clippy lints** including pedantic and nursery.
+### Local development
-Refer to `SECURITY.md` for reporting vulnerabilities and additional security guidelines.
+```bash
+# Format check
+cargo fmt --all -- --check
----
+# Lint across the workspace (treat warnings as errors for CI)
+cargo clippy --workspace --all-targets -- -D warnings
-## Contributing
-
-Contributions are welcome. Please read `CONTRIBUTING.md` and follow the project's code of conduct.
-
-General guidelines:
+# Documentation build
+cargo doc --workspace --no-deps
+```
-- All public items must have documentation with doctests.
-- Run `cargo fmt`.
-- Run `cargo clippy --workspace --all-targets --all-features -- -D warnings`.
-- Run `cargo test --workspace --all-features`.
-- Avoid unsafe code; if necessary, justify it thoroughly.
+For contribution guidelines, code style, and the full lint configuration, see
+`CONTRIBUTING.md` and this README. When contributing, preserve the layered invariants: new
+contracts and types belong in `libvctrl_handler`; new reference implementations belong in
+`libvctrl_core`; new user-facing commands belong in `libvctrl_plumbing` or
+`libvctrl_porcelain`; and no `unsafe` code may be introduced in any member.
---
-## License
-
-- Most crates in this workspace are licensed under the **MIT License**.
-- `libvctrl_sha512` is licensed under the **ISC License**.
+## Licence
-See the `LICENSE` file in each crate for details.
+The workspace is licensed under the **MIT** licence, except for `libvctrl_sha512`, which is
+licensed under the **ISC** licence. See each crate's `LICENSE` file for the authoritative
+text.
diff --git a/libvctrl/Cargo.toml b/libvctrl/Cargo.toml
index 556c66de..6eccb760 100644
--- a/libvctrl/Cargo.toml
+++ b/libvctrl/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "libvctrl"
-version = "2.1.2"
+version = "2.1.3"
edition = "2024"
description = "A precision toolkit for building custom version control systems"
license = "MIT"
diff --git a/libvctrl/README.md b/libvctrl/README.md
index 75f7366d..68b74b2e 100644
--- a/libvctrl/README.md
+++ b/libvctrl/README.md
@@ -1,175 +1,180 @@
# libvctrl
-**Version:** 2.1.1
-**License:** MIT
-**Crate type:** Rust library (facade / SDK)
-**Workspace:** libvcrtl
-
-`libvctrl` is the **all-in-one Version Control System (VCS) Software Development Kit**. It aggregates the three foundational crates of the `libvcrtl` workspace into a single, coherent namespace, allowing developers to bootstrap a fully functional version control system without manually stitching together multiple dependencies.
-
-The crate itself contains almost no new logic. Instead, it re-exports the essential types, traits, implementations, and cryptographic primitives from:
-
-- `libvctrl_handler` – pure contracts and data types
-- `libvctrl_core` – ready-to-use reference implementations
-- `libvctrl_sha512` – zero-dependency cryptographic primitives
-
-This facade design gives downstream users one convenient entry point while preserving strict separation of concerns internally.
-
----
-
-## Table of Contents
-
-- [Overview](#overview)
-- [System Architecture](#system-architecture)
-- [Core Features](#core-features)
-- [Technology Stack](#technology-stack)
-- [Project Structure](#project-structure)
-- [Getting Started](#getting-started)
- - [Prerequisites](#prerequisites)
- - [Installation](#installation)
- - [Configuration](#configuration)
-- [Usage](#usage)
-- [API Reference](#api-reference)
- - [Sub-crate Modules](#sub-crate-modules)
- - [handler](#handler)
- - [reference](#reference)
- - [crypto](#crypto)
- - [Root Re-exports: Contracts](#root-re-exports-contracts)
- - [Root Re-exports: Reference Implementations](#root-re-exports-reference-implementations)
-- [Testing](#testing)
-- [CI/CD Pipeline](#cicd-pipeline)
-- [Deployment / Distribution](#deployment--distribution)
-- [Security & Compliance](#security--compliance)
-- [Contributing](#contributing)
-- [License](#license)
-- [Changelog](#changelog)
+A precision toolkit for building custom version control systems. `libvctrl` is the
+all-in-one facade crate of the `libvctrl` workspace: it re-exports the contract layer,
+the reference implementation, and the cryptographic primitives of a content-addressable
+VCS into a single, ergonomic namespace.
+
+- **Crate:** `libvctrl` 2.1.3 (library-only, `std`-only)
+- **Language:** Rust, edition 2024 — MSRV **1.96.0**
+- **License:** MIT
+- **Repository:** https://github.com/mroczect/libvctrl
+- **Documentation:** https://docs.rs/libvctrl
+
+> `libvctrl` is a **library facade**. It contains no logic of its own; every public
+> item is a compile-time re-export of one of three underlying workspace crates. A
+> future binary crate (for example, a `vctrl` CLI) may be built on top of this facade,
+> but no such binary exists at the 2.1.2 release.
---
## Overview
-`libvctrl` is designed for developers who want to build a custom version control system, or use an existing VCS core, without needing to know the exact module paths of each underlying crate.
+`libvctrl` aggregates the three foundational crates of the `libvctrl` ecosystem into one
+dependency. Integrators who need a complete, batteries-included VCS stack can depend on
+a single crate instead of stitching together the contract, reference, and crypto layers
+manually.
-It provides:
+The facade exposes three top-level namespaces and lifts the most commonly used items to
+the crate root:
-- **Contracts**: Immutable domain types like `Blob`, `Commit`, `Tree`, `Hash`, and behavior traits like `ObjectStore`, `Encoder`, `Hasher`, and `Transport`.
-- **Reference implementations**: In-memory stores (`MemoryStore`, `MemoryRefStore`), binary serialization (`BinaryEncoder`, `BinaryDecoder`), SHA-512 hasher adapter (`Sha512Hasher`), and ergonomic builders.
-- **Cryptography**: Full SHA-512, HMAC-SHA-512, HKDF-SHA-512, and optional SHA-384 implementations.
+- `handler` — re-export of `libvctrl_handler`: abstract traits, immutable data types,
+ system limits, and validation functions.
+- `reference` — re-export of `libvctrl_core`: production-ready implementations of the
+ handler contracts (binary codec, SHA-512 hasher adapter, builders, in-memory stores).
+- `crypto` — re-export of `libvctrl_sha512`: zero-dependency SHA-512, HMAC-SHA512,
+ HKDF-SHA512, and optional SHA-384 primitives.
-All public items are re-exported at the crate root for maximum ergonomics, while the original sub-crate modules remain accessible for explicit use.
+All re-exports are zero-cost aliases. There is no runtime overhead and no duplicated
+code; the only cost is a larger public API surface.
---
-## System Architecture
+## Architecture
-`libvctrl` acts as a facade. It re-exports three underlying crates into top-level modules and then lifts many of their types to the root.
+`libvctrl` is a classic facade over a strictly layered dependency graph. The contract
+layer (`libvctrl_handler`) depends only on the Rust standard library and defines _what_
+a VCS object model looks like. The reference layer (`libvctrl_core`) depends on the
+contract layer and provides _how_ those contracts are realised. The crypto layer
+(`libvctrl_sha512`) provides the hashing primitive and is wired into the facade with
+`default-features = false` so the facade controls which crypto symbols are visible.
+
+The `crypto` namespace alias exists for a deliberate reason: it isolates the
+cryptographic `Hash` hasher type from the VCS `Hash` content-address type, preventing a
+name collision when both are imported into the same scope.
```mermaid
-graph TD
- LIBVCTRL[libvctrl facade crate]
- HANDLER[libvctrl_handler Contracts & Types]
- CORE[libvctrl_core Reference Implementations]
- SHA512[libvctrl_sha512 Cryptography]
-
- LIBVCTRL -->|pub use as handler| HANDLER
- LIBVCTRL -->|pub use as reference| CORE
- LIBVCTRL -->|pub use as crypto| SHA512
-
- subgraph Root Re-exports
- ROOT_TYPES[Blob, Tree, Commit, Tag, Hash, UserID, TreeEntry, CommitMeta]
- ROOT_TRAITS[ObjectStore, RefStore, Hasher, Encoder, Decoder, Signer, Verifier, Transport]
- ROOT_CONST[constants, HASH_LENGTH, MAX_*]
- ROOT_ENUMS[EntryKind]
- ROOT_ERRORS[VctrlError]
- ROOT_MACROS[vctrl_error_other]
- ROOT_BUILDERS[BlobBuilder, CommitBuilder, TagBuilder, TreeBuilder, TreeEntryBuilder]
- ROOT_STORES[MemoryStore, MemoryRefStore]
- ROOT_CODEC[BinaryEncoder, BinaryDecoder]
- ROOT_HASHER[Sha512Hasher]
- ROOT_VALIDATE[validate_name, validate_hash_bytes]
+flowchart TD
+ subgraph Facade["libvctrl facade crate (std-only, library)"]
+ Root["Root re-exports Blob, Commit, Tree, Tag, Hash, UserID... Encoder, Decoder, Hasher, ObjectStore, RefStore... BinaryEncoder, BinaryDecoder, Sha512Hasher Builders, MemoryStore, MemoryRefStore constants, validation, VctrlError"]
+ HandlerNS["handler namespace libvctrl_handler"]
+ RefNS["reference namespace libvctrl_core"]
+ CryptoNS["crypto namespace libvctrl_sha512"]
+ Root --> HandlerNS
+ Root --> RefNS
+ Root --> CryptoNS
end
- HANDLER --> ROOT_TYPES
- HANDLER --> ROOT_TRAITS
- HANDLER --> ROOT_CONST
- HANDLER --> ROOT_ENUMS
- HANDLER --> ROOT_ERRORS
- HANDLER --> ROOT_MACROS
- CORE --> ROOT_BUILDERS
- CORE --> ROOT_STORES
- CORE --> ROOT_CODEC
- CORE --> ROOT_HASHER
- CORE --> ROOT_VALIDATE
-```
+ subgraph Contracts["Contract layer"]
+ Handler["libvctrl_handler traits, types, constants, validation, errors, enums"]
+ end
-This architecture ensures that users can choose between:
+ subgraph Reference["Reference implementation"]
+ Core["libvctrl_core codec, builders, stores, Sha512Hasher adapter"]
+ Core -->|depends on| Handler
+ end
-- **Implicit, root-level imports** for rapid development: `use libvctrl::*;`
-- **Explicit, module-qualified imports** for clarity: `use libvctrl::handler::Blob;`
+ subgraph CryptoLayer["Cryptography"]
+ Sha["libvctrl_sha512 SHA-512, HMAC-SHA512, HKDF-SHA512, optional SHA-384"]
+ end
----
+ HandlerNS --> Handler
+ RefNS --> Core
+ CryptoNS --> Sha
+```
-## Core Features
+The crate is `std`-only. The facade and its immediate dependencies rely on `String`,
+`Vec`, `HashMap`, `std::io`, and `std::error::Error`. Although the underlying
+`libvctrl_sha512` core may be `no_std`-compatible, the facade re-exports the full SDK,
+including the `std`-dependent stores and codecs, so `libvctrl` itself cannot be built
+without the standard library.
-- **Facade pattern**
- A single crate exposes the entire VCS stack, reducing dependency management burden.
+### Object lifecycle workflow
-- **Namespace isolation**
- The cryptographic primitives are grouped under `crypto` to avoid conflicts between the VCS `Hash` type and the SHA-512 `Hash` hasher.
+A typical interaction with the facade follows the same pattern as a Git-like
+content-addressable store: build a validated object, encode it to deterministic bytes,
+hash the encoded bytes to obtain a content address, store the bytes under that address,
+and later retrieve and verify them.
-- **Batteries-included**
- In-memory storage, binary serialization, SHA-512 hashing, and builders are all available out of the box.
+```mermaid
+sequenceDiagram
+ participant App as Application
+ participant B as Builder
+ participant E as BinaryEncoder
+ participant H as Sha512Hasher
+ participant S as MemoryStore
+
+ App->>B: Build object (Blob / Tree / Commit / Tag)
+ B->>B: Validate fields and limits
+ B-->>App: Validated immutable object
+ App->>E: encode_*(&object, &mut buf)
+ E->>E: Produce deterministic, versioned bytes
+ E-->>App: Encoded payload
+ App->>H: hash(&mut encoded.as_slice())
+ H-->>App: Hash (64-byte content address)
+ App->>S: put(&hash, &encoded)
+ S-->>App: ()
+ App->>S: exists(&hash)
+ S-->>App: true
+ App->>S: get(&hash)
+ S-->>App: Reader over stored bytes
+ App->>App: Decode / verify round-trip
+```
-- **Strict safety**
- `#![forbid(unsafe_code)]` and a comprehensive set of denied Clippy lints ensure memory safety and code quality.
+---
-- **Root-level ergonomics**
- Frequently used types and traits are re-exported at the crate root, enabling `use libvctrl::Blob;` instead of deep paths.
+## Core Features
-- **Feature forwarding**
- Features for SHA-384 and code-size optimization are forwarded to `libvctrl_sha512`, allowing users to configure the underlying crypto implementation.
+- **Facade pattern.** One crate exposes the entire VCS stack, removing the need to
+ manage three separate dependencies.
+- **Namespace isolation.** The cryptographic primitives live under `crypto` to avoid a
+ name collision between the VCS `Hash` content-address type and the SHA-512 `Hash`
+ hasher type.
+- **Batteries included.** In-memory storage, binary serialization, a SHA-512 hasher
+ adapter, and fluent builders are available out of the box.
+- **Root-level ergonomics.** Frequently used types and traits are re-exported at the
+ crate root, so `use libvctrl::Blob;` works without a long path.
+- **Strict safety.** `#![forbid(unsafe_code)]` is enforced, and the crate inherits
+ strict, denied Clippy and rustc documentation lints from the workspace.
+- **Feature forwarding.** The `sha384` and `opt_size` features are forwarded to
+ `libvctrl_sha512`, letting integrators configure the cryptographic backend without
+ touching the underlying crate directly.
---
## Technology Stack
-- **Language:** Rust (edition 2024)
+- **Language:** Rust (edition 2024, MSRV 1.96.0)
- **Dependencies:**
- - `libvctrl_handler` 4.4.0 – contracts and types
- - `libvctrl_core` 2.0.1 – reference implementations
- - `libvctrl_sha512` 2.0.0 – cryptography (with `default-features = false`)
-- **Dev dependencies:**
- - `proptest` 1.11.0
-- **Features:**
- - `default = ["sha384"]`
- - `sha384` – enables `libvctrl_sha512/sha384`
- - `opt_size` – enables `libvctrl_sha512/opt_size`
-- **Strict lints:**
- - Clippy: `all`, `pedantic`, `nursery`, `cargo`, `missing_const_for_fn`, `redundant_clone`, `unwrap_used`, `expect_used`, `panic` (all denied)
- - Rust: `unsafe_code` forbidden, `missing_docs` denied, `rust_2018_idioms` denied, `unreachable_pub` denied, `unused_qualifications` denied
+ - `libvctrl_handler` 5.0.0 — contracts and types (path dependency)
+ - `libvctrl_core` 3.0.0 — reference implementations (path dependency)
+ - `libvctrl_sha512` 3.0.0 — cryptography, `default-features = false` (path dependency)
+- **Dev-dependencies:** `proptest` 1.11.0
+- **Lint policy:** workspace-inherited, `#![forbid(unsafe_code)]`, denied missing-docs,
+ rust-2018-idioms, and a broad set of Clippy lints (including pedantic and nursery
+ groups). See the repository for the authoritative lint configuration.
---
## Project Structure
-The crate consists of a single source file that re-exports the underlying crates.
+The facade crate consists of a single source file. All functionality is provided
+through re-exports; no additional modules are defined.
```text
libvctrl/
├── Cargo.toml
└── src/
- └── lib.rs
+ └── lib.rs # Re-exports only; no runtime logic
```
-No additional modules are defined. All functionality is provided through re-exports.
-
---
## Getting Started
### Prerequisites
-- Rust toolchain 1.96.0 or newer (edition 2024)
+- Rust toolchain **1.96.0** or newer (edition 2024 is required)
- Cargo
No system libraries or external services are required.
@@ -180,83 +185,123 @@ Add `libvctrl` to your `Cargo.toml`:
```toml
[dependencies]
-libvctrl = "2.1.1"
+libvctrl = "2.1.2"
```
-Or use Cargo:
+Or use Cargo directly:
-```sh
+```bash
cargo add libvctrl
```
-This will automatically pull the required `libvctrl_handler`, `libvctrl_core`, and `libvctrl_sha512` dependencies.
+This will automatically pull `libvctrl_handler`, `libvctrl_core`, and `libvctrl_sha512`
+as transitive dependencies.
### Configuration
-No runtime configuration is required. Available feature flags:
+No runtime configuration is required. The behaviour of the cryptographic backend is
+controlled through Cargo features.
+
+| Use case | Configuration |
+| ----------------------------- | --------------------------------------------------- |
+| Default full functionality | `default` (includes `sha384`) |
+| Minimal SHA-512 only | `default-features = false` |
+| Size-optimised build | `features = ["opt_size"]` |
+| Size-optimised + SHA-512 only | `default-features = false, features = ["opt_size"]` |
```toml
-[dependencies]
-libvctrl = { version = "2.1.1", features = ["sha384", "opt_size"] }
-```
+# Default (SHA-512 + SHA-384)
+libvctrl = "2.1.2"
-- `sha384` is enabled by default and adds SHA-384, HMAC-SHA-384, and HKDF-SHA-384.
-- `opt_size` favors smaller binary size over speed by changing inline attributes in the SHA-512 implementation.
+# Minimal: SHA-512 only
+libvctrl = { version = "2.1.2", default-features = false }
-Disable default features if you do not need SHA-384:
+# Size-optimised, full crypto
+libvctrl = { version = "2.1.2", features = ["opt_size"] }
-```toml
-[dependencies]
-libvctrl = { version = "2.1.1", default-features = false }
+# Size-optimised, SHA-512 only
+libvctrl = { version = "2.1.2", default-features = false, features = ["opt_size"] }
```
+- **`sha384`** (default): enables SHA-384, HMAC-SHA-384, and HKDF-SHA-384 in the `crypto`
+ namespace. Disable it to reduce compile time and code size when only SHA-512 is needed.
+- **`opt_size`**: favours smaller binary size over speed by selecting smaller, slower
+ SHA-512 variants. Intended for binary-size-sensitive targets such as embedded devices,
+ WebAssembly, or minimal CLI builds. It does **not** enable `no_std`.
+
+> `libvctrl` is `std`-only. `opt_size` is a code-size optimisation, not a `no_std`
+> switch. If you need a `no_std`-compatible hashing core, depend on `libvctrl_sha512`
+> directly rather than through this facade.
+
---
## Usage
-### Build, Encode, Hash, and Store a Tree
+### Build, encode, hash, and store a Blob
```rust
use libvctrl::{
- EntryKind, Hash, TreeBuilder, TreeEntryBuilder, BinaryEncoder, Sha512Hasher,
- MemoryStore, Encoder, Hasher, ObjectStore, VctrlError,
+ Blob, Encoder, Hasher, ObjectStore,
+ BinaryEncoder, Sha512Hasher, MemoryStore, VctrlError,
};
-use std::io::Read;
-
-// 1. Build a Tree containing a single file entry
-let blob_hash = Hash::from_bytes(&[0xAB; 64])?;
-let entry = TreeEntryBuilder::new("file.txt".to_string(), EntryKind::Blob, blob_hash).build()?;
-let tree = TreeBuilder::new().entry(entry).build()?;
-// 2. Encode the Tree into binary format
-let encoder = BinaryEncoder;
-let encoded_bytes = encoder.encode_tree(&tree)?;
+fn main() -> Result<(), VctrlError> {
+ // 1. Create a validated blob.
+ let blob = Blob::new(b"my content".to_vec())?;
-// 3. Hash the encoded bytes to get an address
-let hasher = Sha512Hasher;
-let tree_hash = hasher.hash(&encoded_bytes)?;
+ // 2. Encode the blob into deterministic, versioned bytes.
+ let mut encoded = Vec::new();
+ BinaryEncoder.encode_blob(&blob, &mut encoded)?;
-// 4. Store the encoded object in memory
-let mut store = MemoryStore::new();
-store.put(&tree_hash, &encoded_bytes)?;
+ // 3. Hash the encoded bytes to obtain a content address.
+ let hash = Sha512Hasher.hash(&mut encoded.as_slice())?;
-// 5. Retrieve and verify the object
-assert!(store.exists(&tree_hash)?);
-let mut reader = store.get(&tree_hash)?;
-let mut buf = Vec::new();
-reader.read_to_end(&mut buf).map_err(VctrlError::IoError)?;
-assert_eq!(buf, encoded_bytes);
+ // 4. Store the encoded object in memory.
+ let mut store = MemoryStore::new();
+ store.put(&hash, &encoded)?;
-# Ok::<(), VctrlError>(())
+ // 5. Verify the object exists.
+ assert!(store.exists(&hash)?);
+ Ok(())
+}
```
-### Using Namespace-Isolated Cryptography
+### Build, encode, hash, and store a Tree
```rust
-use libvctrl::crypto::Hash as Sha512Hasher;
+use libvctrl::{
+ EntryKind, Hash, TreeBuilder, TreeEntryBuilder,
+ BinaryEncoder, Sha512Hasher, MemoryStore,
+ Encoder, Hasher, ObjectStore, VctrlError,
+};
+use std::io::Read;
-let digest = Sha512Hasher::hash(b"hello world");
-assert_eq!(digest.len(), 64);
+fn main() -> Result<(), VctrlError> {
+ // 1. Build a Tree containing a single file entry.
+ let blob_hash = Hash::from_bytes(&[0xAB; 64])?;
+ let entry = TreeEntryBuilder::new("file.txt".to_string(), EntryKind::Blob, blob_hash).build()?;
+ let tree = TreeBuilder::new().entry(entry).build()?;
+
+ // 2. Encode the Tree into binary format.
+ let encoder = BinaryEncoder;
+ let encoded_bytes = encoder.encode_tree(&tree)?;
+
+ // 3. Hash the encoded bytes to get an address.
+ let hasher = Sha512Hasher;
+ let tree_hash = hasher.hash(&encoded_bytes)?;
+
+ // 4. Store the encoded object in memory.
+ let mut store = MemoryStore::new();
+ store.put(&tree_hash, &encoded_bytes)?;
+
+ // 5. Retrieve and verify the object.
+ assert!(store.exists(&tree_hash)?);
+ let mut reader = store.get(&tree_hash)?;
+ let mut buf = Vec::new();
+ reader.read_to_end(&mut buf).map_err(VctrlError::IoError)?;
+ assert_eq!(buf, encoded_bytes);
+ Ok(())
+}
```
### Building a Commit
@@ -264,314 +309,159 @@ assert_eq!(digest.len(), 64);
```rust
use libvctrl::{CommitBuilder, Hash, UserID};
-let tree = Hash::from_bytes(&[0; 64]).unwrap();
-let user = UserID::new("Alice".to_owned(), "alice@example.com".to_owned()).unwrap();
-
-let commit = CommitBuilder::new()
- .tree(tree)
- .author(user.clone())
- .committer(user)
- .message("Initial commit")
- .build()
- .unwrap();
-
-assert_eq!(commit.message(), "Initial commit");
-```
-
----
-
-## API Reference
-
-### Sub-crate Modules
-
-The three underlying crates are re-exported as top-level modules.
-
-#### handler
-
-Full namespace: `libvctrl::handler`
-
-Re-exports `libvctrl_handler` – the pure contracts crate.
-
-Contains:
-
-- Data types: `Blob`, `Tree`, `TreeEntry`, `Commit`, `CommitMeta`, `Tag`, `Hash`, `UserID`
-- Enum: `EntryKind`
-- Error type: `VctrlError`
-- Traits: `ObjectStore`, `RefStore`, `Hasher`, `Encoder`, `Decoder`, `Signer`, `Verifier`, `Transport`
-- Constants and limits
-- Macros
-
-**Example:**
-
-```rust
-use libvctrl::handler::Blob;
-
-let blob = Blob::new(b"hello".to_vec());
-```
-
-#### reference
-
-Full namespace: `libvctrl::reference`
-
-Re-exports `libvctrl_core` – the reference implementation crate.
-
-Contains:
-
-- Codec: `BinaryEncoder`, `BinaryDecoder`
-- Hash adapter: `Sha512Hasher`
-- Stores: `MemoryStore`, `MemoryRefStore`
-- Builders: `BlobBuilder`, `CommitBuilder`, `TagBuilder`, `TreeBuilder`, `TreeEntryBuilder`
-- Validation utilities
-
-**Example:**
-
-```rust
-use libvctrl::reference::MemoryStore;
+fn main() -> Result<(), Box> {
+ let tree = Hash::from_bytes(&[0; 64])?;
+ let user = UserID::new("Alice".to_owned(), "alice@example.com".to_owned())?;
+ let commit = CommitBuilder::new()
+ .tree(tree)
+ .author(user.clone())
+ .committer(user)
+ .message("Initial commit")
+ .build()?;
+ assert_eq!(commit.message(), "Initial commit");
+ Ok(())
+}
```
-#### crypto
-
-Full namespace: `libvctrl::crypto`
-
-Re-exports `libvctrl_sha512` – the cryptographic primitives crate.
-
-Contains:
+### Namespace-isolated cryptography
-- SHA-512 hasher
-- HMAC-SHA-512
-- HKDF-SHA-512
-- Optional SHA-384 and HMAC/HKDF-SHA-384 (feature-gated)
-
-**Example:**
+Because the VCS `Hash` type and the SHA-512 `Hash` hasher share a name, use the `crypto`
+namespace to access raw hashing primitives unambiguously:
```rust
-use libvctrl::crypto::Hash as Sha512Hash;
+use libvctrl::crypto::Hash as Sha512Hasher;
-let digest = Sha512Hash::hash(b"data");
+let digest = Sha512Hasher::hash(b"hello world");
+assert_eq!(digest.len(), 64);
```
---
-### Root Re-exports: Contracts
-
-These items are available directly at `libvctrl::`.
-
-#### Constants
-
-| Item | Description |
-| -------------------- | ----------- |
-| `HASH_LENGTH` | 64 bytes |
-| `MAX_NAME_LENGTH` | 255 bytes |
-| `MAX_BLOB_SIZE` | 100 MiB |
-| `MAX_TREE_ENTRIES` | 100,000 |
-| `MAX_MESSAGE_LENGTH` | 1 MiB |
+## API Reference / Core Modules
-Also available: `libvctrl::constants::{HASH_LENGTH, ...}`.
+Full API documentation is published at . The summary below
+describes the module organisation and the most important re-exports.
-#### Enums
+### Sub-crate namespaces
-| Item | Description |
-| ----------- | ------------------------------------------------------------------------ |
-| `EntryKind` | Logical entry kind: `Blob`, `Executable`, `Symlink`, `Tree`, `Submodule` |
+| Namespace | Underlying crate | Contents |
+| ----------- | ------------------ | ---------------------------------------------------------------- |
+| `handler` | `libvctrl_handler` | Traits, immutable types, constants, validation, errors, enums |
+| `reference` | `libvctrl_core` | Binary codec, builders, in-memory stores, SHA-512 hasher adapter |
+| `crypto` | `libvctrl_sha512` | SHA-512, HMAC-SHA512, HKDF-SHA512, optional SHA-384 |
-#### Errors
+### Root re-exports: contracts (from `handler`)
-| Item | Description |
-| ------------ | ---------------------------------------------- |
-| `VctrlError` | Unified error type for all fallible operations |
+**Traits:** `Encoder`, `Decoder`, `Hasher`, `ObjectStore`, `RefStore`, `Signer`,
+`Verifier`, `Transport`.
-#### Traits
+**Types:** `Blob`, `Tree`, `TreeEntry`, `Commit`, `CommitMeta`, `Tag`, `Hash`,
+`UserID`, `EntryKind`.
-| Item | Description |
-| ------------- | ---------------------------------- |
-| `ObjectStore` | Content-addressable object storage |
-| `RefStore` | Named reference management |
-| `Hasher` | Cryptographic hashing |
-| `Encoder` | Serialization to bytes |
-| `Decoder` | Deserialization from bytes |
-| `Signer` | Cryptographic signing |
-| `Verifier` | Signature verification |
-| `Transport` | Remote object synchronization |
+**Error:** `VctrlError` — the unified error type returned by every fallible operation
+across the ecosystem.
-#### Types
+**Constants:** `HASH_LENGTH`, `MAX_BLOB_SIZE`, `MAX_MESSAGE_LENGTH`, `MAX_NAME_LENGTH`,
+`MAX_PARENT_COUNT`, `MAX_TREE_ENTRIES`.
-| Item | Description |
-| ------------ | -------------------------------------- |
-| `Blob` | Immutable raw byte content |
-| `Tree` | Sorted list of `TreeEntry` |
-| `TreeEntry` | Name, kind, and hash |
-| `Commit` | Snapshot with parents and metadata |
-| `CommitMeta` | Timestamp, timezone, encoding |
-| `Tag` | Named reference with optional metadata |
-| `Hash` | 64-byte content address |
-| `UserID` | Name and email identity |
+**Validation functions:** `validate_hash_bytes`, `validate_name`, `validate_ref_name`,
+`validate_tree_entry_name`.
-#### Macros
-
-| Item | Description |
-| -------------------- | -------------------------------------------------- |
-| `vctrl_error_other!` | Creates `VctrlError::Other` with formatted message |
-
----
+**Modules:** `constants`, `enums`, `errors`, `macros`, `traits`, `types`, `validation`.
-### Root Re-exports: Reference Implementations
+### Root re-exports: reference implementations (from `reference`)
-These items are available directly at `libvctrl::`.
+**Codec:** `BinaryEncoder`, `BinaryDecoder` — deterministic, versioned binary payloads
+with strict bounds checking.
-#### Codec
+**Hasher:** `Sha512Hasher` — implements the `Hasher` trait and produces 64-byte content
+addresses.
-| Item | Description |
-| --------------- | ---------------------- |
-| `BinaryEncoder` | Implements `Encoder` |
-| `BinaryDecoder` | Implements `Decoder` |
-| `codec` | Module containing both |
+**Builders:** `BlobBuilder`, `CommitBuilder`, `TagBuilder`, `TreeBuilder`,
+`TreeEntryBuilder` — fluent APIs for constructing validated objects.
-#### Hash
+**Stores:** `MemoryStore` (implements `ObjectStore` via `HashMap`) and `MemoryRefStore`
+(implements `RefStore` via `HashMap`).
-| Item | Description |
-| -------------- | ----------------------------------------- |
-| `Sha512Hasher` | Adapter for SHA-512 implementing `Hasher` |
+**Modules:** `codec`, `object`, `store`.
-#### Stores
+### Root re-exports: cryptography (from `crypto`)
-| Item | Description |
-| ---------------- | ----------------------- |
-| `MemoryStore` | In-memory `ObjectStore` |
-| `MemoryRefStore` | In-memory `RefStore` |
-| `store` | Module containing both |
-
-#### Builders
-
-| Item | Description |
-| ------------------ | ------------------------------ |
-| `BlobBuilder` | Builder for `Blob` |
-| `CommitBuilder` | Builder for `Commit` |
-| `TagBuilder` | Builder for `Tag` |
-| `TreeBuilder` | Builder for `Tree` |
-| `TreeEntryBuilder` | Builder for `TreeEntry` |
-| `object` | Module containing all builders |
-
-#### Validation
-
-| Item | Description |
-| --------------------- | --------------------------------------- |
-| `validate_name` | Validates a name against security rules |
-| `validate_hash_bytes` | Validates hash byte length |
-| `validate` | Module containing validation utilities |
+The `crypto` namespace exposes the `libvctrl_sha512` crate directly. SHA-384 symbols are
+available only when the `sha384` feature is enabled (the default).
---
## Testing
-The crate itself contains only re-exports and no new logic, so most tests reside in the underlying crates. However, doctests in `libvctrl` validate the re-exported API.
-
-Run all tests for this crate:
+Run the crate's test suite with Cargo:
-```sh
-cargo test -p libvctrl
+```bash
+cargo test
```
-Run all tests with default features:
+Property-based tests use `proptest` (a dev-dependency). Because the facade crate contains
+only re-exports, most behavioural tests live in the underlying workspace crates
+(`libvctrl_handler`, `libvctrl_core`, `libvctrl_sha512`). To run the entire workspace
+test suite from the repository root:
-```sh
-cargo test -p libvctrl --all-features
+```bash
+cargo test --workspace
```
-Run doctests only:
+To verify that the strict lint policy is satisfied:
-```sh
-cargo test -p libvctrl --doc
-```
-
-Run strict Clippy checks:
-
-```sh
-cargo clippy -p libvctrl --all-targets --all-features -- -D warnings
+```bash
+cargo clippy --workspace --all-targets -- -D warnings
+cargo doc --workspace --no-deps
```
---
-## CI/CD Pipeline
-
-No CI/CD pipeline is currently configured in the repository.
-
-If one is added, it should include at least the following stages:
-
-```mermaid
-graph LR
- A[Push] --> B[Format Check]
- B --> C[Clippy Lint]
- C --> D[Run Tests]
- D --> E[Build Docs]
- E --> F[Publish]
-```
-
-Recommended commands per stage:
-
-- Format: `cargo fmt --check`
-- Lint: `cargo clippy -p libvctrl --all-targets --all-features -- -D warnings`
-- Tests: `cargo test -p libvctrl --all-features`
-- Docs: `cargo doc -p libvctrl --no-deps`
-- Publish: `cargo publish`
-
----
-
-## Deployment / Distribution
+## Contributing
-The crate is intended to be published to crates.io.
+Contributions are welcome. The crate enforces `#![forbid(unsafe_code)]` and inherits a
+strict, denied Clippy and documentation-lint policy from the workspace; all public items
+must be documented.
-Release process:
+For contribution guidelines, code style, and the full lint configuration, see the
+repository's `CONTRIBUTING.md` and the workspace root `README.md`:
-1. Update version in `Cargo.toml`.
-2. Update `CHANGELOG.md`.
-3. Run `cargo publish --dry-run`.
-4. Run `cargo publish`.
+- Repository: https://github.com/mroczect/libvctrl
-After publication, documentation will be available at `https://docs.rs/libvctrl`.
+When contributing to this facade crate specifically, keep in mind that it must remain a
+pure re-export layer: no new logic, types, or `unsafe` code should be introduced here.
+New functionality belongs in the appropriate underlying crate.
---
-## Security & Compliance
+## Workspace
-`libvctrl` inherits the strict security posture of its underlying crates:
+`libvctrl` is the facade crate of a larger workspace. The sibling crates are listed
+below; each has its own documentation and may be depended on directly when only a subset
+of the stack is required.
-- **No unsafe code**
- `#![forbid(unsafe_code)]` is set at the crate level. The only `unsafe` in the dependency tree is a single reviewed block in `libvctrl_sha512::utils::verify`.
+| Crate | Role | Documentation |
+| -------------------- | -------------------------------------------------- | ---------------------------------- |
+| `libvctrl_handler` | Contract layer: traits, types, limits, validation | https://docs.rs/libvctrl_handler |
+| `libvctrl_core` | Reference implementations: codec, builders, stores | https://docs.rs/libvctrl_core |
+| `libvctrl_sha512` | Zero-dependency SHA-512 / HMAC / HKDF primitives | https://docs.rs/libvctrl_sha512 |
+| `libvctrl_plumbing` | Command-level VCS operations built on `core` | https://docs.rs/libvctrl_plumbing |
+| `libvctrl_porcelain` | High-level, user-facing VCS operations | https://docs.rs/libvctrl_porcelain |
-- **Strict linting**
- Clippy `all`, `pedantic`, `nursery`, `cargo`, and additional lints like `unwrap_used`, `expect_used`, and `panic` are denied, reducing the chance of accidental panics.
+The dependency flow is strictly one-way:
-- **DoS protection**
- Underlying validators and decoders enforce size limits (`MAX_BLOB_SIZE`, `MAX_MESSAGE_LENGTH`, `MAX_TREE_ENTRIES`) and validate UTF-8.
-
-- **Path traversal prevention**
- `validate_name` rejects `/`, `.`, and `..` in names used for refs and tree entries.
-
-- **Side-channel mitigation**
- SHA-512 verification and HMAC comparison use non-short-circuiting XOR accumulation.
-
-- **Zeroization**
- Hash and HMAC implementations clear internal state on drop or explicit call.
-
-Refer to `SECURITY.md` in the workspace root for reporting vulnerabilities and additional security guidelines.
-
----
-
-## Contributing
-
-Contributions are welcome. Follow the workspace `CONTRIBUTING.md`.
-
-For this crate, ensure:
-
-- All public items have documentation with doctests.
-- Do not introduce new logic unless it is strictly necessary for the facade.
-- Run `cargo fmt`.
-- Run `cargo clippy -p libvctrl --all-targets --all-features -- -D warnings`.
-- Run `cargo test -p libvctrl --all-features`.
-- Avoid unsafe code.
+```mermaid
+flowchart LR
+ H[libvctrl_handler contracts] --> C[libvctrl_core reference impl]
+ C --> PL[libvctrl_plumbing]
+ C --> PO[libvctrl_porcelain]
+ H --> F[libvctrl facade]
+ C --> F
+```
---
## License
-This project is licensed under the MIT License. See the `LICENSE` file in the workspace root for details.
+Licensed under the MIT License. See the repository for the full license text.
diff --git a/libvctrl_core/Cargo.toml b/libvctrl_core/Cargo.toml
index 0b4a89a7..6db201c0 100644
--- a/libvctrl_core/Cargo.toml
+++ b/libvctrl_core/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "libvctrl_core"
-version = "3.0.0"
+version = "3.0.1"
edition = "2024"
description = "Reference implementations of the libvctrl contracts (in-memory store, SHA-512 hasher, binary codec)"
license = "MIT"
diff --git a/libvctrl_core/README.md b/libvctrl_core/README.md
index 771587cd..e2e1190d 100644
--- a/libvctrl_core/README.md
+++ b/libvctrl_core/README.md
@@ -1,210 +1,192 @@
# libvctrl_core
-**Version:** 2.0.1
-**Crate type:** Rust library (reference implementations)
-**Workspace:** libvcrtl
-
-`libvctrl_core` is the **batteries-included reference implementation layer** for the abstract contracts defined in [`libvctrl_handler`](https://docs.rs/libvctrl_handler). It provides production-ready, safe implementations of hashing, binary serialization, in-memory storage, reference management, and builder utilities. By consuming `libvctrl_handler` as its first downstream crate, `libvctrl_core` validates the contracts and gives developers a complete, working VCS backend stack out of the box.
-
-The crate enforces the same strict code quality standards as `libvctrl_handler`:
-
-- `#![forbid(unsafe_code)]`
-- `#![deny(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]`
-- `#![deny(missing_docs)]`
-- `#![deny(rust_2018_idioms, unreachable_pub, unused_crate_dependencies, unused_qualifications)]`
-
----
-
-## Table of Contents
-
-- [Overview](#overview)
-- [System Architecture](#system-architecture)
-- [Core Features](#core-features)
-- [Technology Stack](#technology-stack)
-- [Project Structure](#project-structure)
-- [Getting Started](#getting-started)
- - [Prerequisites](#prerequisites)
- - [Installation](#installation)
- - [Configuration](#configuration)
-- [Usage](#usage)
-- [API Reference](#api-reference)
- - [Codec Module](#codec-module)
- - [BinaryEncoder](#binaryencoder)
- - [BinaryDecoder](#binarydecoder)
- - [Binary Format Specifications](#binary-format-specifications)
- - [Hash Module](#hash-module)
- - [Sha512Hasher](#sha512hasher)
- - [Object Module](#object-module)
- - [BlobBuilder](#blobbuilder)
- - [CommitBuilder](#commitbuilder)
- - [TagBuilder](#tagbuilder)
- - [TreeBuilder](#treebuilder)
- - [TreeEntryBuilder](#treeentrybuilder)
- - [Store Module](#store-module)
- - [MemoryStore](#memorystore)
- - [MemoryRefStore](#memoryrefstore)
- - [Validate Module](#validate-module)
- - [validate_hash_bytes](#validate_hash_bytes)
- - [validate_name](#validate_name)
-- [Testing](#testing)
-- [CI/CD Pipeline](#cicd-pipeline)
-- [Deployment / Distribution](#deployment--distribution)
-- [Security & Compliance](#security--compliance)
-- [Contributing](#contributing)
-- [License](#license)
-- [Changelog](#changelog)
+Reference implementations of the `libvctrl` contracts: a deterministic binary codec, a
+SHA-512 content-addressing hasher, fluent object builders, and in-memory storage backends.
+`libvctrl_core` is the layer that turns the abstract `libvctrl_handler` traits and immutable
+types into working, production-ready components.
+
+- **Crate:** `libvctrl_core` 3.0.1 (library, `std`-only)
+- **Language:** Rust, edition 2024 — MSRV **1.96.0**
+- **License:** MIT
+- **Repository:** https://github.com/mroczect/libvctrl
+- **Documentation:** https://docs.rs/libvctrl_core
+
+> Most users should depend on the **`libvctrl` facade** rather than this crate directly.
+> The facade re-exports everything in `libvctrl_core` plus the contracts and the crypto
+> primitives under a single, ergonomic namespace. Reach for `libvctrl_core` directly only
+> when you need the codec, builders, or in-memory stores without pulling in the facade's
+> `crypto` namespace alias.
---
## Overview
-`libvctrl_core` is the first concrete consumer of the `libvctrl_handler` traits. It transforms the abstract contracts into a runnable foundation for version control systems by providing:
-
-- **Binary codec** for deterministic serialization and deserialization.
-- **SHA-512 hasher** for content addressing.
-- **In-memory object and reference stores** for ephemeral storage.
-- **Builder patterns** for ergonomic object construction.
-- **Validation utilities** for names and hashes.
+`libvctrl_handler` defines _what_ a version control object model looks like — the traits
+(`Encoder`, `Decoder`, `Hasher`, `ObjectStore`, `RefStore`) and the immutable data types
+(`Blob`, `Tree`, `TreeEntry`, `Commit`, `CommitMeta`, `Tag`, `Hash`, `UserID`).
+`libvctrl_core` defines _how_ those contracts are realised:
-Because `libvctrl_core` implements every key trait from `libvctrl_handler`, it also serves as a quality exemplar for downstream developers who need to write custom backends. All code is safe, strictly linted, heavily documented, and thoroughly tested.
+- A **binary codec** that serialises objects into a deterministic, versioned byte stream
+ and parses untrusted byte streams back into validated objects.
+- A **SHA-512 hasher** that bridges the raw `libvctrl_sha512` digest engine to the handler
+ `Hash` type used for content addressing.
+- **Fluent builders** for constructing validated `Blob`, `Tree`, `TreeEntry`, `Commit`,
+ and `Tag` objects.
+- **In-memory stores** implementing `ObjectStore` and `RefStore` over `HashMap`.
-This crate intentionally does not perform persistent disk I/O or network operations; it focuses on core VCS logic that can be embedded in larger systems.
+The crate is `std`-only: it relies on `std::io`, `std::sync::Arc`, `HashMap`, `String`, and
+`Vec`. There is no `no_std` build path. The crate exposes **no crate-level feature flags**;
+all feature configuration (`sha384`, `opt_size`) happens at the facade or
+`libvctrl_sha512` level.
---
-## System Architecture
-
-### Workspace Context
-
-Within the `libvcrtl` workspace, `libvctrl_core` sits directly above `libvctrl_handler` and below higher-level crates like `libvctrl_plumbing` and `libvctrl_porcelain`.
-
-```mermaid
-graph TD
- HANDLER[libvctrl_handler Contracts and Types]
- CORE[libvctrl_core Reference Implementations]
- PLUMBING[libvctrl_plumbing]
- PORCELAIN[libvctrl_porcelain]
- SHA512[libvctrl_sha512 Hash Implementation]
- LIBVCTRL[libvctrl CLI]
-
- HANDLER --> CORE
- SHA512 --> CORE
- CORE --> PLUMBING
- CORE --> PORCELAIN
- PLUMBING --> LIBVCTRL
- PORCELAIN --> LIBVCTRL
-```
-
-`libvctrl_core` depends on:
+## Architecture
-- `libvctrl_handler` version 4.4.0 for all contracts and data types.
-- `libvctrl_sha512` version 2.0.0 for the raw SHA-512 hash algorithm.
-
-### Internal Module Architecture
-
-The crate is organized by domain responsibility:
+`libvctrl_core` sits in the middle of a strictly layered, one-way dependency graph. The
+contract layer (`libvctrl_handler`) depends only on the standard library. The reference
+layer (`libvctrl_core`) depends on the contracts and on the raw crypto engine
+(`libvctrl_sha512`). Above it sit the facade and the higher-level command crates.
```mermaid
-graph LR
- ROOT[libvctrl_core]
- CODEC[codec]
- HASH[hash]
- OBJECT[object]
- STORE[store]
- VALIDATE[validate]
-
- ROOT --> CODEC
- ROOT --> HASH
- ROOT --> OBJECT
- ROOT --> STORE
- ROOT --> VALIDATE
-
- CODEC --> HANDLER[libvctrl_handler]
+flowchart TD
+ subgraph Apps["Application layer"]
+ FACADE["libvctrl facade (re-exports)"]
+ PL["libvctrl_plumbing"]
+ PO["libvctrl_porcelain"]
+ end
+
+ subgraph Core["Reference implementation layer — libvctrl_core"]
+ CODEC["codec BinaryEncoder / BinaryDecoder"]
+ HASH["hash Sha512Hasher (adapter)"]
+ OBJ["object builders"]
+ STORE["store MemoryStore / MemoryRefStore"]
+ end
+
+ subgraph Foundation["Foundation"]
+ HANDLER["libvctrl_handler contracts & types"]
+ SHA["libvctrl_sha512 raw crypto engine"]
+ end
+
+ FACADE --> Core
+ PL --> Core
+ PO --> Core
+ CODEC --> HANDLER
HASH --> HANDLER
- HASH --> SHA[libvctrl_sha512]
- OBJECT --> HANDLER
+ HASH --> SHA
+ OBJ --> HANDLER
STORE --> HANDLER
- VALIDATE --> HANDLER
```
-Each module isolates a single responsibility:
-
-- **`codec`**: `BinaryEncoder` and `BinaryDecoder` for binary serialization.
-- **`hash`**: `Sha512Hasher` bridging `libvctrl_sha512` to `Hasher`.
-- **`object`**: Builder structs for ergonomic construction.
-- **`store`**: In-memory `ObjectStore` and `RefStore` implementations.
-- **`validate`**: Validation helpers for names and hashes.
-
-### Object Lifecycle Data Flow
+Internally, each module implements a specific handler trait against the contract types:
-The following sequence shows how a `Blob` is encoded, hashed, stored, and retrieved using `libvctrl_core`.
+```mermaid
+flowchart LR
+ subgraph Handler["libvctrl_handler contracts"]
+ ENC[Encoder trait]
+ DEC[Decoder trait]
+ HAS[Hasher trait]
+ OS[ObjectStore trait]
+ RS[RefStore trait]
+ TYPES[Blob / Tree / Commit / Tag / Hash / UserID]
+ end
+
+ subgraph Core["libvctrl_core modules"]
+ CODEC[codec BinaryEncoder + BinaryDecoder]
+ HASHMOD[hash Sha512Hasher]
+ OBJMOD[object builders]
+ STOREMOD[store MemoryStore + MemoryRefStore]
+ end
+
+ CODEC -.implements.-> ENC
+ CODEC -.implements.-> DEC
+ HASHMOD -.implements.-> HAS
+ STOREMOD -.implements.-> OS
+ STOREMOD -.implements.-> RS
+ CODEC -.consumes.-> TYPES
+ HASHMOD -.produces.-> TYPES
+ OBJMOD -.constructs.-> TYPES
+```
+
+### Codec round-trip
+
+A typical interaction encodes an object, hashes the encoded bytes to obtain a content
+address, stores the bytes, and later decodes them back. The decoder is the trust boundary:
+it treats every input as untrusted and validates structure, UTF-8, and system limits before
+constructing a handler type.
```mermaid
sequenceDiagram
- participant App as Downstream App
- participant Enc as BinaryEncoder
- participant Hash as Sha512Hasher
- participant Store as MemoryStore
-
- App->>Enc: encode_blob(&blob)
- Enc-->>App: Vec
- App->>Hash: hash(&encoded_bytes)
- Hash-->>App: Hash
- App->>Store: put(&hash, &encoded_bytes)
- App->>Store: get(&hash)
- Store-->>App: Box
+ participant App as Application
+ participant E as BinaryEncoder
+ participant H as Sha512Hasher
+ participant S as MemoryStore
+ participant D as BinaryDecoder
+
+ App->>E: encode_*(&object, &mut writer)
+ E-->>App: Deterministic, versioned bytes
+ App->>H: hash(&mut bytes.as_slice())
+ H->>H: Stream SHA-512 in fixed chunks
+ H-->>App: 64-byte Hash (content address)
+ App->>S: put(&hash, &bytes)
+ App->>S: get(&hash)
+ S-->>App: Stored bytes
+ App->>D: decode_*(reader)
+ D->>D: read_bounded (hard size cap)
+ D->>D: check_version (byte == 3)
+ D->>D: require_byte / require_slice
+ D->>D: Validate UTF-8 + re-check limits
+ D-->>App: Validated immutable object
```
---
## Core Features
-- **Binary serialization/deserialization**
- Compact, deterministic, little-endian binary format with versioning and strict bounds checks.
-
-- **SHA-512 content addressing**
- Produces 64-byte digests matching `HASH_LENGTH`, using an audited pure-Rust backend.
-
-- **Streaming object reads**
- `MemoryStore::get` returns `Box`, enabling incremental consumption without large contiguous allocations.
-
-- **In-memory reference store**
- `MemoryRefStore` supports branch and tag management with deterministic sorted iteration.
-
-- **Ergonomic builder patterns**
- Fluent APIs for constructing blobs, commits, tags, trees, and tree entries.
-
-- **Defensive validation**
- Prevents path traversal, empty names, and invalid hash lengths.
-
-- **Full POSIX tree fidelity**
- Encoder and decoder support all five `EntryKind` variants: `Blob`, `Executable`, `Symlink`, `Tree`, `Submodule`.
-
-- **Thread-safe and allocation-efficient**
- All concrete types are `Send + Sync`; builders transfer ownership without cloning.
+- **Deterministic serialization.** The same object always produces the same bytes:
+ fixed version byte, little-endian integers, strict field order, no platform-specific
+ layouts. Determinism is required for content addressing to be stable.
+- **Defense-in-depth decoding.** `BinaryDecoder` bounds the input before parsing, checks
+ every offset before slicing, validates all strings as UTF-8, and re-checks system limits
+ after numeric conversion. No slice indexing occurs without a preceding bounds check.
+- **DoS-resistant reads.** `read_bounded` uses a 4 KiB chunk buffer and refuses to allocate
+ beyond a conservative per-object maximum, preventing allocation-based denial of service.
+- **Versioned format.** Every encoded object begins with a version byte (`3`). The decoder
+ rejects any input whose first byte does not match, allowing the format to evolve safely.
+- **Thin hasher adapter.** `Sha512Hasher` is a zero-sized, stateless, thread-safe adapter
+ that bridges the raw `libvctrl_sha512` engine to the handler `Hash` type, producing
+ 64-byte addresses matching `HASH_LENGTH`.
+- **Fluent builders.** Construct validated `Blob`, `Tree`, `TreeEntry`, `Commit`, and `Tag`
+ objects through ergonomic builder APIs.
+- **In-memory stores.** `MemoryStore` and `MemoryRefStore` provide ready-to-use
+ `ObjectStore` and `RefStore` implementations backed by `HashMap`.
+- **Strict safety.** `#![forbid(unsafe_code)]` and a comprehensive set of denied Clippy and
+ rustc documentation lints are inherited from the workspace.
---
## Technology Stack
-- **Language:** Rust (edition 2024)
+- **Language:** Rust (edition 2024, MSRV 1.96.0)
- **Dependencies:**
- - `libvctrl_handler` 4.4.0 — contracts and types
- - `libvctrl_sha512` 2.0.0 — SHA-512 implementation
-- **Dev dependencies:**
- - `proptest` 1.11.0 — property-based testing
-- **Standard library:**
- - `std::collections::HashMap`
- - `std::io::{Cursor, Read}`
- - `std::str`
-- **Lints:** Clippy all, pedantic, nursery, cargo (all denied)
+ - `libvctrl_handler` 5.0.0 — contracts, types, constants, validation (path dependency)
+ - `libvctrl_sha512` 3.0.0 — raw SHA-512 / HMAC / HKDF engine, **with default features**
+ (SHA-384 enabled)
+- **Dev-dependencies:** `proptest` 1.11.0
+- **Lint policy:** workspace-inherited, `#![forbid(unsafe_code)]`, denied missing-docs,
+ rust-2018-idioms, and a broad set of Clippy lints (including pedantic and nursery
+ groups). See the repository for the authoritative lint configuration.
+- **Feature flags:** none at the crate level.
+
+> Note on the MSRV field: this crate's `Cargo.toml` does not yet declare
+> `rust-version = "1.96"`. The workspace standard is Rust 1.96.0, and this README
+> documents that as the MSRV. Adding `rust-version = "1.96"` to
+> `libvctrl_core/Cargo.toml` is recommended in a future maintenance pass.
---
## Project Structure
-Within the `libvctrl_core` crate:
-
```text
libvctrl_core/
├── Cargo.toml
@@ -223,14 +205,10 @@ libvctrl_core/
│ ├── commit.rs
│ ├── tag.rs
│ └── tree.rs
- ├── store/
- │ ├── mod.rs
- │ ├── memory.rs
- │ └── ref_store.rs
- └── validate/
+ └── store/
├── mod.rs
- ├── hash.rs
- └── name.rs
+ ├── memory.rs
+ └── ref_store.rs
```
---
@@ -239,605 +217,402 @@ libvctrl_core/
### Prerequisites
-- Rust toolchain 1.96.0 or newer (edition 2024 required)
+- Rust toolchain **1.96.0** or newer (edition 2024 is required)
- Cargo
-- No external services or system dependencies
+
+No system libraries or external services are required.
### Installation
-Add `libvctrl_core` to your `Cargo.toml`:
+For most users, depend on the facade instead:
+
+```toml
+[dependencies]
+libvctrl = "2.1"
+```
+
+To depend on `libvctrl_core` directly (codec/builders/stores only, without the facade's
+`crypto` namespace alias):
```toml
[dependencies]
-libvctrl_core = "2.0.1"
+libvctrl_core = "3.0"
```
-Or use Cargo:
+Or via Cargo:
-```sh
+```bash
cargo add libvctrl_core
```
-This will automatically pull the required `libvctrl_handler` and `libvctrl_sha512` dependencies.
+This will pull `libvctrl_handler` and `libvctrl_sha512` as transitive dependencies.
### Configuration
-No configuration is required. The crate is a pure library with no environment variables or runtime configuration.
+`libvctrl_core` exposes **no crate-level feature flags**. Feature configuration
+(`sha384`, `opt_size`) is controlled at the `libvctrl` facade or `libvctrl_sha512` level.
+Because this crate depends on `libvctrl_sha512` **with default features**, SHA-384 support
+is enabled transitively. If you need to control the crypto feature set, use the facade,
+which wires `libvctrl_sha512` with `default-features = false` and re-enables only what it
+needs.
---
## Usage
-### Quick Start: Encode, Hash, Store, Retrieve
-
-```rust
-use libvctrl_handler::{Blob, Encoder, Hasher, ObjectStore};
-use libvctrl_core::codec::BinaryEncoder;
-use libvctrl_core::hash::Sha512Hasher;
-use libvctrl_core::store::MemoryStore;
-use std::io::Read;
-
-// 1. Create content
-let blob = Blob::new(b"my content".to_vec());
-
-// 2. Encode to deterministic bytes
-let encoder = BinaryEncoder;
-let bytes = encoder.encode_blob(&blob).unwrap();
-
-// 3. Hash the bytes to get a content address
-let hasher = Sha512Hasher;
-let hash = hasher.hash(&bytes).unwrap();
-
-// 4. Store the encoded bytes in memory
-let mut store = MemoryStore::new();
-store.put(&hash, &bytes).unwrap();
-
-// 5. Read back via streaming interface
-let mut reader = store.get(&hash).unwrap();
-let mut buf = Vec::new();
-reader.read_to_end(&mut buf).unwrap();
-assert_eq!(buf, bytes);
-```
-
-### Building a Commit Using Builders
+### Encode, hash, store, and decode a Blob
```rust
-use libvctrl_core::object::CommitBuilder;
-use libvctrl_handler::{Hash, UserID};
-
-let tree = Hash::from_bytes(&[0; 64]).unwrap();
-let author = UserID::new("Alice".to_owned(), "alice@example.com".to_owned()).unwrap();
-let committer = UserID::new("Bob".to_owned(), "bob@example.com".to_owned()).unwrap();
-
-let commit = CommitBuilder::new()
- .tree(tree)
- .author(author)
- .committer(committer)
- .message("Initial commit")
- .build()
- .unwrap();
-
-assert_eq!(commit.message(), "Initial commit");
-```
-
----
-
-## API Reference
-
-All public items are exported from their respective modules. The recommended import paths are shown in each section.
-
-### Codec Module
-
-Module path: `libvctrl_core::codec`
-
-Contains the binary encoder and decoder.
-
-#### BinaryEncoder
-
-```rust
-pub struct BinaryEncoder;
-```
-
-Implements `libvctrl_handler::Encoder`.
-
-| Method | Description |
-| ---------------------------------------------------------------------- | -------------------------------------------------------- |
-| `encode_blob(&self, blob: &Blob) -> Result, VctrlError>` | Encodes a `Blob` into versioned, length-prefixed binary. |
-| `encode_tree(&self, tree: &Tree) -> Result, VctrlError>` | Encodes a `Tree` with entries, kinds, and hashes. |
-| `encode_commit(&self, commit: &Commit) -> Result, VctrlError>` | Encodes a `Commit` with metadata and parents. |
-| `encode_tag(&self, tag: &Tag) -> Result, VctrlError>` | Encodes a `Tag` with optional tagger. |
-
-**Example:**
-
-```rust
-use libvctrl_handler::{Blob, Encoder};
-use libvctrl_core::codec::BinaryEncoder;
-
-let encoder = BinaryEncoder;
-let blob = Blob::new(b"hello".to_vec());
-let bytes = encoder.encode_blob(&blob).unwrap();
-
-assert_eq!(bytes[0], 2); // version byte
-```
-
-#### BinaryDecoder
-
-```rust
-pub struct BinaryDecoder;
-```
-
-Implements `libvctrl_handler::Decoder`.
-
-| Method | Description |
-| ----------------------------------------------------------------- | ----------------------------------------- |
-| `decode_blob(&self, data: &[u8]) -> Result` | Parses a binary blob. |
-| `decode_tree(&self, data: &[u8]) -> Result` | Parses a binary tree with sorted entries. |
-| `decode_commit(&self, data: &[u8]) -> Result` | Parses a binary commit with all fields. |
-| `decode_tag(&self, data: &[u8]) -> Result` | Parses a binary tag. |
-
-**Example:**
-
-```rust
-use libvctrl_handler::{Blob, Encoder, Decoder};
+use std::io::Cursor;
+use libvctrl_handler::{Blob, Decoder, Encoder, Hasher, ObjectStore};
use libvctrl_core::codec::{BinaryEncoder, BinaryDecoder};
-
-let original = Blob::new(b"data".to_vec());
-let bytes = BinaryEncoder.encode_blob(&original).unwrap();
-let decoded = BinaryDecoder.decode_blob(&bytes).unwrap();
-assert_eq!(decoded, original);
-```
-
-#### Binary Format Specifications
-
-All payloads start with a version byte (`VERSION = 2`), followed by little-endian integers and length-prefixed strings.
-
-**Blob format:**
-
-| Offset | Size | Field |
-| ------ | ---------- | ------------------- |
-| 0 | 1 | Version |
-| 1 | 8 | `data_len` (u64 LE) |
-| 9 | `data_len` | `data` |
-
-**Tree format:**
-
-| Offset | Size | Field |
-| ------ | ------ | ------------------------------------------------------------------------- |
-| 0 | 1 | Version |
-| 1 | 4 | `entry_count` (u32 LE) |
-| 5 | varies | Repeated entries: `name_len` (u8), `name`, `kind` (u8), `hash` (64 bytes) |
-
-**Commit format:**
-
-| Field | Size |
-| --------------------------- | ---------- |
-| Version | 1 |
-| Tree hash | 64 |
-| Parent count | 1 |
-| Parent hashes | 64 * count |
-| Author name len + name | 1 + len |
-| Author email len + email | 1 + len |
-| Committer name len + name | 1 + len |
-| Committer email len + email | 1 + len |
-| Message len | 4 |
-| Message | len |
-| Timestamp | 8 |
-| Timezone offset | 2 |
-| Encoding len | 1 |
-| Encoding (if len > 0) | len |
-
-**Tag format:**
-
-Similar to commit, but starts with name and target hash, then optional tagger.
-
-The decoder enforces all system limits (`MAX_BLOB_SIZE`, `MAX_MESSAGE_LENGTH`, `MAX_TREE_ENTRIES`) and validates UTF-8 to prevent denial-of-service attacks.
-
----
-
-### Hash Module
-
-Module path: `libvctrl_core::hash`
-
-#### Sha512Hasher
-
-```rust
-#[derive(Debug, Default, Clone)]
-pub struct Sha512Hasher;
-```
-
-Implements `libvctrl_handler::Hasher`.
-
-**Methods:**
-
-- `hash(&self, data: &[u8]) -> Result`
-
-Computes a SHA-512 digest of the input using the `libvctrl_sha512` crate and wraps it in a `Hash`. The digest length is always 64 bytes, so conversion cannot fail.
-
-**Example:**
-
-```rust
-use libvctrl_handler::Hasher;
use libvctrl_core::hash::Sha512Hasher;
+use libvctrl_core::store::MemoryStore;
-let hasher = Sha512Hasher;
-let hash = hasher.hash(b"hello world".as_ref()).unwrap();
-assert_eq!(hash.as_bytes().len(), 64);
-```
-
----
-
-### Object Module
-
-Module path: `libvctrl_core::object`
-
-Contains builders for ergonomic object construction.
-
-#### BlobBuilder
-
-```rust
-#[derive(Debug, Default)]
-pub struct BlobBuilder { /* private */ }
-
-impl BlobBuilder {
- pub const fn new() -> Self;
- pub fn with_data(self, data: Vec) -> Self;
- pub fn build(self) -> Blob;
-}
-```
-
-**Example:**
-
-```rust
-use libvctrl_core::object::BlobBuilder;
-
-let blob = BlobBuilder::new()
- .with_data(b"file content".to_vec())
- .build();
-
-assert_eq!(blob.size(), 12);
-```
-
-#### CommitBuilder
-
-```rust
-#[derive(Debug, Default)]
-pub struct CommitBuilder { /* private */ }
-
-impl CommitBuilder {
- pub const fn new() -> Self;
- pub const fn tree(self, tree: Hash) -> Self;
- pub fn parent(self, parent: Hash) -> Self;
- pub fn author(self, author: UserID) -> Self;
- pub fn committer(self, committer: UserID) -> Self;
- pub fn message(self, msg: impl Into) -> Self;
- pub fn meta(self, meta: CommitMeta) -> Self;
- pub fn build(self) -> Result;
-}
-```
-
-`build()` returns `VctrlError::Other` if any required field is missing.
+fn main() -> Result<(), Box> {
+ // 1. Create a validated blob.
+ let blob = Blob::new(b"hello world".to_vec())?;
-**Example:**
+ // 2. Encode into a deterministic, versioned byte stream.
+ let mut encoded = Vec::new();
+ BinaryEncoder.encode_blob(&blob, &mut encoded)?;
-```rust
-use libvctrl_core::object::CommitBuilder;
-use libvctrl_handler::{Hash, UserID};
-
-let tree = Hash::from_bytes(&[0; 64]).unwrap();
-let user = UserID::new("Alice".to_owned(), "a@b.com".to_owned()).unwrap();
-
-let commit = CommitBuilder::new()
- .tree(tree)
- .author(user.clone())
- .committer(user)
- .message("Initial commit")
- .build()
- .unwrap();
-```
+ // 3. Hash the encoded bytes to obtain a 64-byte content address.
+ let hash = Sha512Hasher.hash(&mut encoded.as_slice())?;
-#### TagBuilder
+ // 4. Store the encoded object in memory.
+ let mut store = MemoryStore::new();
+ store.put(&hash, &encoded)?;
-```rust
-#[derive(Debug, Default)]
-pub struct TagBuilder { /* private */ }
-
-impl TagBuilder {
- pub const fn new() -> Self;
- pub fn name(self, name: impl Into) -> Self;
- pub const fn target(self, target: Hash) -> Self;
- pub fn tagger(self, tagger: UserID) -> Self;
- pub fn message(self, msg: impl Into) -> Self;
- pub fn meta(self, meta: CommitMeta) -> Self;
- pub fn build(self) -> Result;
+ // 5. Retrieve and decode back into a validated object.
+ let reader = store.get(&hash)?;
+ let decoded = BinaryDecoder.decode_blob(reader)?;
+ assert_eq!(decoded, blob);
+ Ok(())
}
```
-**Example:**
+### Encode and decode a Tree
```rust
-use libvctrl_core::object::TagBuilder;
-use libvctrl_handler::Hash;
-
-let target = Hash::from_bytes(&[0; 64]).unwrap();
-let tag = TagBuilder::new()
- .name("v1.0.0")
- .target(target)
- .build()
- .unwrap();
-
-assert_eq!(tag.name(), "v1.0.0");
-```
-
-#### TreeBuilder
-
-```rust
-#[derive(Debug, Default)]
-pub struct TreeBuilder { /* private */ }
-
-impl TreeBuilder {
- pub const fn new() -> Self;
- pub fn entry(self, entry: TreeEntry) -> Self;
- pub fn add_entry(self, name: String, kind: EntryKind, hash: Hash) -> Result;
- pub fn build(self) -> Result;
-}
-```
-
-`build()` delegates to `Tree::new`, enforcing sorted entry order.
-
-**Example:**
-
-```rust
-use libvctrl_core::object::TreeBuilder;
-use libvctrl_handler::{EntryKind, Hash};
-
-let hash = Hash::from_bytes(&[0; 64]).unwrap();
-let tree = TreeBuilder::new()
- .add_entry("a.txt".to_owned(), EntryKind::Blob, hash)?
- .add_entry("b.txt".to_owned(), EntryKind::Blob, hash)?
- .build()
- .unwrap();
-# Ok::<(), libvctrl_handler::VctrlError>(())
-```
+use std::io::Cursor;
+use libvctrl_handler::{Encoder, Decoder, EntryKind, Hash, Tree, TreeEntry};
+use libvctrl_core::codec::{BinaryEncoder, BinaryDecoder};
-#### TreeEntryBuilder
+fn main() -> Result<(), Box> {
+ let hash = Hash::from_bytes(&[0u8; 64])?;
+ let entry = TreeEntry::new("a.txt".to_owned(), EntryKind::Blob, hash)?;
+ let tree = Tree::new(vec![entry])?;
-```rust
-#[derive(Debug)]
-pub struct TreeEntryBuilder { /* private */ }
+ let mut encoded = Vec::new();
+ BinaryEncoder.encode_tree(&tree, &mut encoded)?;
-impl TreeEntryBuilder {
- pub const fn new(name: String, kind: EntryKind, hash: Hash) -> Self;
- pub fn build(self) -> Result;
+ let decoded = BinaryDecoder.decode_tree(Cursor::new(encoded.as_slice()))?;
+ assert_eq!(decoded, tree);
+ Ok(())
}
```
-**Example:**
+### Encode and decode a Commit
```rust
-use libvctrl_core::object::TreeEntryBuilder;
-use libvctrl_handler::{EntryKind, Hash};
-
-let hash = Hash::from_bytes(&[0; 64]).unwrap();
-let entry = TreeEntryBuilder::new("file.txt".to_owned(), EntryKind::Blob, hash)
- .build()
- .unwrap();
-```
-
----
-
-### Store Module
-
-Module path: `libvctrl_core::store`
-
-#### MemoryStore
+use std::io::Cursor;
+use libvctrl_handler::{Commit, Decoder, Encoder, Hash, UserID};
+use libvctrl_core::codec::{BinaryEncoder, BinaryDecoder};
-```rust
-#[derive(Debug, Default)]
-pub struct MemoryStore { /* private */ }
+fn main() -> Result<(), Box> {
+ let tree = Hash::from_bytes(&[1u8; 64])?;
+ let author = UserID::new("Alice".to_owned(), "alice@example.com".to_owned())?;
+ let committer = UserID::new("Bob".to_owned(), "bob@example.com".to_owned())?;
+ let commit = Commit::new(tree, vec![], author, committer, "Initial commit".to_owned())?;
-impl MemoryStore {
- pub fn new() -> Self;
-}
+ let mut encoded = Vec::new();
+ BinaryEncoder.encode_commit(&commit, &mut encoded)?;
-impl ObjectStore for MemoryStore {
- fn put(&mut self, hash: &Hash, data: &[u8]) -> Result<(), VctrlError>;
- fn get(&self, hash: &Hash) -> Result, VctrlError>;
- fn delete(&mut self, hash: &Hash) -> Result<(), VctrlError>;
- fn exists(&self, hash: &Hash) -> Result;
+ let decoded = BinaryDecoder.decode_commit(Cursor::new(encoded.as_slice()))?;
+ assert_eq!(decoded, commit);
+ Ok(())
}
```
-Uses a `HashMap>` internally. `get` clones the stored bytes and wraps them in a `std::io::Cursor`, enabling streaming reads.
-
-**Example:**
+### Hash a streaming input
```rust
-use libvctrl_core::store::MemoryStore;
-use libvctrl_handler::{Hash, ObjectStore};
-use std::io::Read;
-
-let mut store = MemoryStore::new();
-let hash = Hash::from_bytes(&[0; 64]).unwrap();
-store.put(&hash, b"my data").unwrap();
-
-let mut reader = store.get(&hash).unwrap();
-let mut buf = Vec::new();
-reader.read_to_end(&mut buf).unwrap();
-assert_eq!(buf, b"my data");
-```
-
-#### MemoryRefStore
-
-```rust
-#[derive(Debug, Default)]
-pub struct MemoryRefStore { /* private */ }
-
-impl MemoryRefStore {
- pub fn new() -> Self;
-}
-
-impl RefStore for MemoryRefStore {
- type RefsIterator = std::vec::IntoIter>;
+use libvctrl_core::hash::Sha512Hasher;
+use libvctrl_handler::Hasher;
- fn set_ref(&mut self, name: &str, hash: &Hash) -> Result<(), VctrlError>;
- fn get_ref(&self, name: &str) -> Result;
- fn delete_ref(&mut self, name: &str) -> Result<(), VctrlError>;
- fn list_refs(&self) -> Result;
+fn main() -> Result<(), Box> {
+ let hash = Sha512Hasher.hash(b"hello world".as_ref())?;
+ assert_eq!(hash.as_bytes().len(), 64);
+ Ok(())
}
```
-Enforces name length limits and returns sorted reference names.
+### Building objects with fluent builders
-**Example:**
+The `object` module provides ergonomic builders that wrap the handler constructors with
+validation. The builder surface mirrors the facade re-exports
+(`BlobBuilder`, `CommitBuilder`, `TagBuilder`, `TreeBuilder`, `TreeEntryBuilder`):
```rust
-use libvctrl_core::store::MemoryRefStore;
-use libvctrl_handler::{Hash, RefStore};
-
-let mut store = MemoryRefStore::new();
-let hash = Hash::from_bytes(&[0; 64]).unwrap();
-store.set_ref("refs/heads/main", &hash).unwrap();
-assert_eq!(store.get_ref("refs/heads/main").unwrap(), hash);
+// Conceptual — see docs.rs/libvctrl_core for the exact builder API.
+// use libvctrl_core::object::{BlobBuilder, CommitBuilder, TreeBuilder, TreeEntryBuilder};
+// use libvctrl_handler::{EntryKind, Hash, UserID};
+//
+// let blob = BlobBuilder::new().data(b"content".to_vec()).build()?;
+// let entry = TreeEntryBuilder::new("file.txt".to_owned(), EntryKind::Blob, hash).build()?;
+// let tree = TreeBuilder::new().entry(entry).build()?;
+// let user = UserID::new("Alice".to_owned(), "alice@example.com".to_owned())?;
+// let commit = CommitBuilder::new()
+// .tree(tree_hash)
+// .author(user.clone())
+// .committer(user)
+// .message("Initial commit")
+// .build()?;
```
---
-### Validate Module
+## API Reference / Core Modules
-Module path: `libvctrl_core::validate`
+Full API documentation is published at . The summary below
+describes each module and, for the codec, the canonical binary format.
-#### validate_hash_bytes
+### `codec` — Binary codec
-```rust
-pub const fn validate_hash_bytes(bytes: &[u8]) -> Result<(), VctrlError>;
-```
+Implements the `Encoder` and `Decoder` traits. Two zero-sized types:
-Checks that a byte slice is exactly `HASH_LENGTH` (64) bytes long.
+- **`BinaryEncoder`** — writes objects to any `std::io::Write` sink. Stateless; streams
+ fields directly without allocating the entire payload upfront. All length conversions are
+ checked with `try_from` so impossible lengths are reported as
+ `VctrlError::SerializationError` rather than causing silent truncation.
+- **`BinaryDecoder`** — reads objects from any `std::io::Read` source. The trust boundary
+ for untrusted input.
-**Example:**
+The current format version is `VERSION = 3` (`pub const VERSION: u8 = 3`). The decoder
+rejects any input whose first byte does not match `EXPECTED_VERSION = 3`.
-```rust
-use libvctrl_core::validate::hash::validate_hash_bytes;
-use libvctrl_handler::HASH_LENGTH;
-
-let valid = [0u8; HASH_LENGTH];
-assert!(validate_hash_bytes(&valid).is_ok());
-```
+#### Decoder validation pipeline
-#### validate_name
+The decoder follows a defense-in-depth strategy. No slice indexing is performed without a
+preceding bounds check.
-```rust
-pub fn validate_name(name: &str) -> Result<(), VctrlError>;
+```mermaid
+flowchart TD
+ R[Untrusted Read stream] --> RB[read_bounded 4 KiB chunks, hard size cap]
+ RB -->|exceeds cap| ERR1[VctrlError::CorruptedData]
+ RB --> CV[check_version first byte == 3]
+ CV -->|wrong/missing| ERR2[VctrlError::CorruptedData]
+ CV -->|ok| PARSE[Parse with require_byte / require_slice overflow-safe slicing]
+ PARSE -->|truncated / unknown kind / trailing bytes| ERR3[VctrlError::CorruptedData]
+ PARSE --> UTF[Validate all strings as UTF-8]
+ UTF -->|invalid| ERR4[VctrlError::CorruptedData]
+ UTF --> LIM[Re-check system limits MAX_BLOB_SIZE / MAX_TREE_ENTRIES / MAX_MESSAGE_LENGTH]
+ LIM -->|exceeds limit| ERR5[VctrlError::CorruptedData / SerializationError]
+ LIM --> CONSTRUCT[Construct handler type Blob / Tree / Commit / Tag]
+ CONSTRUCT --> OBJ[Immutable validated object]
```
-Validates that a name is:
+#### Binary format layouts
-- Non-empty
-- Not longer than `MAX_NAME_LENGTH`
-- Does not contain `/`
-- Is not `.` or `..`
+All integers are little-endian. Strings are `u8` length-prefixed. Larger payloads use
+`u32` or `u64` length prefixes. Every object begins with a one-byte version field (`3`).
-**Example:**
+**Blob**
-```rust
-use libvctrl_core::validate::name::validate_name;
-
-assert!(validate_name("feature_branch").is_ok());
-assert!(validate_name("../invalid").is_err());
-```
+| Offset | Size | Field |
+| ------ | ---------- | ------------------- |
+| 0 | 1 | Version byte |
+| 1 | 8 | `data_len` (u64 LE) |
+| 9 | `data_len` | Raw blob data |
+
+**Tree**
+
+| Offset | Size | Field |
+| ------ | ------ | ---------------------------- |
+| 0 | 1 | Version byte |
+| 1 | 4 | `entry_count` (u32 LE) |
+| 5 | varies | Repeated entries (see below) |
+
+Each tree entry:
+
+| Field | Size |
+| ----------- | ---------- |
+| `name_len` | 1 (u8) |
+| `name` | `name_len` |
+| `kind_byte` | 1 (u8) |
+| `hash` | 64 |
+
+`EntryKind` discriminants:
+
+| Byte | Kind |
+| ---- | ---------- |
+| 0 | Blob |
+| 1 | Executable |
+| 2 | Symlink |
+| 3 | Tree |
+| 4 | Submodule |
+
+**Commit**
+
+| Field | Size |
+| ---------------------- | ----------- |
+| Version | 1 |
+| Tree hash | 64 |
+| Parent count | 2 (u16 LE) |
+| Parent hashes | 64 * count |
+| Author name length | 1 |
+| Author name | length |
+| Author email length | 1 |
+| Author email | length |
+| Committer name length | 1 |
+| Committer name | length |
+| Committer email length | 1 |
+| Committer email | length |
+| Message length | 4 (u32 LE) |
+| Message | length |
+| Timestamp | 8 (i64 LE) |
+| Timezone offset | 2 (i16 LE) |
+| Encoding length | 1 |
+| Encoding | length or 0 |
+
+**Tag**
+
+| Field | Size |
+| ------------------- | -------------- |
+| Version | 1 |
+| Name length | 1 |
+| Name | length |
+| Target hash | 64 |
+| Tagger presence | 1 |
+| Tagger name length | 1 (if present) |
+| Tagger name | length |
+| Tagger email length | 1 (if present) |
+| Tagger email | length |
+| Message length | 4 (u32 LE) |
+| Message | length |
+| Timestamp | 8 (i64 LE) |
+| Timezone offset | 2 (i16 LE) |
+| Encoding length | 1 |
+| Encoding | length or 0 |
+
+#### Error mapping
+
+The codec surfaces three `VctrlError` variants:
+
+- `VctrlError::CorruptedData` — version mismatch, missing/truncated length prefix,
+ length mismatch, unknown entry-kind byte, trailing bytes, invalid UTF-8, or input
+ exceeding the bounded size cap. The dominant failure mode on the decode path.
+- `VctrlError::SerializationError` — length overflow that cannot be represented in the
+ prefix integer (e.g. a name longer than `u8::MAX`, a message longer than `u32::MAX`),
+ or a message exceeding `MAX_MESSAGE_LENGTH`. The dominant failure mode on the encode
+ path.
+- `VctrlError::IoError` — underlying `Read`/`Write` failure, wrapped via
+ `std::sync::Arc` so the error remains cloneable.
+
+### `hash` — Content addressing
+
+- **`Sha512Hasher`** — a zero-sized, stateless, thread-safe type implementing the `Hasher`
+ trait. It is a **thin adapter** that bridges the raw `libvctrl_sha512` digest engine to
+ the handler `Hash` type. The `hash` method reads from any `std::io::Read` in fixed-size
+ chunks, feeds each chunk into the SHA-512 engine, and finalises into a 64-byte `Hash`
+ whose length always matches `HASH_LENGTH`.
+
+### `object` — Fluent builders
+
+Builders for `Blob`, `Commit`, `Tag`, `Tree`, and `TreeEntry`. Each builder wraps the
+corresponding handler constructor with validation and a fluent API:
+
+- `BlobBuilder`
+- `CommitBuilder`
+- `TagBuilder`
+- `TreeBuilder`
+- `TreeEntryBuilder`
+
+See for the exact builder method surface. The builders are
+also re-exported at the root of the `libvctrl` facade.
+
+### `store` — In-memory storage
+
+Two `HashMap`-backed implementations:
+
+- **`MemoryStore`** — implements `ObjectStore`. Stores encoded object bytes keyed by `Hash`.
+- **`MemoryRefStore`** — implements `RefStore`. Stores named references (e.g. branch and
+ tag names) pointing at `Hash` values.
+
+Both are intended for testing, prototyping, and ephemeral in-process VCS sessions. For
+persistent or remote backends, implement `ObjectStore` and `RefStore` directly.
---
## Testing
-The crate includes unit tests and doctests. Run all tests with:
+Run the crate's test suite with Cargo:
-```sh
-cargo test --all-features
+```bash
+cargo test
```
-Run only doctests:
+Property-based tests use `proptest` (a dev-dependency). To run the entire workspace test
+suite from the repository root:
-```sh
-cargo test --doc
+```bash
+cargo test --workspace
```
-Run property-based tests (using `proptest`):
+To verify the strict lint policy is satisfied:
-```sh
-cargo test --test proptest
-```
-
-Run Clippy with strict lints:
-
-```sh
-cargo clippy --all-targets --all-features -- -D warnings
+```bash
+cargo clippy --workspace --all-targets -- -D warnings
+cargo doc --workspace --no-deps
```
---
-## CI/CD Pipeline
-
-No CI/CD pipeline is currently configured in the repository.
-
-If one is added, it should include the following stages:
-
-```mermaid
-graph LR
- A[Push] --> B[Format Check]
- B --> C[Clippy Lint]
- C --> D[Run Tests]
- D --> E[Build Docs]
- E --> F[Publish to crates.io]
-```
-
----
-
-## Deployment / Distribution
+## Contributing
-The crate is intended to be published to crates.io.
+Contributions are welcome. The crate enforces `#![forbid(unsafe_code)]` and inherits a
+strict, denied Clippy and documentation-lint policy from the workspace; all public items
+must be documented.
-Release process:
+For contribution guidelines, code style, and the full lint configuration, see the
+repository's `CONTRIBUTING.md` and the workspace root `README.md`:
-1. Update `version` in `Cargo.toml`.
-2. Update `CHANGELOG.md`.
-3. Run `cargo publish --dry-run`.
-4. Run `cargo publish`.
+- Repository: https://github.com/mroczect/libvctrl
-After publication, documentation will be available at `https://docs.rs/libvctrl_core`.
+When contributing to `libvctrl_core`, keep the contract/implementation boundary clean: new
+behaviour belongs here, new contracts belong in `libvctrl_handler`, and new user-facing
+commands belong in `libvctrl_plumbing` or `libvctrl_porcelain`.
---
-## Security & Compliance
-
-`libvctrl_core` is a foundational layer for version control systems and adheres to strict security practices:
-
-- **No unsafe code:** `#![forbid(unsafe_code)]` guarantees memory safety.
-- **DoS protection:** Binary decoder enforces `MAX_BLOB_SIZE`, `MAX_TREE_ENTRIES`, and `MAX_MESSAGE_LENGTH` before allocation.
-- **Strict UTF-8 validation:** All decoded strings are checked for valid UTF-8.
-- **Path traversal prevention:** `validate_name` rejects `/`, `.`, and `..`.
-- **Deterministic serialization:** Binary format ensures reproducible hashes.
-- **Streaming reads:** `MemoryStore::get` returns `Box` to avoid loading large objects entirely into memory.
-- **Audited cryptography:** `Sha512Hasher` delegates to `libvctrl_sha512`, which is pure Rust and auditable.
+## Ecosystem
-Downstream implementations must follow the guidelines in `SECURITY.md` at the workspace root.
+`libvctrl_core` is one layer of a larger workspace. The related crates are listed below;
+each has its own documentation.
----
-
-## Contributing
+| Crate | Role | Documentation |
+| -------------------- | -------------------------------------------------------- | ---------------------------------- |
+| `libvctrl` | Facade: re-exports contracts, reference impl, and crypto | https://docs.rs/libvctrl |
+| `libvctrl_handler` | Contract layer: traits, types, limits, validation | https://docs.rs/libvctrl_handler |
+| `libvctrl_sha512` | Zero-dependency SHA-512 / HMAC / HKDF primitives | https://docs.rs/libvctrl_sha512 |
+| `libvctrl_plumbing` | Command-level VCS operations built on `libvctrl_core` | https://docs.rs/libvctrl_plumbing |
+| `libvctrl_porcelain` | High-level, user-facing VCS operations | https://docs.rs/libvctrl_porcelain |
-Contributions are welcome. Follow the workspace `CONTRIBUTING.md`.
+The dependency flow is strictly one-way: `handler` is the foundation, `core` implements the
+contracts, the facade re-exports both, and `plumbing`/`porcelain` build on `core`.
-For this crate, ensure:
-
-- All public items have documentation with doctests.
-- No `unsafe` code.
-- Run `cargo fmt`.
-- Run `cargo clippy --all-targets --all-features -- -D warnings`.
-- All tests pass with `cargo test --all-features`.
+```mermaid
+flowchart LR
+ H[libvctrl_handler contracts] --> C[libvctrl_core reference impl]
+ C --> PL[libvctrl_plumbing]
+ C --> PO[libvctrl_porcelain]
+ H --> F[libvctrl facade]
+ C --> F
+```
---
## License
-This project is licensed under the MIT License. See the `LICENSE` file in the workspace root for details.
+Licensed under the MIT License. See the repository for the full license text.
diff --git a/libvctrl_handler/Cargo.toml b/libvctrl_handler/Cargo.toml
index 9283dbe1..dcde7cb9 100644
--- a/libvctrl_handler/Cargo.toml
+++ b/libvctrl_handler/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "libvctrl_handler"
-version = "5.0.0"
+version = "5.0.1"
edition = "2024"
description = "Fundamental contracts for building a version control system – no implementations, only traits and types"
license = "MIT"
diff --git a/libvctrl_handler/README.md b/libvctrl_handler/README.md
index c52d1c5b..259ba0da 100644
--- a/libvctrl_handler/README.md
+++ b/libvctrl_handler/README.md
@@ -1,152 +1,182 @@
# libvctrl_handler
-**Fundamental contracts for building a version control system – no implementations, only traits and types**
-
-_Constitution (handler), reference implementation (core), and plumbing commands_
+Fundamental contracts for building a version control system — no implementations, only
+traits, types, and validation. `libvctrl_handler` is the "constitution" layer of the
+`libvctrl` ecosystem: it defines _what_ a VCS object model looks like without prescribing
+_how_ it is stored, serialised, signed, or transported. Every other crate in the workspace
+implements or consumes these contracts.
+
+- **Crate:** `libvctrl_handler` 5.0.1 (library, `std`-only, zero external dependencies)
+- **Language:** Rust, edition 2024 — MSRV **1.96.0**
+- **License:** MIT
+- **Repository:** https://github.com/mroczect/libvctrl
+- **Documentation:** https://docs.rs/libvctrl_handler
+
+> Most users should depend on the **`libvctrl` facade**, which re-exports this crate
+> alongside the reference implementation and the crypto primitives. Reach for
+> `libvctrl_handler` directly only when you are implementing a custom backend or need the
+> contract surface without the reference implementation.
---
## Overview
-`libvctrl` is a modular framework for building version control systems, structured around a strict separation between **contracts** and **implementations**. This repository contains the foundational contract layer, packaged as the crate `libvctrl_handler`.
-
-The handler crate defines:
+`libvctrl_handler` is a pure contracts crate. It contains no concrete implementations —
+no storage backends, no serializers, no hashing engines. Instead it provides:
-- A complete set of **traits** for every major VCS operation: object storage, encoding, decoding, hashing, indexing, reference management, reflogs, remote transport, packing, signing, verification, revision walking, diffing, blame, and configuration.
-- **Data types** representing Git objects (`Blob`, `Tree`, `Commit`, `Tag`) and supporting structures (`Hash`, `UserID`, `TreeEntry`, deltas, merges, reflog entries).
-- **Constants** enforcing safe size and count limits.
-- **Validation functions** that define the security boundary for names, references, tree entries, and hashes.
-- A unified **error type** (`VctrlError`) that all trait implementations must use.
+- **Traits** defining every major VCS operation: object storage, encoding, decoding,
+ hashing, indexing, reference management, reflogs, remote transport, packing, signing,
+ verification, revision walking, diffing, blame, and configuration.
+- **Immutable data types** representing Git objects (`Blob`, `Tree`, `Commit`, `Tag`) and
+ supporting structures (`Hash`, `UserID`, `TreeEntry`, `CommitMeta`, deltas, merges,
+ reflog entries).
+- **Constants** enforcing safe size and count limits to prevent resource exhaustion.
+- **Validation functions** that define the security boundary for names, references, tree
+ entries, and hashes.
+- A unified **error type** (`VctrlError`) that all trait implementations must return.
-`libvctrl_handler` contains **no concrete implementations**. It is the "constitution" upon which all other crates in the `libvctrl` ecosystem are built. The reference implementation `libvctrl_core` provides working implementations of the traits (in-memory object store, binary encoder/decoder, SHA-512 hasher, etc.). Higher-level crates `libvctrl_plumbing` and `libvctrl_porcelain` build on top of `libvctrl_core`.
-
-The primary facade crate is `libvctrl`, which re-exports the handler types and the reference implementation so integrators can use the whole framework with a single dependency.
+The crate depends only on the Rust standard library. It is `std`-only and exposes no
+crate-level feature flags. There is no `no_std` build path at present.
---
## Architecture
-The architecture enforces a one-way dependency flow:
-
-- **Handler (contract layer)** — this crate — depends only on the Rust standard library.
-- **Core (reference implementation)** depends on the handler and provides concrete implementations.
-- **Plumbing/Porcelain** depend on the core and provide command-level or high-level VCS operations.
-
-The following diagram illustrates the crate dependency structure:
+`libvctrl_handler` is the foundation of a strictly layered, one-way dependency graph. It
+sits at the bottom; the reference implementation (`libvctrl_core`) implements its traits;
+the facade (`libvctrl`) re-exports both; and the command crates (`libvctrl_plumbing`,
+`libvctrl_porcelain`) build on top.
```mermaid
-graph TD
- subgraph Contract Layer
- H[libvctrl_handler]
- H --> C[constants]
- H --> E[enums]
- H --> ER[errors]
- H --> M[macros]
- H --> T[traits]
- H --> TY[types]
- H --> V[validation]
+flowchart TD
+ subgraph Apps["Application layer"]
+ FACADE["libvctrl facade (re-exports)"]
+ PL["libvctrl_plumbing"]
+ PO["libvctrl_porcelain"]
+ end
+
+ subgraph Ref["Reference implementation"]
+ CORE["libvctrl_core codec, builders, stores, hasher"]
end
- subgraph Reference Implementation
- CORE[libvctrl_core]
- CORE --> H
+ subgraph Contracts["Contract layer — libvctrl_handler (this crate)"]
+ HANDLER["traits + types + constants enums + errors + macros + validation std-only, zero dependencies"]
end
- subgraph Applications
- PL[libvctrl_plumbing]
- PO[libvctrl_porcelain]
- PL --> CORE
- PO --> CORE
+ subgraph Crypto["Cryptography"]
+ SHA["libvctrl_sha512 raw SHA-512 engine"]
end
- FACADE[libvctrl facade crate]
- FACADE --> H
+ FACADE --> HANDLER
FACADE --> CORE
+ FACADE --> SHA
+ PL --> CORE
+ PO --> CORE
+ CORE --> HANDLER
+ CORE --> SHA
```
-Within the handler crate, the module organization is as follows:
+### Internal module organization
+
+The crate is separated into seven modules, each with a single responsibility. The crate
+root (`lib.rs`) re-exports the most commonly used items for ergonomic access.
+
+```mermaid
+flowchart LR
+ LIB["lib.rs crate root + root re-exports"]
+ LIB --> CONST["constants limits + entry_mode"]
+ LIB --> ENUMS["enums EntryKind"]
+ LIB --> ERRORS["errors VctrlError"]
+ LIB --> MACROS["macros vctrl_error_other!"]
+ LIB --> TRAITS["traits/core 17 contracts"]
+ LIB --> TYPES["types/core 14 immutable data types"]
+ LIB --> VAL["validation 4 input checks"]
+
+ VAL -.gates construction.-> TYPES
+ TRAITS -.consume / return.-> TYPES
+ TYPES -.return.-> ERRORS
+ TRAITS -.return.-> ERRORS
+ ENUMS -.used by.-> TYPES
+ CONST -.used by.-> TYPES
+ CONST -.used by.-> VAL
+```
+
+### Invalid states are unrepresentable
+
+A core design idiom is that all public data types are constructed via **fallible
+constructors** that enforce invariants at construction time. Once built, objects are
+immutable and expose only `&self` accessors. This pushes validation to the boundary of the
+system and guarantees that invalid objects cannot exist at runtime.
```mermaid
-graph TD
- ROOT[lib.rs]
- ROOT --> CONST[constants]
- ROOT --> ENUMS[enums]
- ROOT --> ERR[errors]
- ROOT --> MAC[macros]
- ROOT --> TRAITS[traits]
- ROOT --> TYPES[types]
- ROOT --> VAL[validation]
-
- ENUMS --> EK[enums::core::entry_kind]
- TRAITS --> TC[traits::core]
- TC --> BLAME[blame]
- TC --> CFG[config]
- TC --> DEC[decoder]
- TC --> DIFF[diff]
- TC --> ENC[encoder]
- TC --> HASHER[hasher]
- TC --> IDX[index]
- TC --> OS[object_store]
- TC --> PACK[pack]
- TC --> RF[ref_store]
- TC --> RL[reflog]
- TC --> REM[remote]
- TC --> RW[revwalk]
- TC --> SIGN[signer]
- TC --> TRAN[transport]
- TC --> VER[verifier]
-
- TYPES --> TYC[types::core]
- TYC --> BLOB[blob]
- TYC --> COMMIT[commit]
- TYC --> DELTA[delta]
- TYC --> HASH[hash]
- TYC --> MERGE[merge]
- TYC --> REFLOG[reflog]
- TYC --> TAG[tag]
- TYC --> TREE[tree]
- TYC --> UID[user_id]
+flowchart LR
+ INPUT[Raw input name / hash bytes / ref name / tree entry]
+ INPUT --> VALFN[validation function validate_name / validate_hash_bytes / ...]
+ VALFN -->|invalid| ERR1[VctrlError InvalidName / InvalidHashLength / ...]
+ VALFN -->|valid| CTOR[Fallible constructor Blob::new / Tree::new / UserID::new / ...]
+ CTOR -->|invariant violated| ERR2[VctrlError]
+ CTOR -->|ok| OBJ[Immutable validated object only &self accessors]
+ OBJ -.Send + Sync.-> THREADS[Cross-thread consumers]
```
---
## Core Features
-- **Trait-only contracts** — Every VCS subsystem is expressed as a `trait` with clear method signatures, error returns, and `Send + Sync` bounds. Implementations are decoupled from consumers.
-- **Git-compatible data types** — `Blob`, `Tree`, `TreeEntry`, `Commit`, `Tag`, `UserID`, and their supporting types mirror the Git object model and enforce Git-like invariants.
-- **Fixed-size hash** — `Hash` is a newtype over `[u8; 64]` (SHA-512 length), with hexadecimal parsing, display, and ordering.
-- **Validation as a security boundary** — Dedicated functions validate names, references, tree entry names, and hash lengths. Implementation crates must call these functions, never duplicate the logic.
-- **Comprehensive error hierarchy** — `VctrlError` covers invalid lengths, missing objects, corrupted data, I/O failures, serialization issues, tree structure errors, duplicate parents, size limit breaches, and invalid blame ranges.
-- **Strict compile-time guarantees** — The crate uses `#![forbid(unsafe_code)]`, `#![deny(missing_docs)]`, and a suite of Clippy lints to ensure safe, well-documented, idiomatic code.
+- **Pure contracts.** No implementations — only traits, types, constants, and
+ validation. Backend authors implement the traits; tool authors depend on the types.
+- **Invalid states unrepresentable.** All data types use fallible constructors that reject
+ malformed input at construction time; objects are immutable thereafter.
+- **Resource-exhaustion prevention.** Hard `MAX_*` limits act as fail-fast circuit
+ breakers during construction, bounding memory allocation against malicious input.
+- **Strong typing over raw integers.** Git mode bits are represented by the `EntryKind`
+ enum with `const fn` conversions to and from raw `u32` modes, preventing invalid
+ combinations at compile time.
+- **Forward-compatible enums and errors.** `EntryKind` and `VctrlError` are
+ `#[non_exhaustive]`, allowing new variants without breaking API compatibility.
+- **Thread-safe contracts.** Traits carry `Send + Sync` bounds so backends can be shared
+ across threads; `&mut self` is required only for write operations.
+- **Cloneable I/O errors.** `std::io::Error` is wrapped in `Arc` inside `VctrlError` so
+ the error remains `Clone` despite `io::Error` not being `Clone`.
+- **Compile-time computation.** `const fn` is used where possible (`EntryKind::mode`,
+ `from_mode`) to shift work to compile time.
+- **Strict safety.** `#![forbid(unsafe_code)]` and a comprehensive set of denied Clippy
+ and documentation lints are inherited from the workspace.
---
## Technology Stack
-- **Language:** Rust (edition 2024)
-- **Standard library only:** No external dependencies. The handler crate uses only `std` types (`std::io`, `std::collections::HashSet`, `std::path`, etc.).
-- **Frameworks/Libraries:** None. This crate is a pure contract definition.
-- **Toolchain:** Requires Rust 1.85 or newer (for edition 2024 support).
+- **Language:** Rust (edition 2024, MSRV 1.96.0)
+- **Dependencies:** none (standard library only)
+- **Dev-dependencies:** `proptest` 1.11.0
+- **Lint policy:** workspace-inherited, `#![forbid(unsafe_code)]`, denied `missing_docs`,
+ `rust_2018_idioms`, and a broad set of Clippy lints (including `pedantic` and `nursery`
+ groups). See the repository for the authoritative lint configuration.
+- **Feature flags:** none.
+
+> Note on the MSRV field: this crate's `Cargo.toml` does not yet declare
+> `rust-version = "1.96"`. The workspace standard is Rust 1.96.0, and this README
+> documents that as the MSRV. Adding `rust-version = "1.96"` to
+> `libvctrl_handler/Cargo.toml` is recommended in a future maintenance pass.
---
## Project Structure
-The source tree of `libvctrl_handler` is organized as follows:
-
```text
libvctrl_handler/
├── Cargo.toml
└── src/
├── lib.rs
├── constants.rs
+ ├── errors.rs
+ ├── macros.rs
├── enums/
│ ├── mod.rs
│ └── core/
│ ├── mod.rs
│ └── entry_kind.rs
- ├── errors.rs
- ├── macros.rs
├── traits/
│ ├── mod.rs
│ └── core/
@@ -170,16 +200,7 @@ libvctrl_handler/
├── types/
│ ├── mod.rs
│ └── core/
- │ ├── mod.rs
- │ ├── blob.rs
- │ ├── commit.rs
- │ ├── delta.rs
- │ ├── hash.rs
- │ ├── merge.rs
- │ ├── reflog.rs
- │ ├── tag.rs
- │ ├── tree.rs
- │ └── user_id.rs
+ │ └── ... (data type definitions)
└── validation/
├── mod.rs
├── hash.rs
@@ -192,571 +213,360 @@ libvctrl_handler/
### Prerequisites
-- **Rust 1.85 or newer** — required for the 2024 edition.
-- **Cargo** — the Rust package manager.
-- No system-level dependencies are required; the handler crate is pure Rust.
+- Rust toolchain **1.96.0** or newer (edition 2024 is required)
+- Cargo
+
+No system libraries or external services are required.
### Installation
-For most integrators, the recommended entry point is the `libvctrl` facade crate, which re-exports both the handler contracts and the reference implementation:
+For most users, depend on the facade instead:
```toml
[dependencies]
-libvctrl = "4.4"
+libvctrl = "2.1"
```
-If you are developing an implementation crate and need to depend directly on the contract layer:
+To depend on `libvctrl_handler` directly (contracts only, no reference implementation):
```toml
[dependencies]
-libvctrl_handler = "4.4"
+libvctrl_handler = "5.0"
```
-To use the handler from a local checkout or a Git repository:
+Or via Cargo:
-```toml
-[dependencies]
-libvctrl_handler = { git = "https://github.com/mroczect/libvctrl", branch = "master" }
+```bash
+cargo add libvctrl_handler
```
-### Configuration
+Because the crate has no external dependencies, adding it is essentially zero-weight
+beyond the standard library.
-The handler crate itself requires no configuration or environment variables. All size and count limits are defined as constants in `libvctrl_handler::constants` and are enforced by the validation functions and type constructors.
+### Configuration
-However, the `ConfigStore` trait defines an abstraction for reading and writing configuration values. The reference implementation and higher-level crates may use this trait to handle user configuration.
+`libvctrl_handler` exposes **no crate-level feature flags** and requires **no runtime
+configuration**. The contract surface is fixed; behavioural configuration (such as the
+`sha384` / `opt_size` crypto features) lives at the facade or `libvctrl_sha512` level.
---
## Usage
-The handler crate is not meant to be used directly by end users; it is consumed by implementors and integrators. The following examples illustrate how the contracts are used.
-
-### Implementing a trait
-
-Implementations must satisfy the trait's method signatures and return `VctrlError` on failure. The following example shows a minimal in-memory object store:
+### Create a Hash and inspect an EntryKind
```rust
-use libvctrl_handler::{ObjectStore, Hash, VctrlError};
-use std::collections::HashMap;
-use std::io::{self, Read};
+use libvctrl_handler::{EntryKind, Hash};
-pub struct MemoryStore {
- objects: HashMap>,
-}
+// Hash requires exactly 64 bytes (SHA-512).
+let raw_bytes = [0_u8; 64];
+let hash = Hash::from_bytes(&raw_bytes);
+assert!(hash.is_ok());
-impl MemoryStore {
- pub fn new() -> Self {
- Self { objects: HashMap::new() }
- }
-}
-
-impl ObjectStore for MemoryStore {
- fn put(&mut self, hash: &Hash, data: &[u8]) -> Result<(), VctrlError> {
- self.objects.insert(*hash, data.to_vec());
- Ok(())
- }
-
- fn get(&self, hash: &Hash) -> Result, VctrlError> {
- match self.objects.get(hash) {
- Some(data) => Ok(Box::new(io::Cursor::new(data.clone()))),
- None => Err(VctrlError::ObjectNotFound(*hash)),
- }
- }
-
- fn delete(&mut self, hash: &Hash) -> Result<(), VctrlError> {
- self.objects.remove(hash).map(|_| ()).ok_or(VctrlError::ObjectNotFound(*hash))
- }
-
- fn exists(&self, hash: &Hash) -> Result {
- Ok(self.objects.contains_key(hash))
- }
-}
-```
-
-### Constructing a validated data type
-
-Data types enforce validation in their constructors. For example, creating a `Commit` with metadata:
-
-```rust
-use libvctrl_handler::{Commit, CommitMeta, UserID, Hash};
-use libvctrl_handler::VctrlError;
-
-fn create_commit(tree_hash: Hash, parent: Hash, author: UserID, committer: UserID) -> Result {
- let meta = CommitMeta::new(
- 1_700_000_000, // timestamp
- 0, // timezone offset (UTC)
- Some("UTF-8".into()),
- )?;
-
- Commit::with_meta(
- tree_hash,
- vec![parent],
- author,
- committer,
- "Initial commit".to_string(),
- meta,
- )
-}
+// Git object modes are accessible via the strongly-typed EntryKind enum.
+let blob_mode = EntryKind::Blob.mode();
+assert_eq!(blob_mode, 0o100_644);
```
-### Encoder/Decoder roundtrip
-
-The `Encoder` and `Decoder` traits define how objects are serialized and deserialized. Implementations must adhere to the binary format contract:
+### Convert between EntryKind and raw mode bits
```rust
-use libvctrl_handler::{Encoder, Decoder, Commit, VctrlError};
-use std::io::{Cursor, Read, Write};
-
-fn roundtrip_commit(
- decoder: &D,
- encoder: &E,
- commit: &Commit,
-) -> Result {
- let mut buffer = Vec::new();
- encoder.encode_commit(commit, &mut buffer)?;
-
- let mut reader = Cursor::new(buffer);
- decoder.decode_commit(reader)
-}
-```
-
----
-
-## API Reference / Core Modules
-
-This section documents the public API of the handler crate.
-
-### `constants`
-
-Defines size and count limits and Git entry mode bits.
-
-| Constant | Value | Description |
-| -------------------- | ------------------- | --------------------------------------------------- |
-| `HASH_LENGTH` | `64` | Length of a hash in bytes (SHA-512). |
-| `MAX_NAME_LENGTH` | `255` | Maximum length for names, in bytes. |
-| `MAX_BLOB_SIZE` | `100 * 1024 * 1024` | Maximum blob size in bytes (100 MiB). |
-| `MAX_TREE_ENTRIES` | `100_000` | Maximum number of entries in a tree. |
-| `MAX_MESSAGE_LENGTH` | `1024 * 1024` | Maximum commit/tag message length in bytes (1 MiB). |
-| `MAX_PARENT_COUNT` | `65535` | Maximum number of parent commits. |
-
-`constants::entry_mode` provides Git mode bits:
-
-| Mode | Value (octal) | Description |
-| ------------ | ------------- | ----------------- |
-| `BLOB` | `0o100_644` | Regular file. |
-| `EXECUTABLE` | `0o100_755` | Executable file. |
-| `SYMLINK` | `0o120_000` | Symbolic link. |
-| `TREE` | `0o40_000` | Directory (tree). |
-| `SUBMODULE` | `0o160_000` | Submodule commit. |
-
-### `enums::EntryKind`
-
-Represents the kind of an entry in a Git tree.
-
-| Variant | Mode | Description |
-| ------------ | ------------ | ----------------- |
-| `Blob` | `BLOB` | Regular file. |
-| `Executable` | `EXECUTABLE` | Executable file. |
-| `Symlink` | `SYMLINK` | Symbolic link. |
-| `Tree` | `TREE` | Directory. |
-| `Submodule` | `SUBMODULE` | Submodule commit. |
-
-Methods: `mode()` returns the mode bits; `from_mode(mode: u32) -> Option` converts raw mode bits.
-
-### `errors::VctrlError`
-
-The unified error type for all operations.
-
-| Variant | Description |
-| ------------------------------ | --------------------------------------------------------------- |
-| `InvalidHashLength(usize)` | Hash length did not match expected 64 bytes. |
-| `InvalidName(String)` | Name invalid (empty, too long, or contains control characters). |
-| `InvalidEmail(String)` | Email invalid. |
-| `ObjectNotFound(Hash)` | Object not found. |
-| `RefNotFound(String)` | Reference not found. |
-| `CorruptedData(String)` | Data corrupted or malformed. |
-| `IoError(Arc)` | I/O error. |
-| `SerializationError(String)` | Serialization/deserialization error. |
-| `Other(String)` | Any other error. |
-| `InvalidTreeStructure(String)` | Tree structure invalid (unsorted entries, duplicates). |
-| `InvalidTimezoneOffset(i16)` | Timezone offset out of range (-1440 to 1440). |
-| `DuplicateParent` | Commit contains duplicate parent hashes. |
-| `ExceededMaxSize(String)` | Size or count limit exceeded. |
-| `InvalidBlameRange` | Invalid blame range (zero line count). |
-
-`VctrlError` implements `Display`, `Error`, `PartialEq`, and `Eq`. It also provides `from_io(e: std::io::Error) -> Self` for canonical I/O error conversion.
-
-### `macros`
-
-- **`vctrl_error_other!`** — Constructs a `VctrlError::Other` from a format string and arguments.
-
-```rust
-let err = vctrl_error_other!("Failed to parse {}", "object");
-```
-
-### `traits::core`
-
-The following traits are defined. All are `Send + Sync`.
-
-#### `Blame`
-
-Computes blame information for files.
-
-```rust
-fn blame_file(&self, path: &str) -> Result, VctrlError>;
-```
-
-`BlameEntry` represents a line range attributed to a commit.
-
-#### `ConfigStore`
-
-Reads and writes configuration values.
-
-```rust
-fn get_string(&self, section: &str, key: &str) -> Result