delaunay 0.8.0

D-dimensional Delaunay triangulations and convex hulls in Rust, with exact predicates, deterministic degeneracy handling, explicit topology validation, and bistellar flips for finite point sets.
Documentation
# Diagnostics

This document covers the crate's diagnostic surfaces: structured validation
reports, construction and repair telemetry, opt-in debug helpers, and runtime
debug switches.

Keep this separate from [`property_testing_summary.md`](property_testing_summary.md).
Property testing explains which randomized invariants the repository checks;
diagnostics explains what evidence to collect when a construction, validation,
repair, or test failure needs investigation.

## Diagnostic Surfaces

The crate exposes two kinds of diagnostics.

Always available:

- `validate()` and `validation_report()` for cumulative Levels 1-5 validation.
- Typed construction, insertion, validation, topology, and repair errors.
- Repair diagnostics attached to non-convergence and repair-neighbor failures.
- Construction statistics and telemetry through
  `delaunay::prelude::diagnostics`.

Feature-gated with `diagnostics`:

- `delaunay::prelude::diagnostics::delaunay_violation_report`.
- `DelaunayViolationReport` and `DelaunayViolationDetail`.
- `debug_print_first_delaunay_violation`.
- `verify_conflict_region_completeness`.
- Extra test/debug tracing in selected integration tests and debug harnesses.

The `diagnostics` feature does not change triangulation construction,
validation, repair, or query semantics. It only compiles in additional
inspection tools.

Examples that derive `thiserror::Error` assume the example crate includes
`thiserror`; run `cargo add thiserror` alongside `delaunay` when copying those
snippets into an application.

## Commands

Use the repository recipe for the standard diagnostics harness:

```bash
just test-diagnostics
```

Run the diagnostics example:

```bash
cargo run --release --features diagnostics --example diagnostics
```

Run a diagnostics-enabled test directly:

```bash
cargo test --test circumsphere_debug_tools --features diagnostics -- --nocapture
```

In downstream application code:

```toml
[dependencies]
delaunay = { version = "0.8.0", features = ["diagnostics"] }
```

## Validation Reports

For most validation work, start with the always-available APIs:

```rust
use delaunay::prelude::construction::{DelaunayResult, DelaunayTriangulationBuilder, vertex};

fn main() -> DelaunayResult<()> {
    let vertices = vec![
        vertex![0.0, 0.0, 0.0]?,
        vertex![1.0, 0.0, 0.0]?,
        vertex![0.0, 1.0, 0.0]?,
        vertex![0.0, 0.0, 1.0]?,
    ];
    let dt = DelaunayTriangulationBuilder::new(&vertices).build()?;

    assert!(dt.validate().is_ok());
    let report = dt.validation_report();
    assert!(report.is_ok());
    Ok(())
}
```

Use `validate()` when a cumulative pass/fail result is enough. Use
`validation_report()` when you need all violated invariants across the stack
instead of the first error.

Layer-local diagnostics follow a standard naming pattern:

- `is_valid()` for unambiguous element/TDS owners, and `is_valid_*` for
  higher-level owners with multiple validation layers.
- `*_diagnostic`: first actionable repair/retry diagnostic for that layer.
- `*_report`: all checkable layer-local failures.

Orientation failures retain their owning layer. Level 2 stored-ordering
incoherence is reported as `TdsError::OrientationViolation`; Level 3 intrinsic
orientability is queried with `Triangulation::orientation_witness()` and reports
`TriangulationValidationError::NonOrientable` for a contradictory 2D/3D parity
system. Level 4 positive geometric orientation remains part of the realization
diagnostic/report surface below.

For Level 4 realization failures specifically, use
`dt.as_triangulation().realization_diagnostic()` for the first repair-oriented
failure and `dt.as_triangulation().realization_report()` for all checkable
realization failures. These report invalid simplices or simplex pairs with
simplex keys, simplex UUIDs, offending vertex keys, and offending vertex UUIDs.
That key-oriented payload is the intended starting point for explicit rollback,
vertex deletion, or future repair workflows; the report itself is pure and does
not mutate the triangulation.

## Construction Telemetry

