Skip to content

Commit 82d9caa

Browse files
committed
feat(cesium): fill groups C+D (hlod, fixtures) + fmt-clean all 12 modules
All 12 cesium modules now ///-commented scaffold; cargo check + cargo test clean (unit + 33 doctests), cargo fmt --check green (fixes the FMT CI). - C: to_cam_soa grounded against real GaussianBatch (sh[i*48+ch*16+k] layout, glTF xyzw -> splat3d wxyz quat reorder, both unit-tested); sse + hlod are live pure-arithmetic (LOD + ADD/REPLACE traversal). - D: oracle MEASURES parity (SSIM/PSNR live); cesium-native FFI is DEFERRED; sort-order (front-to-back vs back-to-front accumulation) = named risk. fixtures: scenes + gates (INRIA/SETTLEMENT/SYNTHETIC).
1 parent d57cbe3 commit 82d9caa

3 files changed

Lines changed: 754 additions & 18 deletions

File tree

crates/cesium/src/esri_crs.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,7 @@ pub struct EsriCrs;
166166
/// // EsriCrs { wkid, latest_wkid, vcs_wkid, latest_vcs_wkid }
167167
/// // }
168168
/// ```
169-
pub fn from_pbf_spatial_ref(
170-
_wkid: u32,
171-
_latest_wkid: u32,
172-
_vcs_wkid: u32,
173-
_latest_vcs_wkid: u32,
174-
) -> EsriCrs {
169+
pub fn from_pbf_spatial_ref(_wkid: u32, _latest_wkid: u32, _vcs_wkid: u32, _latest_vcs_wkid: u32) -> EsriCrs {
175170
unimplemented!("scaffold only")
176171
}
177172

crates/cesium/src/fixtures.rs

Lines changed: 355 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,356 @@
1-
//! `fixtures` (group D) — golden scenes + parity gates
2-
//! Ground against: staehlli/3D-settlement-development.
3-
//! Reverse-engineer ONLY → CAM SoA; NO JSON in hotpath (rule 3).
4-
//! `///` commented scaffold to be filled by Sonnet group D; reviewed live by
5-
//! Opus + CodeRabbit/Codex before any impl is uncommented.
1+
//! `fixtures` (group D) — golden scenes + parity gates.
2+
//!
3+
//! Defines the canonical test scenes used to validate `splat3d` parity against
4+
//! reference renders, and the SSIM / PSNR thresholds that constitute a "pass".
5+
//!
6+
//! # Philosophy
7+
//!
8+
//! The oracle **measures** parity; this module **gates** it. A `ParityGate`
9+
//! bundles a scene descriptor with its acceptable metric bounds. Whether to
10+
//! treat a failed gate as a CI hard-failure is the caller's decision.
11+
//!
12+
//! # First reference scene
13+
//!
14+
//! The first reference is an Inria `.ply` scene, loaded via
15+
//! `splat3d::ply::read_ply` (confirmed: `src/hpc/splat3d/ply.rs` line 110).
16+
//! The `staehlli/3D-settlement-development` scene is the named fixture source
17+
//! from `lib.rs` grounding references.
18+
//!
19+
//! # Threshold rationale
20+
//!
21+
//! | Gate | SSIM | PSNR (dB) | Rationale |
22+
//! |---------------------|-------|-----------|------------------------------------------------|
23+
//! | `SYNTHETIC_TIGHT` | 0.99 | 40.0 | Synthetic scene, controlled camera, no sort risk |
24+
//! | `INRIA_PLY_NOMINAL` | 0.95 | 30.0 | Real scene; sort-order risk may cost ~3–5 dB |
25+
//! | `SMOKE_TEST` | 0.80 | 20.0 | Minimal bar: confirms pipeline runs at all |
26+
//!
27+
//! # Sort-order risk (see `oracle` module doc)
28+
//!
29+
//! All thresholds above are set conservatively to account for the front-to-back
30+
//! vs back-to-front accumulation delta documented in `oracle.rs`. The
31+
//! `INRIA_PLY_NOMINAL` gate in particular leaves 5–10 dB of headroom that a
32+
//! sort-order-aware comparison could reclaim.
33+
//!
34+
//! # Implementation status
35+
//!
36+
//! **Commented scaffold only.** The `Fixture` and `ParityGate` structs are
37+
//! live `std`-only. All references to `splat3d` symbols are commented out
38+
//! pending the ndarray dep re-enable + Opus + CodeRabbit review.
39+
//!
40+
//! # Source grounding
41+
//!
42+
//! Symbols cited (confirmed from local source):
43+
//! - `read_ply` — `src/hpc/splat3d/ply.rs:110`
44+
//! - Framebuffer layout — `raster.rs` doc: interleaved RGB, len = `3·W·H`
45+
//! - `GaussianBatch::len` — `gaussian.rs:89` (active gaussian count)
646
7-
// TODO(group-D): scaffold per src/lib.rs module map + grounding refs above.
47+
// ─────────────────────────────────────────────────────────────────────────────
48+
// Parity threshold constants (live)
49+
// ─────────────────────────────────────────────────────────────────────────────
50+
51+
/// SSIM / PSNR pair for a parity gate.
52+
#[derive(Debug, Clone, Copy, PartialEq)]
53+
pub struct Thresholds {
54+
/// Minimum acceptable SSIM in `[0, 1]`.
55+
pub min_ssim: f32,
56+
/// Minimum acceptable PSNR in dB.
57+
pub min_psnr_db: f32,
58+
}
59+
60+
impl Thresholds {
61+
/// Synthetic scene, controlled camera, minimal sort-order risk.
62+
pub const SYNTHETIC_TIGHT: Self = Self {
63+
min_ssim: 0.99,
64+
min_psnr_db: 40.0,
65+
};
66+
67+
/// Real Inria PLY scene; sort-order risk may cost ~3–5 dB of PSNR.
68+
/// Threshold is set conservatively to account for front-to-back vs
69+
/// back-to-front accumulation divergence (see `oracle` module doc).
70+
pub const INRIA_PLY_NOMINAL: Self = Self {
71+
min_ssim: 0.95,
72+
min_psnr_db: 30.0,
73+
};
74+
75+
/// Smoke test: confirms the pipeline runs and produces a plausible image.
76+
pub const SMOKE_TEST: Self = Self {
77+
min_ssim: 0.80,
78+
min_psnr_db: 20.0,
79+
};
80+
}
81+
82+
// ─────────────────────────────────────────────────────────────────────────────
83+
// Fixture descriptor (live — std-only)
84+
// ─────────────────────────────────────────────────────────────────────────────
85+
86+
/// Descriptor for a golden test scene.
87+
///
88+
/// A `Fixture` names a scene and records its provenance. It does NOT hold the
89+
/// actual scene data (too large for in-memory constants); the oracle pipeline
90+
/// loads data from disk at test time.
91+
#[derive(Debug, Clone)]
92+
pub struct Fixture {
93+
/// Short identifier used in test output (e.g. `"settlement_dev"`).
94+
pub id: &'static str,
95+
/// Human-readable description of the scene and its provenance.
96+
pub description: &'static str,
97+
/// Expected number of Gaussians in the loaded batch (informational).
98+
/// `None` means unchecked.
99+
pub expected_gaussian_count: Option<usize>,
100+
/// Image width used for the reference render, in pixels.
101+
pub width: u32,
102+
/// Image height used for the reference render, in pixels.
103+
pub height: u32,
104+
/// Background colour `[R, G, B]` in `[0, 1]` used for the reference render.
105+
pub background: [f32; 3],
106+
}
107+
108+
/// Named fixtures. Path resolution is left to the test harness so the crate
109+
/// has no compile-time dependency on the filesystem layout.
110+
pub mod scenes {
111+
use super::Fixture;
112+
113+
/// Inria 3DGS garden scene (small variant, ~300K Gaussians).
114+
/// Source: Kerbl et al. 2023 supplemental material.
115+
// UNVERIFIED: exact gaussian count — 300K is an estimate from the paper.
116+
pub const INRIA_GARDEN_SMALL: Fixture = Fixture {
117+
id: "inria_garden_small",
118+
description: "Inria 3DGS garden scene (small variant), Kerbl 2023. \
119+
Loaded via splat3d::ply::read_ply. \
120+
// UNVERIFIED: ~300K gaussians.",
121+
expected_gaussian_count: None, // UNVERIFIED
122+
width: 1920,
123+
height: 1080,
124+
background: [0.0, 0.0, 0.0],
125+
};
126+
127+
/// staehlli/3D-settlement-development scene (named grounding ref in lib.rs).
128+
/// This is the primary parity fixture for the cesium crate.
129+
// UNVERIFIED: gaussian count and exact image dimensions for this scene.
130+
pub const SETTLEMENT_DEV: Fixture = Fixture {
131+
id: "settlement_dev",
132+
description: "staehlli/3D-settlement-development 3DGS scene. \
133+
Grounding reference named in cesium/src/lib.rs. \
134+
Loaded via splat3d::ply::read_ply. \
135+
// UNVERIFIED: gaussian count and image dims.",
136+
expected_gaussian_count: None, // UNVERIFIED
137+
width: 1920,
138+
height: 1080,
139+
background: [0.0, 0.0, 0.0],
140+
};
141+
142+
/// Synthetic unit scene: 4 Gaussians at known positions, controlled camera.
143+
/// Used for `SYNTHETIC_TIGHT` gate — no sort-order ambiguity.
144+
pub const SYNTHETIC_UNIT: Fixture = Fixture {
145+
id: "synthetic_unit",
146+
description: "4 Gaussians at axis-aligned positions, identity camera. \
147+
Fully deterministic: no sort-order risk, SSIM ≥ 0.99 expected.",
148+
expected_gaussian_count: Some(4),
149+
width: 64,
150+
height: 64,
151+
background: [0.0, 0.0, 0.0],
152+
};
153+
}
154+
155+
// ─────────────────────────────────────────────────────────────────────────────
156+
// ParityGate (live — std-only)
157+
// ─────────────────────────────────────────────────────────────────────────────
158+
159+
/// A parity gate bundles a [`Fixture`] with its [`Thresholds`].
160+
///
161+
/// Use [`ParityGate::check`] to evaluate a [`crate::oracle::ParityMetrics`]
162+
/// against the gate. The gate reports pass/fail but does not panic — the
163+
/// caller decides whether a failed gate is a CI hard failure.
164+
#[derive(Debug, Clone)]
165+
pub struct ParityGate {
166+
/// The scene this gate applies to.
167+
pub fixture: Fixture,
168+
/// SSIM / PSNR thresholds.
169+
pub thresholds: Thresholds,
170+
}
171+
172+
/// Result of evaluating a parity gate.
173+
#[derive(Debug, Clone, PartialEq)]
174+
pub struct GateResult {
175+
/// Whether the gate passed.
176+
pub passed: bool,
177+
/// Observed SSIM.
178+
pub ssim: f32,
179+
/// Observed PSNR in dB.
180+
pub psnr: f32,
181+
/// SSIM margin (observed − minimum; negative = failing).
182+
pub ssim_margin: f32,
183+
/// PSNR margin in dB (observed − minimum; negative = failing).
184+
pub psnr_margin_db: f32,
185+
}
186+
187+
impl ParityGate {
188+
/// Evaluate the gate against observed metrics.
189+
pub fn check(&self, metrics: &crate::oracle::ParityMetrics) -> GateResult {
190+
let ssim_margin = metrics.ssim - self.thresholds.min_ssim;
191+
let psnr_margin_db = if metrics.psnr.is_infinite() {
192+
f32::INFINITY
193+
} else {
194+
metrics.psnr - self.thresholds.min_psnr_db
195+
};
196+
let passed = metrics.passes(self.thresholds.min_ssim, self.thresholds.min_psnr_db);
197+
GateResult {
198+
passed,
199+
ssim: metrics.ssim,
200+
psnr: metrics.psnr,
201+
ssim_margin,
202+
psnr_margin_db,
203+
}
204+
}
205+
}
206+
207+
/// Pre-built gates for the named scenes.
208+
pub mod gates {
209+
use super::{scenes, ParityGate, Thresholds};
210+
211+
/// Smoke test gate for the settlement_dev scene.
212+
pub fn settlement_dev_smoke() -> ParityGate {
213+
ParityGate {
214+
fixture: scenes::SETTLEMENT_DEV.clone(),
215+
thresholds: Thresholds::SMOKE_TEST,
216+
}
217+
}
218+
219+
/// Nominal gate for the settlement_dev scene (accounts for sort-order risk).
220+
pub fn settlement_dev_nominal() -> ParityGate {
221+
ParityGate {
222+
fixture: scenes::SETTLEMENT_DEV.clone(),
223+
thresholds: Thresholds::INRIA_PLY_NOMINAL,
224+
}
225+
}
226+
227+
/// Tight gate for the synthetic unit scene.
228+
pub fn synthetic_unit_tight() -> ParityGate {
229+
ParityGate {
230+
fixture: scenes::SYNTHETIC_UNIT.clone(),
231+
thresholds: Thresholds::SYNTHETIC_TIGHT,
232+
}
233+
}
234+
}
235+
236+
// ─────────────────────────────────────────────────────────────────────────────
237+
// Commented scaffold — live oracle integration blocked on ndarray dep
238+
// ─────────────────────────────────────────────────────────────────────────────
239+
240+
// DEFERRED: When ndarray dep is re-enabled, wire the full fixture runner:
241+
//
242+
// use crate::oracle::{load_ply_batch, render_batch, ParityMetrics, OracleError};
243+
// use ndarray_hpc::hpc::splat3d::project::Camera;
244+
//
245+
// /// Run the `settlement_dev` smoke test fixture end-to-end.
246+
// ///
247+
// /// Loads `ply_path`, renders at `SETTLEMENT_DEV` resolution, diffs against
248+
// /// `reference_fb`, and evaluates against `settlement_dev_smoke()`.
249+
// ///
250+
// /// # Sort-order risk
251+
// ///
252+
// /// The `SMOKE_TEST` threshold (SSIM ≥ 0.80, PSNR ≥ 20 dB) is intentionally
253+
// /// loose to tolerate front-to-back vs back-to-front divergence. See `oracle`
254+
// /// module doc for the named risk.
255+
// pub fn run_settlement_dev_smoke(
256+
// ply_path: &std::path::Path,
257+
// reference_fb: &[f32],
258+
// ) -> Result<GateResult, OracleError> {
259+
// let fixture = &scenes::SETTLEMENT_DEV;
260+
// // UNVERIFIED: Camera::identity_at_origin signature — confirm in project.rs
261+
// let camera = Camera::identity_at_origin(fixture.width, fixture.height);
262+
// let metrics = crate::oracle::run_ply_oracle(
263+
// ply_path,
264+
// reference_fb,
265+
// &camera,
266+
// fixture.background,
267+
// )?;
268+
// Ok(gates::settlement_dev_smoke().check(&metrics))
269+
// }
270+
271+
// ─────────────────────────────────────────────────────────────────────────────
272+
// Unit tests (live — std-only)
273+
// ─────────────────────────────────────────────────────────────────────────────
274+
275+
#[cfg(test)]
276+
mod tests {
277+
use super::*;
278+
use crate::oracle::ParityMetrics;
279+
280+
fn make_metrics(ssim: f32, psnr: f32) -> ParityMetrics {
281+
ParityMetrics {
282+
ssim,
283+
psnr,
284+
mse: 0.0,
285+
sample_count: 48,
286+
}
287+
}
288+
289+
#[test]
290+
fn thresholds_constants_are_ordered() {
291+
// SMOKE < INRIA < SYNTHETIC
292+
assert!(Thresholds::SMOKE_TEST.min_ssim < Thresholds::INRIA_PLY_NOMINAL.min_ssim);
293+
assert!(Thresholds::INRIA_PLY_NOMINAL.min_ssim < Thresholds::SYNTHETIC_TIGHT.min_ssim);
294+
assert!(Thresholds::SMOKE_TEST.min_psnr_db < Thresholds::INRIA_PLY_NOMINAL.min_psnr_db);
295+
assert!(Thresholds::INRIA_PLY_NOMINAL.min_psnr_db < Thresholds::SYNTHETIC_TIGHT.min_psnr_db);
296+
}
297+
298+
#[test]
299+
fn gate_check_passes_above_threshold() {
300+
let gate = gates::synthetic_unit_tight();
301+
let m = make_metrics(0.995, 45.0);
302+
let r = gate.check(&m);
303+
assert!(r.passed, "metrics above threshold must pass");
304+
assert!(r.ssim_margin > 0.0, "ssim_margin must be positive");
305+
assert!(r.psnr_margin_db > 0.0, "psnr_margin_db must be positive");
306+
}
307+
308+
#[test]
309+
fn gate_check_fails_below_ssim() {
310+
let gate = gates::synthetic_unit_tight();
311+
let m = make_metrics(0.97, 45.0); // SSIM below 0.99
312+
let r = gate.check(&m);
313+
assert!(!r.passed, "SSIM below threshold must fail");
314+
assert!(r.ssim_margin < 0.0, "ssim_margin must be negative");
315+
}
316+
317+
#[test]
318+
fn gate_check_fails_below_psnr() {
319+
let gate = gates::synthetic_unit_tight();
320+
let m = make_metrics(0.995, 35.0); // PSNR below 40 dB
321+
let r = gate.check(&m);
322+
assert!(!r.passed, "PSNR below threshold must fail");
323+
assert!(r.psnr_margin_db < 0.0, "psnr_margin_db must be negative");
324+
}
325+
326+
#[test]
327+
fn gate_check_infinite_psnr_passes() {
328+
let gate = gates::settlement_dev_nominal();
329+
let m = make_metrics(0.97, f32::INFINITY);
330+
let r = gate.check(&m);
331+
assert!(r.passed, "infinite PSNR (identical buffers) must pass any gate");
332+
assert!(r.psnr_margin_db.is_infinite(), "psnr_margin_db must be infinite");
333+
}
334+
335+
#[test]
336+
fn smoke_gate_is_looser_than_nominal() {
337+
let smoke = gates::settlement_dev_smoke();
338+
let nominal = gates::settlement_dev_nominal();
339+
assert!(smoke.thresholds.min_ssim <= nominal.thresholds.min_ssim);
340+
assert!(smoke.thresholds.min_psnr_db <= nominal.thresholds.min_psnr_db);
341+
}
342+
343+
#[test]
344+
fn fixture_ids_are_unique() {
345+
let fixtures = [scenes::INRIA_GARDEN_SMALL.id, scenes::SETTLEMENT_DEV.id, scenes::SYNTHETIC_UNIT.id];
346+
let mut seen = std::collections::HashSet::new();
347+
for id in &fixtures {
348+
assert!(seen.insert(*id), "duplicate fixture id: {id}");
349+
}
350+
}
351+
352+
#[test]
353+
fn synthetic_unit_fixture_has_known_gaussian_count() {
354+
assert_eq!(scenes::SYNTHETIC_UNIT.expected_gaussian_count, Some(4));
355+
}
356+
}

0 commit comments

Comments
 (0)