Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .deslop.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@
# Docs: https://deslop.live/docs/for-ai/

[defaults]
# Exclude ONLY build/coverage artifacts — never source, and NEVER tests. Tests are
# first-class code here and stay in the duplication budget. node_modules/target/build
# are already default-excluded; dist + coverage are this repo's generated-output dirs.
# Exclude build/coverage artifacts and machine-GENERATED code — never authored
# source, and never authored tests. node_modules/target/build are already
# default-excluded; dist + coverage are this repo's generated-output dirs.
# The `generated_*/mod.rs` fixtures are codegen output of
# `packages/typediagram/src/converters/rust-tdbin.ts` (regenerated via
# `scripts/tdbin-regen-fixtures.mjs`, pinned by rust-tdbin-corpus.test.ts). Their
# structural repetition is emitted by the generator, not hand-written, so it is not
# authored duplication and does not belong in the budget — the fix for any real
# repetition there is in the generator, gated by the codegen pin test.
exclude = [
"**/coverage/**",
"**/dist/**",
"**/tests/generated_*/mod.rs",
]

[threshold]
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ jobs:
- name: Install dependencies
run: npm ci

# [CI-RUST-TOOLCHAIN] The Makefile wires the Rust `crates/` workspace into
# make test/lint/fmt (cargo test --workspace, cargo clippy -D warnings,
# cargo fmt --check). Both CI scopes reach cargo: full scope via `make ci`,
# web scope via `make lint` + `make _fmt_check`. Install/pin stable with the
# clippy + rustfmt components explicitly rather than trusting the runner
# image's implicit default toolchain (which can drift or lack components).
- name: Rust toolchain (stable + clippy + rustfmt)
run: |
rustup toolchain install stable --profile minimal --component clippy,rustfmt
rustup default stable
cargo --version
cargo clippy --version
cargo fmt --version

# [SWR-SEC-VULN-GATE] fail at high for production dependencies. Cheap;
# runs in both scopes.
- name: Dependency vulnerability gate
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ dist-test-pdfs/
packages/web/test-results/

.deslop-cache/
# Deslop report artifacts (generated by `deslop .` in the CI gate, post-`make ci`)
deslop-report.json
deslop-report.html
deslop-report.txt
deslop-*.log

.ghissues/

Expand Down
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"titleBar.activeForeground": "#0b1326",
"titleBar.inactiveBackground": "#6ab3dd",
"titleBar.inactiveForeground": "#0b1326cc"
}
},
"deslop.topOffenders.groupBy": "type"
}
20 changes: 19 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# Cross-platform: Linux, macOS, Windows (via GNU Make)
# =============================================================================

.PHONY: build test lint fmt clean ci setup rebuild-install-vsix dev dev-web clean-start test-playwright
.PHONY: build test lint fmt clean ci setup rebuild-install-vsix dev dev-web clean-start test-playwright bench test-tdbin

# ---------------------------------------------------------------------------
# OS Detection
Expand Down Expand Up @@ -143,6 +143,24 @@ _bundle_size:
# Repo-Specific Targets (not part of the 7 standard targets)
# =============================================================================

## test-tdbin: Run ONLY the tdbin Rust crate tests (cargo test -p tdbin), fail-fast.
## `make test` and `make ci` already run these as part of the whole
## workspace (cargo test --workspace); this is the fast, focused loop
## for iterating on the crate alone.
test-tdbin:
@echo "==> tdbin crate tests (cargo test -p tdbin)..."
cargo test -p tdbin

## bench: TDBIN vs Protobuf benchmark. Runs tests and the full Criterion matrix,
## then generates Markdown and raw JSON reports from the measured output.
bench:
@echo "==> TDBIN crate tests (round-trip + deterministic size gate)..."
cargo test -p tdbin
@echo "==> TDBIN vs Protobuf Criterion benchmark matrix..."
cargo bench -p tdbin --bench gate -- --noplot
@echo "==> Generating data-derived TDBIN benchmark report..."
node scripts/tdbin-bench-report.mjs

