Go to file
Levi Neuwirth 4613078249 Implement the partial B1 namespace-transaction slice
A narrow vertical slice of scope 6.4: StoreEngine::open through one
retained RecoverySession, every shard recovered into the initial
CommittedRoot, and one shard writer wired GroupBuilder -> append_group_and_fence
-> ShardSubtree -> CAS publication -> completion. This closes the Wave A
carry-forward by giving GroupBuilder a production caller; the group bounds
are asserted against the sequencer as fdatasync counts on the device, not
against the builder in isolation.

§6.3's two load-bearing orderings are enforced and asserted, not assumed.
Step 8 follows step 7 with an explicit release fence, so a reader observing
the status root without an entry cannot then read a committed root older
than the publication -- verified by mutation in both directions. Waiters
are woken only after publication, and failure at steps 9-10 leaves a
queryable receipt, because a fence that succeeded and a root that published
is committed.

Three P1 findings from the B2 review are fixed here.

The committed event took its actor from the destination signer rather than
the evidence, so a frame could be signed, fenced, and published and then
fail frozen mirror verification -- first observed by another instance, long
after the bytes were durable. The test could not see it because the signer
key and the evidence actor were the same constant; they are now
deliberately different.

The deadline was rechecked in prepare, before signing and before the group
idle wait, so a slow signer could cross the retry deadline and still
append. The rule is now evaluated again over the whole group immediately
before anything is marked Resolving. The structural half matters more than
the recheck: shard_sequence is no longer consumed at prepare time, so a
dropped member leaves no hole by construction. Repair is re-derivation from
a recorded pre-image through the one sequencing function -- re-sequenced,
re-chained, re-signed -- because signing covers a digest that chains
previous_event_digest, and patching a suffix produces a durable, correctly
fenced frame whose signature verifies against nothing. The test reads every
frame back and checks both the chain and the signature; receipts alone
would not catch a partial repair.

Panic recovery had one catch around the whole writer loop, so every panic
poisoned the shard and reported every waiter as poisoned. Waiters now carry
an explicit phase and an owned reservation. A pre-append panic is
definitively absent and leaves the writer alive, since a dead writer makes
later_append_allowed_before_recovery false whatever the error says; a
request that overflows a publishing group is rolled back before that group
publishes rather than reported as its member; and a panic after publication
still delivers every receipt.

Also: the duplicated object-type and ref-kind tables are deleted in favour
of the amended shared helpers; max_objects_per_transaction and
max_refs_per_transaction are enforced at submit, the entry point a consumer
calls; status occupancy records the newly published root rather than the
one it replaced; and durability_counters/operation_status_metrics return
snapshots only, never the live counters, since a durability claim whose
auditor can write to it is not evidence.

StoreEngine::open constructs the single ProjectionStaging under the held
session before recovery -- it is recovery's projection resolver -- and
holds it exactly as long as the lock.

The remaining deliverables refuse by name: startup states 1/3/4,
coalescing, terminal retention, index sealing, journal rotation,
RepoSnapshot, and checkpoint. This is not a completed B1 deliverable set
and not freeze evidence; the gate's pending-row check stays inert while
engine.rs still returns NotImplemented.

138 library tests, 27 staging tests, 1 intentionally ignored.
scripts/check-phase1.sh GATE_EXIT=0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 18:01:45 -04:00
.github/workflows integrate CI and docs 2026-05-01 11:29:18 -04:00
bench Freeze Wave A: Phase 1 storage spine 2026-07-26 19:47:03 -04:00
crates Implement the partial B1 namespace-transaction slice 2026-07-28 18:01:45 -04:00
deploy levcs 0.1.0 - initial core 2026-05-01 11:14:36 -04:00
doc Amend Wave B storage contracts after adversarial review 2026-07-28 18:01:05 -04:00
scripts Freeze Wave A: Phase 1 storage spine 2026-07-26 19:47:03 -04:00
.gitignore levcs 0.1.0 - initial core 2026-05-01 11:14:36 -04:00
Cargo.lock Implement D0-B storage publication interfaces 2026-07-27 22:31:32 -04:00
Cargo.toml Implement D0-B storage publication interfaces 2026-07-27 22:31:32 -04:00
LICENSE integrate CI and docs 2026-05-01 11:29:18 -04:00
README.md integrate CI and docs 2026-05-01 11:29:18 -04:00

README.md

LeVCS

A distributed version control system with first-class federation, signed authority chains, and a cascading merge engine. Content-addressed by BLAKE3, signed with Ed25519, and built to fix what git can't.

Status: v0.1.0 — protocol substrate complete, workflow surface deferred. The object model, federation API, merge cascade, and instance server all work end-to-end. There is no PR review surface, issue tracker, or web UI yet — those are the next layer up. See doc/technical-report.md for a full framing of where this project is and why.


What's different from git

  • Identity is in the protocol. A repo's membership is a versioned, signed authority object with explicit roles (Reader/Contributor/Maintainer/Owner). Force-push enforcement and push authorization are protocol-level, not server policy.
  • Federation is first-class. Every repo has a global repo_id (BLAKE3 of its genesis authority); instances mirror each other in three storage modes (full / release-only / metadata-only).
  • Merge is a cascade, not a line-level diff. Per-file dispatch to a handler ranked by aggressiveness: textual fallback, format-aware (JSON / YAML / TOML / XML / Markdown / prose), tree-sitter for source code (Rust, Python, JS/TS, Go, C/C++, Java, Ruby, Bash), and wasm-sandboxed plugins for the long tail.
  • BLAKE3, not SHA-1. Tree-hashed, ~5 GiB/s on a laptop, 32-byte IDs everywhere.
  • Releases are signed objects, not mutable name pointers.

