1pub mod compatibility;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum StabilityLevel {
11 Stable,
13 Beta,
15 Experimental,
17 Deprecated {
19 since: &'static str,
21 replacement: Option<&'static str>,
23 },
24}
25
26impl StabilityLevel {
27 pub fn is_production_ready(&self) -> bool {
29 matches!(
30 self,
31 StabilityLevel::Stable | StabilityLevel::Beta | StabilityLevel::Deprecated { .. }
32 )
33 }
34
35 pub fn label(&self) -> &'static str {
37 match self {
38 StabilityLevel::Stable => "Stable",
39 StabilityLevel::Beta => "Beta",
40 StabilityLevel::Experimental => "Experimental",
41 StabilityLevel::Deprecated { .. } => "Deprecated",
42 }
43 }
44
45 pub fn indicator(&self) -> &'static str {
47 match self {
48 StabilityLevel::Stable => "[STABLE]",
49 StabilityLevel::Beta => "[BETA]",
50 StabilityLevel::Experimental => "[EXPERIMENTAL]",
51 StabilityLevel::Deprecated { .. } => "[DEPRECATED]",
52 }
53 }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
58pub enum ApiCategory {
59 QueryLanguage,
60 DataModel,
61 Reasoning,
62 GraphQuery,
63 Geospatial,
64 Validation,
65 Storage,
66 Streaming,
67 Industrial,
68 ArtificialIntelligence,
69 Security,
70 RdfStar,
71 Federation,
72 Server,
73 WebAssembly,
74 TimeSeries,
75 PhysicsSimulation,
76 Quantum,
77 Tooling,
78}
79
80impl ApiCategory {
81 pub fn label(&self) -> &'static str {
83 match self {
84 ApiCategory::QueryLanguage => "Query Language",
85 ApiCategory::DataModel => "Data Model",
86 ApiCategory::Reasoning => "Reasoning",
87 ApiCategory::GraphQuery => "Graph Query",
88 ApiCategory::Geospatial => "Geospatial",
89 ApiCategory::Validation => "Validation",
90 ApiCategory::Storage => "Storage",
91 ApiCategory::Streaming => "Streaming",
92 ApiCategory::Industrial => "Industrial",
93 ApiCategory::ArtificialIntelligence => "Artificial Intelligence",
94 ApiCategory::Security => "Security",
95 ApiCategory::RdfStar => "RDF-star",
96 ApiCategory::Federation => "Federation",
97 ApiCategory::Server => "Server",
98 ApiCategory::WebAssembly => "WebAssembly",
99 ApiCategory::TimeSeries => "Time-Series",
100 ApiCategory::PhysicsSimulation => "Physics Simulation",
101 ApiCategory::Quantum => "Quantum",
102 ApiCategory::Tooling => "Tooling",
103 }
104 }
105}
106
107#[derive(Debug, Clone)]
109pub struct ApiStabilityMarker {
110 pub feature: &'static str,
112 pub category: ApiCategory,
114 pub level: StabilityLevel,
116 pub since: &'static str,
118 pub description: &'static str,
120 pub spec_url: Option<&'static str>,
122}
123
124impl ApiStabilityMarker {
125 pub fn stable(
127 feature: &'static str,
128 category: ApiCategory,
129 since: &'static str,
130 description: &'static str,
131 ) -> Self {
132 Self {
133 feature,
134 category,
135 level: StabilityLevel::Stable,
136 since,
137 description,
138 spec_url: None,
139 }
140 }
141
142 pub fn beta(
144 feature: &'static str,
145 category: ApiCategory,
146 since: &'static str,
147 description: &'static str,
148 ) -> Self {
149 Self {
150 feature,
151 category,
152 level: StabilityLevel::Beta,
153 since,
154 description,
155 spec_url: None,
156 }
157 }
158
159 pub fn experimental(
161 feature: &'static str,
162 category: ApiCategory,
163 since: &'static str,
164 description: &'static str,
165 ) -> Self {
166 Self {
167 feature,
168 category,
169 level: StabilityLevel::Experimental,
170 since,
171 description,
172 spec_url: None,
173 }
174 }
175
176 pub fn deprecated(
178 feature: &'static str,
179 category: ApiCategory,
180 since: &'static str,
181 deprecated_since: &'static str,
182 replacement: Option<&'static str>,
183 description: &'static str,
184 ) -> Self {
185 Self {
186 feature,
187 category,
188 level: StabilityLevel::Deprecated {
189 since: deprecated_since,
190 replacement,
191 },
192 since,
193 description,
194 spec_url: None,
195 }
196 }
197
198 pub fn with_spec(mut self, url: &'static str) -> Self {
200 self.spec_url = Some(url);
201 self
202 }
203
204 pub fn is_stable(&self) -> bool {
206 matches!(self.level, StabilityLevel::Stable)
207 }
208
209 pub fn is_beta(&self) -> bool {
211 matches!(self.level, StabilityLevel::Beta)
212 }
213
214 pub fn is_experimental(&self) -> bool {
216 matches!(self.level, StabilityLevel::Experimental)
217 }
218
219 pub fn is_deprecated(&self) -> bool {
221 matches!(self.level, StabilityLevel::Deprecated { .. })
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq)]
227pub struct RegistrySummary {
228 pub total: usize,
229 pub stable_count: usize,
230 pub beta_count: usize,
231 pub experimental_count: usize,
232 pub deprecated_count: usize,
233}
234
235impl RegistrySummary {
236 pub fn stable_percentage(&self) -> f64 {
238 if self.total == 0 {
239 return 0.0;
240 }
241 (self.stable_count as f64 / self.total as f64) * 100.0
242 }
243
244 pub fn production_ready_percentage(&self) -> f64 {
246 if self.total == 0 {
247 return 0.0;
248 }
249 ((self.stable_count + self.beta_count + self.deprecated_count) as f64 / self.total as f64)
250 * 100.0
251 }
252}
253
254pub struct StabilityRegistry {
256 markers: Vec<ApiStabilityMarker>,
257}
258
259impl StabilityRegistry {
260 pub fn new() -> Self {
262 Self {
263 markers: Vec::new(),
264 }
265 }
266
267 pub fn register(&mut self, marker: ApiStabilityMarker) {
269 self.markers.push(marker);
270 }
271
272 pub fn oxirs_v1_stability() -> Self {
274 let mut r = Self::new();
275
276 r.register(ApiStabilityMarker::stable("SPARQL 1.1 SELECT", ApiCategory::QueryLanguage, "0.1.0",
278 "Full SPARQL 1.1 SELECT query support including projections, DISTINCT, ORDER BY, LIMIT, OFFSET, GROUP BY, HAVING, and aggregate functions.")
279 .with_spec("https://www.w3.org/TR/sparql11-query/"));
280 r.register(
281 ApiStabilityMarker::stable(
282 "SPARQL 1.1 ASK",
283 ApiCategory::QueryLanguage,
284 "0.1.0",
285 "SPARQL 1.1 ASK queries returning boolean existence results.",
286 )
287 .with_spec("https://www.w3.org/TR/sparql11-query/"),
288 );
289 r.register(
290 ApiStabilityMarker::stable(
291 "SPARQL 1.1 CONSTRUCT",
292 ApiCategory::QueryLanguage,
293 "0.1.0",
294 "SPARQL 1.1 CONSTRUCT queries producing new RDF graphs from existing data.",
295 )
296 .with_spec("https://www.w3.org/TR/sparql11-query/"),
297 );
298 r.register(
299 ApiStabilityMarker::stable(
300 "SPARQL 1.1 DESCRIBE",
301 ApiCategory::QueryLanguage,
302 "0.1.0",
303 "SPARQL 1.1 DESCRIBE queries returning RDF descriptions of resources.",
304 )
305 .with_spec("https://www.w3.org/TR/sparql11-query/"),
306 );
307 r.register(ApiStabilityMarker::stable("SPARQL 1.1 Update", ApiCategory::QueryLanguage, "0.1.0",
308 "Full SPARQL 1.1 Update support: INSERT DATA, DELETE DATA, INSERT/DELETE WHERE, LOAD, CLEAR, CREATE, DROP.")
309 .with_spec("https://www.w3.org/TR/sparql11-update/"));
310 r.register(ApiStabilityMarker::stable("SPARQL 1.1 Property Paths", ApiCategory::QueryLanguage, "0.1.0",
311 "SPARQL 1.1 property path expressions including sequence, alternative, inverse, kleene star, and kleene plus."));
312 r.register(ApiStabilityMarker::stable(
313 "SPARQL 1.1 Aggregates",
314 ApiCategory::QueryLanguage,
315 "0.1.0",
316 "SPARQL 1.1 aggregate functions: COUNT, SUM, MIN, MAX, AVG, GROUP_CONCAT, SAMPLE.",
317 ));
318 r.register(
319 ApiStabilityMarker::stable(
320 "SPARQL 1.1 Federated Query (SERVICE)",
321 ApiCategory::QueryLanguage,
322 "0.1.0",
323 "SPARQL 1.1 SERVICE clause for federated queries across multiple SPARQL endpoints.",
324 )
325 .with_spec("https://www.w3.org/TR/sparql11-federated-query/"),
326 );
327 r.register(
328 ApiStabilityMarker::stable(
329 "SPARQL 1.2 RDF-star Expressions",
330 ApiCategory::RdfStar,
331 "0.1.0",
332 "SPARQL 1.2 triple expressions and annotation syntax for quoted triple patterns.",
333 )
334 .with_spec("https://www.w3.org/TR/sparql12-query/"),
335 );
336
337 r.register(ApiStabilityMarker::stable("RDF 1.2 Data Model", ApiCategory::DataModel, "0.1.0",
339 "Complete RDF 1.2 data model: IRIs, blank nodes, literals, language-tagged strings, datatyped literals, and quoted triples.")
340 .with_spec("https://www.w3.org/TR/rdf12-concepts/"));
341 r.register(
342 ApiStabilityMarker::stable(
343 "Turtle Serialization",
344 ApiCategory::DataModel,
345 "0.1.0",
346 "Streaming Turtle 1.1 parser and writer with full namespace prefix support.",
347 )
348 .with_spec("https://www.w3.org/TR/turtle/"),
349 );
350 r.register(
351 ApiStabilityMarker::stable(
352 "N-Triples Serialization",
353 ApiCategory::DataModel,
354 "0.1.0",
355 "N-Triples parser and writer for simple line-oriented RDF serialization.",
356 )
357 .with_spec("https://www.w3.org/TR/n-triples/"),
358 );
359 r.register(
360 ApiStabilityMarker::stable(
361 "N-Quads Serialization",
362 ApiCategory::DataModel,
363 "0.1.0",
364 "N-Quads parser and writer for quad-based RDF dataset serialization.",
365 )
366 .with_spec("https://www.w3.org/TR/n-quads/"),
367 );
368 r.register(
369 ApiStabilityMarker::stable(
370 "TriG Serialization",
371 ApiCategory::DataModel,
372 "0.1.0",
373 "TriG parser and writer for named graph serialization.",
374 )
375 .with_spec("https://www.w3.org/TR/trig/"),
376 );
377 r.register(
378 ApiStabilityMarker::stable(
379 "RDF/XML Serialization",
380 ApiCategory::DataModel,
381 "0.1.0",
382 "RDF/XML parser and writer for legacy compatibility.",
383 )
384 .with_spec("https://www.w3.org/TR/rdf-syntax-grammar/"),
385 );
386 r.register(
387 ApiStabilityMarker::stable(
388 "JSON-LD 1.1 Serialization",
389 ApiCategory::DataModel,
390 "0.1.0",
391 "JSON-LD 1.1 parser and writer with context expansion and compaction.",
392 )
393 .with_spec("https://www.w3.org/TR/json-ld11/"),
394 );
395 r.register(ApiStabilityMarker::stable(
396 "Named Graphs",
397 ApiCategory::DataModel,
398 "0.1.0",
399 "Full quad store support with named graph CRUD operations and graph management.",
400 ));
401
402 r.register(ApiStabilityMarker::stable("RDFS Inference", ApiCategory::Reasoning, "0.1.0",
404 "RDFS entailment regime including subClassOf, subPropertyOf, domain, range, and transitive closure.")
405 .with_spec("https://www.w3.org/TR/rdf-schema/"));
406 r.register(ApiStabilityMarker::stable("OWL 2 RL Reasoning", ApiCategory::Reasoning, "0.1.0",
407 "OWL 2 RL profile reasoning with forward-chaining rules for description logic reasoning over large datasets.")
408 .with_spec("https://www.w3.org/TR/owl2-profiles/#OWL_2_RL"));
409 r.register(ApiStabilityMarker::stable("OWL 2 EL Reasoning", ApiCategory::Reasoning, "0.1.0",
410 "OWL 2 EL profile reasoning optimized for large biomedical and enterprise ontologies.")
411 .with_spec("https://www.w3.org/TR/owl2-profiles/#OWL_2_EL"));
412 r.register(ApiStabilityMarker::beta("OWL 2 QL Reasoning", ApiCategory::Reasoning, "0.2.0",
413 "OWL 2 QL profile reasoning for query rewriting over relational sources. Conjunctive query rewriting is complete.")
414 .with_spec("https://www.w3.org/TR/owl2-profiles/#OWL_2_QL"));
415 r.register(
416 ApiStabilityMarker::stable(
417 "SWRL Rule Execution",
418 ApiCategory::Reasoning,
419 "0.2.0",
420 "Semantic Web Rule Language (SWRL) rule parsing and forward-chaining execution.",
421 )
422 .with_spec("https://www.w3.org/Submission/SWRL/"),
423 );
424
425 r.register(ApiStabilityMarker::stable("GraphQL API", ApiCategory::GraphQuery, "0.1.0",
427 "Full GraphQL query execution over RDF datasets with automatic schema generation from RDF shapes."));
428 r.register(ApiStabilityMarker::stable("GraphQL Federation", ApiCategory::GraphQuery, "0.2.0",
429 "GraphQL Federation v2 support for composing distributed subgraphs into a unified supergraph."));
430 r.register(ApiStabilityMarker::beta(
431 "GraphQL Subscriptions",
432 ApiCategory::GraphQuery,
433 "0.2.0",
434 "GraphQL subscriptions over WebSocket with change tracking and subscription optimizer.",
435 ));
436 r.register(ApiStabilityMarker::beta("GraphQL Mutations", ApiCategory::GraphQuery, "0.2.0",
437 "GraphQL mutations mapped to SPARQL UPDATE operations for write-through to the RDF store."));
438
439 r.register(ApiStabilityMarker::stable("GeoSPARQL 1.1", ApiCategory::Geospatial, "0.1.0",
441 "GeoSPARQL 1.1 spatial query functions, geometry relations, and WKT/GeoJSON serialization.")
442 .with_spec("https://www.ogc.org/standard/geosparql/"));
443 r.register(ApiStabilityMarker::beta(
444 "GeoSPARQL 3D Geometry",
445 ApiCategory::Geospatial,
446 "0.2.0",
447 "3D geometry support (PolyhedralSurface, MultiSolid) for volumetric spatial queries.",
448 ));
449 r.register(ApiStabilityMarker::beta("GeoSPARQL Coordinate Reference Systems", ApiCategory::Geospatial, "0.2.0",
450 "CRS transformation support for queries involving data in multiple spatial reference systems."));
451 r.register(ApiStabilityMarker::beta(
452 "GeoSPARQL R-Tree Index",
453 ApiCategory::Geospatial,
454 "0.2.0",
455 "R-tree spatial index for accelerating GeoSPARQL geometric relation queries.",
456 ));
457
458 r.register(ApiStabilityMarker::stable("SHACL Validation", ApiCategory::Validation, "0.1.0",
460 "Full SHACL 1.0 constraint validation including cardinality, value type, pattern, and SPARQL constraints.")
461 .with_spec("https://www.w3.org/TR/shacl/"));
462 r.register(ApiStabilityMarker::stable(
463 "SHACL-SPARQL Constraints",
464 ApiCategory::Validation,
465 "0.1.0",
466 "SHACL-SPARQL constraints allowing arbitrary SPARQL-based shape validation.",
467 ));
468 r.register(ApiStabilityMarker::stable("SAMM Aspect Model", ApiCategory::Validation, "0.1.0",
469 "SAMM (Semantic Aspect Meta Model) support for industrial asset modeling and validation."));
470 r.register(ApiStabilityMarker::beta("SHACL-AI Shape Learning", ApiCategory::Validation, "0.2.0",
471 "AI-powered automatic SHACL shape inference from example data using pattern mining and constraint learning."));
472
473 r.register(ApiStabilityMarker::stable("In-Memory RDF Store", ApiCategory::Storage, "0.1.0",
475 "High-performance in-memory RDF store with multi-index support (SPO/POS/OSP) and ACID transactions."));
476 r.register(ApiStabilityMarker::stable("TDB Persistent Storage", ApiCategory::Storage, "0.1.0",
477 "TDB-compatible disk-based RDF storage with B-tree indices, WAL journal, and crash recovery."));
478 r.register(ApiStabilityMarker::stable("RocksDB Backend", ApiCategory::Storage, "0.1.0",
479 "RocksDB-backed persistent storage for high-throughput write workloads with SST compaction."));
480 r.register(ApiStabilityMarker::beta("Distributed Cluster Storage", ApiCategory::Storage, "0.2.0",
481 "Raft-based distributed storage cluster with automatic sharding, replication, and leader election."));
482 r.register(ApiStabilityMarker::beta("Full-Text Search Index", ApiCategory::Storage, "0.2.0",
483 "Tantivy-powered full-text search index for literal values with BM25 ranking and language filtering."));
484 r.register(ApiStabilityMarker::beta("Temporal RDF Storage", ApiCategory::Storage, "0.2.0",
485 "Versioned triple storage with time-travel queries, changelog, and bitemporal data support."));
486
487 r.register(ApiStabilityMarker::beta("RDF Streaming Processing", ApiCategory::Streaming, "0.1.0",
489 "Real-time RDF stream processing with windowed aggregations and complex event patterns."));
490 r.register(ApiStabilityMarker::beta("Kafka Integration", ApiCategory::Streaming, "0.1.0",
491 "Apache Kafka consumer/producer integration for ingesting RDF triples from event streams."));
492 r.register(ApiStabilityMarker::beta(
493 "NATS Integration",
494 ApiCategory::Streaming,
495 "0.1.0",
496 "NATS.io message broker integration for lightweight RDF event streaming.",
497 ));
498 r.register(ApiStabilityMarker::beta("Federated SPARQL Query", ApiCategory::Federation, "0.2.0",
499 "Distributed SPARQL query execution across multiple OxiRS endpoints with cost-based join reordering."));
500 r.register(ApiStabilityMarker::beta("Stream Fault Tolerance", ApiCategory::Streaming, "0.2.0",
501 "Bulkhead isolation, supervisor trees, and checkpoint recovery for streaming pipeline resilience."));
502
503 r.register(ApiStabilityMarker::beta("Modbus TCP/RTU", ApiCategory::Industrial, "0.1.0",
505 "Modbus TCP and RTU protocol client with RDF mapping for industrial sensor data ingestion."));
506 r.register(ApiStabilityMarker::beta(
507 "Modbus ASCII Protocol",
508 ApiCategory::Industrial,
509 "0.2.0",
510 "Modbus ASCII framing with LRC checksum for legacy industrial device connectivity.",
511 ));
512 r.register(ApiStabilityMarker::beta(
513 "Modbus TLS Client",
514 ApiCategory::Industrial,
515 "0.2.0",
516 "Modbus Secure (TLS over IANA port 802) for encrypted industrial communications.",
517 ));
518 r.register(ApiStabilityMarker::beta("CANbus/J1939 Integration", ApiCategory::Industrial, "0.1.0",
519 "CANbus and J1939 protocol support with automatic RDF triple generation from CAN frames."));
520 r.register(ApiStabilityMarker::beta("UDS ISO 14229 Diagnostics", ApiCategory::Industrial, "0.2.0",
521 "Unified Diagnostic Services (ISO 14229) protocol client for automotive ECU diagnostics."));
522 r.register(ApiStabilityMarker::beta(
523 "CANopen DS-301",
524 ApiCategory::Industrial,
525 "0.2.0",
526 "CANopen DS-301 protocol support with NMT, SDO, PDO, and object dictionary management.",
527 ));
528
529 r.register(ApiStabilityMarker::beta("Vector Similarity Search", ApiCategory::ArtificialIntelligence, "0.1.0",
531 "HNSW-based approximate nearest neighbour search for semantic similarity queries over RDF entity embeddings."));
532 r.register(ApiStabilityMarker::beta("Knowledge Graph Embeddings", ApiCategory::ArtificialIntelligence, "0.1.0",
533 "TransE, DistMult, ComplEx, and RotatE knowledge graph embedding models for entity and relation representation."));
534 r.register(ApiStabilityMarker::beta("GraphRAG Retrieval", ApiCategory::ArtificialIntelligence, "0.2.0",
535 "Graph-Retrieval-Augmented Generation (GraphRAG) combining SPARQL traversal with LLM reasoning for QA."));
536 r.register(ApiStabilityMarker::beta("Graph Neural Networks", ApiCategory::ArtificialIntelligence, "0.2.0",
537 "GraphSAGE and Graph Attention Network (GAT) implementations for inductive knowledge graph representation learning."));
538 r.register(ApiStabilityMarker::beta("Conversational AI (RAG Chat)", ApiCategory::ArtificialIntelligence, "0.1.0",
539 "Multi-turn conversational AI with retrieval-augmented generation over RDF knowledge graphs."));
540 r.register(ApiStabilityMarker::experimental("Physics Simulation", ApiCategory::PhysicsSimulation, "0.2.0",
541 "RDF-backed physics simulation with digital twin support (DTDL v2), conservation laws, and predictive maintenance."));
542 r.register(ApiStabilityMarker::experimental(
543 "Digital Twin Framework",
544 ApiCategory::PhysicsSimulation,
545 "0.2.0",
546 "DTDL v2 digital twin modeling with synchronisation reports and RDF integration.",
547 ));
548 r.register(ApiStabilityMarker::experimental("Predictive Maintenance", ApiCategory::PhysicsSimulation, "0.2.0",
549 "ML-based predictive maintenance using anomaly detection and remaining useful life estimation."));
550
551 r.register(ApiStabilityMarker::beta("Time-Series Database", ApiCategory::TimeSeries, "0.1.0",
553 "High-performance time-series storage with columnar compression, range queries, and downsampling."));
554 r.register(ApiStabilityMarker::beta("Anomaly Detection", ApiCategory::TimeSeries, "0.2.0",
555 "Statistical anomaly detection using Z-score, IQR, EWMA, and Isolation Forest algorithms."));
556 r.register(ApiStabilityMarker::beta(
557 "Time-Series Forecasting",
558 ApiCategory::TimeSeries,
559 "0.2.0",
560 "Holt-Winters exponential smoothing for time-series forecasting and trend analysis.",
561 ));
562 r.register(ApiStabilityMarker::beta("Prometheus Remote Write", ApiCategory::TimeSeries, "0.2.0",
563 "Prometheus remote write protocol support for ingesting metrics into OxiRS time-series storage."));
564
565 r.register(ApiStabilityMarker::beta("DID (Decentralised Identifiers)", ApiCategory::Security, "0.2.0",
567 "W3C Decentralised Identifier support (did:key, did:web, did:ion, did:pkh, did:ethr) with key management.")
568 .with_spec("https://www.w3.org/TR/did-core/"));
569 r.register(ApiStabilityMarker::beta("W3C Verifiable Credentials", ApiCategory::Security, "0.2.0",
570 "W3C Verifiable Credentials Data Model 2.0 with JSON-LD proof signatures and verification.")
571 .with_spec("https://www.w3.org/TR/vc-data-model-2.0/"));
572 r.register(ApiStabilityMarker::experimental(
573 "Zero-Knowledge Proofs",
574 ApiCategory::Security,
575 "0.2.0",
576 "ZKP-based credential presentations for privacy-preserving identity verification.",
577 ));
578 r.register(ApiStabilityMarker::experimental(
579 "DID Key Rotation",
580 ApiCategory::Security,
581 "0.2.0",
582 "Automated cryptographic key rotation with DID document update propagation.",
583 ));
584
585 r.register(ApiStabilityMarker::stable("SPARQL 1.1 HTTP Protocol", ApiCategory::Server, "0.1.0",
587 "W3C SPARQL 1.1 HTTP protocol endpoint with GET and POST query support, content negotiation, and streaming results.")
588 .with_spec("https://www.w3.org/TR/sparql11-protocol/"));
589 r.register(ApiStabilityMarker::stable("Fuseki-Compatible REST API", ApiCategory::Server, "0.1.0",
590 "Apache Jena Fuseki-compatible REST API for dataset management, upload, and administration."));
591 r.register(ApiStabilityMarker::stable("GraphQL HTTP Server", ApiCategory::Server, "0.1.0",
592 "GraphQL-over-HTTP server with multipart upload, introspection, and schema-first API design."));
593 r.register(ApiStabilityMarker::beta(
594 "Multi-tenancy",
595 ApiCategory::Server,
596 "0.2.0",
597 "Dataset-level multi-tenancy with isolated namespaces and per-tenant resource quotas.",
598 ));
599
600 r.register(ApiStabilityMarker::beta(
602 "WASM RDF Store",
603 ApiCategory::WebAssembly,
604 "0.2.0",
605 "Full OxiRS RDF store compiled to WebAssembly for in-browser and edge deployment.",
606 ));
607 r.register(ApiStabilityMarker::beta(
608 "WASM SPARQL Engine",
609 ApiCategory::WebAssembly,
610 "0.2.0",
611 "SPARQL query execution in WebAssembly with zero native dependencies.",
612 ));
613 r.register(ApiStabilityMarker::beta("WASM SPARQL UPDATE", ApiCategory::WebAssembly, "0.2.0",
614 "SPARQL UPDATE operations available in the WASM build for client-side data modification."));
615
616 r.register(ApiStabilityMarker::experimental("Quantum Graph Optimization", ApiCategory::Quantum, "0.2.0",
618 "Quantum-inspired optimization algorithms for SPARQL query planning over large knowledge graphs."));
619 r.register(ApiStabilityMarker::experimental("Quantum SPARQL Sampling", ApiCategory::Quantum, "0.2.0",
620 "Quantum amplitude estimation for approximate SPARQL aggregate queries on large datasets."));
621
622 r.register(ApiStabilityMarker::stable("OxiRS CLI Tool", ApiCategory::Tooling, "0.1.0",
624 "Command-line interface for SPARQL queries, dataset management, benchmarking, and graph analytics."));
625 r.register(ApiStabilityMarker::stable("SPARQL Query Profiler", ApiCategory::Tooling, "0.2.0",
626 "Query execution profiler with operator-level timing, memory usage, and optimization suggestions."));
627 r.register(ApiStabilityMarker::beta("Jena Parity Checker", ApiCategory::Tooling, "0.2.0",
628 "Automated verification tool comparing OxiRS feature coverage against Apache Jena baseline."));
629 r.register(ApiStabilityMarker::beta("API Stability Report", ApiCategory::Tooling, "0.2.0",
630 "Automated API stability report generation tracking stability commitments across OxiRS releases."));
631
632 r
633 }
634
635 pub fn all_apis(&self) -> &[ApiStabilityMarker] {
637 &self.markers
638 }
639
640 pub fn stable_apis(&self) -> Vec<&ApiStabilityMarker> {
642 self.markers.iter().filter(|m| m.is_stable()).collect()
643 }
644
645 pub fn beta_apis(&self) -> Vec<&ApiStabilityMarker> {
647 self.markers.iter().filter(|m| m.is_beta()).collect()
648 }
649
650 pub fn experimental_apis(&self) -> Vec<&ApiStabilityMarker> {
652 self.markers
653 .iter()
654 .filter(|m| m.is_experimental())
655 .collect()
656 }
657
658 pub fn deprecated_apis(&self) -> Vec<&ApiStabilityMarker> {
660 self.markers.iter().filter(|m| m.is_deprecated()).collect()
661 }
662
663 pub fn apis_by_category(&self, category: &ApiCategory) -> Vec<&ApiStabilityMarker> {
665 self.markers
666 .iter()
667 .filter(|m| &m.category == category)
668 .collect()
669 }
670
671 pub fn production_ready_apis(&self) -> Vec<&ApiStabilityMarker> {
673 self.markers
674 .iter()
675 .filter(|m| m.level.is_production_ready())
676 .collect()
677 }
678
679 pub fn summary(&self) -> RegistrySummary {
681 RegistrySummary {
682 total: self.markers.len(),
683 stable_count: self.stable_apis().len(),
684 beta_count: self.beta_apis().len(),
685 experimental_count: self.experimental_apis().len(),
686 deprecated_count: self.deprecated_apis().len(),
687 }
688 }
689
690 pub fn generate_report(&self) -> String {
692 let summary = self.summary();
693 let mut report = String::with_capacity(8192);
694
695 report.push_str("# OxiRS API Stability Report\n\n");
696 report.push_str("> Auto-generated from the OxiRS StabilityRegistry.\n\n");
697 report.push_str("## Summary\n\n");
698 report.push_str("| Metric | Value |\n|--------|-------|\n");
699 report.push_str(&format!("| Total APIs tracked | {} |\n", summary.total));
700 report.push_str(&format!(
701 "| Stable | {} ({:.0}%) |\n",
702 summary.stable_count,
703 summary.stable_percentage()
704 ));
705 report.push_str(&format!("| Beta | {} |\n", summary.beta_count));
706 report.push_str(&format!(
707 "| Experimental | {} |\n",
708 summary.experimental_count
709 ));
710 report.push_str(&format!("| Deprecated | {} |\n", summary.deprecated_count));
711 report.push_str(&format!(
712 "| Production-ready (Stable+Beta) | {} ({:.0}%) |\n\n",
713 summary.stable_count + summary.beta_count,
714 (summary.stable_count + summary.beta_count) as f64 / summary.total.max(1) as f64
715 * 100.0
716 ));
717
718 let categories = [
719 ApiCategory::QueryLanguage,
720 ApiCategory::DataModel,
721 ApiCategory::RdfStar,
722 ApiCategory::Reasoning,
723 ApiCategory::GraphQuery,
724 ApiCategory::Geospatial,
725 ApiCategory::Validation,
726 ApiCategory::Storage,
727 ApiCategory::Streaming,
728 ApiCategory::Federation,
729 ApiCategory::Industrial,
730 ApiCategory::ArtificialIntelligence,
731 ApiCategory::TimeSeries,
732 ApiCategory::PhysicsSimulation,
733 ApiCategory::Security,
734 ApiCategory::Server,
735 ApiCategory::WebAssembly,
736 ApiCategory::Quantum,
737 ApiCategory::Tooling,
738 ];
739
740 report.push_str("## API Details by Category\n\n");
741 for category in &categories {
742 let apis = self.apis_by_category(category);
743 if apis.is_empty() {
744 continue;
745 }
746 report.push_str(&format!("### {}\n\n", category.label()));
747 report.push_str("| Feature | Status | Since | Description |\n");
748 report.push_str("|---------|--------|-------|-------------|\n");
749 for api in &apis {
750 let desc = if api.description.len() > 80 {
751 format!("{}...", &api.description[..77])
752 } else {
753 api.description.to_string()
754 };
755 report.push_str(&format!(
756 "| {} | {} | {} | {} |\n",
757 api.feature,
758 api.level.indicator(),
759 api.since,
760 desc
761 ));
762 }
763 report.push('\n');
764 }
765
766 report.push_str("## Stability Level Definitions\n\n");
767 report.push_str("| Level | Guarantee |\n|-------|----------|\n");
768 report.push_str("| [STABLE] | Backward compatible throughout 1.x.y |\n");
769 report.push_str("| [BETA] | Stable but may change in minor releases |\n");
770 report.push_str("| [EXPERIMENTAL] | May change or be removed in any release |\n");
771 report.push_str("| [DEPRECATED] | Scheduled for removal in next major version |\n");
772
773 report
774 }
775
776 pub fn validate(&self) -> Vec<String> {
778 let mut errors = Vec::new();
779 for (i, marker) in self.markers.iter().enumerate() {
780 if marker.feature.is_empty() {
781 errors.push(format!("Marker #{i}: feature name is empty"));
782 }
783 if marker.description.is_empty() {
784 errors.push(format!(
785 "Marker #{}: '{}' has empty description",
786 i, marker.feature
787 ));
788 }
789 if marker.since.is_empty() {
790 errors.push(format!(
791 "Marker #{}: '{}' has empty 'since' version",
792 i, marker.feature
793 ));
794 }
795 }
796 errors
797 }
798}
799
800impl Default for StabilityRegistry {
801 fn default() -> Self {
802 Self::new()
803 }
804}
805
806#[cfg(test)]
807mod tests {
808 use super::*;
809 use std::collections::HashSet;
810
811 fn registry() -> StabilityRegistry {
812 StabilityRegistry::oxirs_v1_stability()
813 }
814
815 #[test]
816 fn test_registry_is_non_empty() {
817 assert!(!registry().all_apis().is_empty());
818 }
819
820 #[test]
821 fn test_registry_has_minimum_api_count() {
822 assert!(
823 registry().all_apis().len() >= 40,
824 "Registry should track at least 40 APIs"
825 );
826 }
827
828 #[test]
829 fn test_registry_validates_cleanly() {
830 let errors = registry().validate();
831 assert!(errors.is_empty(), "Validation errors: {:?}", errors);
832 }
833
834 #[test]
835 fn test_stable_apis_non_empty() {
836 assert!(!registry().stable_apis().is_empty());
837 }
838
839 #[test]
840 fn test_beta_apis_non_empty() {
841 assert!(!registry().beta_apis().is_empty());
842 }
843
844 #[test]
845 fn test_experimental_apis_non_empty() {
846 assert!(!registry().experimental_apis().is_empty());
847 }
848
849 #[test]
850 fn test_deprecated_apis_empty_by_default() {
851 assert!(registry().deprecated_apis().is_empty());
852 }
853
854 #[test]
855 fn test_stable_apis_are_all_stable() {
856 for api in registry().stable_apis() {
857 assert!(
858 matches!(api.level, StabilityLevel::Stable),
859 "{} should be Stable",
860 api.feature
861 );
862 }
863 }
864
865 #[test]
866 fn test_beta_apis_are_all_beta() {
867 for api in registry().beta_apis() {
868 assert!(
869 matches!(api.level, StabilityLevel::Beta),
870 "{} should be Beta",
871 api.feature
872 );
873 }
874 }
875
876 #[test]
877 fn test_experimental_apis_are_all_experimental() {
878 for api in registry().experimental_apis() {
879 assert!(
880 matches!(api.level, StabilityLevel::Experimental),
881 "{} should be Experimental",
882 api.feature
883 );
884 }
885 }
886
887 #[test]
888 fn test_counts_sum_to_total() {
889 let reg = registry();
890 let s = reg.summary();
891 assert_eq!(
892 s.stable_count + s.beta_count + s.experimental_count + s.deprecated_count,
893 s.total
894 );
895 }
896
897 #[test]
898 fn test_query_language_apis_exist() {
899 assert!(!registry()
900 .apis_by_category(&ApiCategory::QueryLanguage)
901 .is_empty());
902 }
903
904 #[test]
905 fn test_data_model_apis_exist() {
906 assert!(!registry()
907 .apis_by_category(&ApiCategory::DataModel)
908 .is_empty());
909 }
910
911 #[test]
912 fn test_reasoning_apis_exist() {
913 assert!(!registry()
914 .apis_by_category(&ApiCategory::Reasoning)
915 .is_empty());
916 }
917
918 #[test]
919 fn test_ai_apis_exist() {
920 assert!(!registry()
921 .apis_by_category(&ApiCategory::ArtificialIntelligence)
922 .is_empty());
923 }
924
925 #[test]
926 fn test_security_apis_exist() {
927 assert!(!registry()
928 .apis_by_category(&ApiCategory::Security)
929 .is_empty());
930 }
931
932 #[test]
933 fn test_tooling_apis_exist() {
934 assert!(!registry()
935 .apis_by_category(&ApiCategory::Tooling)
936 .is_empty());
937 }
938
939 #[test]
940 fn test_geospatial_apis_exist() {
941 assert!(!registry()
942 .apis_by_category(&ApiCategory::Geospatial)
943 .is_empty());
944 }
945
946 #[test]
947 fn test_storage_apis_exist() {
948 assert!(!registry()
949 .apis_by_category(&ApiCategory::Storage)
950 .is_empty());
951 }
952
953 #[test]
954 fn test_streaming_apis_exist() {
955 assert!(!registry()
956 .apis_by_category(&ApiCategory::Streaming)
957 .is_empty());
958 }
959
960 #[test]
961 fn test_industrial_apis_exist() {
962 assert!(!registry()
963 .apis_by_category(&ApiCategory::Industrial)
964 .is_empty());
965 }
966
967 #[test]
968 fn test_server_apis_exist() {
969 assert!(!registry().apis_by_category(&ApiCategory::Server).is_empty());
970 }
971
972 #[test]
973 fn test_wasm_apis_exist() {
974 assert!(!registry()
975 .apis_by_category(&ApiCategory::WebAssembly)
976 .is_empty());
977 }
978
979 #[test]
980 fn test_quantum_apis_exist() {
981 assert!(!registry()
982 .apis_by_category(&ApiCategory::Quantum)
983 .is_empty());
984 }
985
986 #[test]
987 fn test_time_series_apis_exist() {
988 assert!(!registry()
989 .apis_by_category(&ApiCategory::TimeSeries)
990 .is_empty());
991 }
992
993 #[test]
994 fn test_physics_apis_exist() {
995 assert!(!registry()
996 .apis_by_category(&ApiCategory::PhysicsSimulation)
997 .is_empty());
998 }
999
1000 #[test]
1001 fn test_rdf_star_apis_exist() {
1002 assert!(!registry()
1003 .apis_by_category(&ApiCategory::RdfStar)
1004 .is_empty());
1005 }
1006
1007 #[test]
1008 fn test_federation_apis_exist() {
1009 assert!(!registry()
1010 .apis_by_category(&ApiCategory::Federation)
1011 .is_empty());
1012 }
1013
1014 #[test]
1015 fn test_sparql_11_select_is_stable() {
1016 let reg = registry();
1017 let api = reg
1018 .all_apis()
1019 .iter()
1020 .find(|m| m.feature == "SPARQL 1.1 SELECT");
1021 assert!(api.is_some(), "SPARQL 1.1 SELECT should be registered");
1022 assert!(api.expect("API should be registered").is_stable());
1023 }
1024
1025 #[test]
1026 fn test_rdf_data_model_is_stable() {
1027 let reg = registry();
1028 let api = reg
1029 .all_apis()
1030 .iter()
1031 .find(|m| m.feature == "RDF 1.2 Data Model");
1032 assert!(api.is_some());
1033 assert!(api.expect("API should be registered").is_stable());
1034 }
1035
1036 #[test]
1037 fn test_graphql_api_is_stable() {
1038 let reg = registry();
1039 let api = reg.all_apis().iter().find(|m| m.feature == "GraphQL API");
1040 assert!(api.is_some());
1041 assert!(api.expect("API should be registered").is_stable());
1042 }
1043
1044 #[test]
1045 fn test_geosparql_is_stable() {
1046 let reg = registry();
1047 let api = reg.all_apis().iter().find(|m| m.feature == "GeoSPARQL 1.1");
1048 assert!(api.is_some());
1049 assert!(api.expect("API should be registered").is_stable());
1050 }
1051
1052 #[test]
1053 fn test_shacl_is_stable() {
1054 let reg = registry();
1055 let api = reg
1056 .all_apis()
1057 .iter()
1058 .find(|m| m.feature == "SHACL Validation");
1059 assert!(api.is_some());
1060 assert!(api.expect("API should be registered").is_stable());
1061 }
1062
1063 #[test]
1064 fn test_time_series_db_is_beta() {
1065 let reg = registry();
1066 let api = reg
1067 .all_apis()
1068 .iter()
1069 .find(|m| m.feature == "Time-Series Database");
1070 assert!(api.is_some());
1071 assert!(api.expect("API should be registered").is_beta());
1072 }
1073
1074 #[test]
1075 fn test_graphrag_is_beta() {
1076 let reg = registry();
1077 let api = reg
1078 .all_apis()
1079 .iter()
1080 .find(|m| m.feature == "GraphRAG Retrieval");
1081 assert!(api.is_some());
1082 assert!(api.expect("API should be registered").is_beta());
1083 }
1084
1085 #[test]
1086 fn test_physics_simulation_is_experimental() {
1087 let reg = registry();
1088 let api = reg
1089 .all_apis()
1090 .iter()
1091 .find(|m| m.feature == "Physics Simulation");
1092 assert!(api.is_some());
1093 assert!(api.expect("API should be registered").is_experimental());
1094 }
1095
1096 #[test]
1097 fn test_quantum_is_experimental() {
1098 let reg = registry();
1099 let api = reg
1100 .all_apis()
1101 .iter()
1102 .find(|m| m.feature == "Quantum Graph Optimization");
1103 assert!(api.is_some());
1104 assert!(api.expect("API should be registered").is_experimental());
1105 }
1106
1107 #[test]
1108 fn test_stable_percentage_in_range() {
1109 let s = registry().summary();
1110 assert!(s.stable_percentage() > 0.0 && s.stable_percentage() <= 100.0);
1111 }
1112
1113 #[test]
1114 fn test_production_ready_percentage_in_range() {
1115 let s = registry().summary();
1116 assert!(s.production_ready_percentage() > 0.0 && s.production_ready_percentage() <= 100.0);
1117 }
1118
1119 #[test]
1120 fn test_production_ready_ge_stable_percentage() {
1121 let s = registry().summary();
1122 assert!(s.production_ready_percentage() >= s.stable_percentage());
1123 }
1124
1125 #[test]
1126 fn test_generate_report_non_empty() {
1127 assert!(!registry().generate_report().is_empty());
1128 }
1129
1130 #[test]
1131 fn test_report_contains_summary_header() {
1132 assert!(registry().generate_report().contains("## Summary"));
1133 }
1134
1135 #[test]
1136 fn test_report_contains_stable_indicator() {
1137 assert!(registry().generate_report().contains("[STABLE]"));
1138 }
1139
1140 #[test]
1141 fn test_report_contains_beta_indicator() {
1142 assert!(registry().generate_report().contains("[BETA]"));
1143 }
1144
1145 #[test]
1146 fn test_report_contains_experimental_indicator() {
1147 assert!(registry().generate_report().contains("[EXPERIMENTAL]"));
1148 }
1149
1150 #[test]
1151 fn test_report_contains_api_details_header() {
1152 assert!(registry()
1153 .generate_report()
1154 .contains("## API Details by Category"));
1155 }
1156
1157 #[test]
1158 fn test_report_contains_sparql_select() {
1159 assert!(registry().generate_report().contains("SPARQL 1.1 SELECT"));
1160 }
1161
1162 #[test]
1163 fn test_stable_is_production_ready() {
1164 assert!(StabilityLevel::Stable.is_production_ready());
1165 }
1166
1167 #[test]
1168 fn test_beta_is_production_ready() {
1169 assert!(StabilityLevel::Beta.is_production_ready());
1170 }
1171
1172 #[test]
1173 fn test_experimental_is_not_production_ready() {
1174 assert!(!StabilityLevel::Experimental.is_production_ready());
1175 }
1176
1177 #[test]
1178 fn test_deprecated_is_production_ready() {
1179 let dep = StabilityLevel::Deprecated {
1180 since: "0.9.0",
1181 replacement: None,
1182 };
1183 assert!(dep.is_production_ready());
1184 }
1185
1186 #[test]
1187 fn test_stability_labels() {
1188 assert_eq!(StabilityLevel::Stable.label(), "Stable");
1189 assert_eq!(StabilityLevel::Beta.label(), "Beta");
1190 assert_eq!(StabilityLevel::Experimental.label(), "Experimental");
1191 let dep = StabilityLevel::Deprecated {
1192 since: "0.9.0",
1193 replacement: None,
1194 };
1195 assert_eq!(dep.label(), "Deprecated");
1196 }
1197
1198 #[test]
1199 fn test_stability_indicators() {
1200 assert_eq!(StabilityLevel::Stable.indicator(), "[STABLE]");
1201 assert_eq!(StabilityLevel::Beta.indicator(), "[BETA]");
1202 assert_eq!(StabilityLevel::Experimental.indicator(), "[EXPERIMENTAL]");
1203 let dep = StabilityLevel::Deprecated {
1204 since: "0.9.0",
1205 replacement: None,
1206 };
1207 assert_eq!(dep.indicator(), "[DEPRECATED]");
1208 }
1209
1210 #[test]
1211 fn test_marker_stable_builder() {
1212 let m = ApiStabilityMarker::stable("Test API", ApiCategory::Tooling, "1.0.0", "A test API");
1213 assert!(m.is_stable());
1214 assert_eq!(m.feature, "Test API");
1215 assert!(m.spec_url.is_none());
1216 }
1217
1218 #[test]
1219 fn test_marker_with_spec_url() {
1220 let m = ApiStabilityMarker::stable("Spec API", ApiCategory::QueryLanguage, "1.0.0", "desc")
1221 .with_spec("https://example.org/spec");
1222 assert_eq!(m.spec_url, Some("https://example.org/spec"));
1223 }
1224
1225 #[test]
1226 fn test_marker_beta_builder() {
1227 let m = ApiStabilityMarker::beta("Beta Feature", ApiCategory::Streaming, "0.5.0", "desc");
1228 assert!(m.is_beta());
1229 assert!(!m.is_stable());
1230 }
1231
1232 #[test]
1233 fn test_marker_experimental_builder() {
1234 let m =
1235 ApiStabilityMarker::experimental("Exp Feature", ApiCategory::Quantum, "0.9.0", "desc");
1236 assert!(m.is_experimental());
1237 assert!(!m.is_beta());
1238 }
1239
1240 #[test]
1241 fn test_marker_deprecated_builder() {
1242 let m = ApiStabilityMarker::deprecated(
1243 "Old Feature",
1244 ApiCategory::Tooling,
1245 "0.1.0",
1246 "0.9.0",
1247 Some("New Feature"),
1248 "desc",
1249 );
1250 assert!(m.is_deprecated());
1251 if let StabilityLevel::Deprecated { since, replacement } = &m.level {
1252 assert_eq!(*since, "0.9.0");
1253 assert_eq!(*replacement, Some("New Feature"));
1254 }
1255 }
1256
1257 #[test]
1258 fn test_feature_names_are_unique() {
1259 let reg = registry();
1260 let mut seen = HashSet::new();
1261 for api in reg.all_apis() {
1262 assert!(
1263 seen.insert(api.feature),
1264 "Duplicate feature name: '{}'",
1265 api.feature
1266 );
1267 }
1268 }
1269
1270 #[test]
1271 fn test_production_ready_apis_non_empty() {
1272 assert!(!registry().production_ready_apis().is_empty());
1273 }
1274
1275 #[test]
1276 fn test_production_ready_count_matches_summary() {
1277 let reg = registry();
1278 let s = reg.summary();
1279 let actual = reg.production_ready_apis().len();
1280 assert_eq!(actual, s.stable_count + s.beta_count + s.deprecated_count);
1281 }
1282
1283 #[test]
1284 fn test_default_registry_is_empty() {
1285 let reg = StabilityRegistry::default();
1286 assert_eq!(reg.all_apis().len(), 0);
1287 }
1288
1289 #[test]
1290 fn test_register_and_retrieve() {
1291 let mut reg = StabilityRegistry::new();
1292 reg.register(ApiStabilityMarker::stable(
1293 "Custom API",
1294 ApiCategory::Tooling,
1295 "1.0.0",
1296 "Custom",
1297 ));
1298 assert_eq!(reg.all_apis().len(), 1);
1299 assert_eq!(reg.stable_apis().len(), 1);
1300 }
1301
1302 #[test]
1303 fn test_all_markers_have_valid_since_version() {
1304 for api in registry().all_apis() {
1305 assert!(
1306 api.since.starts_with('0') || api.since.starts_with('1'),
1307 "'{}' has invalid since version: '{}'",
1308 api.feature,
1309 api.since
1310 );
1311 }
1312 }
1313
1314 #[test]
1315 fn test_stable_sparql_update_exists() {
1316 let reg = registry();
1317 let api = reg
1318 .all_apis()
1319 .iter()
1320 .find(|m| m.feature == "SPARQL 1.1 Update");
1321 assert!(api.is_some());
1322 assert!(api.expect("API should be registered").is_stable());
1323 }
1324
1325 #[test]
1326 fn test_owl2_rl_is_stable() {
1327 let reg = registry();
1328 let api = reg
1329 .all_apis()
1330 .iter()
1331 .find(|m| m.feature == "OWL 2 RL Reasoning");
1332 assert!(api.is_some());
1333 assert!(api.expect("API should be registered").is_stable());
1334 }
1335
1336 #[test]
1337 fn test_owl2_ql_is_beta() {
1338 let reg = registry();
1339 let api = reg
1340 .all_apis()
1341 .iter()
1342 .find(|m| m.feature == "OWL 2 QL Reasoning");
1343 assert!(api.is_some());
1344 assert!(api.expect("API should be registered").is_beta());
1345 }
1346
1347 #[test]
1348 fn test_category_label_non_empty() {
1349 let categories = [
1350 ApiCategory::QueryLanguage,
1351 ApiCategory::DataModel,
1352 ApiCategory::Reasoning,
1353 ApiCategory::GraphQuery,
1354 ApiCategory::Geospatial,
1355 ApiCategory::Validation,
1356 ApiCategory::Storage,
1357 ApiCategory::Streaming,
1358 ApiCategory::Industrial,
1359 ApiCategory::ArtificialIntelligence,
1360 ApiCategory::Security,
1361 ApiCategory::RdfStar,
1362 ApiCategory::Federation,
1363 ApiCategory::Server,
1364 ApiCategory::WebAssembly,
1365 ApiCategory::TimeSeries,
1366 ApiCategory::PhysicsSimulation,
1367 ApiCategory::Quantum,
1368 ApiCategory::Tooling,
1369 ];
1370 for cat in &categories {
1371 assert!(
1372 !cat.label().is_empty(),
1373 "Category label should not be empty"
1374 );
1375 }
1376 }
1377
1378 #[test]
1379 fn test_zkp_is_experimental() {
1380 let reg = registry();
1381 let api = reg
1382 .all_apis()
1383 .iter()
1384 .find(|m| m.feature == "Zero-Knowledge Proofs");
1385 assert!(api.is_some());
1386 assert!(api.expect("API should be registered").is_experimental());
1387 }
1388
1389 #[test]
1390 fn test_did_is_beta() {
1391 let reg = registry();
1392 let api = reg
1393 .all_apis()
1394 .iter()
1395 .find(|m| m.feature == "DID (Decentralised Identifiers)");
1396 assert!(api.is_some());
1397 assert!(api.expect("API should be registered").is_beta());
1398 }
1399
1400 #[test]
1401 fn test_turtle_serialization_has_spec_url() {
1402 let reg = registry();
1403 let api = reg
1404 .all_apis()
1405 .iter()
1406 .find(|m| m.feature == "Turtle Serialization");
1407 assert!(api.is_some());
1408 assert!(api.expect("API should be registered").spec_url.is_some());
1409 }
1410
1411 #[test]
1412 fn test_report_contains_stability_level_defs() {
1413 let report = registry().generate_report();
1414 assert!(report.contains("Stability Level Definitions"));
1415 }
1416}