@@ -314,6 +314,154 @@ pub static BANK_KEY: LazyLock<RoleKey> = LazyLock::new(|| RoleKey::generate
314314pub static FIBU_KEY : LazyLock < RoleKey > = LazyLock :: new ( || RoleKey :: generate ( "smb.fibu" , 13_072 , 13_584 ) ) ;
315315pub static STEUER_KEY : LazyLock < RoleKey > = LazyLock :: new ( || RoleKey :: generate ( "smb.steuer" , 13_584 , 14_096 ) ) ;
316316
317+ // ---------------------------------------------------------------------------
318+ // D6 — RoleKeySlice catalogue (const-addressable [start:stop) slices + FNV-64
319+ // fingerprint over the role label). This layer is the **catalogue index** for
320+ // the live `RoleKey` static instances above: same boundaries, no duplication
321+ // of the bipolar payload — just `Copy`/`const`-friendly descriptors that can
322+ // be embedded in tables, dispatch maps, or codecs without taking a LazyLock.
323+ //
324+ // `RoleKeySlice::fnv_seed` is the FNV-64 of the canonical label string and
325+ // can be used as a stable per-role identifier (e.g. unbinding lookup, codec
326+ // keying). All slices are sub-ranges of the existing 16,384-dim VSA space.
327+ // ---------------------------------------------------------------------------
328+
329+ /// A role key descriptor: a contiguous `[start:stop)` slice of the VSA space
330+ /// plus a deterministic FNV-64 fingerprint over the role's canonical label
331+ /// (used for unbinding / similarity / codec keying).
332+ ///
333+ /// This is the `Copy`/`const`-friendly companion to [`RoleKey`]; both share
334+ /// the same slice boundaries by construction (see `role_key_slice_*` tests).
335+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
336+ pub struct RoleKeySlice {
337+ pub start : usize ,
338+ pub stop : usize ,
339+ pub fnv_seed : u64 ,
340+ }
341+
342+ impl RoleKeySlice {
343+ /// Construct a const slice. `start <= stop <= VSA_DIMS` is the caller's
344+ /// invariant (debug-checked at first use, not in this `const fn` body).
345+ pub const fn new ( start : usize , stop : usize , fnv_seed : u64 ) -> Self {
346+ Self { start, stop, fnv_seed }
347+ }
348+ pub const fn len ( & self ) -> usize { self . stop - self . start }
349+ pub const fn is_empty ( & self ) -> bool { self . start == self . stop }
350+ pub const fn range ( & self ) -> std:: ops:: Range < usize > { self . start ..self . stop }
351+ }
352+
353+ /// Hand-rolled FNV-64a over raw bytes. `const fn` so role-key tables can
354+ /// be evaluated at compile time. No new deps.
355+ pub const fn fnv64_bytes ( bytes : & [ u8 ] ) -> u64 {
356+ let mut hash: u64 = 0xcbf29ce484222325 ;
357+ let mut i = 0 ;
358+ while i < bytes. len ( ) {
359+ hash ^= bytes[ i] as u64 ;
360+ hash = hash. wrapping_mul ( 0x100000001b3 ) ;
361+ i += 1 ;
362+ }
363+ hash
364+ }
365+
366+ // --- SPO core role slices (mirror of SUBJECT_KEY..CONTEXT_KEY) --------------
367+
368+ pub const SUBJECT_SLICE : RoleKeySlice = RoleKeySlice :: new ( 0 , 2000 , fnv64_bytes ( b"SUBJECT" ) ) ;
369+ pub const PREDICATE_SLICE : RoleKeySlice = RoleKeySlice :: new ( 2000 , 4000 , fnv64_bytes ( b"PREDICATE" ) ) ;
370+ pub const OBJECT_SLICE : RoleKeySlice = RoleKeySlice :: new ( 4000 , 6000 , fnv64_bytes ( b"OBJECT" ) ) ;
371+ pub const MODIFIER_SLICE : RoleKeySlice = RoleKeySlice :: new ( 6000 , 7500 , fnv64_bytes ( b"MODIFIER" ) ) ;
372+ pub const CONTEXT_SLICE : RoleKeySlice = RoleKeySlice :: new ( 7500 , 9000 , fnv64_bytes ( b"CONTEXT" ) ) ;
373+
374+ // --- TEKAMOLO sub-slices (mirror of TEMPORAL_KEY..LOKAL_KEY + extras) ------
375+
376+ pub const TEMPORAL_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9000 , 9200 , fnv64_bytes ( b"TEMPORAL" ) ) ;
377+ pub const KAUSAL_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9200 , 9400 , fnv64_bytes ( b"KAUSAL" ) ) ;
378+ pub const MODAL_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9400 , 9500 , fnv64_bytes ( b"MODAL" ) ) ;
379+ pub const LOKAL_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9500 , 9650 , fnv64_bytes ( b"LOKAL" ) ) ;
380+ pub const INSTRUMENT_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9650 , 9750 , fnv64_bytes ( b"INSTRUMENT" ) ) ;
381+ pub const BENEFICIARY_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9750 , 9780 , fnv64_bytes ( b"BENEFICIARY" ) ) ;
382+ pub const GOAL_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9780 , 9810 , fnv64_bytes ( b"GOAL" ) ) ;
383+ pub const SOURCE_SLICE : RoleKeySlice = RoleKeySlice :: new ( 9810 , 9840 , fnv64_bytes ( b"SOURCE" ) ) ;
384+
385+ // --- Finnish 15 cases (mirror FINNISH_SLICES, indexed by FinnishCase as u8)
386+
387+ pub static FINNISH_CASE_SLICES : LazyLock < [ ( FinnishCase , RoleKeySlice ) ; 15 ] > = LazyLock :: new ( || {
388+ [
389+ ( FinnishCase :: Nominative , RoleKeySlice :: new ( FINNISH_SLICES [ 0 ] . 0 , FINNISH_SLICES [ 0 ] . 1 , fnv64_bytes ( b"FI_NOMINATIVE" ) ) ) ,
390+ ( FinnishCase :: Genitive , RoleKeySlice :: new ( FINNISH_SLICES [ 1 ] . 0 , FINNISH_SLICES [ 1 ] . 1 , fnv64_bytes ( b"FI_GENITIVE" ) ) ) ,
391+ ( FinnishCase :: Accusative , RoleKeySlice :: new ( FINNISH_SLICES [ 2 ] . 0 , FINNISH_SLICES [ 2 ] . 1 , fnv64_bytes ( b"FI_ACCUSATIVE" ) ) ) ,
392+ ( FinnishCase :: Partitive , RoleKeySlice :: new ( FINNISH_SLICES [ 3 ] . 0 , FINNISH_SLICES [ 3 ] . 1 , fnv64_bytes ( b"FI_PARTITIVE" ) ) ) ,
393+ ( FinnishCase :: Inessive , RoleKeySlice :: new ( FINNISH_SLICES [ 4 ] . 0 , FINNISH_SLICES [ 4 ] . 1 , fnv64_bytes ( b"FI_INESSIVE" ) ) ) ,
394+ ( FinnishCase :: Elative , RoleKeySlice :: new ( FINNISH_SLICES [ 5 ] . 0 , FINNISH_SLICES [ 5 ] . 1 , fnv64_bytes ( b"FI_ELATIVE" ) ) ) ,
395+ ( FinnishCase :: Illative , RoleKeySlice :: new ( FINNISH_SLICES [ 6 ] . 0 , FINNISH_SLICES [ 6 ] . 1 , fnv64_bytes ( b"FI_ILLATIVE" ) ) ) ,
396+ ( FinnishCase :: Adessive , RoleKeySlice :: new ( FINNISH_SLICES [ 7 ] . 0 , FINNISH_SLICES [ 7 ] . 1 , fnv64_bytes ( b"FI_ADESSIVE" ) ) ) ,
397+ ( FinnishCase :: Ablative , RoleKeySlice :: new ( FINNISH_SLICES [ 8 ] . 0 , FINNISH_SLICES [ 8 ] . 1 , fnv64_bytes ( b"FI_ABLATIVE" ) ) ) ,
398+ ( FinnishCase :: Allative , RoleKeySlice :: new ( FINNISH_SLICES [ 9 ] . 0 , FINNISH_SLICES [ 9 ] . 1 , fnv64_bytes ( b"FI_ALLATIVE" ) ) ) ,
399+ ( FinnishCase :: Essive , RoleKeySlice :: new ( FINNISH_SLICES [ 10 ] . 0 , FINNISH_SLICES [ 10 ] . 1 , fnv64_bytes ( b"FI_ESSIVE" ) ) ) ,
400+ ( FinnishCase :: Translative , RoleKeySlice :: new ( FINNISH_SLICES [ 11 ] . 0 , FINNISH_SLICES [ 11 ] . 1 , fnv64_bytes ( b"FI_TRANSLATIVE" ) ) ) ,
401+ ( FinnishCase :: Instructive , RoleKeySlice :: new ( FINNISH_SLICES [ 12 ] . 0 , FINNISH_SLICES [ 12 ] . 1 , fnv64_bytes ( b"FI_INSTRUCTIVE" ) ) ) ,
402+ ( FinnishCase :: Abessive , RoleKeySlice :: new ( FINNISH_SLICES [ 13 ] . 0 , FINNISH_SLICES [ 13 ] . 1 , fnv64_bytes ( b"FI_ABESSIVE" ) ) ) ,
403+ ( FinnishCase :: Comitative , RoleKeySlice :: new ( FINNISH_SLICES [ 14 ] . 0 , FINNISH_SLICES [ 14 ] . 1 , fnv64_bytes ( b"FI_COMITATIVE" ) ) ) ,
404+ ]
405+ } ) ;
406+
407+ /// Lookup the [`RoleKeySlice`] for a Finnish case (round-trip via the
408+ /// `LazyLock` array — exactly one slice per variant by construction).
409+ pub fn finnish_case_slice ( case : FinnishCase ) -> RoleKeySlice {
410+ FINNISH_CASE_SLICES [ case as usize ] . 1
411+ }
412+
413+ // --- 12 Tense slices (mirror TENSE_KEYS) -----------------------------------
414+
415+ pub static TENSE_SLICES : LazyLock < [ ( Tense , RoleKeySlice ) ; 12 ] > = LazyLock :: new ( || {
416+ let s = |i : usize | TENSE_START + i * TENSE_WIDTH ;
417+ let e = |i : usize | TENSE_START + ( i + 1 ) * TENSE_WIDTH ;
418+ [
419+ ( Tense :: Present , RoleKeySlice :: new ( s ( 0 ) , e ( 0 ) , fnv64_bytes ( b"T_PRESENT" ) ) ) ,
420+ ( Tense :: Past , RoleKeySlice :: new ( s ( 1 ) , e ( 1 ) , fnv64_bytes ( b"T_PAST" ) ) ) ,
421+ ( Tense :: Future , RoleKeySlice :: new ( s ( 2 ) , e ( 2 ) , fnv64_bytes ( b"T_FUTURE" ) ) ) ,
422+ ( Tense :: PresentContinuous , RoleKeySlice :: new ( s ( 3 ) , e ( 3 ) , fnv64_bytes ( b"T_PRESENT_CONTINUOUS" ) ) ) ,
423+ ( Tense :: PastContinuous , RoleKeySlice :: new ( s ( 4 ) , e ( 4 ) , fnv64_bytes ( b"T_PAST_CONTINUOUS" ) ) ) ,
424+ ( Tense :: FutureContinuous , RoleKeySlice :: new ( s ( 5 ) , e ( 5 ) , fnv64_bytes ( b"T_FUTURE_CONTINUOUS" ) ) ) ,
425+ ( Tense :: Perfect , RoleKeySlice :: new ( s ( 6 ) , e ( 6 ) , fnv64_bytes ( b"T_PERFECT" ) ) ) ,
426+ ( Tense :: Pluperfect , RoleKeySlice :: new ( s ( 7 ) , e ( 7 ) , fnv64_bytes ( b"T_PLUPERFECT" ) ) ) ,
427+ ( Tense :: FuturePerfect , RoleKeySlice :: new ( s ( 8 ) , e ( 8 ) , fnv64_bytes ( b"T_FUTURE_PERFECT" ) ) ) ,
428+ ( Tense :: Habitual , RoleKeySlice :: new ( s ( 9 ) , e ( 9 ) , fnv64_bytes ( b"T_HABITUAL" ) ) ) ,
429+ ( Tense :: Potential , RoleKeySlice :: new ( s ( 10 ) , e ( 10 ) , fnv64_bytes ( b"T_POTENTIAL" ) ) ) ,
430+ ( Tense :: Imperative , RoleKeySlice :: new ( s ( 11 ) , e ( 11 ) , fnv64_bytes ( b"T_IMPERATIVE" ) ) ) ,
431+ ]
432+ } ) ;
433+
434+ pub fn tense_slice ( tense : Tense ) -> RoleKeySlice {
435+ TENSE_SLICES [ tense as usize ] . 1
436+ }
437+
438+ // --- 7 NARS-inference slices (mirror NARS_SLICES) --------------------------
439+
440+ pub static NARS_INFERENCE_SLICES : LazyLock < [ ( NarsInference , RoleKeySlice ) ; 7 ] > = LazyLock :: new ( || {
441+ [
442+ ( NarsInference :: Deduction , RoleKeySlice :: new ( NARS_SLICES [ 0 ] . 0 , NARS_SLICES [ 0 ] . 1 , fnv64_bytes ( b"N_DEDUCTION" ) ) ) ,
443+ ( NarsInference :: Induction , RoleKeySlice :: new ( NARS_SLICES [ 1 ] . 0 , NARS_SLICES [ 1 ] . 1 , fnv64_bytes ( b"N_INDUCTION" ) ) ) ,
444+ ( NarsInference :: Abduction , RoleKeySlice :: new ( NARS_SLICES [ 2 ] . 0 , NARS_SLICES [ 2 ] . 1 , fnv64_bytes ( b"N_ABDUCTION" ) ) ) ,
445+ ( NarsInference :: Revision , RoleKeySlice :: new ( NARS_SLICES [ 3 ] . 0 , NARS_SLICES [ 3 ] . 1 , fnv64_bytes ( b"N_REVISION" ) ) ) ,
446+ ( NarsInference :: Synthesis , RoleKeySlice :: new ( NARS_SLICES [ 4 ] . 0 , NARS_SLICES [ 4 ] . 1 , fnv64_bytes ( b"N_SYNTHESIS" ) ) ) ,
447+ ( NarsInference :: Extrapolation , RoleKeySlice :: new ( NARS_SLICES [ 5 ] . 0 , NARS_SLICES [ 5 ] . 1 , fnv64_bytes ( b"N_EXTRAPOLATION" ) ) ) ,
448+ ( NarsInference :: CounterfactualSynthesis , RoleKeySlice :: new ( NARS_SLICES [ 6 ] . 0 , NARS_SLICES [ 6 ] . 1 , fnv64_bytes ( b"N_COUNTERFACTUAL" ) ) ) ,
449+ ]
450+ } ) ;
451+
452+ pub fn nars_inference_slice ( inf : NarsInference ) -> RoleKeySlice {
453+ let idx = match inf {
454+ NarsInference :: Deduction => 0 ,
455+ NarsInference :: Induction => 1 ,
456+ NarsInference :: Abduction => 2 ,
457+ NarsInference :: Revision => 3 ,
458+ NarsInference :: Synthesis => 4 ,
459+ NarsInference :: Extrapolation => 5 ,
460+ NarsInference :: CounterfactualSynthesis => 6 ,
461+ } ;
462+ NARS_INFERENCE_SLICES [ idx] . 1
463+ }
464+
317465// ---------------------------------------------------------------------------
318466// Tests
319467// ---------------------------------------------------------------------------
@@ -461,4 +609,169 @@ mod tests {
461609 assert ! ( k. slice_end <= TENSE_END ) ;
462610 }
463611 }
612+
613+ // -----------------------------------------------------------------------
614+ // D6 — RoleKeySlice catalogue tests
615+ // -----------------------------------------------------------------------
616+
617+ /// All five SPO core slices are non-overlapping and union to [0, 9000)
618+ /// (the "SPO-spine" prefix of the 16,384-dim VSA carrier).
619+ #[ test]
620+ fn spo_slices_disjoint_and_contiguous ( ) {
621+ let spo = [
622+ SUBJECT_SLICE , PREDICATE_SLICE , OBJECT_SLICE , MODIFIER_SLICE , CONTEXT_SLICE ,
623+ ] ;
624+ // Contiguous: each slice starts where the previous ended.
625+ for pair in spo. windows ( 2 ) {
626+ assert_eq ! (
627+ pair[ 0 ] . stop, pair[ 1 ] . start,
628+ "SPO slices not contiguous: {:?} vs {:?}" , pair[ 0 ] , pair[ 1 ]
629+ ) ;
630+ }
631+ // Union covers [0, 9000) — the SPO+TEKAMOLO-prefix region. (CONTEXT
632+ // ends at 9000; TEKAMOLO sub-slices begin there.)
633+ assert_eq ! ( spo[ 0 ] . start, 0 ) ;
634+ assert_eq ! ( spo[ spo. len( ) - 1 ] . stop, 9000 ) ;
635+ }
636+
637+ /// TEKAMOLO sub-slices fit within [9000, 9840) — the slice region beyond
638+ /// CONTEXT_KEY where the original prompt placed them. (CONTEXT_KEY itself
639+ /// owns [7500, 9000) and TEKAMOLO sits AFTER it in the LF-2 layout.)
640+ #[ test]
641+ fn tekamolo_sub_slices_in_post_context_band ( ) {
642+ let teka = [
643+ TEMPORAL_SLICE , KAUSAL_SLICE , MODAL_SLICE , LOKAL_SLICE ,
644+ INSTRUMENT_SLICE , BENEFICIARY_SLICE , GOAL_SLICE , SOURCE_SLICE ,
645+ ] ;
646+ for s in teka {
647+ assert ! ( s. start >= 9000 , "TEKAMOLO slice starts before 9000: {s:?}" ) ;
648+ assert ! ( s. stop <= 9840 , "TEKAMOLO slice ends after 9840: {s:?}" ) ;
649+ assert ! ( s. len( ) > 0 , "empty TEKAMOLO slice: {s:?}" ) ;
650+ }
651+ }
652+
653+ /// Finnish case slices are non-overlapping AND fall inside the existing
654+ /// `FINNISH_START..FINNISH_END` band.
655+ #[ test]
656+ fn finnish_case_slices_disjoint_in_band ( ) {
657+ let arr = & * FINNISH_CASE_SLICES ;
658+ let mut by_start: Vec < RoleKeySlice > = arr. iter ( ) . map ( |( _, s) | * s) . collect ( ) ;
659+ by_start. sort_by_key ( |s| s. start ) ;
660+ for pair in by_start. windows ( 2 ) {
661+ assert ! (
662+ pair[ 0 ] . stop <= pair[ 1 ] . start,
663+ "Finnish slice overlap: {:?} vs {:?}" , pair[ 0 ] , pair[ 1 ]
664+ ) ;
665+ }
666+ for ( _, s) in arr. iter ( ) {
667+ assert ! ( s. start >= FINNISH_START ) ;
668+ assert ! ( s. stop <= FINNISH_END ) ;
669+ }
670+ }
671+
672+ /// FNV-64 of distinct labels does not collide on the canonical role names.
673+ #[ test]
674+ fn fnv64_no_collisions_on_role_labels ( ) {
675+ let labels: & [ & [ u8 ] ] = & [
676+ b"SUBJECT" , b"PREDICATE" , b"OBJECT" , b"MODIFIER" , b"CONTEXT" ,
677+ b"TEMPORAL" , b"KAUSAL" , b"MODAL" , b"LOKAL" ,
678+ b"INSTRUMENT" , b"BENEFICIARY" , b"GOAL" , b"SOURCE" ,
679+ b"FI_NOMINATIVE" , b"FI_GENITIVE" , b"FI_ACCUSATIVE" , b"FI_PARTITIVE" ,
680+ b"FI_INESSIVE" , b"FI_ELATIVE" , b"FI_ILLATIVE" ,
681+ b"FI_ADESSIVE" , b"FI_ABLATIVE" , b"FI_ALLATIVE" ,
682+ b"FI_ESSIVE" , b"FI_TRANSLATIVE" , b"FI_INSTRUCTIVE" ,
683+ b"FI_ABESSIVE" , b"FI_COMITATIVE" ,
684+ b"T_PRESENT" , b"T_PAST" , b"T_FUTURE" ,
685+ b"T_PRESENT_CONTINUOUS" , b"T_PAST_CONTINUOUS" , b"T_FUTURE_CONTINUOUS" ,
686+ b"T_PERFECT" , b"T_PLUPERFECT" , b"T_FUTURE_PERFECT" ,
687+ b"T_HABITUAL" , b"T_POTENTIAL" , b"T_IMPERATIVE" ,
688+ b"N_DEDUCTION" , b"N_INDUCTION" , b"N_ABDUCTION" , b"N_REVISION" ,
689+ b"N_SYNTHESIS" , b"N_EXTRAPOLATION" , b"N_COUNTERFACTUAL" ,
690+ ] ;
691+ let mut seen = std:: collections:: HashSet :: new ( ) ;
692+ for l in labels {
693+ let h = fnv64_bytes ( l) ;
694+ assert ! ( seen. insert( h) , "FNV-64 collision on label {:?}" , std:: str :: from_utf8( l) . unwrap( ) ) ;
695+ }
696+ // Spot-check the prompt's pinned non-collision.
697+ assert_ne ! ( fnv64_bytes( b"SUBJECT" ) , fnv64_bytes( b"OBJECT" ) ) ;
698+ }
699+
700+ /// Round-trip: each FinnishCase variant maps to exactly one
701+ /// `RoleKeySlice` via the LazyLock array, and the array is keyed by
702+ /// `FinnishCase as u8` (i.e. `arr[c as usize].0 == c`).
703+ #[ test]
704+ fn finnish_case_round_trip ( ) {
705+ let all = [
706+ FinnishCase :: Nominative , FinnishCase :: Genitive , FinnishCase :: Accusative ,
707+ FinnishCase :: Partitive , FinnishCase :: Inessive , FinnishCase :: Elative ,
708+ FinnishCase :: Illative , FinnishCase :: Adessive , FinnishCase :: Ablative ,
709+ FinnishCase :: Allative , FinnishCase :: Essive , FinnishCase :: Translative ,
710+ FinnishCase :: Instructive , FinnishCase :: Abessive , FinnishCase :: Comitative ,
711+ ] ;
712+ for case in all {
713+ let ( stored_case, slice) = FINNISH_CASE_SLICES [ case as usize ] ;
714+ assert_eq ! ( stored_case, case, "FINNISH_CASE_SLICES not indexed by `as u8`" ) ;
715+ // The free-function lookup must agree with the array entry.
716+ assert_eq ! ( finnish_case_slice( case) , slice) ;
717+ // Slice mirrors the live RoleKey boundaries.
718+ let live = finnish_case_key ( case) ;
719+ assert_eq ! ( slice. start, live. slice_start) ;
720+ assert_eq ! ( slice. stop, live. slice_end) ;
721+ // And the FNV-64 fingerprint is non-zero (every label hashes to
722+ // something distinct from the empty string's seed).
723+ assert_ne ! ( slice. fnv_seed, 0xcbf29ce484222325 ) ;
724+ }
725+ }
726+
727+ /// The slice catalogue mirrors the live `RoleKey` boundaries for SPO/
728+ /// TEKAMOLO so consumers can swap the two without re-deriving widths.
729+ #[ test]
730+ fn role_key_slice_mirrors_live_role_key_boundaries ( ) {
731+ let pairs: & [ ( RoleKeySlice , & RoleKey ) ] = & [
732+ ( SUBJECT_SLICE , & SUBJECT_KEY ) ,
733+ ( PREDICATE_SLICE , & PREDICATE_KEY ) ,
734+ ( OBJECT_SLICE , & OBJECT_KEY ) ,
735+ ( MODIFIER_SLICE , & MODIFIER_KEY ) ,
736+ ( CONTEXT_SLICE , & CONTEXT_KEY ) ,
737+ ( TEMPORAL_SLICE , & TEMPORAL_KEY ) ,
738+ ( KAUSAL_SLICE , & KAUSAL_KEY ) ,
739+ ( MODAL_SLICE , & MODAL_KEY ) ,
740+ ( LOKAL_SLICE , & LOKAL_KEY ) ,
741+ ( INSTRUMENT_SLICE , & INSTRUMENT_KEY ) ,
742+ ( BENEFICIARY_SLICE , & BENEFICIARY_KEY ) ,
743+ ( GOAL_SLICE , & GOAL_KEY ) ,
744+ ( SOURCE_SLICE , & SOURCE_KEY ) ,
745+ ] ;
746+ for ( slice, live) in pairs {
747+ assert_eq ! ( slice. start, live. slice_start, "slice/live start mismatch for {}" , live. label) ;
748+ assert_eq ! ( slice. stop, live. slice_end, "slice/live stop mismatch for {}" , live. label) ;
749+ assert ! ( slice. stop <= VSA_DIMS ) ;
750+ }
751+ }
752+
753+ #[ test]
754+ fn role_key_slice_const_helpers ( ) {
755+ assert_eq ! ( SUBJECT_SLICE . len( ) , 2000 ) ;
756+ assert ! ( !SUBJECT_SLICE . is_empty( ) ) ;
757+ let r = SUBJECT_SLICE . range ( ) ;
758+ assert_eq ! ( r. start, 0 ) ;
759+ assert_eq ! ( r. end, 2000 ) ;
760+ }
761+
762+ #[ test]
763+ fn nars_inference_slice_round_trip ( ) {
764+ let all = [
765+ NarsInference :: Deduction , NarsInference :: Induction ,
766+ NarsInference :: Abduction , NarsInference :: Revision ,
767+ NarsInference :: Synthesis , NarsInference :: Extrapolation ,
768+ NarsInference :: CounterfactualSynthesis ,
769+ ] ;
770+ for inf in all {
771+ let s = nars_inference_slice ( inf) ;
772+ assert ! ( s. start >= NARS_START ) ;
773+ assert ! ( s. stop <= NARS_END ) ;
774+ assert ! ( s. len( ) > 0 ) ;
775+ }
776+ }
464777}
0 commit comments