For a deeper comparison and context, see the technical report.


Building

LeVCS is a Rust workspace. You'll need a recent stable toolchain (workspace MSRV is 1.75) and a C compiler for the tree-sitter grammars.

cargo build --release

Two binaries land in target/release/:

  • levcs — the user-facing CLI.
  • levcs-instance — the federation HTTP server.

Install them somewhere on PATH:

sudo install -m 0755 \
    target/release/levcs target/release/levcs-instance \
    /usr/local/bin/

Quick start (single user, local only)

# Generate an identity key (stored in $XDG_CONFIG_HOME/levcs/keys.toml).
levcs key generate --label me

# Create a repository wherever you have files to track.
mkdir /tmp/demo && cd /tmp/demo
echo "hello" > a.txt

levcs init --key me
levcs track --all
levcs commit -m "first commit"
levcs log

That's a fully working LeVCS repo. Branch and merge:

levcs branch feature/x
echo "more" >> a.txt
levcs commit -m "wip"
levcs branch main
levcs merge feature/x

If a merge produces conflicts, drop into the resolution TUI:

levcs merge --resolve

Cut a release:

levcs release v0.1.0 --notes "first release"

Hosting an instance

To dogfood the federation surface, run levcs-instance on a VPS behind nginx or Caddy. The full walkthrough is in deploy/README.md: build, systemd unit, reverse proxy templates, firewall, and the laptop-side bootstrap.

The compressed version:

sudo cp deploy/levcs-instance.service /etc/systemd/system/
sudo cp deploy/instance.toml.example /etc/levcs/instance.toml
sudo $EDITOR /etc/levcs/instance.toml
sudo systemctl enable --now levcs-instance
# ... then drop deploy/Caddyfile.example into /etc/caddy/Caddyfile

From your laptop, point the local repo at the instance and push:

levcs instance --set https://levcs.example.com/levcs/v1
levcs push refs/branches/main

The first push to a fresh instance auto-inits the repo with your genesis authority. Subsequent pushes are role-checked against the authority chain.


Repository layout

crates/
  levcs-core/        Object model (Blob/Tree/Commit/Release/Authority),
                     hash, store, refs, repository abstractions.
  levcs-identity/    Authority objects, Ed25519 keys, signing/verify.
  levcs-merge/       Cascade engine, format and tree-sitter handlers,
                     plugin runtime, merge records.
  levcs-protocol/    Pack codec, wire types, request signing, P2P.
  levcs-client/      Thin HTTP client over the federation API.
  levcs-instance/    Axum HTTP server (the federation peer).
  levcs-cli/         The `levcs` user-facing CLI.
  levcs-tui/         Conflict-resolution terminal UI.

deploy/              Production deployment artifacts (systemd, Caddy, nginx).
scripts/             Reproducible benchmark and ops scripts.
doc/                 Technical report and architecture docs.
.github/workflows/   CI configuration.

Testing

cargo test --workspace

Runs the full suite — unit tests, integration tests, federation end-to-end tests including the three-instance "dogfood" scenario, the merge conformance corpus, and property-based fuzz tests. ~194 tests at v0.1.0; full run is well under a minute on a modern laptop.

Useful subsets:

# A single crate's tests
cargo test -p levcs-merge

# A specific integration test
cargo test -p levcs-instance --test dogfood

# Property tests only
cargo test -p levcs-merge --test proptest_textual

Benchmarks

Microbenchmarks live in each crate's benches/ directory and use criterion. A reproducible runner with metadata capture and optional flamegraph generation is at scripts/bench.sh:

scripts/bench.sh --quick               # smoke test (~ a minute total)
scripts/bench.sh                       # full criterion run (~ a few minutes)
scripts/bench.sh --flamegraph          # generate per-bench SVG flamegraphs
scripts/bench.sh --bench pack_codec    # one bench only

Output goes to bench-results/<host>-<UTC-timestamp>/ with a parsed summary.txt, criterion's HTML reports, and a metadata.txt capturing rustc version, kernel, CPU, and git rev for run-to-run comparison.

Headline numbers on a Ryzen 7 laptop:

  • Pack decode at 10 × 1 MiB entries: ~2.3 ms (4.3 GiB/s).
  • Blob serialize + BLAKE3 at 1 MiB: ~190 µs (5.1 GiB/s).
  • Textual three-way merge of a 100 KiB document: ~4.6 ms.

Pack encoding is the throughput floor at ~380 MiB/s — bottlenecked by zstd level 3 on incompressible data.


Documentation

  • doc/technical-report.md — Distribution document. What LeVCS is, how to use it, and how it differs from / improves upon git. Targets technical evaluators and the workflow-spec reader.
  • deploy/README.md — Comprehensive VPS deployment walkthrough.
  • spec/ — The protocol specification and trust-root revision. Currently kept private; ask the maintainer for a copy.

Contributing

This is a young project. The most useful contributions right now are:

  1. Trying it. Run levcs init on a real project, push to a local instance, and report friction.
  2. Workflow design. The next major piece of work is the workflow spec — PR/review surface, issues, CI conventions. Discussion welcome.
  3. Plugin handlers. The wasm plugin protocol exists; concrete handlers (e.g. protobuf, SQL migrations) are needed to validate it.
  4. Tightening CI. The fmt and clippy GitHub jobs are informational; flipping them to gating would close a small but real quality gap.

Please open an issue or reach out before starting non-trivial work so we can coordinate.


License

Released under the Apache License 2.0 — see LICENSE for the full text.


Citation

If LeVCS supports academic work, please cite the v0.1.0 release. A formal citation entry will land with the workflow spec; in the meantime a repository-URL reference is fine.