Construction statistics expose aggregate insertion and repair behavior for batch
construction workflows. Telemetry is intentionally coarse enough to be useful in
release-mode characterization without turning every insertion into a trace.

Useful fields include:

- skipped duplicate and degeneracy counts
- representative skipped-vertex samples
- insertion, locate, conflict-region, and cavity counters
- local repair timings and slow repair samples
- final topology and Delaunay validation timings

For large-scale reproducible diagnostics, prefer the documented debug recipes in
[`benches/README.md`](../benches/README.md) and
[`docs/dev/debug_env_vars.md`](dev/debug_env_vars.md).

## Delaunay Violation Reports

Use `delaunay_violation_report` when you want key-based data about Level 5
empty-circumsphere violations:

```rust
use delaunay::prelude::diagnostics::delaunay_violation_report;
use delaunay::prelude::construction::{
    DelaunayResult, DelaunayTriangulationBuilder, vertex,
};

fn main() -> DelaunayResult<()> {
    let vertices = vec![
        vertex![0.0, 0.0, 0.0]?,
        vertex![1.0, 0.0, 0.0]?,
        vertex![0.0, 1.0, 0.0]?,
        vertex![0.0, 0.0, 1.0]?,
    ];
    let dt = DelaunayTriangulationBuilder::new(&vertices).build()?;

    let report = dt.delaunay_violation_report(None)?;
    assert!(report.is_valid());
    Ok(())
}
```

Reports store `SimplexKey` and `VertexKey` values rather than copying every
coordinate. This keeps diagnostics compact and lets callers recover coordinates,
UUIDs, or attached data from the original triangulation through key-based
queries such as `dt.simplex(key)`, `dt.vertex(key)`, and
`dt.simplex_vertices(key)`.

Useful fields:

- `number_of_vertices`, `number_of_simplices`: size of the inspected TDS.
- `checked_simplices`: number of requested simplices considered by the scan.
- `violating_simplices`: all simplices that violate the Delaunay property.
- `violation_details`: per-violation repair seeds with the simplex vertices,
  neighbor slots, and one offending external vertex when identified.
- `first_violation()`: borrowed view of the first `violation_details` entry,
  avoiding a duplicate stored detail that could drift from the aggregate report.

## Tracing Output

The logging helper is useful when a failure is easier to inspect as a trace:

```rust
dt.debug_print_first_delaunay_violation(None);
```

Install a `tracing` subscriber in tests or applications to see output. In tests,
`-- --nocapture` is often useful.

## Conflict Region Cross-Checks

`verify_conflict_region_completeness` is a deliberately expensive brute-force
check. It compares the conflict region discovered by local traversal against a
full scan of all simplices. The insertion path can invoke this check when both are
true:

- the crate was compiled with `diagnostics`
- `DELAUNAY_DEBUG_CONFLICT_VERIFY=1` is set

Use it when investigating missed conflict simplices, broken neighbor traversal, or
cavity construction failures.

## Debug Environment Variables

Runtime debug switches are documented in
[`docs/dev/debug_env_vars.md`](dev/debug_env_vars.md). The most relevant ones
for diagnostics work are:

- `DELAUNAY_DEBUG_CONFLICT_VERIFY`: enable conflict-region completeness checks.
- `DELAUNAY_DEBUG_CAVITY`: trace cavity boundary extraction and filling.
- `DELAUNAY_DEBUG_NEIGHBORS`: trace neighbor wiring checks.
- `DELAUNAY_DEBUG_RIDGE_LINK`: trace ridge-link validation failures.
- `DELAUNAY_DEBUG_RETRYABLE_SKIP`: trace retryable conflict skips after rollback.
- `DELAUNAY_DUPLICATE_METRICS`: emit duplicate-detection grid metrics.

These switches should remain investigation tools. Normal user-facing validation
should use `validate()`, `validation_report()`, and typed errors.

## Property-Test Failures

When a property test fails, start with the reproduction seed and minimized input
from `proptest`. If the failure is geometric or topological, rerun the narrowed
test with `-- --nocapture`; then enable the `diagnostics` feature or one of the
debug environment variables above only when the ordinary typed error/report is
not enough.

See [`property_testing_summary.md`](property_testing_summary.md) for the property
test map and reproduction workflow.