benchy-mesh: the mesh validation engine
Six Rust crates for bounded STL, OBJ, GLB/glTF, and 3MF inspection, a versioned decision contract, and a defensive grading corpus.
The crates
benchy-mesh (v0.1.0, dual-licensed MIT OR Apache-2.0) is a seven-member Rust workspace — six crates plus the grading harness:
| Crate | Role |
|---|---|
benchy-mesh-core | Versioned checks and policy decisions through validate_bytes and the context-aware API |
benchy-mesh-formats | Content-based format detection and bounded STL / OBJ / GLB / glTF / 3MF parsing |
benchy-mesh-geom | Geometry and evidence-backed topology analysis |
benchy-mesh-print | Prerequisite-based print-readiness assessment without numeric scores |
benchy-mesh-cli | The benchy-mesh validate --json binary |
benchy-mesh-wasm | WASM bindings for Cloudflare Workers and browsers |
benchy-mesh-grader | The grading harness — scores implementations over a defensive fixture corpus |
One engine, two execution substrates: the same crates run natively in the CLI and compiled to WASM inside Cloudflare Workers, producing identical reports in both.
Hostile input by design
Uploaded bytes are untrusted input. Filename extensions and declared media types are hints, not proof; supported formats are detected from content, then parsed within explicit limits for bytes, counts, allocations, strings, textures, archive entries, and expansion. Defenses include:
- Truncation and lying headers — binary STLs whose declared triangle count doesn't match the body, GLBs whose chunk lengths overrun the file, header-only files.
- Poisoned geometry — NaN and infinite vertices (in binary STL, ASCII STL, and OBJ) are reported without contaminating bounds or geometry calculations.
- Archive attacks in 3MF — zip bombs are caught by compression-ratio and expansion limits, invalid internal paths are rejected, entry counts are capped, and the required OPC relationship identifies the model part.
- Resource exhaustion — declared-mesh floods (a GLB claiming more meshes than the 10,000 ceiling) and limit overruns fail fast with typed errors.
Failures are never panics: you get stable, typed issue codes like BINARY_STL_LENGTH_MISMATCH, INVALID_ARCHIVE_PATH, or ARCHIVE_COMPRESSION_RATIO_LIMIT_EXCEEDED in a machine-readable report. Every hostile input that has ever broken a candidate implementation graduates into both the grading corpus and a permanent regression suite.
The JSON contract
Results use a camelCase contract with schemaVersion: 2 and the current policy version. The schema identifies field meanings; the policy version changes whenever a check, threshold, issue, coverage rule, parser decision, or verdict can change for the same input. Clients branch on stable codes and enums, never English messages.
{
"schemaVersion": 2,
"policyVersion": "2026.08.12.1",
"validationProfile": "marketplace_publish",
"executionMode": "server_enforced",
"identification": {
"detectedFormat": "stl",
"confidence": "high",
"evidence": ["content_format_signal", "bounded_parser_completed"]
},
"decision": { "verdict": "allow", "reasonCodes": [] },
"checks": [
{ "id": "format.structure", "status": "passed", "coverage": "full", "summary": "…" }
],
"issues": [],
"printReadiness": {
"assessment": "ready",
"checks": [ … ],
"notes": [],
"limitations": []
},
"ok": true,
"format": "stl",
"sha256": "…"
}The grading harness
The repo ships the exam alongside the validator. The grader builds named candidate implementations of the formats stack (including model-authored ones) into the real CLI and scores them over a committed corpus of 43 fixtures — 9 valid and 34 hostile, every one generated rather than hand-edited, and all of them tiny. Each fixture is validated twice under a hard 10-second kill, and four weighted axes make up the score:
| Axis | Weight | Pass condition |
|---|---|---|
| Correctness | 60 | Format, verdict, error codes, and warning codes match the manifest |
| Robustness | 20 | Clean exits only — no panics, signals, timeouts, or non-JSON output |
| Determinism | 10 | Both runs produce identical JSON, on a fixture that also passed correctness |
| No-hang | 10 | Neither run hit the 10-second kill |
cargo run -p benchy-mesh-grader -- gen-fixtures --check
cargo run -p benchy-mesh-grader -- run --candidate baseline
cargo run -p benchy-mesh-grader -- run --allRun it yourself
git clone https://github.com/benchystudio/benchy-mesh
cd benchy-mesh
cargo test -p benchy-mesh-core
cargo run -p benchy-mesh-cli -- validate --json path/to/model.stlExit code 0 means the selected CLI policy allowed the file. Exit code 2 means it emitted a valid result with a non-allowing verdict. Exit code 1 means the command itself failed — a usage error is a command failure, not a verdict. The default CLI context is structural and standalone. Benchy's publishing decision is produced separately with the marketplace profile in server-enforced mode; a local structural result cannot grant eligibility.
Use ← and → to move between pages.