A bundle's verification flags were assertions about methodology that
nothing checked. This makes them conditional on machine-readable
declarations of what the run actually did, and fixes five cases where the
emitter stated something it had not established.
bench/result-schema.json gains a required run_conditions block of ten
closed enumerations -- initialization and mutation path, checkpoint and
index state, index-run ceiling, receipt reconciliation, objects_new
source, commit-id uniqueness, build profile, environment fidelity. It is
not disclosure beside the claims; it is what the claims are conditioned
on, so a harness can only assert what its declaration permits. A prose
caveat field was rejected: free text is not a condition a consumer can
check, and a bundle whose caveats live only in a report reads as
unconditional to everyone who receives it.
The branch conditional forbids the three newly earnable claims on the
journal-drive path and pins its four provenance declarations to the only
values that seam can make. Forbidding the claims alone left the hole one
field over -- a drive bundle could otherwise declare exact receipt
reconciliation it has no receipts to perform.
Emitter defects, each found by reading the schema against the code:
- Setup traffic was inside the measured interval. Both counter baselines
were read only at the end, so repository creation -- which goes through
submit, and therefore fences and signs -- was counted as measured work
while the bundle asserted setup_traffic_excluded. A false exclusion
claim is worse than a wrong number: a wrong number invites scrutiny
and this deflects it.
- A zero-work run produced a schema-valid bundle asserting uniqueness
over zero ids and three-objects-per-commit over zero commits. Both are
vacuously true, which is why they must not be earnable that way: the
result is indistinguishable from a measured run by the consumer the
schema exists to serve. Refused by name at two altitudes.
- An ACK-journal write failure ended the run quietly. It set a stop flag
without recording a refusal, so neither the fatal guard nor the
zero-work guard saw it, and the bundle omitted a committed transaction
while still counting its fence and its signature -- one counted
transaction against two fences and two signings. It is now a fatal
incomplete-accounting refusal carrying the original errno, because the
commit happened: folding it into the refused count would report a
transaction the store committed as one it declined.
- Widening that class to "a failure that produces a value nobody read"
found three more. A shard with no counters summed to zero fences,
silently shrinking the total that bounds every durability claim. A
digest of an unreadable file returned the digest of empty input -- a
well-formed 64-hex value indistinguishable from a real one, feeding
five attested fields. An unreadable /proc/meminfo published one byte
of RAM. All three refuse now.
- Index steady state was inferred from any directory entry, so one stray
file declared the index sealed. Entries are parsed back as index runs
against the root's own uuid; an unparseable entry is reported as
unvalidatable rather than lowering a count, and a backlog is refused
because neither named value describes sealing that did not keep up.
deployment.tmpfs, persistent_data_mount, and hardware.filesystem were
constants -- the emitter could assert deployment facts it had never
checked. They are read from /proc/mounts now. Both deployment fields relax
to booleans so a diagnostic run is representable at all: it was previously
not disqualified but unencodable, and a schema that can only express
successful runs is not a record of what was measured. outcome=pass
requires reference fidelity at every gate, and a diagnostic run may never
carry a pass verdict.
Hardware profiles are derived, never accepted. store-bench parses the
whole frozen profile tables and names a profile only by exact comparison,
iterating every pinned fact rather than every supplied one -- so a fact
the emitter does not model eliminates the profile instead of being
invisible. That took the honest unobserved list on this host from 7 facts
to 24, which is the inversion working. A deployed-node harness supplies
privileged facts as evidence to compare, never as a label. The outcome
derivation now also requires the checkpoint and index conditions, because
fidelity was the only thing preventing a pass and would have stopped being
so the moment profile recognition started working, at which point the
emitter would have produced a pass its own validator rejects.
operation_receipts_reconciled is expressible and deliberately not emitted:
the bench accepts any Committed status without comparing the payload, and
the digest it records is of the operation id rather than the receipt.
Contract review 2026-07-28-C records the amendment and the ceiling it does
not close: run_conditions is self-reported, and only the index-run ceiling
is cross-checked against an independent value. Scope 5.1 records why a
full filesystem is indistinguishable from a concurrency flake by symptom,
and that an I/O error must reach a report with its errno intact -- the
same requirement as the incomplete-accounting refusal above.
scripts/check-phase1.sh GATE_EXIT=0; verify-store-recovery.sh reports
bundle=schema-valid on both paths, zero_work_run=refused, and
unaccounted_ack_run=refused.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .github/workflows | ||
| bench | ||
| crates | ||
| deploy | ||
| doc | ||
| scripts | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
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.mdfor 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:
- Trying it. Run
levcs initon a real project, push to a local instance, and report friction. - Workflow design. The next major piece of work is the workflow spec — PR/review surface, issues, CI conventions. Discussion welcome.
- Plugin handlers. The wasm plugin protocol exists; concrete handlers (e.g. protobuf, SQL migrations) are needed to validate it.
- Tightening CI. The
fmtandclippyGitHub 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.