## test-playwright: Run Playwright end-to-end tests only (packages/web), both
## desktop and mobile viewports. Does NOT run vitest or enforce
## coverage threshold — for that, use `make test`. Useful for
Expand Down
14 changes: 7 additions & 7 deletions coverage-thresholds.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"default_threshold": 90,
"projects": {
"packages/typediagram": {
"statements": 96.12,
"statements": 96.98,
"branches": 91.05,
"functions": 98.68,
"lines": 96.01
"functions": 98.7,
"lines": 96.92
},
"packages/cli": {
"statements": 99,
Expand All @@ -16,10 +16,10 @@
"lines": 99
},
"packages/web": {
"statements": 97.65996649916248,
"branches": 95.86,
"functions": 97.93617021276596,
"lines": 97.63481228668942
"statements": 97.7878787878788,
"branches": 96.46835443037975,
"functions": 98.05660377358491,
"lines": 97.7012987012987
},
"packages/vscode": {
"statements": 99,
Expand Down
83 changes: 66 additions & 17 deletions crates/tdbin/benches/gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ mod bench_corpus;
use std::hint::black_box;
use std::time::Duration;

use bench_corpus::corpus;
use bench_corpus::{batches, corpus, documents, events};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use prost::Message;
use tdbin::{pack, Struct, TdBin};
use tdbin::{Struct, TdBin};

/// Return a TDBIN encoded message or terminate the benchmark process.
fn td_bytes<T: Struct>(value: &T) -> Vec<u8> {
Expand All @@ -27,12 +27,17 @@ fn td_bytes<T: Struct>(value: &T) -> Vec<u8> {
}
}

/// Return a packed TDBIN body or terminate the benchmark process.
fn packed_bytes(body: &[u8]) -> Vec<u8> {
match pack::encode(body) {
/// Return a framed TDBIN message or terminate the benchmark process.
fn td_framed_bytes<T: Struct>(value: &T, packed: bool) -> Vec<u8> {
let encoded = if packed {
value.to_packed_framed_bytes(None)
} else {
value.to_framed_bytes(None)
};
match encoded {
Ok(bytes) => bytes,
Err(error) => {
eprintln!("tdbin pack failed before benchmark: {error:?}");
eprintln!("tdbin framed encode failed before benchmark: {error:?}");
std::process::exit(1);
}
}
Expand All @@ -57,12 +62,14 @@ where
P: Message + Default,
{
let bare = td_bytes(td);
let packed = packed_bytes(&bare);
let framed = td_framed_bytes(td, false);
let packed_framed = td_framed_bytes(td, true);
let protobuf = pb_bytes(pb);
println!(
"[{label}] sizes: tdbin_bare={} tdbin_packed={} protobuf={}",
"[{label}] sizes: tdbin_bare={} tdbin_framed={} tdbin_packed_framed={} protobuf={}",
bare.len(),
packed.len(),
framed.len(),
packed_framed.len(),
protobuf.len()
);

Expand All @@ -74,6 +81,20 @@ where
b.iter(|| black_box(value).to_bytes());
},
);
let _ = group.bench_with_input(
BenchmarkId::new("tdbin_encode_framed", label),
td,
|b, value| {
b.iter(|| black_box(value).to_framed_bytes(None));
},
);
let _ = group.bench_with_input(
BenchmarkId::new("tdbin_encode_packed_framed", label),
td,
|b, value| {
b.iter(|| black_box(value).to_packed_framed_bytes(None));
},
);
let _ = group.bench_with_input(
BenchmarkId::new("protobuf_encode", label),
pb,
Expand All @@ -92,13 +113,17 @@ where
},
);
let _ = group.bench_with_input(
BenchmarkId::new("tdbin_decode_packed_framed_body", label),
&packed,
BenchmarkId::new("tdbin_decode_framed", label),
&framed,
|b, bytes| {
b.iter(|| {
pack::decode(black_box(bytes.as_slice()))
.and_then(|body| T::from_bytes(black_box(body.as_slice())))
});
b.iter(|| T::from_framed_bytes(black_box(bytes.as_slice())));
},
);
let _ = group.bench_with_input(
BenchmarkId::new("tdbin_decode_packed_framed", label),
&packed_framed,
|b, bytes| {
b.iter(|| T::from_framed_bytes(black_box(bytes.as_slice())));
},
);
let _ = group.bench_with_input(
Expand Down Expand Up @@ -131,13 +156,37 @@ fn criterion_benchmark(c: &mut Criterion) {
&corpus::td_metric_batch(),
&corpus::pb_metric_batch(),
);
bench_fixture(
c,
"person_batch",
&batches::td_person_batch(),
&batches::pb_person_batch(),
);
bench_fixture(
c,
"contact_batch",
&batches::td_contact_batch(),
&batches::pb_contact_batch(),
);
bench_fixture(
c,
"diagram_document",
&documents::td_document(),
&documents::pb_document(),
);
bench_fixture(
c,
"event_batch",
&events::td_event_batch(),
&events::pb_event_batch(),
);
}

criterion_group! {
name = benches;
config = Criterion::default()
.sample_size(20)
.measurement_time(Duration::from_secs(3));
.sample_size(50)
.measurement_time(Duration::from_secs(5));
targets = criterion_benchmark
}
criterion_main!(benches);
Loading
Loading