1use std::mem::size_of;
2use std::sync::Arc;
3
4use sha2::{Digest, Sha256};
5
6use crate::launch::LaunchEnqueueError;
7use crate::memory::{DeviceMemoryView, TrackedCudaSlice};
8use crate::provider::resident_schedule::{validate_execution_domain, ResidentExecutionDomain};
9use crate::semantic_transition::{
10 Identity256, SemanticPublishedIdentity, SemanticRngBinding, SemanticTaskContentIdentity,
11 SemanticTransitionError, SemanticTransitionKind,
12};
13use crate::{
14 CudaFunction, CudaKernelProvider, DeviceRepr, LaunchAsync, LaunchConfig, SemanticTruth,
15};
16
17type TrainingViewPort = (DeviceMemoryView<u8>, Vec<i64>, Vec<i64>, (u8, u8));
18type ValidatedTrainingObjective = (
19 SemanticTrainingObjectiveRecord,
20 Vec<SemanticTrainingObjectiveGroupRecord>,
21 Vec<u64>,
22 Vec<SemanticTrainingCanaryRecord>,
23 Vec<u64>,
24);
25
26const MODULE: &str = "xlog_semantic_training_view";
27const SELECT_KERNEL: &str = "semantic_training_view_select";
28const GATHER_KERNEL: &str = "semantic_training_view_gather";
29const TRAINING_VIEW_HEADER_BYTES: usize = 264;
30const TRAINING_VIEW_ROW_BYTES: usize = 84;
31const PROPOSAL_TRANSITION: u64 = 1;
32pub const SEMANTIC_TRAINING_CANARY_EVALUATOR_ABI: u64 = 3;
33
34#[derive(Clone, Copy, Debug)]
36pub struct SemanticTrainingViewLayout {
37 pub window: usize,
38 pub source_length: u64,
39 pub block_size: u64,
40 pub prefix_extent: u64,
41 pub answer_start: u64,
42 pub branch_words: [u64; 16],
43}
44
45#[repr(u64)]
47#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub enum SemanticTrainingViewBasis {
49 Episode = 1,
50 CorpusLanguageAnchor = 2,
51 CorpusSymbolicAnchor = 3,
52}
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
57pub struct SemanticTrainingViewOrigin {
58 pub transition: SemanticTransitionKind,
59 pub predecessor: SemanticPublishedIdentity,
60 pub successor: SemanticPublishedIdentity,
61 pub invocation: SemanticRngBinding,
62 pub model_geometry_digest: Identity256,
63 pub model_numerical_digest: Identity256,
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
69pub struct SemanticTrainingManifest {
70 pub identity: Identity256,
71 pub caps: [u64; 4],
72}
73
74#[derive(Clone, Debug, PartialEq, Eq)]
78pub struct SemanticTrainingDomain {
79 pub manifests: Vec<SemanticTrainingManifest>,
81 pub window: u64,
82 pub pad_id: u64,
83 pub mask_id: u64,
84 pub block_size: u64,
85 pub batch_size: u64,
86 pub mask_permille: u64,
87 pub training_seed: String,
89 pub mask_policy: Identity256,
90}
91
92impl SemanticTrainingDomain {
93 pub(crate) fn validate(&self) -> Result<(), SemanticTransitionError> {
94 let seed = self.training_seed.as_bytes();
95 if self.manifests.is_empty()
96 || self.manifests.iter().any(|manifest| {
97 manifest.identity == Identity256::default() || manifest.caps.contains(&0)
98 })
99 || self
100 .manifests
101 .windows(2)
102 .any(|pair| pair[0].identity.as_bytes() >= pair[1].identity.as_bytes())
103 || self.window == 0
104 || self.block_size == 0
105 || self.batch_size == 0
106 || !(1..=1000).contains(&self.mask_permille)
107 || self.mask_policy == Identity256::default()
108 || !(seed == b"0"
109 || (matches!(seed.first(), Some(b'1'..=b'9'))
110 && seed.iter().all(u8::is_ascii_digit)))
111 {
112 return Err(input_error(
113 "training domain requires exact manifests and loader geometry",
114 ));
115 }
116 Ok(())
117 }
118
119 pub fn record_limit(&self) -> u64 {
122 self.manifests
123 .iter()
124 .map(|manifest| manifest.caps[2])
125 .min()
126 .unwrap_or(0)
127 }
128
129 pub fn identity(&self) -> Identity256 {
131 let mut hash = Sha256::new();
132 hash.update(b"xlog.semantic.training-domain.v1\0");
133 hash.update((self.manifests.len() as u64).to_le_bytes());
134 for manifest in &self.manifests {
135 hash.update(manifest.identity.as_bytes());
136 for cap in manifest.caps {
137 hash.update(cap.to_le_bytes());
138 }
139 }
140 for word in [
141 self.window,
142 self.pad_id,
143 self.mask_id,
144 self.block_size,
145 self.batch_size,
146 self.mask_permille,
147 ] {
148 hash.update(word.to_le_bytes());
149 }
150 hash.update((self.training_seed.len() as u64).to_le_bytes());
151 hash.update(self.training_seed.as_bytes());
152 hash.update(self.mask_policy.as_bytes());
153 Identity256::from_bytes(hash.finalize().into())
154 }
155}
156
157pub struct SemanticTrainingViewRow {
159 pub basis: SemanticTrainingViewBasis,
160 pub identity: Identity256,
161 pub bytes_identity: Identity256,
162 pub content_identity: Identity256,
163 pub data_manifest: Identity256,
165 pub mask_policy: Identity256,
166 pub training_seed: String,
167 pub task_content: Option<SemanticTaskContentIdentity>,
170 pub origin: Option<SemanticTrainingViewOrigin>,
171 pub bytes: Vec<u8>,
172}
173
174#[repr(u64)]
176#[derive(Clone, Copy, Debug, Eq, PartialEq)]
177pub enum SemanticTrainingObjectiveGroupKind {
178 MaskedLanguage = 1,
179 AutoregressiveLanguage = 2,
180 Semantic = 3,
181 Edit = 4,
182 Execution = 5,
183 RetentionLanguage = 6,
184 RetentionSymbolic = 7,
185 ActorCriticCost = 8,
186}
187
188#[derive(Clone, Debug, Eq, PartialEq)]
190pub struct SemanticTrainingObjectiveGroup {
191 pub kind: SemanticTrainingObjectiveGroupKind,
192 pub denominator: u64,
193 pub row_ordinals: Vec<u64>,
194}
195
196#[repr(u64)]
198#[derive(Clone, Copy, Debug, Eq, PartialEq)]
199pub enum SemanticTrainingCanaryKind {
200 SymbolicUtility = 1,
201 RetainedBehavior = 2,
202 LogitDrift = 3,
203 GoalChain = 4,
204 ResourceLimits = 5,
205}
206
207#[derive(Clone, Debug, PartialEq)]
209pub struct SemanticTrainingCanary {
210 pub kind: SemanticTrainingCanaryKind,
211 pub row_ordinal: u64,
212 pub lower_bound: f64,
213 pub upper_bound: f64,
214 pub memory_limit: u64,
215 pub work_limit: u64,
216 pub obligation_positions: [u64; 3],
221 pub protected_positions: Vec<u64>,
225}
226
227#[derive(Clone, Debug, PartialEq)]
229pub struct SemanticTrainingObjective {
230 pub evaluator_min: f64,
231 pub evaluator_max: f64,
232 pub coefficients: [f32; 9],
235 pub cost_unit: Identity256,
236 pub cost_cap: u64,
237 pub truth_tokens: [u64; 4],
239 pub groups: Vec<SemanticTrainingObjectiveGroup>,
240 pub canaries: Vec<SemanticTrainingCanary>,
241}
242
243pub(crate) fn frozen_training_coefficients(evaluator_min: f64, evaluator_max: f64) -> [f32; 9] {
245 let return_scale = evaluator_min.abs().max(evaluator_max.abs()).max(1.0);
246 let mut coefficients = [1.0f32; 9];
247 coefficients[6] = (1.0 / return_scale) as f32;
248 coefficients[7] = (1.0 / (return_scale * return_scale)) as f32;
249 coefficients
250}
251
252#[repr(C)]
253#[derive(Clone, Copy, Debug, Default)]
254pub struct SemanticTrainingObjectiveRecord {
255 pub evaluator_abi: u64,
256 pub identity: [u64; 4],
257 pub task_identity: [u64; 4],
258 pub row_count: u64,
259 pub capacity: u64,
260 pub group_count: u64,
261 pub group_member_count: u64,
262 pub canary_count: u64,
263 pub protected_member_count: u64,
264 pub evaluator_min_bits: u64,
265 pub evaluator_max_bits: u64,
266 pub coefficient_bits: [u64; 9],
267 pub cost_unit: [u64; 4],
268 pub cost_cap: u64,
269 pub truth_tokens: [u64; 4],
270}
271
272unsafe impl DeviceRepr for SemanticTrainingObjectiveRecord {}
274
275#[repr(C)]
276#[derive(Clone, Copy, Debug, Default)]
277pub struct SemanticTrainingObjectiveGroupRecord {
278 pub kind: u64,
279 pub denominator: u64,
280 pub member_offset: u64,
281 pub member_count: u64,
282}
283
284unsafe impl DeviceRepr for SemanticTrainingObjectiveGroupRecord {}
286
287#[repr(C)]
288#[derive(Clone, Copy, Debug, Default)]
289pub struct SemanticTrainingCanaryRecord {
290 pub evaluator_abi: u64,
291 pub kind: u64,
292 pub row_ordinal: u64,
293 pub lower_bound_bits: u64,
294 pub upper_bound_bits: u64,
295 pub memory_limit: u64,
296 pub work_limit: u64,
297 pub obligation_positions: [u64; 3],
298 pub protected_member_offset: u64,
299 pub protected_member_count: u64,
300 pub row_identity: [u64; 4],
301 pub row_content_identity: [u64; 4],
302 pub task_identity: [u64; 4],
303 pub identity: [u64; 4],
304}
305
306unsafe impl DeviceRepr for SemanticTrainingCanaryRecord {}
308
309#[repr(C)]
316#[derive(Clone, Copy, Debug, Default)]
317pub(crate) struct SemanticTrainingCanaryResultRecord {
318 pub abi: u64,
319 pub kind: u64,
320 pub row_ordinal: u64,
321 pub availability: u64,
324 pub reason: u64,
325 pub measurement_bits: u64,
326 pub memory_used: u64,
327 pub work_used: u64,
328 pub identity: [u64; 4],
329}
330
331unsafe impl DeviceRepr for SemanticTrainingCanaryResultRecord {}
333
334const _: () = assert!(size_of::<SemanticTrainingCanaryResultRecord>() == 96);
335
336#[repr(u64)]
338#[derive(Clone, Copy, Debug, PartialEq, Eq)]
339pub enum SemanticTrainingCanaryRefusalReason {
340 NonFiniteMeasurement = 1,
341 OutsideBounds = 2,
342 MemoryLimitExceeded = 3,
343 WorkLimitExceeded = 4,
344 IncompleteOperands = 5,
345 ProtectedRetentionLost = 6,
346 GoalWitnessInvalid = 7,
347 WorkOverflow = 8,
348 GenerationMismatch = 9,
349}
350
351#[repr(C)]
357#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
358pub struct SemanticTrainingCanaryRefusalRecord {
359 pub abi: u64,
360 pub reason: u64,
361 pub kind: u64,
362 pub row_ordinal: u64,
363 pub measurement_bits: u64,
364 pub lower_bound_bits: u64,
365 pub upper_bound_bits: u64,
366 pub memory_used: u64,
367 pub memory_limit: u64,
368 pub work_used: u64,
369 pub work_limit: u64,
370 pub identity: [u64; 4],
371 pub selection_identity: [u64; 4],
372}
373
374impl SemanticTrainingCanaryRefusalRecord {
375 pub fn reason(&self) -> Option<SemanticTrainingCanaryRefusalReason> {
376 match self.reason {
377 1 => Some(SemanticTrainingCanaryRefusalReason::NonFiniteMeasurement),
378 2 => Some(SemanticTrainingCanaryRefusalReason::OutsideBounds),
379 3 => Some(SemanticTrainingCanaryRefusalReason::MemoryLimitExceeded),
380 4 => Some(SemanticTrainingCanaryRefusalReason::WorkLimitExceeded),
381 5 => Some(SemanticTrainingCanaryRefusalReason::IncompleteOperands),
382 6 => Some(SemanticTrainingCanaryRefusalReason::ProtectedRetentionLost),
383 7 => Some(SemanticTrainingCanaryRefusalReason::GoalWitnessInvalid),
384 8 => Some(SemanticTrainingCanaryRefusalReason::WorkOverflow),
385 9 => Some(SemanticTrainingCanaryRefusalReason::GenerationMismatch),
386 _ => None,
387 }
388 }
389}
390
391unsafe impl DeviceRepr for SemanticTrainingCanaryRefusalRecord {}
393
394#[repr(C)]
395#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
396pub struct SemanticTrainingViewOriginRecord {
397 pub present: u64,
398 pub transition: u64,
399 pub lineage_instance: [u64; 4],
403 pub predecessor_instance: [u64; 4],
404 pub predecessor_word: u64,
405 pub predecessor_logical: [u64; 4],
406 pub predecessor_state: [u64; 4],
407 pub successor_instance: [u64; 4],
408 pub successor_word: u64,
409 pub successor_logical: [u64; 4],
410 pub successor_state: [u64; 4],
411 pub model_generation: u64,
412 pub stream_serial: u64,
413 pub family_id: u64,
414 pub proposal: u64,
415 pub model_geometry_digest: [u64; 4],
416 pub model_numerical_digest: [u64; 4],
417}
418
419unsafe impl DeviceRepr for SemanticTrainingViewOriginRecord {}
421
422#[repr(C)]
423#[derive(Clone, Copy, Default)]
424struct TrainingViewRowDescriptor {
425 ordinal: u64,
426 basis: u64,
427 raw_offset: u64,
428 raw_bytes: u64,
429 window: u64,
430 source_length: u64,
431 block_size: u64,
432 prefix_extent: u64,
433 answer_start: u64,
434 identity: [u64; 4],
435 source_identity: [u64; 4],
436 content_identity: [u64; 4],
437 task_query_identity: [u64; 4],
438 task_theory_program_identity: [u64; 4],
439 task_result_identity: [u64; 4],
440 origin: SemanticTrainingViewOriginRecord,
441}
442
443unsafe impl DeviceRepr for TrainingViewRowDescriptor {}
445
446#[repr(C)]
448#[derive(Clone, Copy, Debug, Default)]
449pub struct SemanticTrainingRosterRow {
450 pub ordinal: u64,
451 pub basis: u64,
452 pub window: u64,
453 pub source_length: u64,
454 pub block_size: u64,
455 pub prefix_extent: u64,
456 pub answer_start: u64,
457 pub origin_candidate: u64,
458 pub identity: [u64; 4],
459 pub source_identity: [u64; 4],
460 pub content_identity: [u64; 4],
461 pub origin: SemanticTrainingViewOriginRecord,
464}
465
466unsafe impl DeviceRepr for SemanticTrainingRosterRow {}
468
469#[repr(C)]
472#[derive(Clone, Copy, Debug, Default)]
473pub struct SemanticTrainingViewSelection {
474 pub status: u64,
475 pub row_count: u64,
476 pub capacity: u64,
477 pub ordinal: u64,
478 pub basis: u64,
479 pub window: u64,
480 pub source_length: u64,
481 pub block_size: u64,
482 pub prefix_extent: u64,
483 pub answer_start: u64,
484 pub identity: [u64; 4],
485 pub source_identity: [u64; 4],
486 pub content_identity: [u64; 4],
487 pub origin: SemanticTrainingViewOriginRecord,
488 pub origin_candidate: u64,
489 pub training_rng: [u64; 4],
490}
491
492unsafe impl DeviceRepr for SemanticTrainingViewSelection {}
494
495#[repr(C)]
496#[derive(Clone, Copy, Default)]
497struct TrainingViewLaunch {
498 descriptors: u64,
499 raw: u64,
500 row_count: u64,
501 selected_view: u64,
502 selected_view_bytes: u64,
503 cursor: u64,
504 training_rng: [u64; 4],
505 coordinates: u64,
506 origin_candidates: u64,
507 origin_candidate_count: u64,
508 selection: u64,
509 roster_rows: u64,
510 capacity: u64,
511 token_ids: u64,
512 mask_labels: u64,
513 mask_weights: u64,
514 ar_labels: u64,
515 retention_labels: u64,
516 branch_labels: u64,
517 branch_ids: u64,
518 source_slots: u64,
519 logical_positions: u64,
520 kinds: u64,
521 parents: u64,
522}
523
524unsafe impl DeviceRepr for TrainingViewLaunch {}
526
527struct TrainingViewLaunchParam(TrainingViewLaunch);
528
529impl crate::cuda_compat::KernelParamStorage for TrainingViewLaunchParam {
530 fn as_kernel_param(&self) -> *mut std::ffi::c_void {
531 (&self.0 as *const TrainingViewLaunch).cast_mut().cast()
532 }
533}
534
535impl crate::cuda_compat::IntoKernelParamStorage for TrainingViewLaunch {
536 type Storage = TrainingViewLaunchParam;
537
538 fn into_kernel_param_storage(self) -> Self::Storage {
539 TrainingViewLaunchParam(self)
540 }
541}
542
543struct SelectedTrainingViewStorage {
544 selection: TrackedCudaSlice<SemanticTrainingViewSelection>,
545 roster_rows: TrackedCudaSlice<SemanticTrainingRosterRow>,
546 token_ids: TrackedCudaSlice<i64>,
547 mask_labels: TrackedCudaSlice<i64>,
548 mask_weights: TrackedCudaSlice<f32>,
549 ar_labels: TrackedCudaSlice<i64>,
550 retention_labels: TrackedCudaSlice<i64>,
551 branch_labels: TrackedCudaSlice<i64>,
552 branch_ids: TrackedCudaSlice<i64>,
553 source_slots: TrackedCudaSlice<i64>,
554 logical_positions: TrackedCudaSlice<i64>,
555 kinds: TrackedCudaSlice<i64>,
556 parents: TrackedCudaSlice<i64>,
557 #[cfg(feature = "semantic-policy")]
558 critic_terms: TrackedCudaSlice<f32>,
559 #[cfg(feature = "semantic-policy")]
560 critic_total: TrackedCudaSlice<f32>,
561}
562
563pub struct SemanticSelectedTrainingView {
566 arena: Arc<SemanticTrainingViewArena>,
567 _origin_candidates: Option<Arc<TrackedCudaSlice<SemanticTrainingViewOriginRecord>>>,
568 storage: SelectedTrainingViewStorage,
569}
570
571#[cfg(feature = "semantic-policy")]
572#[derive(Clone, Copy)]
573pub(crate) struct FrozenPolicyGroupMember {
574 pub ordinal: u64,
575 pub identity: [u64; 4],
576 pub source_identity: [u64; 4],
577 pub bytes_identity: Identity256,
578 pub content_identity: [u64; 4],
579 pub origin: SemanticTrainingViewOriginRecord,
580}
581
582#[derive(Clone, Copy, Debug, Eq, PartialEq)]
584pub enum SemanticTrainingViewPort {
585 Selection,
586 RosterRows,
587 Objective,
588 ObjectiveGroups,
589 ObjectiveGroupMembers,
590 Canaries,
591 TokenIds,
592 MaskLabels,
593 MaskWeights,
594 AutoregressiveLabels,
595 RetentionLabels,
596 BranchLabels,
597 BranchIds,
598 SourceSlots,
599 LogicalPositions,
600 Kinds,
601 Parents,
602}
603
604impl SemanticTrainingViewPort {
605 pub const ALL: [Self; 17] = [
607 Self::Selection,
608 Self::RosterRows,
609 Self::Objective,
610 Self::ObjectiveGroups,
611 Self::ObjectiveGroupMembers,
612 Self::Canaries,
613 Self::TokenIds,
614 Self::MaskLabels,
615 Self::MaskWeights,
616 Self::AutoregressiveLabels,
617 Self::RetentionLabels,
618 Self::BranchLabels,
619 Self::BranchIds,
620 Self::SourceSlots,
621 Self::LogicalPositions,
622 Self::Kinds,
623 Self::Parents,
624 ];
625}
626
627impl SemanticSelectedTrainingView {
628 pub fn capacity(&self) -> usize {
629 self.arena.capacity
630 }
631
632 #[cfg(feature = "semantic-policy")]
633 pub(crate) fn accounted_allocation_bytes(&self) -> Result<u64, SemanticTransitionError> {
634 let mut allocations: Vec<crate::memory::DeviceAllocationProvenance> = Vec::new();
635 macro_rules! account {
636 ($slice:expr) => {{
637 let provenance = $slice
638 .view()
639 .allocation_provenance()
640 .ok_or(SemanticTransitionError::ObservationMismatch)?;
641 if !allocations
642 .iter()
643 .any(|known| provenance.same_allocation(known))
644 {
645 allocations.push(provenance);
646 }
647 }};
648 }
649 account!(self.arena.descriptors);
650 account!(self.arena.raw);
651 account!(self.arena.objective);
652 account!(self.arena.groups);
653 account!(self.arena.group_members);
654 account!(self.arena.canaries);
655 account!(self.arena.protected_members);
656 account!(self.storage.selection);
657 account!(self.storage.roster_rows);
658 account!(self.storage.token_ids);
659 account!(self.storage.mask_labels);
660 account!(self.storage.mask_weights);
661 account!(self.storage.ar_labels);
662 account!(self.storage.retention_labels);
663 account!(self.storage.branch_labels);
664 account!(self.storage.branch_ids);
665 account!(self.storage.source_slots);
666 account!(self.storage.logical_positions);
667 account!(self.storage.kinds);
668 account!(self.storage.parents);
669 #[cfg(feature = "semantic-policy")]
670 account!(self.storage.critic_terms);
671 #[cfg(feature = "semantic-policy")]
672 account!(self.storage.critic_total);
673 allocations.into_iter().try_fold(0u64, |total, allocation| {
674 total
675 .checked_add(allocation.allocation_bytes())
676 .ok_or(SemanticTransitionError::GenerationExhausted)
677 })
678 }
679
680 pub fn row_count(&self) -> usize {
681 self.arena.row_count
682 }
683
684 pub fn selection(&self) -> DeviceMemoryView<SemanticTrainingViewSelection> {
685 self.storage.selection.view()
686 }
687
688 pub fn roster_rows(&self) -> DeviceMemoryView<SemanticTrainingRosterRow> {
689 self.storage.roster_rows.view()
690 }
691
692 #[cfg(feature = "semantic-policy")]
693 pub(crate) fn objective(&self) -> DeviceMemoryView<SemanticTrainingObjectiveRecord> {
694 self.arena.objective.view()
695 }
696
697 #[cfg(feature = "semantic-policy")]
698 pub(crate) fn objective_groups(
699 &self,
700 ) -> DeviceMemoryView<SemanticTrainingObjectiveGroupRecord> {
701 self.arena.groups.view()
702 }
703
704 #[cfg(feature = "semantic-policy")]
705 pub(crate) fn objective_group_members(&self) -> DeviceMemoryView<u64> {
706 self.arena.group_members.view()
707 }
708
709 #[cfg(feature = "semantic-policy")]
710 pub(crate) fn actor_group_member_count(&self) -> u64 {
711 self.arena.actor_group_member_count
712 }
713
714 #[cfg(feature = "semantic-policy")]
715 pub(crate) fn actor_group_members(&self) -> &[FrozenPolicyGroupMember] {
716 &self.arena.actor_group_members
717 }
718
719 #[cfg(feature = "semantic-policy")]
720 pub(crate) fn edit_group_members(&self) -> &[FrozenPolicyGroupMember] {
721 &self.arena.edit_group_members
722 }
723
724 #[cfg(feature = "semantic-policy")]
725 pub(crate) fn actor_group_member_index(
726 &self,
727 ordinal: u64,
728 row: &SemanticTrainingViewRow,
729 ) -> Result<usize, SemanticTransitionError> {
730 let descriptor = validate_row(
731 usize::try_from(ordinal)
732 .map_err(|_| input_error("actor group ordinal exceeds host address space"))?,
733 row,
734 0,
735 &self.arena.training_domain,
736 )?;
737 self.actor_group_members()
738 .iter()
739 .position(|member| {
740 member.ordinal == ordinal
741 && member.identity == descriptor.identity
742 && member.source_identity == descriptor.source_identity
743 && member.bytes_identity == row.bytes_identity
744 && member.content_identity == descriptor.content_identity
745 && member.origin == descriptor.origin
746 })
747 .ok_or_else(|| input_error("original replay is not an exact frozen actor group member"))
748 }
749
750 #[cfg(feature = "semantic-policy")]
751 pub(crate) fn edit_group_member_index(
752 &self,
753 ordinal: u64,
754 row: &SemanticTrainingViewRow,
755 ) -> Result<Option<usize>, SemanticTransitionError> {
756 let descriptor = validate_row(
757 usize::try_from(ordinal)
758 .map_err(|_| input_error("edit group ordinal exceeds host address space"))?,
759 row,
760 0,
761 &self.arena.training_domain,
762 )?;
763 Ok(self.edit_group_members().iter().position(|member| {
764 member.ordinal == ordinal
765 && member.identity == descriptor.identity
766 && member.source_identity == descriptor.source_identity
767 && member.bytes_identity == row.bytes_identity
768 && member.content_identity == descriptor.content_identity
769 && member.origin == descriptor.origin
770 }))
771 }
772
773 #[cfg(feature = "semantic-policy")]
774 pub(crate) fn critic_term(&self, index: usize) -> DeviceMemoryView<f32> {
775 self.storage.critic_terms.slice(index..index + 1)
776 }
777
778 #[cfg(feature = "semantic-policy")]
779 pub(crate) fn critic_terms(&self) -> DeviceMemoryView<f32> {
780 self.storage.critic_terms.view()
781 }
782
783 #[cfg(feature = "semantic-policy")]
784 pub(crate) fn critic_total(&self) -> DeviceMemoryView<f32> {
785 self.storage.critic_total.view()
786 }
787
788 #[cfg(feature = "semantic-policy")]
789 pub(crate) fn canaries(&self) -> DeviceMemoryView<SemanticTrainingCanaryRecord> {
790 self.arena.canaries.view()
791 }
792
793 #[cfg(feature = "semantic-policy")]
794 pub(crate) fn protected_members(&self) -> DeviceMemoryView<u64> {
795 self.arena.protected_members.view()
796 }
797
798 pub fn token_ids(&self) -> DeviceMemoryView<i64> {
799 self.storage.token_ids.view()
800 }
801
802 pub fn mask_labels(&self) -> DeviceMemoryView<i64> {
803 self.storage.mask_labels.view()
804 }
805
806 pub fn mask_weights(&self) -> DeviceMemoryView<f32> {
807 self.storage.mask_weights.view()
808 }
809
810 pub fn ar_labels(&self) -> DeviceMemoryView<i64> {
811 self.storage.ar_labels.view()
812 }
813
814 pub fn retention_labels(&self) -> DeviceMemoryView<i64> {
815 self.storage.retention_labels.view()
816 }
817
818 pub fn branch_labels(&self) -> DeviceMemoryView<i64> {
819 self.storage.branch_labels.view()
820 }
821
822 pub fn branch_ids(&self) -> DeviceMemoryView<i64> {
823 self.storage.branch_ids.view()
824 }
825
826 pub fn source_slots(&self) -> DeviceMemoryView<i64> {
827 self.storage.source_slots.view()
828 }
829
830 pub fn logical_positions(&self) -> DeviceMemoryView<i64> {
831 self.storage.logical_positions.view()
832 }
833
834 pub fn kinds(&self) -> DeviceMemoryView<i64> {
835 self.storage.kinds.view()
836 }
837
838 pub fn parents(&self) -> DeviceMemoryView<i64> {
839 self.storage.parents.view()
840 }
841
842 pub(crate) fn port(
843 &self,
844 port: SemanticTrainingViewPort,
845 ) -> Result<TrainingViewPort, SemanticTransitionError> {
846 let words = |bytes: usize| {
847 i64::try_from(bytes / size_of::<u64>())
848 .map_err(|_| SemanticTransitionError::GenerationExhausted)
849 };
850 let rows = i64::try_from(self.row_count())
851 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
852 let capacity = i64::try_from(self.capacity())
853 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
854 let extent = |length: usize| {
855 i64::try_from(length).map_err(|_| SemanticTransitionError::GenerationExhausted)
856 };
857 let matrix = |view, dtype| (view, vec![rows, capacity], vec![capacity, 1], dtype);
858 let result = match port {
859 SemanticTrainingViewPort::Selection => (
860 unsafe { self.storage.selection.view().cast::<u8>() }
861 .ok_or(SemanticTransitionError::ObservationMismatch)?,
862 vec![words(size_of::<SemanticTrainingViewSelection>())?],
863 vec![1],
864 (1, 64),
865 ),
866 SemanticTrainingViewPort::RosterRows => (
867 unsafe { self.storage.roster_rows.view().cast::<u8>() }
868 .ok_or(SemanticTransitionError::ObservationMismatch)?,
869 vec![rows, words(size_of::<SemanticTrainingRosterRow>())?],
870 vec![words(size_of::<SemanticTrainingRosterRow>())?, 1],
871 (1, 64),
872 ),
873 SemanticTrainingViewPort::Objective => (
874 unsafe { self.arena.objective.view().cast::<u8>() }
875 .ok_or(SemanticTransitionError::ObservationMismatch)?,
876 vec![words(size_of::<SemanticTrainingObjectiveRecord>())?],
877 vec![1],
878 (1, 64),
879 ),
880 SemanticTrainingViewPort::ObjectiveGroups => {
881 let width = words(size_of::<SemanticTrainingObjectiveGroupRecord>())?;
882 (
883 unsafe { self.arena.groups.view().cast::<u8>() }
884 .ok_or(SemanticTransitionError::ObservationMismatch)?,
885 vec![extent(self.arena.groups.len())?, width],
886 vec![width, 1],
887 (1, 64),
888 )
889 }
890 SemanticTrainingViewPort::ObjectiveGroupMembers => (
891 unsafe { self.arena.group_members.view().cast::<u8>() }
892 .ok_or(SemanticTransitionError::ObservationMismatch)?,
893 vec![extent(self.arena.group_members.len())?],
894 vec![1],
895 (1, 64),
896 ),
897 SemanticTrainingViewPort::Canaries => {
898 let width = words(size_of::<SemanticTrainingCanaryRecord>())?;
899 (
900 unsafe { self.arena.canaries.view().cast::<u8>() }
901 .ok_or(SemanticTransitionError::ObservationMismatch)?,
902 vec![extent(self.arena.canaries.len())?, width],
903 vec![width, 1],
904 (1, 64),
905 )
906 }
907 SemanticTrainingViewPort::TokenIds => (
908 unsafe { self.storage.token_ids.view().cast::<u8>() }
909 .ok_or(SemanticTransitionError::ObservationMismatch)?,
910 vec![],
911 vec![],
912 (0, 64),
913 ),
914 SemanticTrainingViewPort::MaskLabels => (
915 unsafe { self.storage.mask_labels.view().cast::<u8>() }
916 .ok_or(SemanticTransitionError::ObservationMismatch)?,
917 vec![],
918 vec![],
919 (0, 64),
920 ),
921 SemanticTrainingViewPort::MaskWeights => (
922 unsafe { self.storage.mask_weights.view().cast::<u8>() }
923 .ok_or(SemanticTransitionError::ObservationMismatch)?,
924 vec![],
925 vec![],
926 (2, 32),
927 ),
928 SemanticTrainingViewPort::AutoregressiveLabels => (
929 unsafe { self.storage.ar_labels.view().cast::<u8>() }
930 .ok_or(SemanticTransitionError::ObservationMismatch)?,
931 vec![],
932 vec![],
933 (0, 64),
934 ),
935 SemanticTrainingViewPort::RetentionLabels => (
936 unsafe { self.storage.retention_labels.view().cast::<u8>() }
937 .ok_or(SemanticTransitionError::ObservationMismatch)?,
938 vec![],
939 vec![],
940 (0, 64),
941 ),
942 SemanticTrainingViewPort::BranchLabels => (
943 unsafe { self.storage.branch_labels.view().cast::<u8>() }
944 .ok_or(SemanticTransitionError::ObservationMismatch)?,
945 vec![],
946 vec![],
947 (0, 64),
948 ),
949 SemanticTrainingViewPort::BranchIds => (
950 unsafe { self.storage.branch_ids.view().cast::<u8>() }
951 .ok_or(SemanticTransitionError::ObservationMismatch)?,
952 vec![],
953 vec![],
954 (0, 64),
955 ),
956 SemanticTrainingViewPort::SourceSlots => (
957 unsafe { self.storage.source_slots.view().cast::<u8>() }
958 .ok_or(SemanticTransitionError::ObservationMismatch)?,
959 vec![],
960 vec![],
961 (0, 64),
962 ),
963 SemanticTrainingViewPort::LogicalPositions => (
964 unsafe { self.storage.logical_positions.view().cast::<u8>() }
965 .ok_or(SemanticTransitionError::ObservationMismatch)?,
966 vec![],
967 vec![],
968 (0, 64),
969 ),
970 SemanticTrainingViewPort::Kinds => (
971 unsafe { self.storage.kinds.view().cast::<u8>() }
972 .ok_or(SemanticTransitionError::ObservationMismatch)?,
973 vec![],
974 vec![],
975 (0, 64),
976 ),
977 SemanticTrainingViewPort::Parents => (
978 unsafe { self.storage.parents.view().cast::<u8>() }
979 .ok_or(SemanticTransitionError::ObservationMismatch)?,
980 vec![],
981 vec![],
982 (0, 64),
983 ),
984 };
985 Ok(match port {
986 SemanticTrainingViewPort::TokenIds
987 | SemanticTrainingViewPort::MaskLabels
988 | SemanticTrainingViewPort::MaskWeights
989 | SemanticTrainingViewPort::AutoregressiveLabels
990 | SemanticTrainingViewPort::RetentionLabels
991 | SemanticTrainingViewPort::BranchLabels
992 | SemanticTrainingViewPort::BranchIds
993 | SemanticTrainingViewPort::SourceSlots
994 | SemanticTrainingViewPort::LogicalPositions
995 | SemanticTrainingViewPort::Kinds
996 | SemanticTrainingViewPort::Parents => matrix(result.0, result.3),
997 _ => result,
998 })
999 }
1000
1001 pub(crate) fn enqueue_device_selection(
1002 &self,
1003 selected_view: DeviceMemoryView<u8>,
1004 coordinates: DeviceMemoryView<u64>,
1005 ) -> Result<(), SemanticTransitionError> {
1006 if coordinates.len() != 5 {
1007 return Err(input_error(
1008 "prepared training-view coordinates require cursor and four RNG words",
1009 ));
1010 }
1011 self.enqueue(selected_view, 0, [0; 4], Some(coordinates))
1012 }
1013
1014 fn enqueue(
1015 &self,
1016 selected_view: DeviceMemoryView<u8>,
1017 cursor: u64,
1018 training_rng: [u64; 4],
1019 coordinates: Option<DeviceMemoryView<u64>>,
1020 ) -> Result<(), SemanticTransitionError> {
1021 let (origin_candidate_ptr, origin_candidate_count) =
1022 if let Some(candidates) = self._origin_candidates.as_ref() {
1023 (
1024 candidates.device_ptr_value(),
1025 u64::try_from(candidates.len())
1026 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1027 )
1028 } else {
1029 (0, 0)
1030 };
1031 let launch = TrainingViewLaunch {
1032 descriptors: self.arena.descriptors.device_ptr_value(),
1033 raw: self.arena.raw.device_ptr_value(),
1034 row_count: u64::try_from(self.arena.row_count)
1035 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1036 selected_view: *selected_view.device_ptr(),
1037 selected_view_bytes: u64::try_from(selected_view.len())
1038 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1039 cursor,
1040 training_rng,
1041 coordinates: coordinates.as_ref().map_or(0, |view| *view.device_ptr()),
1042 origin_candidates: origin_candidate_ptr,
1043 origin_candidate_count,
1044 selection: self.storage.selection.device_ptr_value(),
1045 roster_rows: self.storage.roster_rows.device_ptr_value(),
1046 capacity: u64::try_from(self.arena.capacity)
1047 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1048 token_ids: self.storage.token_ids.device_ptr_value(),
1049 mask_labels: self.storage.mask_labels.device_ptr_value(),
1050 mask_weights: self.storage.mask_weights.device_ptr_value(),
1051 ar_labels: self.storage.ar_labels.device_ptr_value(),
1052 retention_labels: self.storage.retention_labels.device_ptr_value(),
1053 branch_labels: self.storage.branch_labels.device_ptr_value(),
1054 branch_ids: self.storage.branch_ids.device_ptr_value(),
1055 source_slots: self.storage.source_slots.device_ptr_value(),
1056 logical_positions: self.storage.logical_positions.device_ptr_value(),
1057 kinds: self.storage.kinds.device_ptr_value(),
1058 parents: self.storage.parents.device_ptr_value(),
1059 };
1060 let mut recorder = self.arena.domain.new_strict_recorder();
1061 recorder.read(&self.arena.descriptors);
1062 recorder.read(&self.arena.raw);
1063 recorder.read(&selected_view);
1064 if let Some(candidates) = &self._origin_candidates {
1065 recorder.read(candidates.as_ref());
1066 }
1067 if let Some(coordinates) = &coordinates {
1068 recorder.read(coordinates);
1069 }
1070 recorder.write(&self.storage.selection);
1071 recorder.write(&self.storage.roster_rows);
1072 recorder.write(&self.storage.token_ids);
1073 recorder.write(&self.storage.mask_labels);
1074 recorder.write(&self.storage.mask_weights);
1075 recorder.write(&self.storage.ar_labels);
1076 recorder.write(&self.storage.retention_labels);
1077 recorder.write(&self.storage.branch_labels);
1078 recorder.write(&self.storage.branch_ids);
1079 recorder.write(&self.storage.source_slots);
1080 recorder.write(&self.storage.logical_positions);
1081 recorder.write(&self.storage.kinds);
1082 recorder.write(&self.storage.parents);
1083 let select = self.arena.select.clone();
1084 let gather = self.arena.gather.clone();
1085 let gather_grid = u32::try_from(self.arena.row_count)
1086 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
1087 let enqueued = unsafe {
1088 self.arena.domain.enqueue(recorder, |stream| {
1089 select.clone().launch_in(
1090 stream,
1091 LaunchConfig {
1092 grid_dim: (1, 1, 1),
1093 block_dim: (256, 1, 1),
1094 shared_mem_bytes: 0,
1095 },
1096 (launch,),
1097 )?;
1098 gather.clone().launch_in(
1099 stream,
1100 LaunchConfig {
1101 grid_dim: (gather_grid, 1, 1),
1102 block_dim: (256, 1, 1),
1103 shared_mem_bytes: 0,
1104 },
1105 (launch,),
1106 )
1107 })
1108 }
1109 .map_err(map_enqueue_error)?;
1110 enqueued
1111 .commit()
1112 .map_err(|error| runtime_error("training-view launch commit", error))
1113 }
1114}
1115
1116pub(crate) struct SemanticTrainingViewArena {
1118 #[cfg(feature = "semantic-policy")]
1119 training_domain: SemanticTrainingDomain,
1120 provider: Arc<CudaKernelProvider>,
1121 domain: ResidentExecutionDomain,
1122 select: CudaFunction,
1123 gather: CudaFunction,
1124 descriptors: TrackedCudaSlice<TrainingViewRowDescriptor>,
1125 raw: TrackedCudaSlice<u8>,
1126 objective: TrackedCudaSlice<SemanticTrainingObjectiveRecord>,
1127 groups: TrackedCudaSlice<SemanticTrainingObjectiveGroupRecord>,
1128 group_members: TrackedCudaSlice<u64>,
1129 canaries: TrackedCudaSlice<SemanticTrainingCanaryRecord>,
1130 #[cfg(feature = "semantic-policy")]
1131 protected_members: TrackedCudaSlice<u64>,
1132 #[cfg(feature = "semantic-policy")]
1133 actor_group_member_count: u64,
1134 #[cfg(feature = "semantic-policy")]
1135 actor_group_members: Box<[FrozenPolicyGroupMember]>,
1136 #[cfg(feature = "semantic-policy")]
1137 edit_group_members: Box<[FrozenPolicyGroupMember]>,
1138 row_count: usize,
1139 capacity: usize,
1140}
1141
1142impl SemanticTrainingViewArena {
1143 #[cfg(feature = "semantic-policy")]
1144 pub(crate) fn training_domain_identity(&self) -> Identity256 {
1145 self.training_domain.identity()
1146 }
1147
1148 pub(crate) fn selection_bytes(&self) -> Result<usize, SemanticTransitionError> {
1149 let roster_bytes = self
1150 .row_count
1151 .checked_mul(size_of::<SemanticTrainingRosterRow>())
1152 .ok_or(SemanticTransitionError::GenerationExhausted)?;
1153 let port_bytes = self
1154 .capacity
1155 .checked_mul(self.row_count)
1156 .and_then(|cells| cells.checked_mul(TRAINING_VIEW_ROW_BYTES))
1157 .ok_or(SemanticTransitionError::GenerationExhausted)?;
1158 let bytes = size_of::<SemanticTrainingViewSelection>()
1159 .checked_add(roster_bytes)
1160 .and_then(|bytes| bytes.checked_add(port_bytes))
1161 .ok_or(SemanticTransitionError::GenerationExhausted)?;
1162 #[cfg(feature = "semantic-policy")]
1163 let bytes = bytes
1164 .checked_add(
1165 (self.actor_group_members.len() + 1)
1166 .checked_mul(size_of::<f32>())
1167 .ok_or(SemanticTransitionError::GenerationExhausted)?,
1168 )
1169 .ok_or(SemanticTransitionError::GenerationExhausted)?;
1170 Ok(bytes)
1171 }
1172
1173 pub(crate) fn allocate_selection_reserved(
1174 self: &Arc<Self>,
1175 reservation: &mut crate::memory::GpuMemoryReservation,
1176 origin_candidates: Option<Arc<TrackedCudaSlice<SemanticTrainingViewOriginRecord>>>,
1177 ) -> Result<SemanticSelectedTrainingView, SemanticTransitionError> {
1178 let storage = SelectedTrainingViewStorage {
1179 selection: reservation
1180 .alloc::<SemanticTrainingViewSelection>(1)
1181 .map_err(|error| runtime_error("training-view selection allocation", error))?,
1182 roster_rows: reservation
1183 .alloc::<SemanticTrainingRosterRow>(self.row_count)
1184 .map_err(|error| runtime_error("training-view roster allocation", error))?,
1185 token_ids: allocate_port(reservation, self.row_count, self.capacity)?,
1186 mask_labels: allocate_port(reservation, self.row_count, self.capacity)?,
1187 mask_weights: allocate_port(reservation, self.row_count, self.capacity)?,
1188 ar_labels: allocate_port(reservation, self.row_count, self.capacity)?,
1189 retention_labels: allocate_port(reservation, self.row_count, self.capacity)?,
1190 branch_labels: allocate_port(reservation, self.row_count, self.capacity)?,
1191 branch_ids: allocate_port(reservation, self.row_count, self.capacity)?,
1192 source_slots: allocate_port(reservation, self.row_count, self.capacity)?,
1193 logical_positions: allocate_port(reservation, self.row_count, self.capacity)?,
1194 kinds: allocate_port(reservation, self.row_count, self.capacity)?,
1195 parents: allocate_port(reservation, self.row_count, self.capacity)?,
1196 #[cfg(feature = "semantic-policy")]
1197 critic_terms: reservation
1198 .alloc::<f32>(self.actor_group_members.len())
1199 .map_err(|error| runtime_error("group critic term allocation", error))?,
1200 #[cfg(feature = "semantic-policy")]
1201 critic_total: reservation
1202 .alloc::<f32>(1)
1203 .map_err(|error| runtime_error("group critic scalar allocation", error))?,
1204 };
1205 Ok(SemanticSelectedTrainingView {
1206 arena: Arc::clone(self),
1207 _origin_candidates: origin_candidates,
1208 storage,
1209 })
1210 }
1211
1212 #[expect(
1213 clippy::too_many_arguments,
1214 reason = "arena retains the task, numerical law and original input domain"
1215 )]
1216 pub(crate) fn allocate(
1217 provider: &Arc<CudaKernelProvider>,
1218 domain: &ResidentExecutionDomain,
1219 rows: Vec<SemanticTrainingViewRow>,
1220 objective: SemanticTrainingObjective,
1221 training_domain: &SemanticTrainingDomain,
1222 task_identity: Identity256,
1223 task_content: SemanticTaskContentIdentity,
1224 expected_truth: [SemanticTruth; 3],
1225 ) -> Result<Arc<Self>, SemanticTransitionError> {
1226 validate_execution_domain(provider, domain)
1227 .map_err(|error| runtime_error("training-view domain validation", error))?;
1228 if rows.is_empty() {
1229 return Err(input_error(
1230 "training-view arena requires at least one admitted row",
1231 ));
1232 }
1233 training_domain.validate()?;
1234 let record_limit = training_domain.record_limit();
1235 let mut episode_count = 0u64;
1236 let mut anchor_count = 0u64;
1237 let mut content_identities = std::collections::BTreeSet::new();
1238 for row in &rows {
1239 let count = if row.basis == SemanticTrainingViewBasis::Episode {
1240 &mut episode_count
1241 } else {
1242 &mut anchor_count
1243 };
1244 *count = count
1245 .checked_add(1)
1246 .ok_or(SemanticTransitionError::GenerationExhausted)?;
1247 if *count > record_limit || !content_identities.insert(*row.content_identity.as_bytes())
1248 {
1249 return Err(input_error(
1250 "training rows exceed the original input bound or repeat content",
1251 ));
1252 }
1253 }
1254 let select = provider
1255 .device()
1256 .inner()
1257 .get_func(MODULE, SELECT_KERNEL)
1258 .ok_or_else(|| runtime_error("training-view kernel lookup", "selector unavailable"))?;
1259 let gather = provider
1260 .device()
1261 .inner()
1262 .get_func(MODULE, GATHER_KERNEL)
1263 .ok_or_else(|| runtime_error("training-view kernel lookup", "gather unavailable"))?;
1264 let mut raw = Vec::new();
1265 let mut descriptors = Vec::with_capacity(rows.len());
1266 #[cfg(feature = "semantic-policy")]
1267 let mut row_bytes_identities = Vec::with_capacity(rows.len());
1268 let mut capacity = 0usize;
1269 for (ordinal, row) in rows.into_iter().enumerate() {
1270 let descriptor = validate_row(ordinal, &row, raw.len(), training_domain)?;
1271 #[cfg(feature = "semantic-policy")]
1272 row_bytes_identities.push(row.bytes_identity);
1273 capacity = capacity.max(descriptor.window as usize);
1274 raw.extend_from_slice(&row.bytes);
1275 descriptors.push(descriptor);
1276 }
1277 #[cfg(feature = "semantic-policy")]
1278 let (objective, groups, group_members, canaries, protected_members) = validate_objective(
1279 objective,
1280 &descriptors,
1281 &raw,
1282 capacity,
1283 task_identity,
1284 task_content,
1285 expected_truth,
1286 record_limit,
1287 )?;
1288 #[cfg(not(feature = "semantic-policy"))]
1289 let (objective, groups, group_members, canaries, _) = validate_objective(
1290 objective,
1291 &descriptors,
1292 &raw,
1293 capacity,
1294 task_identity,
1295 task_content,
1296 expected_truth,
1297 record_limit,
1298 )?;
1299 #[cfg(feature = "semantic-policy")]
1300 let actor_group = groups
1301 .iter()
1302 .find(|group| group.kind == SemanticTrainingObjectiveGroupKind::ActorCriticCost as u64)
1303 .ok_or_else(|| input_error("training objective has no actor-critic-cost group"))?;
1304 #[cfg(feature = "semantic-policy")]
1305 let actor_group_member_count = actor_group.member_count;
1306 #[cfg(feature = "semantic-policy")]
1307 let actor_group_members = {
1308 let start = usize::try_from(actor_group.member_offset)
1309 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
1310 let count = usize::try_from(actor_group.member_count)
1311 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
1312 group_members[start..start + count]
1313 .iter()
1314 .map(|&ordinal| {
1315 let row = &descriptors[ordinal as usize];
1316 FrozenPolicyGroupMember {
1317 ordinal,
1318 identity: row.identity,
1319 source_identity: row.source_identity,
1320 bytes_identity: row_bytes_identities[ordinal as usize],
1321 content_identity: row.content_identity,
1322 origin: row.origin,
1323 }
1324 })
1325 .collect::<Vec<_>>()
1326 .into_boxed_slice()
1327 };
1328 #[cfg(feature = "semantic-policy")]
1329 let edit_group_members = {
1330 let group = groups
1331 .iter()
1332 .find(|group| group.kind == SemanticTrainingObjectiveGroupKind::Edit as u64)
1333 .ok_or_else(|| input_error("training objective has no supervised-edit group"))?;
1334 let start = usize::try_from(group.member_offset)
1335 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
1336 let count = usize::try_from(group.member_count)
1337 .map_err(|_| SemanticTransitionError::GenerationExhausted)?;
1338 group_members[start..start + count]
1339 .iter()
1340 .map(|&ordinal| {
1341 let row = &descriptors[ordinal as usize];
1342 FrozenPolicyGroupMember {
1343 ordinal,
1344 identity: row.identity,
1345 source_identity: row.source_identity,
1346 bytes_identity: row_bytes_identities[ordinal as usize],
1347 content_identity: row.content_identity,
1348 origin: row.origin,
1349 }
1350 })
1351 .collect::<Vec<_>>()
1352 .into_boxed_slice()
1353 };
1354 let bytes = descriptors
1355 .len()
1356 .checked_mul(size_of::<TrainingViewRowDescriptor>())
1357 .and_then(|bytes| bytes.checked_add(raw.len()))
1358 .and_then(|bytes| bytes.checked_add(size_of::<SemanticTrainingObjectiveRecord>()))
1359 .and_then(|bytes| {
1360 groups
1361 .len()
1362 .checked_mul(size_of::<SemanticTrainingObjectiveGroupRecord>())
1363 .and_then(|group_bytes| bytes.checked_add(group_bytes))
1364 })
1365 .and_then(|bytes| {
1366 group_members
1367 .len()
1368 .checked_mul(size_of::<u64>())
1369 .and_then(|member_bytes| bytes.checked_add(member_bytes))
1370 })
1371 .and_then(|bytes| {
1372 canaries
1373 .len()
1374 .checked_mul(size_of::<SemanticTrainingCanaryRecord>())
1375 .and_then(|canary_bytes| bytes.checked_add(canary_bytes))
1376 });
1377 #[cfg(feature = "semantic-policy")]
1378 let bytes = bytes.and_then(|bytes| {
1379 protected_members
1380 .len()
1381 .checked_mul(size_of::<u64>())
1382 .and_then(|member_bytes| bytes.checked_add(member_bytes))
1383 });
1384 let bytes = bytes.ok_or(SemanticTransitionError::GenerationExhausted)?;
1385 let mut reservation = provider
1386 .memory()
1387 .reserve_bytes(
1388 u64::try_from(bytes).map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1389 )
1390 .map_err(|error| runtime_error("training-view reservation", error))?;
1391 let mut device_descriptors = reservation
1392 .alloc::<TrainingViewRowDescriptor>(descriptors.len())
1393 .map_err(|error| runtime_error("training-view descriptor allocation", error))?;
1394 let mut device_raw = reservation
1395 .alloc::<u8>(raw.len())
1396 .map_err(|error| runtime_error("training-view byte allocation", error))?;
1397 let mut device_objective = reservation
1398 .alloc::<SemanticTrainingObjectiveRecord>(1)
1399 .map_err(|error| runtime_error("training objective allocation", error))?;
1400 let mut device_groups = reservation
1401 .alloc::<SemanticTrainingObjectiveGroupRecord>(groups.len())
1402 .map_err(|error| runtime_error("training objective group allocation", error))?;
1403 let mut device_group_members = reservation
1404 .alloc::<u64>(group_members.len())
1405 .map_err(|error| runtime_error("training objective member allocation", error))?;
1406 let mut device_canaries = reservation
1407 .alloc::<SemanticTrainingCanaryRecord>(canaries.len())
1408 .map_err(|error| runtime_error("training canary allocation", error))?;
1409 #[cfg(feature = "semantic-policy")]
1410 let mut device_protected_members = reservation
1411 .alloc::<u64>(protected_members.len())
1412 .map_err(|error| runtime_error("protected retention member allocation", error))?;
1413 if reservation.remaining_bytes() != 0 {
1414 return Err(SemanticTransitionError::ObservationMismatch);
1415 }
1416 provider
1417 .htod_sync_copy_into_tracked(&descriptors, &mut device_descriptors)
1418 .map_err(|error| runtime_error("training-view descriptor upload", error))?;
1419 provider
1420 .htod_sync_copy_into_tracked(&raw, &mut device_raw)
1421 .map_err(|error| runtime_error("training-view byte upload", error))?;
1422 provider
1423 .htod_sync_copy_into_tracked(&[objective], &mut device_objective)
1424 .map_err(|error| runtime_error("training objective upload", error))?;
1425 provider
1426 .htod_sync_copy_into_tracked(&groups, &mut device_groups)
1427 .map_err(|error| runtime_error("training objective group upload", error))?;
1428 provider
1429 .htod_sync_copy_into_tracked(&group_members, &mut device_group_members)
1430 .map_err(|error| runtime_error("training objective member upload", error))?;
1431 provider
1432 .htod_sync_copy_into_tracked(&canaries, &mut device_canaries)
1433 .map_err(|error| runtime_error("training canary upload", error))?;
1434 #[cfg(feature = "semantic-policy")]
1435 provider
1436 .htod_sync_copy_into_tracked(&protected_members, &mut device_protected_members)
1437 .map_err(|error| runtime_error("protected retention member upload", error))?;
1438 Ok(Arc::new(Self {
1439 #[cfg(feature = "semantic-policy")]
1440 training_domain: training_domain.clone(),
1441 provider: Arc::clone(provider),
1442 domain: domain.clone(),
1443 select,
1444 gather,
1445 descriptors: device_descriptors,
1446 raw: device_raw,
1447 objective: device_objective,
1448 groups: device_groups,
1449 group_members: device_group_members,
1450 canaries: device_canaries,
1451 #[cfg(feature = "semantic-policy")]
1452 protected_members: device_protected_members,
1453 #[cfg(feature = "semantic-policy")]
1454 actor_group_member_count,
1455 #[cfg(feature = "semantic-policy")]
1456 actor_group_members,
1457 #[cfg(feature = "semantic-policy")]
1458 edit_group_members,
1459 row_count: descriptors.len(),
1460 capacity,
1461 }))
1462 }
1463
1464 pub(crate) fn enqueue_selection(
1465 self: &Arc<Self>,
1466 selected_view: DeviceMemoryView<u8>,
1467 cursor: u64,
1468 training_rng: [u64; 4],
1469 origin_candidates: Option<Arc<TrackedCudaSlice<SemanticTrainingViewOriginRecord>>>,
1470 ) -> Result<SemanticSelectedTrainingView, SemanticTransitionError> {
1471 let output_bytes = self.selection_bytes()?;
1472 let mut reservation = self
1473 .provider
1474 .memory()
1475 .reserve_bytes(
1476 u64::try_from(output_bytes)
1477 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1478 )
1479 .map_err(|error| runtime_error("selected training-view reservation", error))?;
1480 let selected = self.allocate_selection_reserved(&mut reservation, origin_candidates)?;
1481 if reservation.remaining_bytes() != 0 {
1482 return Err(SemanticTransitionError::ObservationMismatch);
1483 }
1484 selected.enqueue(selected_view, cursor, training_rng, None)?;
1485 Ok(selected)
1486 }
1487}
1488
1489fn allocate_port<T: DeviceRepr>(
1490 reservation: &mut crate::memory::GpuMemoryReservation,
1491 row_count: usize,
1492 capacity: usize,
1493) -> Result<TrackedCudaSlice<T>, SemanticTransitionError> {
1494 reservation
1495 .alloc::<T>(
1496 row_count
1497 .checked_mul(capacity)
1498 .ok_or(SemanticTransitionError::GenerationExhausted)?,
1499 )
1500 .map_err(|error| runtime_error("selected training-view port allocation", error))
1501}
1502
1503#[expect(
1504 clippy::too_many_arguments,
1505 reason = "objective admission checks task, truth and original input bound"
1506)]
1507fn validate_objective(
1508 objective: SemanticTrainingObjective,
1509 rows: &[TrainingViewRowDescriptor],
1510 raw: &[u8],
1511 capacity: usize,
1512 task_identity: Identity256,
1513 task_content: SemanticTaskContentIdentity,
1514 expected_truth: [SemanticTruth; 3],
1515 record_limit: u64,
1516) -> Result<ValidatedTrainingObjective, SemanticTransitionError> {
1517 if objective.groups.len() != 8 || objective.canaries.len() != 5 {
1518 return Err(input_error(
1519 "training objective requires all eight reduction groups and five canaries",
1520 ));
1521 }
1522 if !objective.evaluator_min.is_finite()
1523 || !objective.evaluator_max.is_finite()
1524 || objective.evaluator_min > objective.evaluator_max
1525 || objective
1526 .coefficients
1527 .iter()
1528 .any(|value| !value.is_finite() || *value <= 0.0)
1529 || objective.cost_unit == Identity256::default()
1530 || objective.cost_cap == 0
1531 || task_identity == Identity256::default()
1532 || objective
1533 .truth_tokens
1534 .iter()
1535 .copied()
1536 .collect::<std::collections::BTreeSet<_>>()
1537 .len()
1538 != objective.truth_tokens.len()
1539 {
1540 return Err(input_error(
1541 "training objective has invalid evaluator, coefficient or cost bounds",
1542 ));
1543 }
1544 let expected_query = identity_words(task_content.query);
1545 let expected_theory_program = identity_words(task_content.theory_program);
1546 let expected_result = identity_words(task_content.result);
1547 for row in rows {
1548 let symbolic = row.basis == SemanticTrainingViewBasis::CorpusSymbolicAnchor as u64;
1549 let bound = row.task_query_identity == expected_query
1550 && row.task_theory_program_identity == expected_theory_program
1551 && row.task_result_identity == expected_result;
1552 let absent = row.task_query_identity == [0; 4]
1553 && row.task_theory_program_identity == [0; 4]
1554 && row.task_result_identity == [0; 4];
1555 if (symbolic && !bound) || (!symbolic && !absent) {
1556 return Err(input_error(
1557 "symbolic training view differs from the native query, theory/program or result binding",
1558 ));
1559 }
1560 }
1561 let mut seen_groups = [false; 8];
1562 let mut referenced_rows = vec![false; rows.len()];
1563 let mut groups = Vec::with_capacity(objective.groups.len());
1564 let mut group_members = Vec::new();
1565 for group in &objective.groups {
1566 let index = group.kind as usize - 1;
1567 if seen_groups[index]
1568 || group.row_ordinals.is_empty()
1569 || group.denominator > record_limit
1570 || group.denominator
1571 != u64::try_from(group.row_ordinals.len())
1572 .map_err(|_| SemanticTransitionError::GenerationExhausted)?
1573 {
1574 return Err(input_error(
1575 "training objective groups must be unique, nonempty and use their exact member count as denominator",
1576 ));
1577 }
1578 seen_groups[index] = true;
1579 let member_offset = group_members.len();
1580 let mut previous = None;
1581 for &ordinal in &group.row_ordinals {
1582 let row_ordinal = usize::try_from(ordinal)
1583 .map_err(|_| input_error("training objective row exceeds host address space"))?;
1584 let row = rows
1585 .get(row_ordinal)
1586 .ok_or_else(|| input_error("training objective names an unknown replay row"))?;
1587 if previous.is_some_and(|value| value >= ordinal) {
1588 return Err(input_error(
1589 "training objective row ordinals must be strictly increasing",
1590 ));
1591 }
1592 let policy_group = group.kind == SemanticTrainingObjectiveGroupKind::ActorCriticCost;
1593 let expected_anchor = match group.kind {
1594 SemanticTrainingObjectiveGroupKind::RetentionLanguage => {
1595 Some(SemanticTrainingViewBasis::CorpusLanguageAnchor)
1596 }
1597 SemanticTrainingObjectiveGroupKind::RetentionSymbolic => {
1598 Some(SemanticTrainingViewBasis::CorpusSymbolicAnchor)
1599 }
1600 _ => None,
1601 };
1602 if expected_anchor.map_or(
1603 row.basis != SemanticTrainingViewBasis::Episode as u64,
1604 |basis| row.basis != basis as u64,
1605 ) || (policy_group
1606 && (row.basis != SemanticTrainingViewBasis::Episode as u64
1607 || row.origin.transition != PROPOSAL_TRANSITION))
1608 {
1609 return Err(input_error(
1610 "training objective group refers to an incompatible replay basis",
1611 ));
1612 }
1613 referenced_rows[row_ordinal] = true;
1614 group_members.push(ordinal);
1615 previous = Some(ordinal);
1616 }
1617 groups.push(SemanticTrainingObjectiveGroupRecord {
1618 kind: group.kind as u64,
1619 denominator: group.denominator,
1620 member_offset: u64::try_from(member_offset)
1621 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1622 member_count: u64::try_from(group.row_ordinals.len())
1623 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1624 });
1625 }
1626 if seen_groups.iter().any(|seen| !seen) || referenced_rows.iter().any(|seen| !seen) {
1627 return Err(input_error(
1628 "training objective must cover every mandatory group and replay row",
1629 ));
1630 }
1631 if objective.coefficients.map(f32::to_bits)
1632 != frozen_training_coefficients(objective.evaluator_min, objective.evaluator_max)
1633 .map(f32::to_bits)
1634 {
1635 return Err(input_error(
1636 "training coefficients differ from the frozen primary and evaluator-scaled law",
1637 ));
1638 }
1639 let mut seen_canaries = [false; 5];
1640 let mut canaries = Vec::with_capacity(objective.canaries.len());
1641 let mut protected_members = Vec::new();
1642 for canary in &objective.canaries {
1643 let index = canary.kind as usize - 1;
1644 let row = usize::try_from(canary.row_ordinal)
1645 .ok()
1646 .and_then(|ordinal| rows.get(ordinal));
1647 let obligation_kind = matches!(
1648 canary.kind,
1649 SemanticTrainingCanaryKind::SymbolicUtility | SemanticTrainingCanaryKind::GoalChain
1650 );
1651 let positions_valid = if obligation_kind {
1652 row.is_some_and(|row| {
1653 row.basis == SemanticTrainingViewBasis::CorpusSymbolicAnchor as u64
1654 && canary
1655 .obligation_positions
1656 .windows(2)
1657 .all(|pair| pair[0] < pair[1])
1658 && canary
1659 .obligation_positions
1660 .iter()
1661 .all(|position| *position < row.window)
1662 && canary.obligation_positions.iter().zip(expected_truth).all(
1663 |(position, truth)| {
1664 position
1665 .checked_add(1)
1666 .filter(|target| {
1667 *target >= row.answer_start
1668 && *target < row.window
1669 && *target < row.source_length
1670 })
1671 .and_then(|target| {
1672 usize::try_from(row.raw_offset).ok().and_then(|base| {
1673 usize::try_from(target).ok().and_then(|target| {
1674 base.checked_add(TRAINING_VIEW_HEADER_BYTES).and_then(
1675 |offset| {
1676 target
1677 .checked_mul(size_of::<i64>())
1678 .and_then(|bytes| offset.checked_add(bytes))
1679 },
1680 )
1681 })
1682 })
1683 })
1684 .and_then(|offset| {
1685 offset
1686 .checked_add(size_of::<i64>())
1687 .and_then(|end| raw.get(offset..end))
1688 })
1689 .map(|bytes| {
1690 u64::from_le_bytes(
1691 bytes.try_into().expect("bounded truth token"),
1692 ) == objective.truth_tokens[truth as usize]
1693 })
1694 .unwrap_or(false)
1695 },
1696 )
1697 })
1698 } else {
1699 canary.obligation_positions == [u64::MAX; 3]
1700 };
1701 let protected_valid = if canary.kind == SemanticTrainingCanaryKind::RetainedBehavior {
1702 canary
1703 .protected_positions
1704 .windows(2)
1705 .all(|pair| pair[0] < pair[1])
1706 && row.is_some_and(|row| {
1707 canary
1708 .protected_positions
1709 .iter()
1710 .all(|position| *position < row.window)
1711 })
1712 } else {
1713 canary.protected_positions.is_empty()
1714 };
1715 if index != canaries.len()
1716 || seen_canaries[index]
1717 || !canary.lower_bound.is_finite()
1718 || !canary.upper_bound.is_finite()
1719 || canary.lower_bound > canary.upper_bound
1720 || canary.memory_limit == 0
1721 || canary.work_limit == 0
1722 || row.is_none()
1723 || !positions_valid
1724 || !protected_valid
1725 || (canary.kind == SemanticTrainingCanaryKind::GoalChain
1726 && (canary.lower_bound.to_bits() != 0.0f64.to_bits()
1727 || canary.upper_bound.to_bits() != 0.0f64.to_bits()))
1728 {
1729 return Err(input_error(
1730 "training canaries require canonical kind order, valid rows, bounds and resource ceilings",
1731 ));
1732 }
1733 seen_canaries[index] = true;
1734 let row = row.expect("checked canary row");
1735 let identity = canary_identity(&objective, canary, row, task_identity);
1736 let protected_member_offset = protected_members.len();
1737 protected_members.extend_from_slice(&canary.protected_positions);
1738 canaries.push(SemanticTrainingCanaryRecord {
1739 evaluator_abi: SEMANTIC_TRAINING_CANARY_EVALUATOR_ABI,
1740 kind: canary.kind as u64,
1741 row_ordinal: canary.row_ordinal,
1742 lower_bound_bits: canary.lower_bound.to_bits(),
1743 upper_bound_bits: canary.upper_bound.to_bits(),
1744 memory_limit: canary.memory_limit,
1745 work_limit: canary.work_limit,
1746 obligation_positions: canary.obligation_positions,
1747 protected_member_offset: u64::try_from(protected_member_offset)
1748 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1749 protected_member_count: u64::try_from(canary.protected_positions.len())
1750 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1751 row_identity: row.identity,
1752 row_content_identity: row.content_identity,
1753 task_identity: identity_words(task_identity),
1754 identity: identity_words(identity),
1755 });
1756 }
1757 if seen_canaries.iter().any(|seen| !seen) {
1758 return Err(input_error("training objective is incomplete"));
1759 }
1760 let identity = objective_identity(&objective, rows, task_identity, &canaries);
1761 Ok((
1762 SemanticTrainingObjectiveRecord {
1763 evaluator_abi: SEMANTIC_TRAINING_CANARY_EVALUATOR_ABI,
1764 identity: identity_words(identity),
1765 task_identity: identity_words(task_identity),
1766 row_count: u64::try_from(rows.len())
1767 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1768 capacity: u64::try_from(capacity)
1769 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1770 group_count: u64::try_from(groups.len())
1771 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1772 group_member_count: u64::try_from(group_members.len())
1773 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1774 canary_count: u64::try_from(canaries.len())
1775 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1776 protected_member_count: u64::try_from(protected_members.len())
1777 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
1778 evaluator_min_bits: objective.evaluator_min.to_bits(),
1779 evaluator_max_bits: objective.evaluator_max.to_bits(),
1780 coefficient_bits: objective
1781 .coefficients
1782 .map(|value| u64::from(value.to_bits())),
1783 cost_unit: identity_words(objective.cost_unit),
1784 cost_cap: objective.cost_cap,
1785 truth_tokens: objective.truth_tokens,
1786 },
1787 groups,
1788 group_members,
1789 canaries,
1790 protected_members,
1791 ))
1792}
1793
1794fn objective_identity(
1795 objective: &SemanticTrainingObjective,
1796 rows: &[TrainingViewRowDescriptor],
1797 task_identity: Identity256,
1798 canaries: &[SemanticTrainingCanaryRecord],
1799) -> Identity256 {
1800 let mut hasher = Sha256::new();
1801 hasher.update(b"xlog.semantic.training-objective.v3\0");
1802 hasher.update(SEMANTIC_TRAINING_CANARY_EVALUATOR_ABI.to_le_bytes());
1803 hasher.update(task_identity.as_bytes());
1804 hasher.update(objective.evaluator_min.to_bits().to_le_bytes());
1805 hasher.update(objective.evaluator_max.to_bits().to_le_bytes());
1806 for coefficient in objective.coefficients {
1807 hasher.update(coefficient.to_bits().to_le_bytes());
1808 }
1809 hasher.update(objective.cost_unit.as_bytes());
1810 hasher.update(objective.cost_cap.to_le_bytes());
1811 for token in objective.truth_tokens {
1812 hasher.update(token.to_le_bytes());
1813 }
1814 hasher.update(
1815 u64::try_from(objective.groups.len())
1816 .expect("validated training objective group count")
1817 .to_le_bytes(),
1818 );
1819 for group in &objective.groups {
1820 hasher.update((group.kind as u64).to_le_bytes());
1821 hasher.update(group.denominator.to_le_bytes());
1822 hasher.update(
1823 u64::try_from(group.row_ordinals.len())
1824 .expect("validated training objective group extent")
1825 .to_le_bytes(),
1826 );
1827 for ordinal in &group.row_ordinals {
1828 hasher.update(ordinal.to_le_bytes());
1829 let row = &rows[*ordinal as usize];
1830 for word in row.identity {
1831 hasher.update(word.to_le_bytes());
1832 }
1833 for word in row.content_identity {
1834 hasher.update(word.to_le_bytes());
1835 }
1836 }
1837 }
1838 hasher.update(
1839 u64::try_from(objective.canaries.len())
1840 .expect("validated training canary count")
1841 .to_le_bytes(),
1842 );
1843 for canary in canaries {
1844 for word in canary.identity {
1845 hasher.update(word.to_le_bytes());
1846 }
1847 }
1848 Identity256::from_bytes(hasher.finalize().into())
1849}
1850
1851fn canary_identity(
1852 objective: &SemanticTrainingObjective,
1853 canary: &SemanticTrainingCanary,
1854 row: &TrainingViewRowDescriptor,
1855 task_identity: Identity256,
1856) -> Identity256 {
1857 let mut hasher = Sha256::new();
1858 hasher.update(b"xlog.semantic.training-canary.v3\0");
1859 hasher.update(SEMANTIC_TRAINING_CANARY_EVALUATOR_ABI.to_le_bytes());
1860 hasher.update((canary.kind as u64).to_le_bytes());
1861 hasher.update(canary.row_ordinal.to_le_bytes());
1862 hasher.update(canary.lower_bound.to_bits().to_le_bytes());
1863 hasher.update(canary.upper_bound.to_bits().to_le_bytes());
1864 hasher.update(canary.memory_limit.to_le_bytes());
1865 hasher.update(canary.work_limit.to_le_bytes());
1866 for position in canary.obligation_positions {
1867 hasher.update(position.to_le_bytes());
1868 }
1869 hasher.update(
1870 u64::try_from(canary.protected_positions.len())
1871 .expect("validated protected retention member count")
1872 .to_le_bytes(),
1873 );
1874 for position in &canary.protected_positions {
1875 hasher.update(position.to_le_bytes());
1876 }
1877 for word in row.identity {
1878 hasher.update(word.to_le_bytes());
1879 }
1880 for word in row.content_identity {
1881 hasher.update(word.to_le_bytes());
1882 }
1883 hasher.update(task_identity.as_bytes());
1884 for token in objective.truth_tokens {
1885 hasher.update(token.to_le_bytes());
1886 }
1887 Identity256::from_bytes(hasher.finalize().into())
1888}
1889
1890pub fn validate_training_view_layout(
1892 bytes: &[u8],
1893) -> Result<SemanticTrainingViewLayout, SemanticTransitionError> {
1894 let mut schema = [0u8; 32];
1895 let tag = b"dlm-new/training-view/v2";
1896 schema[..tag.len()].copy_from_slice(tag);
1897 if bytes.len() < TRAINING_VIEW_HEADER_BYTES || bytes[..32] != schema {
1898 return Err(input_error("training-view row has another schema"));
1899 }
1900 let word = |offset: usize| {
1901 u64::from_le_bytes(
1902 bytes[offset..offset + 8]
1903 .try_into()
1904 .expect("bounded training-view header"),
1905 )
1906 };
1907 let window = usize::try_from(word(96))
1908 .map_err(|_| input_error("training-view window exceeds host address space"))?;
1909 let expected = window
1910 .checked_mul(TRAINING_VIEW_ROW_BYTES)
1911 .and_then(|length| length.checked_add(TRAINING_VIEW_HEADER_BYTES + (window % 2) * 4));
1912 if window == 0
1913 || word(104) == 0
1914 || word(112) == 0
1915 || word(104) > word(96)
1916 || word(120) > word(104)
1917 || word(128) == 0
1918 || word(128) > word(104)
1919 || expected != Some(bytes.len())
1920 {
1921 return Err(input_error(
1922 "training-view row has invalid extent or geometry",
1923 ));
1924 }
1925 let branch_words = std::array::from_fn(|index| word(136 + index * 8));
1926 let shared_context_end = branch_words[0];
1927 if shared_context_end == 0 {
1928 if branch_words[1..].iter().any(|&value| value != 0) {
1929 return Err(input_error(
1930 "training-view row has incomplete branch geometry",
1931 ));
1932 }
1933 } else {
1934 let mut next_begin = word(104)
1935 .checked_mul(2)
1936 .ok_or_else(|| input_error("training-view branch extent exceeds address space"))?;
1937 if shared_context_end > word(128) || next_begin > word(96) {
1938 return Err(input_error("training-view row has invalid branch geometry"));
1939 }
1940 for branch in 0..3 {
1941 let offset = 1 + branch * 5;
1942 let [tail_begin, tail_end, answer_begin, answer_end, answer_start] = branch_words
1943 [offset..offset + 5]
1944 .try_into()
1945 .expect("bounded branch words");
1946 if tail_begin != next_begin
1947 || tail_end <= tail_begin
1948 || answer_begin != tail_end
1949 || answer_end <= answer_begin
1950 || answer_end > word(96)
1951 || shared_context_end.checked_add(tail_end - tail_begin) != Some(answer_start)
1952 || answer_start
1953 .checked_add(answer_end - answer_begin)
1954 .is_none_or(|end| end > word(96))
1955 {
1956 return Err(input_error("training-view row has invalid branch geometry"));
1957 }
1958 next_begin = answer_end;
1959 }
1960 }
1961 let padding = TRAINING_VIEW_HEADER_BYTES + window * 20;
1962 if bytes[padding..padding + (window % 2) * 4]
1963 .iter()
1964 .any(|&byte| byte != 0)
1965 {
1966 return Err(input_error(
1967 "training-view row has noncanonical alignment padding",
1968 ));
1969 }
1970 Ok(SemanticTrainingViewLayout {
1971 window,
1972 source_length: word(104),
1973 block_size: word(112),
1974 prefix_extent: word(120),
1975 answer_start: word(128),
1976 branch_words,
1977 })
1978}
1979
1980fn validate_row(
1981 ordinal: usize,
1982 row: &SemanticTrainingViewRow,
1983 raw_offset: usize,
1984 training_domain: &SemanticTrainingDomain,
1985) -> Result<TrainingViewRowDescriptor, SemanticTransitionError> {
1986 let bytes = &row.bytes;
1987 let layout = validate_training_view_layout(bytes)?;
1988 if layout.window as u64 != training_domain.window
1989 || layout.block_size != training_domain.block_size
1990 || layout
1991 .source_length
1992 .checked_mul(2)
1993 .is_none_or(|extent| extent > training_domain.window)
1994 || row.mask_policy != training_domain.mask_policy
1995 || row.training_seed != training_domain.training_seed
1996 || training_domain
1997 .manifests
1998 .binary_search_by(|manifest| {
1999 manifest
2000 .identity
2001 .as_bytes()
2002 .cmp(row.data_manifest.as_bytes())
2003 })
2004 .is_err()
2005 {
2006 return Err(input_error(
2007 "training view lies outside its original manifest or loader domain",
2008 ));
2009 }
2010 let kinds_offset = TRAINING_VIEW_HEADER_BYTES + layout.window * 68 + (layout.window % 2) * 4;
2011 for slot in 0..layout.window {
2012 let token_offset = TRAINING_VIEW_HEADER_BYTES + slot * 8;
2013 let kind_offset = kinds_offset + slot * 8;
2014 let token = i64::from_le_bytes(bytes[token_offset..token_offset + 8].try_into().unwrap());
2015 let kind = i64::from_le_bytes(bytes[kind_offset..kind_offset + 8].try_into().unwrap());
2016 if (kind == 0 && u64::try_from(token).ok() != Some(training_domain.pad_id))
2017 || (kind == 2 && u64::try_from(token).ok() != Some(training_domain.mask_id))
2018 {
2019 return Err(input_error(
2020 "training view changed the original padding or mask token",
2021 ));
2022 }
2023 }
2024 if !raw_offset.is_multiple_of(8) {
2025 return Err(input_error("training-view row has invalid raw alignment"));
2026 }
2027 let identity: [u8; 32] = bytes[32..64].try_into().expect("bounded identity");
2028 let source_identity: [u8; 32] = bytes[64..96].try_into().expect("bounded identity");
2029 if matches!(row.basis, SemanticTrainingViewBasis::Episode) != row.origin.is_some() {
2030 return Err(input_error(
2031 "only an episode training view has an authentic execution origin",
2032 ));
2033 }
2034 if matches!(row.basis, SemanticTrainingViewBasis::CorpusSymbolicAnchor)
2035 != row.task_content.is_some()
2036 {
2037 return Err(input_error(
2038 "only a symbolic corpus training view carries a native task-content binding",
2039 ));
2040 }
2041 if identity != *row.identity.as_bytes()
2042 || Sha256::digest(bytes).as_slice() != row.bytes_identity.as_bytes()
2043 || source_identity == [0; 32]
2044 || row.content_identity == Identity256::default()
2045 {
2046 return Err(input_error(
2047 "training-view row differs from its logical identity, material bytes, source or replay content",
2048 ));
2049 }
2050 Ok(TrainingViewRowDescriptor {
2051 ordinal: u64::try_from(ordinal)
2052 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
2053 basis: row.basis as u64,
2054 raw_offset: u64::try_from(raw_offset)
2055 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
2056 raw_bytes: u64::try_from(bytes.len())
2057 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
2058 window: u64::try_from(layout.window)
2059 .map_err(|_| SemanticTransitionError::GenerationExhausted)?,
2060 source_length: layout.source_length,
2061 block_size: layout.block_size,
2062 prefix_extent: layout.prefix_extent,
2063 answer_start: layout.answer_start,
2064 identity: identity_words(Identity256::from_bytes(identity)),
2065 source_identity: identity_words(Identity256::from_bytes(source_identity)),
2066 content_identity: identity_words(row.content_identity),
2067 task_query_identity: row
2068 .task_content
2069 .map(|binding| identity_words(binding.query))
2070 .unwrap_or_default(),
2071 task_theory_program_identity: row
2072 .task_content
2073 .map(|binding| identity_words(binding.theory_program))
2074 .unwrap_or_default(),
2075 task_result_identity: row
2076 .task_content
2077 .map(|binding| identity_words(binding.result))
2078 .unwrap_or_default(),
2079 origin: row.origin.map(origin_record).unwrap_or_default(),
2080 })
2081}
2082
2083fn origin_record(origin: SemanticTrainingViewOrigin) -> SemanticTrainingViewOriginRecord {
2084 SemanticTrainingViewOriginRecord {
2085 present: 1,
2086 transition: match origin.transition {
2087 SemanticTransitionKind::Proposal => 1,
2088 SemanticTransitionKind::Recompute => 2,
2089 SemanticTransitionKind::Drain => 3,
2090 SemanticTransitionKind::Update => 4,
2091 },
2092 lineage_instance: identity_words(origin.predecessor.instance),
2093 predecessor_instance: identity_words(origin.predecessor.instance),
2094 predecessor_word: origin.predecessor.word,
2095 predecessor_logical: identity_words(origin.predecessor.logical_digest),
2096 predecessor_state: identity_words(origin.predecessor.state_digest),
2097 successor_instance: identity_words(origin.successor.instance),
2098 successor_word: origin.successor.word,
2099 successor_logical: identity_words(origin.successor.logical_digest),
2100 successor_state: identity_words(origin.successor.state_digest),
2101 model_generation: u64::from(origin.invocation.model_generation),
2102 stream_serial: origin.invocation.stream_serial,
2103 family_id: u64::from(origin.invocation.family_id),
2104 proposal: u64::from(origin.invocation.proposal),
2105 model_geometry_digest: identity_words(origin.model_geometry_digest),
2106 model_numerical_digest: identity_words(origin.model_numerical_digest),
2107 }
2108}
2109
2110fn identity_words(identity: Identity256) -> [u64; 4] {
2111 std::array::from_fn(|index| {
2112 let begin = index * 8;
2113 u64::from_le_bytes(
2114 identity.as_bytes()[begin..begin + 8]
2115 .try_into()
2116 .expect("identity word"),
2117 )
2118 })
2119}
2120
2121fn input_error(detail: impl Into<String>) -> SemanticTransitionError {
2122 SemanticTransitionError::InvalidInput {
2123 detail: detail.into(),
2124 }
2125}
2126
2127fn runtime_error(
2128 operation: &'static str,
2129 error: impl std::fmt::Display,
2130) -> SemanticTransitionError {
2131 SemanticTransitionError::Runtime {
2132 operation,
2133 detail: error.to_string(),
2134 }
2135}
2136
2137fn map_enqueue_error<E: std::fmt::Display>(
2138 error: LaunchEnqueueError<E>,
2139) -> SemanticTransitionError {
2140 runtime_error("training-view device selection", error)
2141}