Skip to main content

qualia_core_db/render/
contract.rs

1//! Phenomenal viewport CI contract — WGSL bindings, binary layout, and regression oracles.
2//!
3//! Run via `cargo test -p qualia-core-db render::contract::tests::phenomenal_ --lib` or
4//! `node docs/tests/phenomenal-verify.mjs`.
5
6/// Rust `portal_gpu` projector camera bind group (group 0).
7pub const PROJECTOR_GROUP0_BINDINGS: &[u32] = &[0, 1];
8/// Rust `portal_gpu` projector tensor SOA bind group (group 1).
9pub const PROJECTOR_GROUP1_BINDINGS: &[u32] = &[0];
10/// Rust ambient layout — binding 4 is reserved for `ObserverStandpoint` (not yet in WGSL).
11pub const AMBIENT_GROUP0_BINDINGS: &[u32] = &[0, 1, 2, 3, 4];
12pub const BLOOM_GROUP0_BINDINGS: &[u32] = &[0, 1, 2, 3, 4];
13
14/// Parse `@group(G) @binding(B)` declarations from WGSL source lines.
15pub fn parse_wgsl_bindings(source: &str) -> Vec<(u32, u32)> {
16    let mut out = Vec::new();
17    for line in source.lines() {
18        if !line.contains("@group(") || !line.contains("@binding(") {
19            continue;
20        }
21        let Some(group) = parse_u32_after(line, "@group(") else {
22            continue;
23        };
24        let Some(binding) = parse_u32_after(line, "@binding(") else {
25            continue;
26        };
27        if !out.contains(&(group, binding)) {
28            out.push((group, binding));
29        }
30    }
31    out.sort_by(|a, b| a.0.cmp(&b.0).then(a.1.cmp(&b.1)));
32    out
33}
34
35fn parse_u32_after(line: &str, token: &str) -> Option<u32> {
36    let rest = line.split(token).nth(1)?;
37    let digits: String = rest.chars().take_while(|c| c.is_ascii_digit()).collect();
38    digits.parse().ok()
39}
40
41/// Every WGSL-declared binding must exist in the Rust bind-group layout manifest.
42pub fn assert_wgsl_bindings_covered(
43    wgsl_source: &str,
44    group: u32,
45    rust_bindings: &[u32],
46) -> Result<(), String> {
47    let wgsl: Vec<u32> = parse_wgsl_bindings(wgsl_source)
48        .into_iter()
49        .filter(|(g, _)| *g == group)
50        .map(|(_, b)| b)
51        .collect();
52    for b in wgsl {
53        if !rust_bindings.contains(&b) {
54            return Err(format!(
55                "WGSL group({group}) binding({b}) missing from Rust layout {rust_bindings:?}"
56            ));
57        }
58    }
59    Ok(())
60}
61
62#[cfg(test)]
63fn validate_wgsl_smoke(label: &str, source: &str) {
64    use naga::front::wgsl::Frontend;
65
66    // Parse-only smoke: catches syntax regressions on native CI. Full layout validation
67    // is enforced by `CameraUniform`/`ObserverStandpoint` size tests below and by
68    // `cargo check --target wasm32-unknown-unknown --features portal` (wgpu pipeline create).
69    Frontend::new()
70        .parse(source)
71        .unwrap_or_else(|e| panic!("{label}: WGSL parse failed: {e:?}"));
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::audio::acoustic_plane::{AcousticUniform, SONIC_RING_CAP};
78    use crate::audio::acoustic_sab::{init_acoustic_sab, ACOUSTIC_SAB_BYTES};
79    use crate::audio::audio_spectral_sheet::SPECTRAL_PREVIEW_BINS;
80    use crate::audio::hrtf::binaural_from_position;
81    use crate::gpu_context::{
82        ambient_draw_instances_for_mode, ComputeUniverse, OperationalMode, UniverseOrchestrator,
83    };
84    use crate::render::acoustic::{
85        sigma_to_center_frequency_hz, sigma_to_wavelength_nm, ACOUSTIC_UNIFORM_FLOAT_COUNT,
86    };
87    use crate::render::control::{PortalControlCommand, CONTROL_RING_CAP, ICP_MAGIC_BIT};
88    use crate::render::pga::motor_rq_gated;
89    use crate::render::spectral::sigma_to_cie_xyz;
90    use crate::render::telemetry::{
91        CameraUniform, ObserverStandpoint, ParticleInstance, SystemTelemetry, STANDPOINT_DID,
92        STANDPOINT_EPHEMERAL, STANDPOINT_SPECTATOR, STANDPOINT_VAULT,
93    };
94    use crate::shaders::viewport::{AMBIENT_WGSL, BLOOM_WGSL, PROJECTOR_WGSL};
95    use crate::sonic_token::SonicToken;
96    use crate::tensor::buffer_export::tensor_node_count;
97    use crate::tensor::buffer_export::{TensorBufferHeader, TENSOR_HEADER_BYTES, TENSOR_STRIDE};
98    use crate::tensor::Tensor10D;
99
100    const IDENTITY_ROTOR: [f32; 4] = [1.0, 0.0, 0.0, 0.0];
101
102    #[test]
103    fn phenomenal_shader_modules_parse() {
104        validate_wgsl_smoke("ambient", AMBIENT_WGSL);
105        validate_wgsl_smoke("projector", PROJECTOR_WGSL);
106        validate_wgsl_smoke("bloom", BLOOM_WGSL);
107    }
108
109    #[test]
110    fn phenomenal_binding_layout_matches_wgsl() {
111        assert_wgsl_bindings_covered(AMBIENT_WGSL, 0, AMBIENT_GROUP0_BINDINGS)
112            .expect("ambient bindings");
113        assert_wgsl_bindings_covered(PROJECTOR_WGSL, 0, PROJECTOR_GROUP0_BINDINGS)
114            .expect("projector group0");
115        assert_wgsl_bindings_covered(PROJECTOR_WGSL, 1, PROJECTOR_GROUP1_BINDINGS)
116            .expect("projector group1");
117        assert_wgsl_bindings_covered(BLOOM_WGSL, 0, BLOOM_GROUP0_BINDINGS).expect("bloom");
118    }
119
120    #[test]
121    fn phenomenal_uniform_struct_sizes_match_wgsl() {
122        assert_eq!(std::mem::size_of::<TensorBufferHeader>(), 32);
123        assert_eq!(TENSOR_HEADER_BYTES, 32);
124        assert_eq!(std::mem::size_of::<Tensor10D>(), 40);
125        assert_eq!(TENSOR_STRIDE, 40);
126        assert_eq!(std::mem::size_of::<SystemTelemetry>(), 48);
127        assert_eq!(std::mem::size_of::<ParticleInstance>(), 16);
128        assert_eq!(std::mem::size_of::<CameraUniform>(), 128);
129        assert_eq!(std::mem::size_of::<ObserverStandpoint>(), 128);
130    }
131
132    #[test]
133    fn phenomenal_tensor_header_stride_matches_gpu_upload() {
134        let tensors = [Tensor10D::ground_truth(
135            0.0, 0.0, 0.1, 0.2, 0.3, 0.0, 1.0, 0.0, 0.5,
136        )];
137        let need = TensorBufferHeader::total_bytes(tensors.len());
138        let mut buf = vec![0u8; need];
139        crate::tensor::buffer_export::write_tensor_buffer(&tensors, &mut buf).unwrap();
140        let (header, header_len) =
141            crate::tensor::buffer_export::parse_header(&buf).expect("header");
142        assert_eq!(header_len, TENSOR_HEADER_BYTES);
143        assert_eq!(header.stride as usize, TENSOR_STRIDE);
144        assert_eq!(tensor_node_count(&buf).unwrap(), 1);
145        // `PortalGpu::upload_tensor_buffer` skips the 32 B header when binding SOA storage.
146        assert_eq!(
147            header_len + header.node_count as usize * TENSOR_STRIDE,
148            buf.len()
149        );
150    }
151
152    #[test]
153    fn phenomenal_standpoint_rq_motor_identity_gate() {
154        for class in [
155            STANDPOINT_SPECTATOR,
156            STANDPOINT_EPHEMERAL,
157            STANDPOINT_DID,
158            STANDPOINT_VAULT,
159        ] {
160            assert_eq!(
161                motor_rq_gated(0.0, 0.5, 1.0, 1.0, class, 1.0),
162                IDENTITY_ROTOR,
163                "collapsed q class={class}"
164            );
165        }
166        assert_eq!(
167            motor_rq_gated(0.9, 0.5, 1.0, 1.0, STANDPOINT_DID, 0.0),
168            IDENTITY_ROTOR,
169            "DID epistemic aperture 0"
170        );
171        assert_eq!(
172            motor_rq_gated(0.9, 0.5, 1.0, 1.0, STANDPOINT_VAULT, 1.0),
173            IDENTITY_ROTOR,
174            "vault always identity"
175        );
176        let active = motor_rq_gated(0.5, 0.25, 2.0, 1.0, STANDPOINT_SPECTATOR, 1.0);
177        assert!(
178            (active[0] - 1.0).abs() > 1e-4 || active[1].abs() > 1e-4,
179            "sandbox q should spin: {active:?}"
180        );
181    }
182
183    #[test]
184    fn phenomenal_vram_ledger_full_mode_draws_above_eco_cap() {
185        let resident = 50_000_u32;
186        let full = ambient_draw_instances_for_mode(resident, OperationalMode::Full);
187        let eco = ambient_draw_instances_for_mode(resident, OperationalMode::Eco);
188        assert!(full > 8_000, "Full mode must draw >8k instances");
189        assert_eq!(eco, 8_000, "Eco mode caps at 8k");
190        assert_eq!(
191            UniverseOrchestrator::from_total_budget(6 * 1024 * 1024 * 1024, OperationalMode::Full)
192                .max_particles(ComputeUniverse::Viewport, OperationalMode::Full),
193            50_000
194        );
195    }
196
197    #[test]
198    fn phenomenal_vram_ledger_pressure_step_down() {
199        let local = crate::gpu_context::VramLedger::new(1000);
200        local.record_tensor(500);
201        assert_eq!(local.mode(), OperationalMode::Full);
202        local.record_kv_cache(300);
203        assert_eq!(local.mode(), OperationalMode::Eco);
204        local.record_render(200);
205        assert_eq!(local.mode(), OperationalMode::Reserve);
206    }
207
208    #[test]
209    fn phenomenal_acoustic_uniform_layout() {
210        assert_eq!(std::mem::size_of::<SonicToken>(), 8);
211        assert_eq!(SONIC_RING_CAP, 128);
212        let uniform = AcousticUniform::default();
213        let bytes = bytemuck::bytes_of(&uniform);
214        assert_eq!(bytes.len(), std::mem::size_of::<AcousticUniform>());
215        // 18 scalars (binaural + STFT frame) + 64 preview bins
216        assert_eq!(
217            std::mem::size_of::<AcousticUniform>(),
218            72 + SPECTRAL_PREVIEW_BINS * 4
219        );
220        assert_eq!(std::mem::size_of::<AcousticUniform>(), 328);
221    }
222
223    #[test]
224    fn phenomenal_sigma_visual_audio_parity() {
225        for i in 0..=10 {
226            let sigma = i as f32 / 10.0;
227            let lambda = sigma_to_wavelength_nm(sigma);
228            assert!(lambda >= 400.0 && lambda <= 700.0);
229            let _xyz = sigma_to_cie_xyz(sigma);
230            let hz = sigma_to_center_frequency_hz(sigma);
231            assert!(hz >= 55.0 && hz <= 8_000.0);
232            let hz2 = sigma_to_center_frequency_hz(sigma + 1.0);
233            assert!((hz - hz2).abs() < 1e-3, "σ fract parity");
234        }
235        assert_eq!(ACOUSTIC_UNIFORM_FLOAT_COUNT, 82);
236    }
237
238    #[test]
239    fn phenomenal_hrtf_and_sab_layout() {
240        let g = binaural_from_position([1.0, 0.0, -1.0], 0.0);
241        assert!(g.gain_r > g.gain_l);
242        let mut sab = [0u8; ACOUSTIC_SAB_BYTES];
243        assert!(init_acoustic_sab(&mut sab));
244        assert_eq!(ACOUSTIC_SAB_BYTES, 1024);
245    }
246
247    #[test]
248    fn phenomenal_icp_command_layout() {
249        let cmd = PortalControlCommand::navigate_index(9);
250        assert_eq!(std::mem::size_of::<PortalControlCommand>(), 8);
251        assert!((cmd.raw & ICP_MAGIC_BIT) != 0);
252        assert_eq!(cmd.tensor_or_menu_index(), 9);
253        assert!(CONTROL_RING_CAP >= 64);
254    }
255
256    #[test]
257    fn phenomenal_u3_aliases_u1_partition() {
258        let orch = UniverseOrchestrator::from_total_budget_full(10_000);
259        let u1 = orch.partition(ComputeUniverse::Tensor10D).ledger_range;
260        let u3 = orch.partition(ComputeUniverse::AcousticPlane).ledger_range;
261        assert_eq!(u1.offset, u3.offset);
262        assert_eq!(u1.size, u3.size);
263        assert_eq!(
264            orch.effective_mode(ComputeUniverse::AcousticPlane, OperationalMode::Reserve),
265            OperationalMode::Reserve
266        );
267    }
268}