Skip to content

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:

CrateRole
benchy-mesh-coreVersioned checks and policy decisions through validate_bytes and the context-aware API
benchy-mesh-formatsContent-based format detection and bounded STL / OBJ / GLB / glTF / 3MF parsing
benchy-mesh-geomGeometry and evidence-backed topology analysis
benchy-mesh-printPrerequisite-based print-readiness assessment without numeric scores
benchy-mesh-cliThe benchy-mesh validate --json binary
benchy-mesh-wasmWASM bindings for Cloudflare Workers and browsers
benchy-mesh-graderThe 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.

MeshValidationResult (abridged)
{
  "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:

AxisWeightPass condition
Correctness60Format, verdict, error codes, and warning codes match the manifest
Robustness20Clean exits only — no panics, signals, timeouts, or non-JSON output
Determinism10Both runs produce identical JSON, on a fixture that also passed correctness
No-hang10Neither run hit the 10-second kill
shell
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 --all

Run it yourself

shell
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.stl

Exit 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.