macrame-db 0.13.0

A Bitemporal Graph Ledger on libSQL · Embedded knowledge database
Documentation
[package]
# `macrame` is taken on crates.io — an unrelated wasm-bindgen macro crate at
# 0.0.1 — so the *package* is published as `macrame-db`. The `[lib]` name below
# keeps the import path `use macrame::…` unchanged, so this is a registry name
# and not a rename of the crate anyone writes against.
name = "macrame-db"
version = "0.13.0"
edition = "2021"
# Measured, not declared: `cargo +1.88.0 check --all-features --all-targets`
# passes and 1.85 does not.
#
# **This floor is not ours.** Macrame's own code needs 1.73 (`div_ceil`; 1.70
# for `Option::is_some_and`). The binding constraint is `home@0.5.12` at 1.88,
# reached through `libsql-ffi`'s *build*-dependency on bindgen -> which -> home
# — and a build-dependency binds consumers too, because libsql-ffi compiles the
# amalgamation on every downstream build. Lowering it means pinning that chain
# (`cargo update home --precise …`), not changing anything here.
rust-version = "1.88"
authors = ["opticsWolf"]
description = "A Bitemporal Graph Ledger on libSQL · Embedded knowledge database"
# crates.io only *warns* locally when these are missing — `cargo publish
# --dry-run` passes without them — but the registry API rejects an upload with
# no license, so the first real publish would fail after a full verify build.
license = "MIT OR Apache-2.0"
repository = "https://github.com/opticsWolf/Macrame"
readme = "README.md"
keywords = ["bitemporal", "graph", "libsql", "ledger", "database"]
categories = ["database", "database-implementations", "data-structures"]

# The Python binding's tree, kept out of the `.crate` tarball (P0, D-098).
#
# The package root is the repo root — deliberately, because `tests/` reaches
# `docs/` and `src/` through `include_str!` and moving the crate down a level
# would put those outside the published tarball. The cost of that choice is
# this list: everything at the root is packaged unless named here.
#
# `bindings/` is **not** listed and does not need to be. Cargo already skips a
# subdirectory that carries its own `Cargo.toml`, since that is another
# package; `cargo package --list` is the check, and it is asserted by
# `tests/packaging_tests.rs` rather than left to memory.
exclude = [
    "pyproject.toml",
    "python/",
    "tests_py/",
    "/.venv/",
    "*.whl",
]

# The Python bindings (P0, D-098). Additive on purpose: the root stays a
# *package*, and Cargo's default for a workspace root that is itself a package
# is that package alone — so `default-members` is deliberately absent and
# `cargo test`, `cargo clippy --all-targets`, `cargo check --all-features` and
# `cargo publish` here are the same commands they were before, scoped to
# `macrame-db`. pyo3 is compiled only when something names it (`-p macrame-py`,
# or maturin).
#
# That is a claim about Cargo's behaviour, so it is checked rather than
# believed: `tests/packaging_tests.rs` asserts `cargo metadata`'s
# `workspace_default_members` is this package alone.
#
# `bindings/python` is `publish = false`, so `cargo publish` still uploads
# exactly one package.
[workspace]
members = ["bindings/python"]

# The import path stays `macrame`, independent of the registry name above.
# Without this a dependent would have to write `use macrame_db::…`, and every
# rustdoc link, doc-test and example in the crate says `macrame`.
[lib]
name = "macrame"
path = "src/lib.rs"

[dependencies]
libsql = "0.9.30"

tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
bincode = "1.3"
zstd = "0.13"
thiserror = "1.0"
tracing = "0.1"
ulid = "1.1"

[dev-dependencies]
tempfile = "3.8"
tokio-test = "0.4"
proptest = "1"
# §9's harness (D-055). `default-features = false` drops the plotting and HTML
# report stack, which is most of criterion's dependency tree and none of the
# measurement — the numbers come out on stdout and into `target/criterion` either
# way.
criterion = { version = "0.5", default-features = false, features = [
    "async_tokio",
    "cargo_bench_support",
] }

[features]
# `metrics` is on by default since 0.12.11 (W4.5, D-154). See its own paragraph
# below for the cost and for the argument, which is not that the cost is small.
default = ["metrics"]

