This is the canonical entry point for validating timeless-libsql. Run all
commands from the repository root unless a section says otherwise. The
query release report records the most recent
complete result; this file defines how to reproduce it.
- A current stable Rust toolchain and Cargo. The Cargo manifests do not yet declare an MSRV, so do not infer a supported minimum compiler from an old benchmark or badge; the most recent complete local gates used Rust 1.97.
sqlite33.34.1 or newer with loadable extensions enabled.- A C compiler and CMake for bundled SQLite and compression dependencies.
- Docker only for refreshing the pinned Prometheus, VictoriaMetrics, and VictoriaLogs oracles.
- Linux for the complete signal-process fault and RSS-watermark gate. Core, extension, SQL, and most API tests also run on macOS.
Test and benchmark scratch data is temporary by default. Rust tempfile
owners and shell trap handlers remove databases, WAL/SHM files, and server
logs on both success and ordinary failure. This matters on systems where
/tmp is tmpfs: a leaked benchmark database consumes memory or swap, not just
disk space.
The query evidence runner also removes failed captures by default. Pass
--keep-failed only when you need its diagnostic database and server logs;
the error prints their retained path. The production gate removes its
generated scratch tree, but an explicit --data-dir NEW_DIRECTORY is
operator-owned and retained. General benchmarks remove their databases; pass
--keep-dir NEW_DIRECTORY to bench, bench-logs, or bench-traces only
when you intend to inspect them afterward. Prefer a disk-backed path outside
/tmp for retained or large runs.
Result files named by --output and database paths explicitly supplied by a
caller are also caller-owned. Remove them when their evidence is no longer
needed. A successful test must never silently retain an internally selected
scratch path.
On macOS, /usr/bin/sqlite3 disables extension loading. Install SQLite with
Homebrew and put its bin directory first in PATH before running the shell
suites.
The extension, API, query-contract, SQL-equivalence, fixture, crash-workload, and persistent-host test logic is Rust. Shell files only orchestrate the SQLite CLI and Rust binaries.
The following older utilities are still Python and are being replaced in bounded sessions. Their replacement commands and this inventory must change in the same commit:
servers/crates/timeless-metrics-api/bench_shell.py;servers/crates/timeless-traces-api/bench/*.py(7 files);tools/bench/session6_log_compaction.py;tools/demogen/screencast.py; andtools/demogen/schema_screencast.py.
Do not describe the complete repository as Python-free until
git ls-files '*.py' returns no paths and the final command below passes:
test -z "$(git ls-files '*.py')"cargo build --release -p timeless-ext --locked
timeless_smoke_dir="$(mktemp -d)"
trap 'rm -rf -- "$timeless_smoke_dir"' EXIT
sqlite3 "$timeless_smoke_dir/timeless-smoke.db" \
".load target/release/libtimeless_ext" \
"CREATE VIRTUAL TABLE m USING timeless_metrics;
INSERT INTO m(name, ts, value) VALUES ('cpu', 1, 42.5);
INSERT INTO m(m) VALUES ('flush');
SELECT * FROM m;"The final command prints cpu|1|42.5|{}.
The order matters. Build the current extension before running API contracts
so a stale target/debug or target/release library cannot masquerade as the
current source.
cargo fmt --all only reaches the workspace it is pointed at. The root
workspace excludes servers/, and every tools/* crate is a DETACHED
workspace, so the root invocation checks roughly a fifth of the tree. Check
each manifest — servers/ and four tool workspaces had all drifted before
the gate did this (issue #45):
for manifest in Cargo.toml servers/Cargo.toml \
tools/query-harness/Cargo.toml tools/bench/Cargo.toml \
tools/demogen/Cargo.toml tools/release-tool/Cargo.toml \
tools/libsql-check/Cargo.toml tools/clp-vet/Cargo.toml
do
cargo fmt --all --manifest-path "$manifest" -- --check || exit
donecargo build --locked
cargo test --workspace --locked
cargo clippy --workspace --all-targets --locked -- -D warnings
RUSTDOCFLAGS='-D warnings' \
cargo doc --workspace --no-deps --lockedDo not run cargo test --workspace --all-targets at the repository root.
That option overrides the standalone dbhealth-ext test-harness boundary and
tries to link two loadable extensions that intentionally export the same
SQLite entry-point name. cargo test --workspace is the supported root test;
dbhealth is validated separately below. Root Clippy may use --all-targets
because it checks rather than links the conflicting test binary.
What lives where:
crates/timeless-core/tests/roundtrip.rs— write → query-before-flush → flush → aggregate → shutdown → cold-recovery lifecyclecrates/timeless-core/tests/compression_honesty.rs— every point of 1M verified bit-exact after recovery; bytes measured from disk, not bookkeepingcrates/timeless-core/tests/store_seam.rs— FsStore/ChunkStore seam + recoverycrates/timeless-core/tests/txn_journal.rs— rollback of buffers, intra-txn flushes, optimize-in-txncrates/timeless-core/tests/dup_min_ts.rs— the (series,min_ts) shadowing regression (found by the oracle, fixed here and upstream)- unit tests inside
src/blocks/andsrc/spans/— codecs, partitioned flush, term pruning read-count proofs, projection/late-materialization, and merge caps
Build identities are part of the test contract:
build_commit="$(git rev-parse HEAD)"
TIMELESS_BUILD_COMMIT="$build_commit" \
cargo build --release -p timeless-ext --locked
TIMELESS_BUILD_COMMIT="$build_commit" \
cargo build --release --workspace \
--manifest-path servers/Cargo.toml --locked
cargo fmt --manifest-path servers/Cargo.toml --all -- --check
TIMELESS_EXT_PATH="$PWD/target/release/libtimeless_ext.so" \
TIMELESS_EXT_TEST_PATH="$PWD/target/release/libtimeless_ext.so" \
cargo test --workspace --manifest-path servers/Cargo.toml \
--locked -- --include-ignored
cargo clippy --workspace --all-targets \
--manifest-path servers/Cargo.toml --locked -- -D warnings
RUSTDOCFLAGS='-D warnings' \
cargo doc --workspace --manifest-path servers/Cargo.toml \
--no-deps --lockedUse libtimeless_ext.dylib instead of .so on macOS. The
--include-ignored run is intentional: it enables the metrics and logs
contracts that require the real release extension. It also covers trace,
OTLP, Jaeger, rich-field fidelity, shutdown, backup, queue, cancellation, and
8,192-span batching behavior.
cargo test --manifest-path tools/query-harness/Cargo.toml --locked
cargo clippy --manifest-path tools/query-harness/Cargo.toml \
--all-targets --locked -- -D warnings
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- contracts
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle validate
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- sql \
--extension "$PWD/target/release/libtimeless_ext.so"These commands validate matrix IDs and states, shipped-row test references, documentation links and inventories, immutable oracle pins, release evidence, and all public SQL equivalents. The SQL command currently executes 135 recipes and 173 statements through the real extension.
tests/cli.sh
tests/dbhealth.sh
for section in r1 r2 r3 r4 r8 logs-rich; do
TIMELESS_EXT="$PWD/target/release/libtimeless_ext.so" \
tests/correctness.sh "$section" || exit
donetests/cli.sh is the comprehensive 45-section direct-SQL gate. It includes
150,000 randomized operations, five random-timing SIGKILL recoveries,
transaction/savepoint rollback, cold reopen, storage/index consistency, all
three signals, public stats and query surfaces, and the SQL cookbook. Run
tests/crash.sh target/release/libtimeless_ext.so only when you want the
five-round crash subset independently.
In those five rounds, the Rust query harness owns an unreaped sqlite3 child
running a long ingest with periodic flushes and watermark logging, sends
SIGKILL to that exact child at a random moment, reaps it, reopens, then
asserts PRAGMA integrity_check is clean, all flushed watermarks are present,
and no _terms/_trace_blocks/_duration_bounds/_attribute_blooms row
dangles. Every current trace block must also have valid duration bounds and
exact configured-attribute results. The durability contract being proven is:
flushed = durable, buffered = lost, never corrupt.
tests/dbhealth.sh builds and loads libdbhealth_ext separately. Never build
timeless-ext and dbhealth-ext with two -p arguments in one Cargo
invocation; their feature variants are deliberately separate products.
cargo run --locked -p timeless-ext \
--no-default-features --features embedded --example embedded
cargo run --manifest-path tools/libsql-check/Cargo.toml --locked -- \
target/release/libtimeless_ext.soThe first command statically registers the production telemetry modules in a Rust host. The second uses libSQL 0.9.30 directly, loads the release extension on multiple connections, verifies all three signals, closes the database, and repeats exact reads after reopen.
Normal development validates checked-in fixtures without network access via
oracle validate. Refreshing the actual upstream evidence is explicit,
requires Docker and network access, and uses immutable image digests:
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle probe
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle prometheus-smoke
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle prometheus-api
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle victoria-metrics-api
cargo run --quiet --manifest-path tools/query-harness/Cargo.toml \
--locked -- oracle victoria-logs-apiThese commands own and remove uniquely named temporary containers. They may
refresh checked fixture files, so review git diff afterward. See
the oracle contract before changing a pin.
Evidence capture requires a clean worktree and exact matching extension and server build identities:
build_commit="$(git rev-parse HEAD)"
TIMELESS_BUILD_COMMIT="$build_commit" \
cargo build --release -p timeless-ext --locked
TIMELESS_BUILD_COMMIT="$build_commit" \
cargo build --release --manifest-path servers/Cargo.toml \
-p timeless-metrics-api -p timeless-logs-api --locked
cargo run --release --manifest-path tools/query-harness/Cargo.toml \
--locked -- evidence \
--output "/tmp/timeless-query-evidence.json"The JSON records durable completed work, p50/p95/p99, cardinality, public
storage work, response and extension bytes, cancellation behavior, physical
storage, and RSS HWM. Do not commit a new evidence artifact without updating
the owning matrix rows and findings in the same session.
Use --keep-failed only for a failure you are actively diagnosing.
The Rust query harness owns the production process, fault, and soak gate:
cargo run --release --manifest-path tools/query-harness/Cargo.toml \
--locked -- production \
--mode short \
--output /tmp/timeless-production-short.json
cargo run --release --manifest-path tools/query-harness/Cargo.toml \
--locked -- production \
--mode release \
--output /tmp/timeless-production-two-hour.jsonShort mode defaults to 120 seconds. Release mode requires at least two hours
per concurrently running signal. Both exercise durable writes and queries,
backups, cancellation/disconnect storms, startup descriptor and disk faults,
graceful and abnormal restarts, storage/WAL/resource watermarks, and final
durability barriers. The runner fails the command when the report verdict is
not passed and preserves a caller-supplied --data-dir for diagnosis.
The detached Rust release tool builds and validates one native candidate:
cargo run --release --manifest-path tools/release-tool/Cargo.toml \
--locked -- \
--target x86_64-unknown-linux-gnu \
--output /tmp/timeless-distThis is a local candidate build, not a tag or publication. The command checks the native target, locked builds, exact binary/extension identity, deterministic archive metadata, inner and outer checksums, manifest, SPDX SBOM, license notices, and an isolated install/remove drill with data and configuration sentinels. See ARTIFACTS.md.
The maintained general extension benchmarks already live in the detached
Rust tools/bench crate:
cargo run --release --manifest-path tools/bench/Cargo.toml \
--bin bench -- target/release/libtimeless_ext.so
cargo run --release --manifest-path tools/bench/Cargo.toml \
--bin bench-logs -- target/release/libtimeless_ext.so
cargo run --release --manifest-path tools/bench/Cargo.toml \
--bin bench-traces -- target/release/libtimeless_ext.so
cargo run --release --manifest-path tools/bench/Cargo.toml \
--bin bench-codec
cargo run --release --manifest-path tools/bench/Cargo.toml \
--bin query-read -- target/release/libtimeless_ext.soThe Rust query harness can measure a copied pre-extrema trace database before and after public optimize backfill. It deliberately mutates the supplied copy; never point it at the only copy of a database:
cp --reflink=auto /path/to/legacy-traces.db /path/to/scratch-traces.db
cargo run --release --manifest-path tools/query-harness/Cargo.toml --locked -- \
gate trace-duration-evidence \
--extension target/release/libtimeless_ext.so \
--database /path/to/scratch-traces.db \
--table traces --service payments \
--minimum-duration-ns 9000000000000000000 \
--iterations 50 --warmup 5 --walChoose a service present in the fixture and a duration above its maximum. The command fails if the legacy phase does not actually decode candidate blocks, if the query returns a row, if optimize leaves an unknown block, or if the post-backfill phase considers/decodes a persisted block. Its JSON reports p50/p95/p99, cardinality, candidate/payload/decoded work, logical and physical storage, optimize backfill time/bytes/entries, and process RSS HWM. This is a same-fixture storage optimization measurement, not a Victoria/Jaeger competitive benchmark.
The Rust query harness can create a temporary deterministic rich-span database,
start the release trace server, measure broad Jaeger reads, stop it cleanly,
and then measure timeless_trace_buckets in a fresh direct-SQL process:
cargo build --release
cargo build --release --manifest-path servers/Cargo.toml --bin timeless-traces-api
cargo build --release --manifest-path tools/query-harness/Cargo.toml
tools/query-harness/target/release/timeless-query-harness trace-baseline \
--output docs/evidence/local_trace_query_baseline.jsonSession 7's opt-in trace-attribute A/B uses separate fresh processes at the
same clean commit. Omit the flag for the public JSON1/write-path control and
include it for the two configured /count and /bool fields:
tools/query-harness/target/release/timeless-query-harness trace-baseline \
--output docs/evidence/local_trace_attributes_unindexed.json
tools/query-harness/target/release/timeless-query-harness trace-baseline \
--attribute-indexes \
--output docs/evidence/local_trace_attributes_indexed.jsonBoth reports include insert/optimize time, file/WAL state before optimize and checkpoint, builder/query HWM, and JSON1 attribute controls. The indexed run also measures the hidden-filter candidate. Compare equal commits and fixtures; the command rejects dirty tracked source or stale extension/server identities.
Run from a clean tracked commit: the command rejects stale extension or server
build identities. The default workload is 16 public 8,192-span batches, 20
measured iterations, and three warmups. It cleans its temporary database and
server log on both success and ordinary failure. Pass --retain-on-failure
only when you deliberately need a failed fixture for diagnosis; remove it
afterward. The output records latency tails, cardinality/result bytes,
extension work, durable fixture construction, storage/WAL/freelist state, and
fresh-server RSS/HWM for each Jaeger shape, and isolated direct-SQL RSS HWM.
It also profiles service, operation-name, kind, and status postings over one-
and four-time-box windows and fails if any query reads a time-disjoint block.
The direct-SQL child additionally compares the readable two-consumer trace
summary CTE with the published single-scan conditional-aggregate recipe,
asserting exact retained-row cardinality, result bytes, public extension work,
and process RSS HWM.
Datasets are generated by a deterministic PRNG (src/datasets.rs) — same
data every run, on every machine, so numbers are comparable across hosts.
The general signal benchmarks clean their scratch databases by default. Add
--keep-dir /disk/backed/new-directory after the extension path when an
inspection copy is genuinely required.
Several historical API and maintenance benchmark drivers are still Python; they are named in the migration inventory above. Their Rust ports must retain the same fixture, completed-work barrier, percentile method, storage counters, and RSS accounting before the Python originals are removed.
For comparable numbers:
- use release builds;
- run twice and report the second run;
- close connections before reporting main-file size;
- separate admission from flush/optimize durability time;
- report logical and physical storage plus WAL/SHM; and
- identify the exact commit, host, fixture, and result cardinality.
This repository has no scheduled, branch-push, or pull-request test trigger.
Manual workflows run only when explicitly dispatched; release builds run only
for v* tags. This runbook is authoritative for local execution. Adding or
changing an automatic trigger requires a separate explicit owner request.