Run everything:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo test --workspace --locked
cargo test --workspace --all-features --locked # adds the process-kill fault tests
cargo bench --workspace --no-run --locked
cargo build --release --locked -p scribe-server-cli -p scribe-cli -p scribe-perf
cargo run --release --locked -p scribe-perf -- run --profile ci --root ./target/perf-sandbox --output ./target/perf/current.json
cargo run --release --locked -p scribe-perf -- compare ./tools/scribe-perf/baselines/macos-ci.json ./target/perf/current.json --policy ./tools/scribe-perf/policy/regression.tomlThe all-features configuration includes the process-kill tests plus an
ignored large-scale qualification. Certificate tests need an OpenSSL 3 executable
(SCRIBE_TEST_OPENSSL names it when it is not openssl on PATH).
Performance harness lifecycle
scribe-perf uses prebuilt executables; it never invokes Cargo or rustup while
running benchmarks. Use --server-bin and --client-bin for explicit executable
paths. Compiler metadata is captured when the harness is built.
--root must be a dedicated new or empty directory with an existing parent.
The harness removes it after success, failure, or a handled interrupt, after
stopping/reaping its children and joining workload threads. --output must be
outside that root and is the retained JSON report. A setup failure leaves an
existing report untouched. --keep-data explicitly retains the root, logs,
and workspaces for diagnosis; subsequent runs refuse a nonempty root, even
one previously marked by the harness. Choose another root or explicitly
remove the retained data yourself.
Each child receives an allowlisted environment with HOME, USERPROFILE, APPDATA, LOCALAPPDATA, XDG directories, and temporary paths under the sandbox. Client config and global-ignore paths, server data, runtime, and log paths are explicit. Inherited Scribe credentials/settings cannot redirect a run. Git metadata probes also use the isolated environment with optional locking and fsmonitor disabled. No process-wide environment mutation is needed.
Lifecycle and scenario progress goes to stderr, with elapsed time and terminal
colors (NO_COLOR, TERM=dumb, and redirection disable colors). The existing
stdout summary, JSON schema, metric names, and timed workload operations remain.
Phase logging is outside the per-operation latency loops. SIGINT/SIGTERM/SIGHUP
request a cooperative stop: an active command/storage operation finishes, then
cleanup runs. Normal server cleanup first requests graceful shutdown, falling
back to kill and wait after 60 seconds. SIGKILL and power loss cannot run cleanup.
Run lifecycle tests with cargo test --locked -p scribe-perf. Full CI-profile
qualification additionally exercises subprocess shutdown, restore verification,
and report retention. Platform coverage must be reported separately.
Lint policy
Every crate inherits [workspace.lints] from the root Cargo.toml. CI treats
warnings as errors and checks every target with every feature. clippy.toml
sets the minimum supported Rust version and permits test assertions to use
unwrap and expect.
The default Clippy set (including perf) is augmented with:
host_endian_bytes: serialization must choose endianness explicitly.cast_possible_truncation,cast_sign_loss,cast_possible_wrap: audit narrowing conversions, lengths, offsets, and signed values.unwrap_used,expect_used: audit production panic paths.print_stdout,print_stderr: libraries return results or emit tracing events.dbg_macro,todo,unimplemented: reject debugging and unfinished code.large_stack_arrays: review oversized stack buffers.
Unsafe code is denied workspace-wide; only scribe-platform explicitly allows
it for documented OS interfaces. unsafe_op_in_unsafe_fn remains denied.
Executable and benchmark entry points allow terminal output. Integration test
helpers and qualification workloads explicitly allow fail-fast assertions;
production invariant exceptions use local #[expect(..., reason = "...")]
so removing the triggering code also exposes a stale exception. Keep exceptions
at the smallest practical scope. Cargo's workspace lint inheritance is
all-or-nothing, so target-specific exceptions live in source attributes.
Infallible encoders check that counts fit their frozen fields rather than silently truncating them. Their callers remain responsible for validating application limits. These checks do not replace golden fixtures, recovery and fault-injection tests, or performance qualification.
What is covered
| area | where |
|---|---|
| golden bytes, pinned digests, LE/BE fixtures, length boundaries, truncation, trailing data, overflow counts, invalid UTF-8, unknown versions and flags | scribe-format unit tests; scribe-protocol-tcp frame and wire tests |
| chunk cut points pinned for profile 1; localized-edit reuse; size-hint independence | scribe-objects chunker tests |
| object store: loose and packed publish, reuse, digest mismatch leaves nothing, pack rollover, torn-tail truncation on reopen, corruption detected not repaired, locator rebuild | scribe-objects store tests |
| metadata: tree head/page snapshot remains consistent across concurrent acceptance; accept, reject, replay, intent mismatch, base mismatch, case collisions (existing and intra-batch), locks with generations, pagination, history, reopen; merge index at 100k and 1M paths (ignored, release mode) | scribe-metadata unit tests |
| platform: positional I/O, flush, preallocation, reflink or copy, free space | scribe-platform unit tests |
| ownership lock, byte budget, authorization contract | scribe-server unit tests |
| service end to end in process: two repositories with identical paths, chunk reuse, conflicts, restart, referential integrity, injected failure before the metadata commit, branches diverging and merging, snapshot interruption and concurrent retry, bounded merge delta pages | crates/scribe-server/tests/service_flow.rs |
| process kill at all six publication fault points with an independent oracle | crates/scribe-server-cli/tests/kill_publication.rs (feature fault-injection) |
| cross-adapter contract (in-process, TCP LE, TCP BE): replay identity, shared locks, malformed frames, obsolete protocol rejected, branch and merge workflows, lost replies, merges that read only affected paths and refuse dirty files | crates/scribe-client/tests/contract.rs |
| async admission: idle/partial hello and frames exceed worker count; stalled uploads retain control capacity; queries progress while mutations wait on a held publication gate; pipelined bytes survive read-ahead; nonreading zero-copy downloads stop at drain | crates/scribe-protocol-tcp/tests/concurrency.rs |
| auth async admission: incomplete TLS and SAU1 frames leave administration responsive; retries and reopening retain acknowledged changes | crates/scribe-auth/tests/tls_e2e.rs |
| safety regressions: interrupted planning, parent symlinks, timestamp-preserving edits, editor saves during transfer, file/directory collisions, symlink inserted during download | crates/scribe-client/tests/safety_regressions.rs |
read-only mode, hostile names, links, .scribe containment, long paths (Linux and Windows), sharing violations (Windows) | crates/scribe-client/tests/platform_behaviour.rs |
| CLI end to end through the client and server executables: repositories, workspaces, views, ignore precedence, forced add, chunk reuse, delete and revert, locks, history, export, restart, JSON logs | crates/scribe-cli/tests/cli_e2e.rs |
| client trust on first use: fingerprint approval, no token before trust, rotation refused | crates/scribe-cli/tests/trust.rs |
| verify, backup, corruption detection, restore with incarnation change, logical export and import, tampered export refused, schema 0 to 1 migration with interruption and rollback rules, doctor on healthy and corrupted roots and beside a live server, usage inventory, branch migration with merge history | crates/scribe-server-cli/tests/maintenance.rs |
| auth store durability, grants, tokens, namespaces, idempotent administration; TLS end to end with roles, ownership, sessions, revocation, outages | crates/scribe-auth/tests/ |
| auth executable: setup, administration, submit and sync through an authenticated server, backup; logging precedence and file retention | crates/scribe-auth-cli/tests/ |
| certificate provisioning: CA creation, issuing, renewal under the same CA, refusals that never overwrite material | crates/scribe-cert/tests/provision.rs, plus the certs subcommand of both service executables |
| terminal output: no escape codes when redirected, JSON errors stay parseable | terminal.rs in each executable crate |
| ignore semantics including malformed rules; scanner; workspace state; canonical paths; descriptor | scribe-workspace, scribe-core unit tests |
| logging precedence, conflicts, malformed filters, JSON escaping, disabled-level cost, stalled sink drops without blocking, unwritable directory | scribe-log |
Fault injection is compiled only with the fault-injection feature on the
server crates and armed by SCRIBE_FAULT; release builds have no such switch.
Where it runs
.github/workflows/ci.yml is manual (workflow_dispatch) only; it does not
run on push or pull request. When started, it runs format, clippy, both test
configurations, benchmark compilation, and the ci perf profile on
ubuntu-latest, windows-latest, and macos-latest, checks the dependency
graph of each executable, and cross-tests scribe-core and scribe-format
on emulated s390x for big-endian correctness. The perf step builds
scribe-server-cli and scribe-cli first; scribe-perf never compiles those
executables itself. Jobs and long steps have timeouts so a hung test cannot
run for the GitHub-hosted six-hour limit. Windows-only and Linux-only tests
are #[cfg]-gated and therefore run only on those runners; a green macOS run
says nothing about them. GitHub re-enables a disabled workflow if this file
is pushed, which is why the automatic triggers are omitted.
Tokio qualification on macOS (2026-09-07)
The server migration passed workspace formatting, Clippy with all targets and features, default and all-feature tests, and benchmark compilation on macOS. The CI performance profile passed its correctness gates. An additional release probe kept 1,024 connections alive per service: storage used 9 OS threads and about 36 MiB RSS; auth used 5 threads and about 26 MiB RSS with TLS. Ping and administration remained responsive, and both services drained in about 39 ms. These are measurements from this machine, not production capacity guarantees.
Performance qualification remains incomplete: the measured mixed-workload sync
p99 was 9,733 ms versus the stored baseline's 427 ms, exceeding the regression
budget. Read p99 was 0.264 ms versus 0.277 ms. Concurrent qualification work was
observed sharing the same machine and disk during follow-up diagnosis; repeat
on an otherwise idle machine before attributing or accepting the sync result.
The baseline and durability requirements were not relaxed. Local reports are
target/perf/current.json, target/tokio-perf-compare.log, and
target/tokio-connection-probe.json.
Linux and Windows execution remains a gap for this migration. Local cross-build
attempts lacked the native compiler/assembler needed by ring; they do not
substitute for platform CI.
Not covered by any automated test
- Power-loss ordering. Process kills do not prove it. A VM or device-level
power interruption with
doctorafterwards is required before claiming the OS-crash row of the failure model on real hardware. - The
million-pathsandscaleperf profiles: implemented, opt-in, run only on dedicated hardware. - Kernel-level syscall counts: the harness reports its own instrumented opens, renames, and flushes.
- Auth replication or failover: not implemented, so not tested.
Hidden password prompt (Unix terminal regression)
cargo build -p scribe-cli -p scribe-auth-cli --locked
python3 crates/scribe-platform/tests/password_prompt.pyThe stdlib-only PTY check runs the auth service and client, verifies hidden input with spaces and Unicode, confirms a saved session, and checks cancellation and terminal echo restoration. On macOS it also checks Secure Input during entry and restoration after success, wrong passwords, Ctrl+C, and EOF. A native guard test covers panic cleanup and preserving another Secure Input assertion. It runs on Unix; it does not claim Windows console coverage. The normal client tests also cover redirected input and password files.
Password pepper and authenticated demo
Auth tests cover salt uniqueness, required matching pepper on restart, rejection
of pepper files under auth data or .scribe, verification failure without the
pepper, password-reset replay, session invalidation, and secret exclusion from
database bytes and service logs. Wire fixtures pin the transient password-change
payload separately from persisted intent.
The scenario runner provisions passwords and logs users in over TLS before exercising saved sessions through collaboration and all four compression variants:
cargo build --release --locked -p scribe-auth-cli -p scribe-server-cli -p scribe-cli
node tools/scenario.js --report /tmp/scribe-results.json
node --test tools/scenario.test.js tools/scenarios/scenarios.test.jsChoose a new report filename for each run. See runner documentation.