# The generated-history test binaries. Off by default, as the second half of
# the R15 mitigation — the first half is `RUST_TEST_THREADS = "1"` in
# .cargo/config.toml. These do not follow it there: a property case needs its
# own database, and `doctrine_property_tests` still faults often enough
# serialised to be unusable as a gate on Windows. The rate is recorded in one
# place only, .cargo/config.toml — this comment carried a stale `~3/25` from
# 0.5.4 long after that file had moved on, and in 0.8.0 the gap between the two
# was briefly misread as a regression, so no figure is restated here. A suite
# that fails for reasons unrelated to the code under test trains people to
# ignore red, so the residue is quarantined rather than tolerated.
#
# D-148 sharpened *why* this set is the residue rather than bad luck: R15 counts
# cumulative `connect()`, and a database per generated case is the highest-volume
# shape in the repo. Serialising cannot help it, because serialising does not
# lower the total.
#
# Quarantined, not silenced. These are the tests that found D-035, they run as
# their own step, and `.proptest-regressions` replays every failure ever found
# before a single new case is generated.
#
#     cargo test --features property-tests
property-tests = []

# Write-actor latency counters (T1.4, D-079). **On by default since 0.12.11**
# (W4.5, D-154), having been off from 0.6.0 to 0.12.10.
#
# The argument is not that the cost is small. It is that a crate organised
# entirely around a latency bound must not ship a default build that cannot
# report whether the bound is met. `violations()` is the answer to the only
# question this design asks about itself, and through 0.12.10 the default build
# could not answer it. D-093 made exactly this argument for the Python wheel --
# where a caller cannot rebuild the extension -- and won it; the Rust default
# was left on the other side of the same reasoning for six releases.
#
# Turn it off with `--no-default-features` if the counters are genuinely not
# wanted. That path is still built and tested.
#
# CORRECTED 0.12.8 (W4.1, review §6.2). This paragraph used to read:
#
#   > with the feature off `HoldTimer` reads no clock and `ActorMetrics` is a
#   > ZST whose methods are empty, so the actor loop compiles to what it
#   > compiled to before
#
# The first half has been false since 0.12.0. W1 made the clock UNCONDITIONAL —
# `src/metrics.rs` says so at length — because `next_chunk_size` sizes each
# chunk from the previous chunk's measured hold, so the reading is a control
# input in every build rather than an observation in some of them. Left gated,
# a default build would have sized its chunks off `Duration::ZERO`, which reads
# as "comfortably under budget", and grown every chunk to the ceiling in
# exactly the builds nobody was measuring.
#
# What is actually gated, and what it actually costs:
#
#   always, feature or not   one `Instant::now()` pair per actor turn
#   gated behind `metrics`   the histogram — `record_hold` and the counters
#                            around it are no-ops without the feature
#
# So the honest statement of the default is: the *clock* is paid unconditionally
# and the *counters* are what the feature buys. `ActorMetrics` is still a ZST
# with empty methods when off, and `src/metrics.rs` explains why that is two
# impls of one type rather than `#[cfg]` inside the loop.
#
# This correction is deliberately kept rather than quietly rewritten, because
# the false half was the stated justification for the off-by-default decision
# and W4.5 revisits that decision. A justification that was wrong for six
# releases should be visible to whoever re-examines it.
#
#     cargo test --features metrics
metrics = []

[[test]]
name = "actor_metrics_tests"
required-features = ["metrics"]

# §8 item 2's evidence (D-166). Needs `metrics` for the same reason as the
# `*_diag` examples below: the question is what the *actor* held the write lock
# for, and the caller's wall time includes queueing. It also reads the turn
# count, to prove the hold it reports belongs to the call it made rather than to
# an `optimize()` some other path ran.
#
# This entry was missing when the example landed in 0.12.23, which broke
# `cargo test --no-default-features` — §8 item 6's configuration, already
# checked one release earlier and so not re-checked (D-169).
[[example]]
name = "analyze_hold"
required-features = ["metrics"]

# T1.1's evidence. Needs `metrics` because the question is what the *actor* held
# for, and wall time on the caller's side includes queueing.
[[example]]
name = "archive_window_diag"
required-features = ["metrics"]

# T1.3's evidence, for the same reason.
[[example]]
name = "bulk_atomic_diag"
required-features = ["metrics"]

# T3.4's evidence: the hold must not move while the total does.
[[example]]
name = "pipeline_diag"
required-features = ["metrics"]

# T1.2's evidence. The question is the longest single *turn*, which only the
# actor's own counters can answer.
[[example]]
name = "shadow_rebuild_diag"
required-features = ["metrics"]

[[test]]
name = "integrity_property_tests"
required-features = ["property-tests"]

[[test]]
name = "doctrine_property_tests"
required-features = ["property-tests"]

[[test]]
name = "graph_property_tests"
required-features = ["property-tests"]

# §9's budgets, measured (D-055). Not a CI gate — see the note at the top of the
# file for why absolute durations on arbitrary hardware are the wrong shape, and
# what criterion baselines do instead.
[[bench]]
name = "budgets"
harness = false