qualia_core_db/sparql_library/immersive/mod.rs
1//! Immersive SPARQL (QISP) — Phase 2 core: typed values + generation-safe
2//! dense-asset registry + typed function descriptors.
3//!
4//! This module is the Phase 2 slice of the **Qualia Immersive SPARQL Profile
5//! (QISP)** described in `docs/plans/immersive-sparql-hypermedia-profile.md`. It is
6//! a *profile and extension layer over the existing SPARQL engine* — not a fork of
7//! the query language and not a second parser/registry. It contributes three
8//! things, each in its own single-purpose submodule (CLAUDE.md §11):
9//!
10//! - [`value`] — the typed function descriptor ([`ImmersiveFunctionDescriptor`]),
11//! its [`ImmersiveValueKind`]/[`ExecutionClass`]/[`ExactnessClass`]
12//! classification, and the stable [`QispError`] codes (plan §4.2–§4.4).
13//! - [`asset_registry`] — the bounded, generation-safe [`DenseAssetRegistry`] and
14//! its fail-closed [`DenseAssetRef`] handle. A handle carries only numeric,
15//! validated fields; **no Rust address is ever stored in an NQuin/RDF term**
16//! (plan §3.4, §10.1 QISP-R03/R04).
17//! - [`profile`] — the fixed Tensor10D dimension order and honest classification,
18//! plus inline-value validation (plan §3.5, §3.6).
19//!
20//! # Standards posture
21//!
22//! These are **Editor's-Draft, provisional IRIs** (plan §2.4): the vocabulary and
23//! semantics may change and there is no compatibility promise until the profile
24//! advances. Nothing here claims W3C or OGC standard status. The namespace owner
25//! and continuity plan are governance items tracked in the plan (§15 QISP-D02).
26//!
27//! The `functions` submodule (the concrete typed-function registry that *uses*
28//! these descriptors) is added by the integrating session — it is intentionally
29//! **not** declared here.
30
31pub mod asset_registry;
32pub mod functions;
33pub mod profile;
34pub mod value;
35
36// ---------------------------------------------------------------------------
37// Provisional namespace IRIs (plan §3.1). Separate ontology / function /
38// datatype namespaces so predicates are never confused with executable
39// functions. These are versioned `0.1` draft IRIs.
40// ---------------------------------------------------------------------------
41
42/// Ontology namespace — classes and properties (`qisp:`).
43pub const QISP_NS: &str = "https://webizen.org/immersive/0.1#";
44
45/// Function namespace — executable extension functions (`qispf:`).
46pub const QISPF_NS: &str = "https://webizen.org/immersive/function/0.1#";
47
48/// Datatype namespace — QISP-specific datatypes (`qispd:`).
49pub const QISPD_NS: &str = "https://webizen.org/immersive/datatype/0.1#";
50
51// ---------------------------------------------------------------------------
52// Public API re-exports.
53// ---------------------------------------------------------------------------
54
55pub use value::{
56 ExactnessClass, ExecutionClass, ImmersiveFunctionDescriptor, ImmersiveValueKind, QispError,
57};
58
59pub use asset_registry::{AssetRecord, DenseAssetRef, DenseAssetRegistry, SectionKind, MAX_ASSETS};
60
61pub use profile::{validate_inline_tensor10d, DimClass, TENSOR10D_DIMS, TENSOR10D_PROFILE_IRI};
62
63pub use functions::{
64 admit_inline, entry_for_iri, entry_for_iri_hash, tensor_distance, tensor_knn_into,
65 tensor_within, FunctionEntry, TensorNeighbor, FUNCTIONS,
66};
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn namespaces_are_distinct_and_versioned() {
74 assert_ne!(QISP_NS, QISPF_NS);
75 assert_ne!(QISP_NS, QISPD_NS);
76 assert_ne!(QISPF_NS, QISPD_NS);
77 assert!(QISP_NS.contains("/immersive/0.1#"));
78 assert!(QISPF_NS.contains("/immersive/function/0.1#"));
79 assert!(QISPD_NS.contains("/immersive/datatype/0.1#"));
80 }
81
82 #[test]
83 fn re_exports_are_reachable() {
84 // Compile-time proof the public surface is wired through `mod`.
85 let _k: ImmersiveValueKind = ImmersiveValueKind::AssetRef;
86 let _e: ExecutionClass = ExecutionClass::HotZeroHeap;
87 let _x: ExactnessClass = ExactnessClass::Exact;
88 let _err: QispError = QispError::UnknownAsset;
89 let _sec: SectionKind = SectionKind::Mesh;
90 let _dim: DimClass = DimClass::Spatial;
91 let mut reg = DenseAssetRegistry::new();
92 let r: DenseAssetRef = reg.insert(SectionKind::Mesh, 0, 1, 0).unwrap();
93 let rec: AssetRecord = *reg.resolve(&r).unwrap();
94 assert_eq!(rec.token(), r.token());
95 assert_eq!(TENSOR10D_DIMS.len(), 10);
96 assert!(!TENSOR10D_PROFILE_IRI.is_empty());
97 assert!(MAX_ASSETS >= 1);
98 assert!(validate_inline_tensor10d(&[0.0; 10]).is_ok());
99 }
100}