Skip to main content

ferrum_interfaces/vnext/operation/
dispatch.rs

1use sha2::{Digest, Sha256};
2use std::{collections::BTreeSet, sync::Arc};
3
4use super::super::{
5    classify_device_error, AllocationKind, AllocationLifetime, BackingInitializationEncodeError,
6    BufferUsage, CompletionHandle, CompletionReaper, CompletionReservation,
7    DefinitelyNotSubmittedRetryAuthority, DeviceBatchingForm, DeviceCommandBatch,
8    DeviceCommandLogicalWork, DeviceComputePathRequirement, DeviceReusableExecutionCapture,
9    DeviceReusableExecutionInvocation, DeviceReusableExecutionProgram,
10    DeviceReusableExecutionProgramId, DeviceReusableExecutionTopologyFingerprint, DeviceRuntime,
11    DeviceTimingMode, ExecutablePlanView, ExecutionIdentityEnvelope, ExecutionIdentityParts,
12    ExecutionLane, InvocationResourceLease, LaneSubmitOutcome, NodeId, NodeInvocationId,
13    OperationId, ParticipantNodeKey, PreparedStepSubmissionWave, ProgramBindingNodeBinding,
14    ProviderId, ResourceId, SpanId, StepParticipantFrameAssignment, SubmissionWavePurpose,
15    TrustedActiveSequenceBinding, VNextError, EXECUTION_IDENTITY_VERSION,
16};
17use super::backing_upload::encode_submission_wave_backing_upload;
18use super::determinism::{
19    SubmissionWaveDeterminismHandle, SubmissionWaveDeterminismReadbackPlan,
20    SubmissionWaveDeterminismRestore,
21};
22use super::dispatch_contract::{
23    BoundDeviceSubmissionAttribution, DisabledSubmissionWaveDispatchTimingSink,
24    DispatchRetryAuthority, OperationDispatchError, ProfiledSubmissionHandle,
25    SubmissionExecutionPolicy, SubmissionScratchInitialization, SubmissionWaveDispatchError,
26    SubmissionWaveDispatchStage, SubmissionWaveDispatchStageTimer,
27    SubmissionWaveDispatchTimingSink, SubmissionWaveInputUpload,
28};
29use super::foundation::invalid_operation;
30use super::invocation::OperationInvocationResources;
31use super::workspace_encoding::{
32    encode_provider_workspace_initialization, encode_submission_wave_workspace_initializations,
33};
34use super::{
35    translate_step_participant_upload_range, BatchOperationIdentity, BatchOperationNodeIdentity,
36    BatchOperationParticipantIdentity, BatchedOperationInvocation, BoundOperationProvider,
37    OperationInvocation, ProviderReplayEquivalence, ResolvedValueRole, ReusableExecutionTopology,
38    ReusableExecutionTopologyRequest, TensorAccess,
39};
40
41/// The only public path from a resolved plan to an operation kernel.
42fn validate_program_binding_patch(
43    resolved: &dyn ExecutablePlanView,
44    node_identity: &BatchOperationNodeIdentity,
45    program_binding: Option<&ProgramBindingNodeBinding>,
46    encoded_program_binding_count: usize,
47    program_binding_resources: &mut BTreeSet<ResourceId>,
48) -> Result<(), VNextError> {
49    if program_binding.is_some() != (encoded_program_binding_count == 1) {
50        return Err(invalid_operation(
51            "compiled program binding slot and provider patch cardinality differ",
52        ));
53    }
54    let Some(program_binding) = program_binding else {
55        return Ok(());
56    };
57    let (plan_node_index, binding_resource) = resolved
58        .execution_plan()
59        .payload()
60        .nodes()
61        .iter()
62        .enumerate()
63        .find(|(_, node)| node.id() == node_identity.node_id())
64        .and_then(|(node_index, node)| {
65            node.binding_resource()
66                .map(|resource| (node_index, resource))
67        })
68        .ok_or_else(|| {
69            invalid_operation("program binding requires a provider-owned binding workspace")
70        })?;
71    if program_binding.node_index() != plan_node_index
72        || program_binding.slot().node_id() != node_identity.node_id()
73        || program_binding.slot().resource_id() != binding_resource
74    {
75        return Err(invalid_operation(
76            "provider program binding differs from its compiled node slot",
77        ));
78    }
79    if !program_binding_resources.insert(binding_resource.clone()) {
80        return Err(invalid_operation(
81            "program bindings from different nodes alias one binding workspace",
82        ));
83    }
84    Ok(())
85}
86
87fn validate_determinism_replay_coverage(
88    program: &DeviceReusableExecutionProgram,
89    node_count: usize,
90    eager_boundary_node_indices: &[u32],
91    batch_identity: &BatchOperationIdentity,
92) -> Result<(), VNextError> {
93    if node_count == 0
94        || eager_boundary_node_indices
95            .windows(2)
96            .any(|pair| pair[0] >= pair[1])
97    {
98        return Err(invalid_operation(
99            "determinism replay topology has no nodes or non-canonical eager boundaries",
100        ));
101    }
102    if program.node_count() as usize != node_count
103        || program.eager_boundary_node_indices() != eager_boundary_node_indices
104    {
105        return Err(invalid_operation(
106            "determinism reusable program coverage differs from the live provider topology",
107        ));
108    }
109    if !program.is_determinism_ready() {
110        let gaps = program
111            .gaps()
112            .iter()
113            .take(8)
114            .map(|gap| {
115                let node_index = gap.node_index() as usize;
116                format!(
117                    "node_index={} node_id={} provider_id={} operation_id={} reason={}",
118                    gap.node_index(),
119                    batch_identity
120                        .node_id_at(node_index)
121                        .map_or("<missing>", NodeId::as_str),
122                    batch_identity
123                        .provider_id_at(node_index)
124                        .map_or("<missing>", ProviderId::as_str),
125                    batch_identity
126                        .operation_id_at(node_index)
127                        .map_or("<missing>", OperationId::as_str),
128                    gap.reason().as_str(),
129                )
130            })
131            .collect::<Vec<_>>()
132            .join("; ");
133        return Err(invalid_operation(format!(
134            "determinism reusable program has {} non-resident replay-eligible gap(s): {gaps}",
135            program.gaps().len()
136        )));
137    }
138    let mut coverage = vec![0_u8; node_count];
139    for node_index in eager_boundary_node_indices {
140        let node_index = usize::try_from(*node_index)
141            .map_err(|_| invalid_operation("determinism eager boundary exceeds usize"))?;
142        let marker = coverage.get_mut(node_index).ok_or_else(|| {
143            invalid_operation("determinism eager boundary is outside the submission wave")
144        })?;
145        *marker = 1;
146    }
147    for segment in program.segments() {
148        let start = usize::try_from(segment.start_node_index())
149            .map_err(|_| invalid_operation("determinism replay segment start exceeds usize"))?;
150        let end = usize::try_from(segment.end_node_index())
151            .map_err(|_| invalid_operation("determinism replay segment end exceeds usize"))?;
152        let range = coverage.get_mut(start..end).ok_or_else(|| {
153            invalid_operation("determinism replay segment is outside the submission wave")
154        })?;
155        if range.iter().any(|marker| *marker != 0) {
156            return Err(invalid_operation(
157                "determinism replay segment overlaps another segment or a declared eager boundary",
158            ));
159        }
160        range.fill(2);
161    }
162    if coverage.iter().any(|marker| *marker == 0) {
163        return Err(invalid_operation(
164            "determinism reusable program does not cover every replay-eligible node",
165        ));
166    }
167    if !coverage.iter().any(|marker| *marker == 2) {
168        return Err(invalid_operation(
169            "determinism replay topology contains no resident replay node",
170        ));
171    }
172    Ok(())
173}
174
175struct ReusableExecutionWaveAuthority {
176    program_id: DeviceReusableExecutionProgramId,
177    eager_boundary_node_indices: Vec<u32>,
178}
179
180pub struct OperationDispatch;
181
182impl OperationDispatch {
183    fn trusted_submission_node_identity(
184        resolved: &dyn ExecutablePlanView,
185        active: &TrustedActiveSequenceBinding,
186        frame: StepParticipantFrameAssignment,
187        node_index: usize,
188    ) -> Result<ExecutionIdentityEnvelope, VNextError> {
189        active.ensure_open_for_emission()?;
190        let plan = resolved.execution_plan();
191        let node_count = u64::try_from(plan.payload().nodes().len())
192            .map_err(|_| invalid_operation("immutable plan node count exceeds u64"))?;
193        let node_index = u64::try_from(node_index)
194            .map_err(|_| invalid_operation("submission wave node index exceeds u64"))?;
195        let node = plan
196            .payload()
197            .nodes()
198            .get(node_index as usize)
199            .ok_or_else(|| invalid_operation("submission wave node index is out of bounds"))?;
200        let completed_frames = frame.frame_id().get() - 1;
201        let node_invocation = completed_frames
202            .checked_mul(node_count)
203            .and_then(|value| value.checked_add(node_index))
204            .and_then(|value| value.checked_add(1))
205            .ok_or_else(|| invalid_operation("node invocation id space is exhausted"))?;
206        let node_invocation_id = NodeInvocationId::try_from(node_invocation)?;
207
208        // RequestAccepted and PlanBuilt consume the first two journal rows.
209        // Every immutable-plan frame then emits FrameStarted, three rows per
210        // node, and FrameCompleted. This operation identity is therefore the
211        // exact future OperationSubmitted row and remains stable across a
212        // definitely-not-submitted retry of the same frame.
213        let events_per_frame = node_count
214            .checked_mul(3)
215            .and_then(|value| value.checked_add(2))
216            .ok_or_else(|| invalid_operation("execution event sequence space is exhausted"))?;
217        let sequence = completed_frames
218            .checked_mul(events_per_frame)
219            .and_then(|value| value.checked_add(node_index.checked_mul(3)?))
220            .and_then(|value| value.checked_add(5))
221            .ok_or_else(|| invalid_operation("execution event sequence space is exhausted"))?;
222
223        let span_root = format!("vnext/request/{}", active.fingerprint());
224        let node_span = SpanId::new(format!(
225            "{span_root}/frame/{}/node/{node_invocation}",
226            frame.frame_id()
227        ))?;
228        let operation_span = SpanId::new(format!("{node_span}/operation"))?;
229        let provisioning = active.static_provisioning_identity();
230        ExecutionIdentityEnvelope::new(ExecutionIdentityParts {
231            version: EXECUTION_IDENTITY_VERSION,
232            run_id: active.run_id().clone(),
233            request_id: active.request_id().clone(),
234            sequence,
235            plan_id: Some(plan.payload().plan_id().clone()),
236            plan_hash: Some(plan.plan_hash().clone()),
237            frame_id: Some(frame.frame_id()),
238            node_invocation_id: Some(node_invocation_id),
239            node_id: Some(node.id().clone()),
240            operation_id: Some(node.operation_id().clone()),
241            provider_id: Some(node.selection().selected_provider().clone()),
242            device_id: Some(plan.payload().device_id().clone()),
243            resource_pool_id: active.static_pool_id(),
244            resource_pool_identity_fingerprint: active
245                .static_pool_identity_fingerprint_ref()
246                .map(str::to_owned),
247            provisioning_run_id: provisioning.map(|identity| identity.run_id().clone()),
248            provisioning_request_id: provisioning.map(|identity| identity.request_id().clone()),
249            transaction_id: provisioning.map(|identity| identity.transaction_id().clone()),
250            active_sequence_slot: Some(active.sequence_authority().sparse_id()),
251            admission_generation: Some(active.sequence_authority().generation()),
252            activation_epoch: Some(active.activation_epoch()),
253            runtime_implementation_fingerprint: Some(
254                active.runtime_implementation_fingerprint().to_owned(),
255            ),
256            active_sequence_fingerprint: Some(active.fingerprint().to_owned()),
257            completed_sequence_fingerprint: None,
258            aborted_sequence_fingerprint: None,
259            resource_id: None,
260            resource_generation: None,
261            resource_batch_fingerprint: None,
262            span_id: operation_span,
263            parent_span_id: Some(node_span),
264            async_links: Vec::new(),
265        })
266    }
267
268    #[allow(clippy::too_many_arguments)]
269    fn bind_node_identity<'binding, R, I>(
270        resolved: &dyn ExecutablePlanView,
271        participant_identities: Vec<ExecutionIdentityEnvelope>,
272        active_bindings: I,
273        resources: OperationInvocationResources<'_, R>,
274        lane: &Arc<ExecutionLane<R>>,
275        node_index: u32,
276        participant_start: u32,
277    ) -> Result<BatchOperationNodeIdentity, VNextError>
278    where
279        R: DeviceRuntime,
280        I: ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
281    {
282        let plan = resolved.execution_plan();
283        let node_id = resources.node_id()?;
284        let node = plan
285            .payload()
286            .nodes()
287            .iter()
288            .find(|node| node.id() == node_id)
289            .ok_or_else(|| invalid_operation(format!("plan has no node `{node_id}`")))?;
290        // Wave construction proves every node shares this authority by Arc identity.
291        let validate_common_authority = match resources {
292            OperationInvocationResources::Invocation(_) => true,
293            OperationInvocationResources::Wave {
294                node_index: resource_node_index,
295                ..
296            } => resource_node_index == 0,
297        };
298        let participant_count = resources.participant_count()?;
299        let frames = resources.participant_frames()?;
300        let plan_identity_matches = validate_common_authority
301            .then(|| {
302                resources.plan_identity_matches(
303                    plan.payload().plan_id(),
304                    plan.plan_hash(),
305                    plan.payload().device_id(),
306                )
307            })
308            .transpose()?;
309        if participant_identities.is_empty()
310            || participant_identities.len() != participant_count
311            || participant_identities.len() != frames.len()
312            || participant_identities.len() != active_bindings.len()
313            || resources.prepared_participant_count()? != participant_count
314            || validate_common_authority && {
315                !plan_identity_matches.expect("common wave authority requested plan evidence")
316                    || !Arc::ptr_eq(resources.runtime(), lane.runtime_arc())
317                    || resources.step_resources().execution_lane().id() != lane.id()
318                    || lane.descriptor() != resolved.device()
319                    || lane.descriptor() != resolved.capabilities().device()
320                    || lane.descriptor().runtime_implementation_fingerprint
321                        != plan.payload().device_runtime_implementation_fingerprint()
322            }
323        {
324            return Err(invalid_operation(
325                "batch node identity inputs differ from submission resources, plan, or lane",
326            ));
327        }
328        let mut participant_projections = Vec::with_capacity(participant_identities.len());
329        for (local_index, (identity, active)) in participant_identities
330            .into_iter()
331            .zip(active_bindings)
332            .enumerate()
333        {
334            let participant = resources.participant(local_index)?;
335            let frame = *frames
336                .get(local_index)
337                .ok_or_else(|| invalid_operation("operation participant frame is missing"))?;
338            let session = validate_common_authority
339                .then(|| resources.participant_session_identity(local_index))
340                .transpose()?;
341            let key =
342                ParticipantNodeKey::new(frame.participant(), frame.frame_id(), node.id().clone());
343            let parts = identity.parts();
344            if key.sequence_authority() != participant.sequence_authority()
345                || key.request_authority() != participant.request_authority()
346                || key.frame_id() != frame.frame_id()
347                || validate_common_authority && {
348                    let session = session
349                        .as_ref()
350                        .expect("common wave authority requested session evidence");
351                    active.sequence_authority() != participant.sequence_authority()
352                        || active.coordinator_id() != resources.coordinator_id()?
353                        || active.run_id() != participant.run_id()
354                        || active.request_id() != participant.request_id()
355                        || !active.matches_sequence_session(session.0, session.1)
356                        || active.plan().plan_id() != plan.payload().plan_id()
357                        || active.plan().plan_hash() != plan.plan_hash()
358                        || active.plan().device_id() != plan.payload().device_id()
359                        || active.runtime_implementation_fingerprint()
360                            != plan.payload().device_runtime_implementation_fingerprint()
361                }
362                || parts.run_id != *active.run_id()
363                || parts.request_id != *active.request_id()
364                || parts.plan_id.as_ref() != Some(plan.payload().plan_id())
365                || parts.plan_hash.as_ref() != Some(plan.plan_hash())
366                || parts.frame_id != Some(frame.frame_id())
367                || parts.node_invocation_id.is_none()
368                || parts.node_id.as_ref() != Some(node.id())
369                || parts.operation_id.as_ref() != Some(node.operation_id())
370                || parts.provider_id.as_ref() != Some(node.selection().selected_provider())
371                || parts.device_id.as_ref() != Some(plan.payload().device_id())
372                || parts.active_sequence_slot != Some(active.sequence_authority().sparse_id())
373                || parts.admission_generation != Some(active.sequence_authority().generation())
374                || parts.activation_epoch != Some(active.activation_epoch())
375                || parts.runtime_implementation_fingerprint.as_deref()
376                    != Some(active.runtime_implementation_fingerprint())
377                || parts.active_sequence_fingerprint.as_deref() != Some(active.fingerprint())
378                || parts.completed_sequence_fingerprint.is_some()
379                || parts.aborted_sequence_fingerprint.is_some()
380                || parts.resource_id.is_some()
381                || parts.resource_generation.is_some()
382                || parts.resource_batch_fingerprint.is_some()
383            {
384                return Err(invalid_operation(format!(
385                    "batch node {node_index} participant {local_index} differs from its resource, frame, session, or plan identity"
386                )));
387            }
388            let local_index = u32::try_from(local_index)
389                .map_err(|_| invalid_operation("batch participant index exceeds u32"))?;
390            participant_projections.push(BatchOperationParticipantIdentity::new(
391                participant_start.checked_add(local_index).ok_or_else(|| {
392                    invalid_operation("physical batch participant index overflows u32")
393                })?,
394                key,
395                identity,
396            ));
397        }
398        BatchOperationNodeIdentity::from_validated(
399            node_index,
400            node.id().clone(),
401            node.operation_id().clone(),
402            node.selection().selected_provider().clone(),
403            node.provider_implementation_fingerprint().to_owned(),
404            node.provider_execution_semantics(),
405            resources.work_shape()?.fingerprint().to_owned(),
406            participant_projections,
407        )
408    }
409
410    #[allow(clippy::too_many_arguments)]
411    pub fn bind_batch_identity<R>(
412        resolved: &dyn ExecutablePlanView,
413        participant_identities: Vec<ExecutionIdentityEnvelope>,
414        active_bindings: &[TrustedActiveSequenceBinding],
415        invocation_resources: &InvocationResourceLease<R>,
416        lane: &Arc<ExecutionLane<R>>,
417    ) -> Result<BatchOperationIdentity, VNextError>
418    where
419        R: DeviceRuntime,
420    {
421        let plan = resolved.execution_plan();
422        let resources = OperationInvocationResources::Invocation(invocation_resources);
423        let node_identity = Self::bind_node_identity(
424            resolved,
425            participant_identities,
426            active_bindings.iter(),
427            resources,
428            lane,
429            0,
430            0,
431        )?;
432        BatchOperationIdentity::from_validated(
433            resources.batch_step_id(),
434            resources.batch_invocation_id(),
435            plan.payload().plan_id().clone(),
436            plan.plan_hash().clone(),
437            plan.payload().device_id().clone(),
438            plan.payload()
439                .device_runtime_implementation_fingerprint()
440                .to_owned(),
441            lane.id(),
442            resources.backing_fingerprint().to_owned(),
443            vec![node_identity],
444        )
445    }
446
447    fn bind_submission_wave_identity_from_envelopes<'binding, R, I>(
448        resolved: &dyn ExecutablePlanView,
449        participant_identities: Vec<Vec<ExecutionIdentityEnvelope>>,
450        active_bindings: I,
451        wave: &PreparedStepSubmissionWave<R>,
452        lane: &Arc<ExecutionLane<R>>,
453    ) -> Result<BatchOperationIdentity, VNextError>
454    where
455        R: DeviceRuntime,
456        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
457    {
458        let plan = resolved.execution_plan();
459        if wave.nodes().is_empty()
460            || wave.execution_lane_id() != lane.id()
461            || participant_identities.len() != wave.nodes().len()
462            || active_bindings.len() == 0
463            || wave.claimed_backing().node_count() != wave.nodes().len()
464            || wave.claimed_backing().plan_node_count() != plan.payload().nodes().len()
465            || wave
466                .nodes()
467                .windows(2)
468                .any(|pair| pair[0].plan_node_index() >= pair[1].plan_node_index())
469            || wave.nodes().iter().any(|prepared| {
470                plan.payload()
471                    .nodes()
472                    .get(prepared.plan_node_index())
473                    .is_none_or(|planned| prepared.node_id() != planned.id())
474            })
475        {
476            return Err(invalid_operation(
477                "submission wave identity must cover one exact canonical immutable-plan node scope",
478            ));
479        }
480        let mut participant_start = 0_u32;
481        let mut nodes = Vec::with_capacity(wave.nodes().len());
482        for (node_index, (identities, _node)) in participant_identities
483            .into_iter()
484            .zip(wave.nodes())
485            .enumerate()
486        {
487            let node_index = u32::try_from(node_index)
488                .map_err(|_| invalid_operation("submission wave node index exceeds u32"))?;
489            let participant_count = u32::try_from(identities.len())
490                .map_err(|_| invalid_operation("submission wave participant count exceeds u32"))?;
491            let node_identity = Self::bind_node_identity(
492                resolved,
493                identities,
494                active_bindings.clone(),
495                OperationInvocationResources::Wave {
496                    wave,
497                    node_index: node_index as usize,
498                },
499                lane,
500                node_index,
501                participant_start,
502            )?;
503            participant_start = participant_start
504                .checked_add(participant_count)
505                .ok_or_else(|| {
506                    invalid_operation("submission wave participant index space overflows u32")
507                })?;
508            nodes.push(node_identity);
509        }
510        BatchOperationIdentity::from_validated(
511            wave.batch_step_id(),
512            wave.batch_invocation_id(),
513            plan.payload().plan_id().clone(),
514            plan.plan_hash().clone(),
515            plan.payload().device_id().clone(),
516            plan.payload()
517                .device_runtime_implementation_fingerprint()
518                .to_owned(),
519            lane.id(),
520            wave.fingerprint().to_owned(),
521            nodes,
522        )
523    }
524
525    /// Binds one immutable-plan submission wave without accepting caller-made
526    /// execution envelopes. Frame, node, provider, provisioning, span, and
527    /// invocation identities are minted from core-owned plan/session evidence.
528    pub fn bind_submission_wave_identity<'binding, R, I>(
529        resolved: &dyn ExecutablePlanView,
530        active_bindings: I,
531        wave: &PreparedStepSubmissionWave<R>,
532        lane: &Arc<ExecutionLane<R>>,
533    ) -> Result<BatchOperationIdentity, VNextError>
534    where
535        R: DeviceRuntime,
536        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
537    {
538        if active_bindings.len() == 0 {
539            return Err(invalid_operation(
540                "submission wave requires a non-empty active participant set",
541            ));
542        }
543        let participant_identities = wave
544            .nodes()
545            .iter()
546            .enumerate()
547            .map(|(node_index, node)| {
548                if active_bindings.len() != node.participant_frames().len() {
549                    return Err(invalid_operation(format!(
550                        "submission wave node {node_index} active binding count differs from its participant frames"
551                    )));
552                }
553                node.participant_frames()
554                    .iter()
555                    .copied()
556                    .zip(active_bindings.clone())
557                    .map(|(frame, active)| {
558                        Self::trusted_submission_node_identity(
559                            resolved,
560                            active,
561                            frame,
562                            node.plan_node_index(),
563                        )
564                    })
565                    .collect::<Result<Vec<_>, _>>()
566            })
567            .collect::<Result<Vec<_>, _>>()?;
568        Self::bind_submission_wave_identity_from_envelopes(
569            resolved,
570            participant_identities,
571            active_bindings,
572            wave,
573            lane,
574        )
575    }
576
577    /// Derives the exact reusable-program identity for the current wave without
578    /// materializing device buffers or entering dispatch.
579    ///
580    /// Provider topology remains opaque. Core binds each topology row to its
581    /// immutable node/provider position before aggregating it, so two providers
582    /// cannot accidentally alias the same program variant. Eager boundaries
583    /// remain part of the program identity while resident segments on either
584    /// side stay eligible for typed reuse.
585    pub fn reusable_execution_program_id_for_wave<R>(
586        providers: &[BoundOperationProvider<'_, R>],
587        resolved: &dyn ExecutablePlanView,
588        wave: &PreparedStepSubmissionWave<R>,
589        lane: &Arc<ExecutionLane<R>>,
590    ) -> Result<Option<DeviceReusableExecutionProgramId>, VNextError>
591    where
592        R: DeviceRuntime,
593    {
594        Ok(
595            Self::reusable_execution_wave_authority(providers, resolved, wave, lane)?
596                .map(|authority| authority.program_id),
597        )
598    }
599
600    fn reusable_execution_wave_authority<R>(
601        providers: &[BoundOperationProvider<'_, R>],
602        resolved: &dyn ExecutablePlanView,
603        wave: &PreparedStepSubmissionWave<R>,
604        lane: &Arc<ExecutionLane<R>>,
605    ) -> Result<Option<ReusableExecutionWaveAuthority>, VNextError>
606    where
607        R: DeviceRuntime,
608    {
609        let plan = resolved.execution_plan();
610        let plan_nodes = plan.payload().nodes();
611        if providers.is_empty()
612            || providers.len() != wave.nodes().len()
613            || wave.execution_lane_id() != lane.id()
614            || lane.descriptor() != resolved.device()
615        {
616            return Err(invalid_operation(
617                "reusable execution topology requires one exact provider per wave node and lane",
618            ));
619        }
620        let Some(program_id) = wave.claimed_backing().reusable_execution_program_id(
621            &lane.descriptor().runtime_implementation_fingerprint,
622            lane.id(),
623        )?
624        else {
625            return Ok(None);
626        };
627
628        const DOMAIN: &[u8] = b"ferrum.runtime-vnext.reusable-program-topology.v3\0";
629        let mut digest = Sha256::new();
630        let mut eager_boundary_node_indices = Vec::new();
631        digest.update(DOMAIN);
632        digest.update(
633            u64::try_from(wave.nodes().len())
634                .map_err(|_| invalid_operation("reusable topology node count exceeds u64"))?
635                .to_le_bytes(),
636        );
637        for (wave_node_index, (provider, prepared_node)) in
638            providers.iter().zip(wave.nodes()).enumerate()
639        {
640            let plan_node_index = prepared_node.plan_node_index();
641            let node = plan_nodes.get(plan_node_index).ok_or_else(|| {
642                invalid_operation("reusable execution wave node is absent from the immutable plan")
643            })?;
644            if !provider.matches_plan_node(plan.payload().plan_id(), plan.plan_hash(), node.id())
645                || prepared_node.node_id() != node.id()
646            {
647                return Err(invalid_operation(
648                    "reusable execution topology provider or node differs from the immutable plan",
649                ));
650            }
651            let request = ReusableExecutionTopologyRequest::new(
652                node.id(),
653                node.operation_id(),
654                node.attributes(),
655                node.values(),
656                node.scratch_resource(),
657                node.binding_resource(),
658                node.persistent_resource(),
659                plan.payload().memory(),
660                prepared_node.work_shape(),
661                wave.claimed_backing(),
662                wave.step_resources().backing_slices(),
663            )?;
664            let declared = node.provider_execution_semantics().replay_equivalence();
665            let topology = provider.provider().reusable_execution_topology(request)?;
666            if topology == ReusableExecutionTopology::EagerBoundary {
667                eager_boundary_node_indices.push(u32::try_from(wave_node_index).map_err(|_| {
668                    invalid_operation("reusable topology wave node index exceeds u32")
669                })?);
670            }
671            let (topology_kind, topology_bytes) = match (
672                declared,
673                &topology,
674            ) {
675                (
676                    ProviderReplayEquivalence::BitwiseEagerEquivalent,
677                    ReusableExecutionTopology::Static,
678                ) => (0_u8, &[][..]),
679                (
680                    ProviderReplayEquivalence::BitwiseEagerEquivalent,
681                    ReusableExecutionTopology::Dynamic(topology),
682                ) => (1_u8, &topology.as_bytes()[..]),
683                (_, ReusableExecutionTopology::EagerBoundary) => (2_u8, &[][..]),
684                (
685                    ProviderReplayEquivalence::Ineligible,
686                    ReusableExecutionTopology::Static | ReusableExecutionTopology::Dynamic(_),
687                ) => {
688                    return Err(invalid_operation(format!(
689                        "provider `{}` returned reusable topology without a bitwise eager-equivalence contract",
690                        provider.descriptor().provider_id()
691                    )))
692                }
693            };
694            let wave_node_index = u64::try_from(wave_node_index)
695                .map_err(|_| invalid_operation("reusable topology wave node index exceeds u64"))?;
696            let plan_node_index = u64::try_from(plan_node_index)
697                .map_err(|_| invalid_operation("reusable topology plan node index exceeds u64"))?;
698            let node_id = node.id().as_str().as_bytes();
699            let provider_id = provider.descriptor().provider_id().as_str().as_bytes();
700            let node_id_len = u64::try_from(node_id.len())
701                .map_err(|_| invalid_operation("reusable topology node id exceeds u64"))?;
702            let provider_id_len = u64::try_from(provider_id.len())
703                .map_err(|_| invalid_operation("reusable topology provider id exceeds u64"))?;
704            let topology_len = u64::try_from(topology_bytes.len())
705                .map_err(|_| invalid_operation("reusable topology payload exceeds u64"))?;
706            digest.update(wave_node_index.to_le_bytes());
707            digest.update(plan_node_index.to_le_bytes());
708            digest.update(node_id_len.to_le_bytes());
709            digest.update(node_id);
710            digest.update(provider_id_len.to_le_bytes());
711            digest.update(provider_id);
712            digest.update([topology_kind]);
713            digest.update(topology_len.to_le_bytes());
714            digest.update(topology_bytes);
715        }
716        Ok(Some(ReusableExecutionWaveAuthority {
717            program_id: program_id.with_topology_fingerprint(
718                DeviceReusableExecutionTopologyFingerprint::from_sha256(digest.finalize().into()),
719            ),
720            eager_boundary_node_indices,
721        }))
722    }
723
724    #[allow(clippy::too_many_arguments)]
725    pub fn encode_and_submit<R>(
726        provider: &BoundOperationProvider<'_, R>,
727        resolved: &dyn ExecutablePlanView,
728        batch_identity: &BatchOperationIdentity,
729        active_bindings: &[TrustedActiveSequenceBinding],
730        mut invocation_resources: InvocationResourceLease<R>,
731        lane: &Arc<ExecutionLane<R>>,
732        reaper: &Arc<CompletionReaper<R>>,
733    ) -> Result<CompletionHandle<R>, OperationDispatchError<R>>
734    where
735        R: DeviceRuntime,
736    {
737        let node_identity = batch_identity.single_node().ok_or_else(|| {
738            OperationDispatchError::Contract(invalid_operation(
739                "single-operation dispatch requires a one-node batch identity",
740            ))
741        })?;
742        provider
743            .validate_binding(resolved, node_identity.node_id())
744            .map_err(OperationDispatchError::Contract)?;
745        if active_bindings.is_empty()
746            || active_bindings.len() != batch_identity.participants().len()
747            || lane.id() != batch_identity.lane_id()
748            || lane.descriptor().id != *batch_identity.device_id()
749            || lane.descriptor().runtime_implementation_fingerprint
750                != batch_identity.runtime_implementation_fingerprint()
751        {
752            return Err(OperationDispatchError::Contract(invalid_operation(
753                "operation execution lane or participant set differs from batch identity",
754            )));
755        }
756        invocation_resources
757            .begin_dispatch()
758            .map_err(OperationDispatchError::Contract)?;
759        let mut completion = CompletionReaper::reserve(
760            reaper,
761            invocation_resources,
762            Arc::clone(lane),
763            batch_identity.clone(),
764        )
765        .map_err(OperationDispatchError::Contract)?;
766        let runtime = lane.runtime();
767        if !lane.current_descriptor_matches_snapshot() {
768            return Err(OperationDispatchError::Contract(invalid_operation(
769                "operation encode runtime differs from its execution lane snapshot",
770            )));
771        }
772        let mut commands = DeviceCommandBatch::with_capacity(3);
773        completion
774            .encode_backing_initializations(runtime, &mut commands)
775            .map_err(|error| map_backing_initialization_error(runtime, batch_identity, error))?;
776        let invocation = BatchedOperationInvocation::from_resolved(
777            runtime,
778            resolved,
779            provider.dispatch(),
780            batch_identity,
781            completion.invocation(),
782            active_bindings,
783        )
784        .map_err(OperationDispatchError::Contract)?;
785        let plan_node = resolved
786            .execution_plan()
787            .payload()
788            .nodes()
789            .iter()
790            .find(|node| node.id() == node_identity.node_id())
791            .ok_or_else(|| {
792                OperationDispatchError::Contract(invalid_operation(
793                    "operation workspace node is absent from the immutable plan",
794                ))
795            })?;
796        if let Some(requirement) = plan_node.provider_resources().scratch() {
797            let scratch_view = invocation
798                .participants()
799                .first()
800                .and_then(OperationInvocation::scratch_view)
801                .ok_or_else(|| {
802                    OperationDispatchError::Contract(invalid_operation(
803                        "operation scratch requirement has no invocation view",
804                    ))
805                })?;
806            encode_provider_workspace_initialization::<R, DefinitelyNotSubmittedRetryAuthority<R>>(
807                runtime,
808                0,
809                node_identity,
810                requirement,
811                invocation.work_shape().resource_work(),
812                scratch_view,
813                SubmissionScratchInitialization::ProviderContract,
814                &mut commands,
815            )?;
816        }
817        let expected_phase = invocation.operation().profile_phase;
818        let operation = match provider.provider().encode_selected(invocation) {
819            Ok(operation) => operation,
820            Err(failure)
821                if batch_identity.contains_identity(failure.identity())
822                    && failure.phase() == expected_phase =>
823            {
824                return Err(OperationDispatchError::Provider(failure));
825            }
826            Err(_) => {
827                return Err(OperationDispatchError::Contract(invalid_operation(
828                    "operation provider returned a failure for a different execution identity or profile phase",
829                )));
830            }
831        };
832        if !lane.current_descriptor_matches_snapshot() {
833            return Err(OperationDispatchError::Contract(invalid_operation(
834                "operation encode completion runtime drifted",
835            )));
836        }
837        commands.push_operation(0, operation);
838        let timing_mode = commands.timing_mode();
839        let mut lane_reservation = lane
840            .reserve_enqueue()
841            .map_err(OperationDispatchError::Contract)?;
842        completion.mark_submission_started();
843        match lane_reservation.submit(commands) {
844            LaneSubmitOutcome::DefinitelyNotSubmitted(error) => {
845                drop(lane_reservation);
846                let retry = completion
847                    .definitely_not_submitted()
848                    .map_err(OperationDispatchError::Contract)?;
849                let failures = batch_identity
850                    .participants()
851                    .iter()
852                    .map(|participant| {
853                        classify_device_error(runtime, participant.identity().clone(), &error)
854                    })
855                    .collect::<Result<Vec<_>, _>>()
856                    .map_err(OperationDispatchError::Contract)?;
857                Err(OperationDispatchError::DefinitelyNotSubmitted { failures, retry })
858            }
859            LaneSubmitOutcome::PossiblySubmittedPanic => {
860                drop(lane_reservation);
861                let recovery = completion.submission_indeterminate();
862                Err(OperationDispatchError::SubmissionIndeterminate { recovery })
863            }
864            LaneSubmitOutcome::Submitted(fence) => {
865                drop(lane_reservation);
866                let completion = match completion.arm(fence, timing_mode) {
867                    Ok(completion) => completion,
868                    Err((error, completion)) => {
869                        return Err(OperationDispatchError::PostSubmitContract {
870                            error,
871                            completion,
872                        });
873                    }
874                };
875                if !lane.current_descriptor_matches_snapshot() {
876                    lane.fail_closed();
877                    return Err(OperationDispatchError::PostSubmitContract {
878                        error: invalid_operation("operation submit completion runtime drifted"),
879                        completion,
880                    });
881                }
882                Ok(completion)
883            }
884        }
885    }
886
887    #[allow(clippy::too_many_arguments)]
888    pub fn encode_and_submit_wave<'binding, R, I>(
889        providers: &[BoundOperationProvider<'_, R>],
890        resolved: &dyn ExecutablePlanView,
891        batch_identity: &BatchOperationIdentity,
892        active_bindings: I,
893        timing_mode: DeviceTimingMode,
894        wave: PreparedStepSubmissionWave<R>,
895        lane: &Arc<ExecutionLane<R>>,
896        reaper: &Arc<CompletionReaper<R>>,
897    ) -> Result<CompletionHandle<R>, SubmissionWaveDispatchError<R>>
898    where
899        R: DeviceRuntime,
900        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
901    {
902        Self::encode_and_submit_wave_with_inputs(
903            providers,
904            resolved,
905            batch_identity,
906            active_bindings,
907            timing_mode,
908            &[],
909            wave,
910            lane,
911            reaper,
912        )
913    }
914
915    #[allow(clippy::too_many_arguments)]
916    pub fn encode_and_submit_wave_with_inputs<'binding, R, I>(
917        providers: &[BoundOperationProvider<'_, R>],
918        resolved: &dyn ExecutablePlanView,
919        batch_identity: &BatchOperationIdentity,
920        active_bindings: I,
921        timing_mode: DeviceTimingMode,
922        input_uploads: &[SubmissionWaveInputUpload],
923        wave: PreparedStepSubmissionWave<R>,
924        lane: &Arc<ExecutionLane<R>>,
925        reaper: &Arc<CompletionReaper<R>>,
926    ) -> Result<CompletionHandle<R>, SubmissionWaveDispatchError<R>>
927    where
928        R: DeviceRuntime,
929        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
930    {
931        Self::encode_and_submit_wave_with_inputs_timed(
932            providers,
933            resolved,
934            batch_identity,
935            active_bindings,
936            timing_mode,
937            input_uploads,
938            SubmissionExecutionPolicy::adaptive(),
939            None,
940            None,
941            &DisabledSubmissionWaveDispatchTimingSink,
942            wave,
943            lane,
944            reaper,
945        )
946        .map(|profiled| profiled.into_parts().0)
947    }
948
949    #[allow(clippy::too_many_arguments)]
950    pub fn encode_and_submit_wave_with_inputs_and_policy<'binding, R, I>(
951        providers: &[BoundOperationProvider<'_, R>],
952        resolved: &dyn ExecutablePlanView,
953        batch_identity: &BatchOperationIdentity,
954        active_bindings: I,
955        timing_mode: DeviceTimingMode,
956        input_uploads: &[SubmissionWaveInputUpload],
957        execution_policy: SubmissionExecutionPolicy,
958        wave: PreparedStepSubmissionWave<R>,
959        lane: &Arc<ExecutionLane<R>>,
960        reaper: &Arc<CompletionReaper<R>>,
961    ) -> Result<CompletionHandle<R>, SubmissionWaveDispatchError<R>>
962    where
963        R: DeviceRuntime,
964        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
965    {
966        Self::encode_and_submit_wave_with_inputs_timed(
967            providers,
968            resolved,
969            batch_identity,
970            active_bindings,
971            timing_mode,
972            input_uploads,
973            execution_policy,
974            None,
975            None,
976            &DisabledSubmissionWaveDispatchTimingSink,
977            wave,
978            lane,
979            reaper,
980        )
981        .map(|profiled| profiled.into_parts().0)
982    }
983
984    /// Dispatches one prepared wave while attributing host time to exact typed
985    /// ownership boundaries. The diagnostic sink receives no access to the
986    /// command, submission, completion, or failure value.
987    #[allow(clippy::too_many_arguments)]
988    pub fn encode_and_submit_wave_with_inputs_and_timing<'binding, R, I, S>(
989        providers: &[BoundOperationProvider<'_, R>],
990        resolved: &dyn ExecutablePlanView,
991        batch_identity: &BatchOperationIdentity,
992        active_bindings: I,
993        timing_mode: DeviceTimingMode,
994        input_uploads: &[SubmissionWaveInputUpload],
995        execution_policy: SubmissionExecutionPolicy,
996        timing_sink: &S,
997        wave: PreparedStepSubmissionWave<R>,
998        lane: &Arc<ExecutionLane<R>>,
999        reaper: &Arc<CompletionReaper<R>>,
1000    ) -> Result<ProfiledSubmissionHandle<R>, SubmissionWaveDispatchError<R>>
1001    where
1002        R: DeviceRuntime,
1003        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1004        S: SubmissionWaveDispatchTimingSink,
1005    {
1006        Self::encode_and_submit_wave_with_inputs_timed(
1007            providers,
1008            resolved,
1009            batch_identity,
1010            active_bindings,
1011            timing_mode,
1012            input_uploads,
1013            execution_policy,
1014            None,
1015            None,
1016            timing_sink,
1017            wave,
1018            lane,
1019            reaper,
1020        )
1021    }
1022
1023    /// Executes one complete plan-derived determinism restore through eager
1024    /// provider commands. The returned profiled handle retains physical path
1025    /// attribution for the hardware artifact.
1026    #[allow(clippy::too_many_arguments)]
1027    pub fn encode_and_submit_determinism_eager_wave<'binding, R, I>(
1028        providers: &[BoundOperationProvider<'_, R>],
1029        resolved: &dyn ExecutablePlanView,
1030        batch_identity: &BatchOperationIdentity,
1031        active_bindings: I,
1032        timing_mode: DeviceTimingMode,
1033        restore: &SubmissionWaveDeterminismRestore,
1034        scratch_fill: u8,
1035        wave: PreparedStepSubmissionWave<R>,
1036        lane: &Arc<ExecutionLane<R>>,
1037        reaper: &Arc<CompletionReaper<R>>,
1038    ) -> Result<SubmissionWaveDeterminismHandle<R>, SubmissionWaveDispatchError<R>>
1039    where
1040        R: DeviceRuntime,
1041        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1042    {
1043        let readback_plan = SubmissionWaveDeterminismReadbackPlan::from_restore(
1044            resolved,
1045            batch_identity,
1046            &wave,
1047            restore,
1048        )
1049        .map_err(SubmissionWaveDispatchError::Contract)?;
1050        let restore_fingerprint = restore
1051            .logical_fingerprint()
1052            .map_err(SubmissionWaveDispatchError::Contract)?;
1053        let initialization_identity = restore
1054            .initialization_identity()
1055            .map_err(SubmissionWaveDispatchError::Contract)?;
1056        let profiled = Self::encode_and_submit_wave_with_inputs_timed(
1057            providers,
1058            resolved,
1059            batch_identity,
1060            active_bindings,
1061            timing_mode,
1062            &[],
1063            SubmissionExecutionPolicy::determinism_eager(scratch_fill),
1064            Some(restore),
1065            None,
1066            &DisabledSubmissionWaveDispatchTimingSink,
1067            wave,
1068            lane,
1069            reaper,
1070        )?;
1071        Ok(SubmissionWaveDeterminismHandle::from_profiled_eager(
1072            profiled,
1073            readback_plan,
1074            restore_fingerprint,
1075            initialization_identity,
1076        ))
1077    }
1078
1079    /// Executes the same complete restore through one sealed resident replay
1080    /// program. No adaptive capture or eager fallback is permitted.
1081    #[allow(clippy::too_many_arguments)]
1082    pub fn encode_and_submit_determinism_replayed_wave<'binding, R, I>(
1083        providers: &[BoundOperationProvider<'_, R>],
1084        resolved: &dyn ExecutablePlanView,
1085        batch_identity: &BatchOperationIdentity,
1086        active_bindings: I,
1087        timing_mode: DeviceTimingMode,
1088        restore: &SubmissionWaveDeterminismRestore,
1089        scratch_fill: u8,
1090        reusable_program: &DeviceReusableExecutionProgram,
1091        wave: PreparedStepSubmissionWave<R>,
1092        lane: &Arc<ExecutionLane<R>>,
1093        reaper: &Arc<CompletionReaper<R>>,
1094    ) -> Result<SubmissionWaveDeterminismHandle<R>, SubmissionWaveDispatchError<R>>
1095    where
1096        R: DeviceRuntime,
1097        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1098    {
1099        let readback_plan = SubmissionWaveDeterminismReadbackPlan::from_restore(
1100            resolved,
1101            batch_identity,
1102            &wave,
1103            restore,
1104        )
1105        .map_err(SubmissionWaveDispatchError::Contract)?;
1106        let restore_fingerprint = restore
1107            .logical_fingerprint()
1108            .map_err(SubmissionWaveDispatchError::Contract)?;
1109        let initialization_identity = restore
1110            .initialization_identity()
1111            .map_err(SubmissionWaveDispatchError::Contract)?;
1112        let replay_authority =
1113            Self::reusable_execution_wave_authority(providers, resolved, &wave, lane)
1114                .map_err(SubmissionWaveDispatchError::Contract)?
1115                .ok_or_else(|| {
1116                    SubmissionWaveDispatchError::Contract(invalid_operation(
1117                        "determinism replay wave has no reusable execution authority",
1118                    ))
1119                })?;
1120        if &replay_authority.program_id != reusable_program.program_id() {
1121            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1122                "determinism replay program differs from the live wave topology",
1123            )));
1124        }
1125        let mut declared_eager_boundary_node_ids = replay_authority
1126            .eager_boundary_node_indices
1127            .iter()
1128            .map(|node_index| {
1129                usize::try_from(*node_index)
1130                    .ok()
1131                    .and_then(|node_index| batch_identity.node_id_at(node_index))
1132                    .cloned()
1133                    .ok_or_else(|| {
1134                        SubmissionWaveDispatchError::Contract(invalid_operation(
1135                            "determinism eager boundary is absent from the batch identity",
1136                        ))
1137                    })
1138            })
1139            .collect::<Result<Vec<_>, _>>()?;
1140        declared_eager_boundary_node_ids.sort();
1141        let profiled = Self::encode_and_submit_wave_with_inputs_timed(
1142            providers,
1143            resolved,
1144            batch_identity,
1145            active_bindings,
1146            timing_mode,
1147            &[],
1148            SubmissionExecutionPolicy::determinism_replayed(scratch_fill),
1149            Some(restore),
1150            Some(reusable_program),
1151            &DisabledSubmissionWaveDispatchTimingSink,
1152            wave,
1153            lane,
1154            reaper,
1155        )?;
1156        SubmissionWaveDeterminismHandle::from_profiled_replayed(
1157            profiled,
1158            readback_plan,
1159            restore_fingerprint,
1160            initialization_identity,
1161            replay_authority.program_id,
1162            declared_eager_boundary_node_ids,
1163        )
1164        .map_err(SubmissionWaveDispatchError::Contract)
1165    }
1166
1167    #[allow(clippy::too_many_arguments)]
1168    pub fn encode_and_submit_reusable_wave_with_inputs<'binding, R, I>(
1169        providers: &[BoundOperationProvider<'_, R>],
1170        resolved: &dyn ExecutablePlanView,
1171        batch_identity: &BatchOperationIdentity,
1172        active_bindings: I,
1173        timing_mode: DeviceTimingMode,
1174        input_uploads: &[SubmissionWaveInputUpload],
1175        reusable_program: &DeviceReusableExecutionProgram,
1176        wave: PreparedStepSubmissionWave<R>,
1177        lane: &Arc<ExecutionLane<R>>,
1178        reaper: &Arc<CompletionReaper<R>>,
1179    ) -> Result<CompletionHandle<R>, SubmissionWaveDispatchError<R>>
1180    where
1181        R: DeviceRuntime,
1182        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1183    {
1184        Self::encode_and_submit_wave_with_inputs_timed(
1185            providers,
1186            resolved,
1187            batch_identity,
1188            active_bindings,
1189            timing_mode,
1190            input_uploads,
1191            SubmissionExecutionPolicy::adaptive(),
1192            None,
1193            Some(reusable_program),
1194            &DisabledSubmissionWaveDispatchTimingSink,
1195            wave,
1196            lane,
1197            reaper,
1198        )
1199        .map(|profiled| profiled.into_parts().0)
1200    }
1201
1202    #[allow(clippy::too_many_arguments)]
1203    pub fn encode_and_submit_reusable_wave_with_inputs_and_policy<'binding, R, I>(
1204        providers: &[BoundOperationProvider<'_, R>],
1205        resolved: &dyn ExecutablePlanView,
1206        batch_identity: &BatchOperationIdentity,
1207        active_bindings: I,
1208        timing_mode: DeviceTimingMode,
1209        input_uploads: &[SubmissionWaveInputUpload],
1210        reusable_program: &DeviceReusableExecutionProgram,
1211        execution_policy: SubmissionExecutionPolicy,
1212        wave: PreparedStepSubmissionWave<R>,
1213        lane: &Arc<ExecutionLane<R>>,
1214        reaper: &Arc<CompletionReaper<R>>,
1215    ) -> Result<CompletionHandle<R>, SubmissionWaveDispatchError<R>>
1216    where
1217        R: DeviceRuntime,
1218        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1219    {
1220        Self::encode_and_submit_wave_with_inputs_timed(
1221            providers,
1222            resolved,
1223            batch_identity,
1224            active_bindings,
1225            timing_mode,
1226            input_uploads,
1227            execution_policy,
1228            None,
1229            Some(reusable_program),
1230            &DisabledSubmissionWaveDispatchTimingSink,
1231            wave,
1232            lane,
1233            reaper,
1234        )
1235        .map(|profiled| profiled.into_parts().0)
1236    }
1237
1238    #[allow(clippy::too_many_arguments)]
1239    pub fn encode_and_submit_reusable_wave_with_inputs_and_timing<'binding, R, I, S>(
1240        providers: &[BoundOperationProvider<'_, R>],
1241        resolved: &dyn ExecutablePlanView,
1242        batch_identity: &BatchOperationIdentity,
1243        active_bindings: I,
1244        timing_mode: DeviceTimingMode,
1245        input_uploads: &[SubmissionWaveInputUpload],
1246        reusable_program: &DeviceReusableExecutionProgram,
1247        execution_policy: SubmissionExecutionPolicy,
1248        timing_sink: &S,
1249        wave: PreparedStepSubmissionWave<R>,
1250        lane: &Arc<ExecutionLane<R>>,
1251        reaper: &Arc<CompletionReaper<R>>,
1252    ) -> Result<ProfiledSubmissionHandle<R>, SubmissionWaveDispatchError<R>>
1253    where
1254        R: DeviceRuntime,
1255        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1256        S: SubmissionWaveDispatchTimingSink,
1257    {
1258        Self::encode_and_submit_wave_with_inputs_timed(
1259            providers,
1260            resolved,
1261            batch_identity,
1262            active_bindings,
1263            timing_mode,
1264            input_uploads,
1265            execution_policy,
1266            None,
1267            Some(reusable_program),
1268            timing_sink,
1269            wave,
1270            lane,
1271            reaper,
1272        )
1273    }
1274
1275    #[allow(clippy::too_many_arguments)]
1276    fn encode_and_submit_wave_with_inputs_timed<'binding, R, I, S>(
1277        providers: &[BoundOperationProvider<'_, R>],
1278        resolved: &dyn ExecutablePlanView,
1279        batch_identity: &BatchOperationIdentity,
1280        active_bindings: I,
1281        timing_mode: DeviceTimingMode,
1282        input_uploads: &[SubmissionWaveInputUpload],
1283        execution_policy: SubmissionExecutionPolicy,
1284        determinism_restore: Option<&SubmissionWaveDeterminismRestore>,
1285        reusable_program: Option<&DeviceReusableExecutionProgram>,
1286        timing_sink: &S,
1287        mut wave: PreparedStepSubmissionWave<R>,
1288        lane: &Arc<ExecutionLane<R>>,
1289        reaper: &Arc<CompletionReaper<R>>,
1290    ) -> Result<ProfiledSubmissionHandle<R>, SubmissionWaveDispatchError<R>>
1291    where
1292        R: DeviceRuntime,
1293        I: Clone + ExactSizeIterator<Item = &'binding TrustedActiveSequenceBinding>,
1294        S: SubmissionWaveDispatchTimingSink,
1295    {
1296        let contract_stage = SubmissionWaveDispatchStageTimer::start(
1297            timing_sink,
1298            SubmissionWaveDispatchStage::ContractValidateAndReserve,
1299        );
1300        let active_participant_count = active_bindings.len();
1301        if providers.is_empty()
1302            || providers.len() != wave.nodes().len()
1303            || providers.len() != batch_identity.node_count()
1304            || active_participant_count == 0
1305            || batch_identity.batch_step_id() != wave.batch_step_id()
1306            || batch_identity.batch_invocation_id() != wave.batch_invocation_id()
1307            || batch_identity.claimed_backing_fingerprint() != wave.fingerprint()
1308            || lane.id() != batch_identity.lane_id()
1309            || lane.descriptor().id != *batch_identity.device_id()
1310            || lane.descriptor().runtime_implementation_fingerprint
1311                != batch_identity.runtime_implementation_fingerprint()
1312        {
1313            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1314                "wave execution lane, resources, nodes, or participants differ from batch identity",
1315            )));
1316        }
1317        if !matches!(
1318            (wave.purpose(), determinism_restore.is_some()),
1319            (SubmissionWavePurpose::FullPlan, false)
1320                | (SubmissionWavePurpose::DeterminismProbe, true)
1321        ) {
1322            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1323                "submission wave purpose differs from its product or determinism dispatch path",
1324            )));
1325        }
1326        if let Some(restore) = determinism_restore {
1327            restore
1328                .validate_for_submission(
1329                    lane.runtime(),
1330                    providers,
1331                    resolved,
1332                    batch_identity,
1333                    active_bindings.clone(),
1334                    &wave,
1335                )
1336                .map_err(SubmissionWaveDispatchError::Contract)?;
1337            if !input_uploads.is_empty()
1338                || usize::try_from(restore.participant_count()).ok()
1339                    != Some(active_participant_count)
1340                || execution_policy.compute_path() == DeviceComputePathRequirement::Adaptive
1341                || execution_policy.scratch_initialization()
1342                    == SubmissionScratchInitialization::ProviderContract
1343            {
1344                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1345                    "determinism submission requires complete restore coverage, explicit scratch fill, and one forced compute path",
1346                )));
1347            }
1348        }
1349        for (node_index, (provider, prepared_node)) in
1350            providers.iter().zip(wave.nodes()).enumerate()
1351        {
1352            let node_id = batch_identity.node_id_at(node_index).ok_or_else(|| {
1353                SubmissionWaveDispatchError::Contract(invalid_operation(
1354                    "physical batch is missing a compiled plan node",
1355                ))
1356            })?;
1357            provider
1358                .validate_binding(resolved, node_id)
1359                .map_err(SubmissionWaveDispatchError::Contract)?;
1360            if prepared_node.node_id() != node_id
1361                || prepared_node.work_shape().fingerprint()
1362                    != batch_identity
1363                        .work_shape_fingerprint_at(node_index)
1364                        .expect("compiled physical batch node has work identity")
1365                || Some(provider.descriptor().provider_id())
1366                    != batch_identity.provider_id_at(node_index)
1367                || Some(provider.descriptor().operation_id())
1368                    != batch_identity.operation_id_at(node_index)
1369                || batch_identity.node_participant_count(node_index)
1370                    != Some(
1371                        usize::try_from(prepared_node.participant_count())
1372                            .expect("prepared wave participant count fits usize"),
1373                    )
1374                || batch_identity.node_participant_count(node_index)
1375                    != Some(active_participant_count)
1376            {
1377                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1378                    "wave provider or node identity differs from its prepared node",
1379                )));
1380            }
1381        }
1382        let reusable_execution_authority =
1383            Self::reusable_execution_wave_authority(providers, resolved, &wave, lane)
1384                .map_err(SubmissionWaveDispatchError::Contract)?;
1385        let mut effective_compute_path = execution_policy.compute_path();
1386        let mut declared_eager_compute_node_indices = Vec::new();
1387        if let Some(reusable_program) = reusable_program {
1388            if !timing_mode.direct_reusable_execution_allowed()
1389                || execution_policy.compute_path() == DeviceComputePathRequirement::EagerOnly
1390            {
1391                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1392                    "submission timing or compute-path policy requires eager provider encoding",
1393                )));
1394            }
1395            if execution_policy.compute_path() == DeviceComputePathRequirement::Adaptive
1396                && !reusable_program.has_resident_segments()
1397            {
1398                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1399                    "product reusable execution requires at least one resident segment",
1400                )));
1401            }
1402            let actual_authority = reusable_execution_authority.as_ref().ok_or_else(|| {
1403                SubmissionWaveDispatchError::Contract(invalid_operation(
1404                    "reusable execution program has no live program binding authority",
1405                ))
1406            })?;
1407            if &actual_authority.program_id != reusable_program.program_id()
1408                || reusable_program.segments().iter().any(|segment| {
1409                    segment.end_node_index() as usize > providers.len()
1410                        || segment.logical_command_count()
1411                            != segment.end_node_index() - segment.start_node_index()
1412                })
1413            {
1414                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1415                    "reusable execution program differs from the exact wave topology",
1416                )));
1417            }
1418            if execution_policy.compute_path() == DeviceComputePathRequirement::ReplayedOnly {
1419                validate_determinism_replay_coverage(
1420                    reusable_program,
1421                    providers.len(),
1422                    &actual_authority.eager_boundary_node_indices,
1423                    batch_identity,
1424                )
1425                .map_err(SubmissionWaveDispatchError::Contract)?;
1426                if !actual_authority.eager_boundary_node_indices.is_empty() {
1427                    effective_compute_path =
1428                        DeviceComputePathRequirement::ReplayedWithDeclaredEagerBoundaries;
1429                    declared_eager_compute_node_indices =
1430                        actual_authority.eager_boundary_node_indices.clone();
1431                }
1432            }
1433        } else if matches!(
1434            execution_policy.compute_path(),
1435            DeviceComputePathRequirement::ReplayedOnly
1436                | DeviceComputePathRequirement::ReplayedWithDeclaredEagerBoundaries
1437        ) {
1438            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1439                "replay-required submission requires one sealed reusable execution program",
1440            )));
1441        }
1442        wave.begin_dispatch()
1443            .map_err(SubmissionWaveDispatchError::Contract)?;
1444        let mut completion =
1445            CompletionReaper::reserve_wave(reaper, wave, Arc::clone(lane), batch_identity.clone())
1446                .map_err(SubmissionWaveDispatchError::Contract)?;
1447        let runtime = lane.runtime();
1448        if !lane.current_descriptor_matches_snapshot() {
1449            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1450                "wave encode runtime differs from its execution lane snapshot",
1451            )));
1452        }
1453        drop(contract_stage);
1454
1455        let backing_stage = SubmissionWaveDispatchStageTimer::start(
1456            timing_sink,
1457            SubmissionWaveDispatchStage::BackingAndInputEncode,
1458        );
1459        let restore_capacity = determinism_restore.map_or(0, |restore| {
1460            restore
1461                .initializations()
1462                .len()
1463                .saturating_mul(active_participant_count)
1464        });
1465        let mut commands = DeviceCommandBatch::with_capacity_timing_and_compute_path(
1466            providers
1467                .len()
1468                .saturating_add(input_uploads.len())
1469                .saturating_add(restore_capacity),
1470            timing_mode,
1471            effective_compute_path,
1472        );
1473        if effective_compute_path
1474            == DeviceComputePathRequirement::ReplayedWithDeclaredEagerBoundaries
1475        {
1476            commands
1477                .set_declared_eager_compute_node_indices(declared_eager_compute_node_indices)
1478                .map_err(SubmissionWaveDispatchError::Contract)?;
1479        }
1480        if determinism_restore.is_some() {
1481            commands.require_logical_execution_path_attribution();
1482        }
1483        let backing_initialization_command_count = completion
1484            .encode_backing_initializations(runtime, &mut commands)
1485            .map_err(|error| map_backing_initialization_error(runtime, batch_identity, error))?;
1486        let workspace_initialization_command_count =
1487            encode_submission_wave_workspace_initializations(
1488                runtime,
1489                resolved,
1490                batch_identity,
1491                execution_policy.scratch_initialization(),
1492                &completion,
1493                &mut commands,
1494            )?;
1495        if commands.len()
1496            != backing_initialization_command_count
1497                .saturating_add(workspace_initialization_command_count)
1498        {
1499            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1500                "backing initialization command accounting differs from encoded commands",
1501            )));
1502        }
1503        if let Some(restore) = determinism_restore {
1504            let restore_start = commands.len();
1505            let restore_command_count = encode_submission_wave_determinism_restore(
1506                runtime,
1507                resolved,
1508                batch_identity,
1509                &completion,
1510                restore,
1511                &mut commands,
1512            )?;
1513            if commands.len()
1514                != restore_start
1515                    .checked_add(restore_command_count)
1516                    .ok_or_else(|| {
1517                        SubmissionWaveDispatchError::Contract(invalid_operation(
1518                            "determinism restore command accounting overflows usize",
1519                        ))
1520                    })?
1521            {
1522                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1523                    "determinism restore command accounting differs from encoded commands",
1524                )));
1525            }
1526        }
1527        encode_submission_wave_inputs(
1528            runtime,
1529            resolved,
1530            batch_identity,
1531            &completion,
1532            input_uploads,
1533            &mut commands,
1534        )?;
1535        drop(backing_stage);
1536
1537        let provider_stage = SubmissionWaveDispatchStageTimer::start(
1538            timing_sink,
1539            SubmissionWaveDispatchStage::ProviderNodeEncode,
1540        );
1541        let pre_provider_command_count = commands.len();
1542        let mut encoded_provider_command_count = 0_usize;
1543        let mut program_bindings = Vec::new();
1544        let mut program_binding_resources = BTreeSet::new();
1545        let mut reusable_execution_binding_nodes = Vec::new();
1546        let mut encoded_operations = Vec::with_capacity(providers.len());
1547        if let Some(reusable_program) = reusable_program {
1548            let mut node_index = 0_usize;
1549            let mut segment_index = 0_usize;
1550            while node_index < providers.len() {
1551                let segment = reusable_program
1552                    .segments()
1553                    .get(segment_index)
1554                    .filter(|segment| segment.start_node_index() as usize == node_index);
1555                if let Some(segment) = segment {
1556                    let mut segment_dynamic_bindings = Vec::new();
1557                    let mut segment_result_bindings = Vec::new();
1558                    for binding_node_index in reusable_program
1559                        .per_wave_binding_node_indices()
1560                        .iter()
1561                        .copied()
1562                        .filter(|binding_node_index| segment.contains_node(*binding_node_index))
1563                    {
1564                        let binding_node_index =
1565                            usize::try_from(binding_node_index).map_err(|_| {
1566                                SubmissionWaveDispatchError::Contract(invalid_operation(
1567                                    "reusable execution binding node exceeds usize",
1568                                ))
1569                            })?;
1570                        let provider = &providers[binding_node_index];
1571                        let node_identity = batch_identity
1572                            .materialize_node(binding_node_index)
1573                            .map_err(SubmissionWaveDispatchError::Contract)?;
1574                        let invocation = BatchedOperationInvocation::from_wave_node(
1575                            runtime,
1576                            resolved,
1577                            provider.dispatch(),
1578                            batch_identity,
1579                            node_identity,
1580                            completion.wave(),
1581                            binding_node_index,
1582                            active_bindings.clone(),
1583                        )
1584                        .map_err(SubmissionWaveDispatchError::Contract)?;
1585                        let expected_phase = invocation.operation().profile_phase;
1586                        let program_binding = invocation.program_binding().cloned();
1587                        let bindings = match provider
1588                            .provider()
1589                            .encode_reusable_execution_bindings(invocation)
1590                        {
1591                            Ok(bindings) => bindings,
1592                            Err(failure)
1593                                if node_identity.contains_identity(failure.identity())
1594                                    && failure.phase() == expected_phase =>
1595                            {
1596                                return Err(SubmissionWaveDispatchError::Provider(failure));
1597                            }
1598                            Err(_) => {
1599                                return Err(SubmissionWaveDispatchError::Contract(
1600                                    invalid_operation(
1601                                        "reusable provider returned a failure for another node identity or profile phase",
1602                                    ),
1603                                ));
1604                            }
1605                        };
1606                        let program_binding_count = bindings.program_binding_count();
1607                        validate_program_binding_patch(
1608                            resolved,
1609                            node_identity,
1610                            program_binding.as_ref(),
1611                            program_binding_count,
1612                            &mut program_binding_resources,
1613                        )
1614                        .map_err(SubmissionWaveDispatchError::Contract)?;
1615                        let (mut node_program_bindings, mut dynamic_bindings, mut result_bindings) =
1616                            bindings.into_parts();
1617                        program_bindings.append(&mut node_program_bindings);
1618                        segment_dynamic_bindings.append(&mut dynamic_bindings);
1619                        segment_result_bindings.append(&mut result_bindings);
1620                    }
1621                    let invocation = DeviceReusableExecutionInvocation::new(
1622                        reusable_program.program_id().clone(),
1623                        segment.clone(),
1624                        u32::try_from(active_participant_count).map_err(|_| {
1625                            SubmissionWaveDispatchError::Contract(invalid_operation(
1626                                "reusable execution participant count exceeds u32",
1627                            ))
1628                        })?,
1629                        completion
1630                            .wave()
1631                            .claimed_backing()
1632                            .work_shape()
1633                            .immediate_tokens(),
1634                    )
1635                    .map_err(SubmissionWaveDispatchError::Contract)?;
1636                    let compute = runtime
1637                        .encode_reusable_execution(invocation)
1638                        .map_err(|error| {
1639                            SubmissionWaveDispatchError::Contract(invalid_operation(format!(
1640                                "device runtime rejected a sealed reusable program: {error}"
1641                            )))
1642                        })?
1643                        .ok_or_else(|| {
1644                            SubmissionWaveDispatchError::Contract(invalid_operation(
1645                                "device runtime published a reusable program it cannot encode",
1646                            ))
1647                        })?;
1648                    let operation_command_count = segment_dynamic_bindings
1649                        .len()
1650                        .checked_add(1)
1651                        .and_then(|count| count.checked_add(segment_result_bindings.len()))
1652                        .ok_or_else(|| {
1653                            SubmissionWaveDispatchError::Contract(invalid_operation(
1654                                "reusable execution command count overflows usize",
1655                            ))
1656                        })?;
1657                    encoded_provider_command_count = encoded_provider_command_count
1658                        .checked_add(operation_command_count)
1659                        .ok_or_else(|| {
1660                            SubmissionWaveDispatchError::Contract(invalid_operation(
1661                                "submission wave command count overflows usize",
1662                            ))
1663                        })?;
1664                    encoded_operations.push((
1665                        segment.start_node_index(),
1666                        segment_dynamic_bindings,
1667                        compute,
1668                        segment_result_bindings,
1669                    ));
1670                    node_index = segment.end_node_index() as usize;
1671                    segment_index += 1;
1672                    continue;
1673                }
1674                if reusable_program
1675                    .segments()
1676                    .get(segment_index)
1677                    .is_some_and(|segment| (segment.start_node_index() as usize) < node_index)
1678                {
1679                    return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1680                        "reusable execution segment traversal is not canonical",
1681                    )));
1682                }
1683                let provider = &providers[node_index];
1684                let node_identity = batch_identity
1685                    .materialize_node(node_index)
1686                    .map_err(SubmissionWaveDispatchError::Contract)?;
1687                let invocation = BatchedOperationInvocation::from_wave_node(
1688                    runtime,
1689                    resolved,
1690                    provider.dispatch(),
1691                    batch_identity,
1692                    node_identity,
1693                    completion.wave(),
1694                    node_index,
1695                    active_bindings.clone(),
1696                )
1697                .map_err(SubmissionWaveDispatchError::Contract)?;
1698                let expected_phase = invocation.operation().profile_phase;
1699                let program_binding = invocation.program_binding().cloned();
1700                let operation = match provider.provider().encode_selected(invocation) {
1701                    Ok(operation) => operation,
1702                    Err(failure)
1703                        if node_identity.contains_identity(failure.identity())
1704                            && failure.phase() == expected_phase =>
1705                    {
1706                        return Err(SubmissionWaveDispatchError::Provider(failure));
1707                    }
1708                    Err(_) => {
1709                        return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1710                            "wave provider returned a failure for another node identity or profile phase",
1711                        )));
1712                    }
1713                };
1714                let program_binding_count = operation.program_binding_count();
1715                validate_program_binding_patch(
1716                    resolved,
1717                    node_identity,
1718                    program_binding.as_ref(),
1719                    program_binding_count,
1720                    &mut program_binding_resources,
1721                )
1722                .map_err(SubmissionWaveDispatchError::Contract)?;
1723                let operation_command_count = operation
1724                    .dynamic_binding_count()
1725                    .checked_add(1)
1726                    .and_then(|count| count.checked_add(operation.result_binding_count()))
1727                    .ok_or_else(|| {
1728                        SubmissionWaveDispatchError::Contract(invalid_operation(
1729                            "provider operation command count overflows usize",
1730                        ))
1731                    })?;
1732                encoded_provider_command_count = encoded_provider_command_count
1733                    .checked_add(operation_command_count)
1734                    .ok_or_else(|| {
1735                        SubmissionWaveDispatchError::Contract(invalid_operation(
1736                            "submission wave command count overflows usize",
1737                        ))
1738                    })?;
1739                let encoded_node_index = u32::try_from(node_index).map_err(|_| {
1740                    SubmissionWaveDispatchError::Contract(invalid_operation(
1741                        "submission wave node index exceeds u32",
1742                    ))
1743                })?;
1744                let (mut node_program_bindings, dynamic_bindings, compute, result_bindings) =
1745                    operation.into_parts();
1746                program_bindings.append(&mut node_program_bindings);
1747                encoded_operations.push((
1748                    encoded_node_index,
1749                    dynamic_bindings,
1750                    compute,
1751                    result_bindings,
1752                ));
1753                node_index += 1;
1754            }
1755            if segment_index != reusable_program.segments().len() {
1756                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1757                    "reusable execution program contains an unreachable segment",
1758                )));
1759            }
1760        } else {
1761            for (node_index, (provider, node_identity)) in
1762                providers.iter().zip(batch_identity.nodes()).enumerate()
1763            {
1764                let invocation = BatchedOperationInvocation::from_wave_node(
1765                    runtime,
1766                    resolved,
1767                    provider.dispatch(),
1768                    batch_identity,
1769                    node_identity,
1770                    completion.wave(),
1771                    node_index,
1772                    active_bindings.clone(),
1773                )
1774                .map_err(SubmissionWaveDispatchError::Contract)?;
1775                let expected_phase = invocation.operation().profile_phase;
1776                let program_binding = invocation.program_binding().cloned();
1777                let operation = match provider.provider().encode_selected(invocation) {
1778                    Ok(operation) => operation,
1779                    Err(failure)
1780                        if node_identity.contains_identity(failure.identity())
1781                            && failure.phase() == expected_phase =>
1782                    {
1783                        return Err(SubmissionWaveDispatchError::Provider(failure));
1784                    }
1785                    Err(_) => {
1786                        return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1787                        "wave provider returned a failure for another node identity or profile phase",
1788                    )));
1789                    }
1790                };
1791                let program_binding_count = operation.program_binding_count();
1792                validate_program_binding_patch(
1793                    resolved,
1794                    node_identity,
1795                    program_binding.as_ref(),
1796                    program_binding_count,
1797                    &mut program_binding_resources,
1798                )
1799                .map_err(SubmissionWaveDispatchError::Contract)?;
1800                let operation_command_count = operation
1801                    .dynamic_binding_count()
1802                    .checked_add(1)
1803                    .and_then(|count| count.checked_add(operation.result_binding_count()))
1804                    .ok_or_else(|| {
1805                        SubmissionWaveDispatchError::Contract(invalid_operation(
1806                            "provider operation command count overflows usize",
1807                        ))
1808                    })?;
1809                let has_per_wave_bindings = program_binding_count > 0
1810                    || operation.dynamic_binding_count() > 0
1811                    || operation.result_binding_count() > 0;
1812                encoded_provider_command_count = encoded_provider_command_count
1813                    .checked_add(operation_command_count)
1814                    .ok_or_else(|| {
1815                        SubmissionWaveDispatchError::Contract(invalid_operation(
1816                            "submission wave command count overflows usize",
1817                        ))
1818                    })?;
1819                let node_index = u32::try_from(node_index).map_err(|_| {
1820                    SubmissionWaveDispatchError::Contract(invalid_operation(
1821                        "submission wave node index exceeds u32",
1822                    ))
1823                })?;
1824                if has_per_wave_bindings {
1825                    reusable_execution_binding_nodes.push(node_index);
1826                }
1827                let (mut node_program_bindings, dynamic_bindings, compute, result_bindings) =
1828                    operation.into_parts();
1829                program_bindings.append(&mut node_program_bindings);
1830                encoded_operations.push((node_index, dynamic_bindings, compute, result_bindings));
1831            }
1832        }
1833        if let Some(layout) = completion.wave().claimed_backing().program_binding_layout() {
1834            let selected_plan_nodes = completion
1835                .wave()
1836                .nodes()
1837                .iter()
1838                .map(|node| node.plan_node_index())
1839                .collect::<BTreeSet<_>>();
1840            let expected_resources = layout
1841                .slots()
1842                .iter()
1843                .filter(|slot| selected_plan_nodes.contains(&slot.node_index()))
1844                .map(|slot| slot.resource_id())
1845                .collect::<BTreeSet<_>>();
1846            if program_binding_resources.len() != expected_resources.len()
1847                || expected_resources
1848                    .iter()
1849                    .any(|resource| !program_binding_resources.contains(*resource))
1850            {
1851                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1852                    "provider program binding patches do not cover the selected compiled layout exactly",
1853                )));
1854            }
1855        }
1856        let uncoalesced_program_binding_count = program_bindings.len();
1857        let coalesced_program_bindings = runtime
1858            .coalesce_program_bindings(program_bindings)
1859            .map_err(|error| {
1860                SubmissionWaveDispatchError::Contract(invalid_operation(format!(
1861                    "device runtime could not coalesce program bindings: {error}"
1862                )))
1863            })?;
1864        if (uncoalesced_program_binding_count == 0) != coalesced_program_bindings.is_empty()
1865            || coalesced_program_bindings.len() > uncoalesced_program_binding_count
1866        {
1867            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1868                "device runtime changed the program binding boundary cardinality illegally",
1869            )));
1870        }
1871        encoded_provider_command_count = encoded_provider_command_count
1872            .checked_add(coalesced_program_bindings.len())
1873            .ok_or_else(|| {
1874                SubmissionWaveDispatchError::Contract(invalid_operation(
1875                    "coalesced program binding command count overflows usize",
1876                ))
1877            })?;
1878        for command in coalesced_program_bindings {
1879            commands.push_dynamic_binding(command);
1880        }
1881        for (node_index, dynamic_bindings, compute, result_bindings) in encoded_operations {
1882            commands.push_operation_parts(node_index, dynamic_bindings, compute, result_bindings);
1883        }
1884        if reusable_program.is_none() {
1885            if let Some(authority) = reusable_execution_authority {
1886                commands
1887                    .set_reusable_execution_capture(
1888                        DeviceReusableExecutionCapture::new(
1889                            authority.program_id,
1890                            u32::try_from(providers.len()).map_err(|_| {
1891                                SubmissionWaveDispatchError::Contract(invalid_operation(
1892                                    "reusable execution capture node count exceeds u32",
1893                                ))
1894                            })?,
1895                            authority.eager_boundary_node_indices,
1896                            reusable_execution_binding_nodes,
1897                        )
1898                        .map_err(SubmissionWaveDispatchError::Contract)?,
1899                    )
1900                    .map_err(SubmissionWaveDispatchError::Contract)?;
1901            }
1902        }
1903        if commands.len()
1904            != pre_provider_command_count.saturating_add(encoded_provider_command_count)
1905            || !lane.current_descriptor_matches_snapshot()
1906        {
1907            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
1908                "wave encode command phases differ from provider-declared operation boundaries",
1909            )));
1910        }
1911        drop(provider_stage);
1912
1913        let lane_stage = SubmissionWaveDispatchStageTimer::start(
1914            timing_sink,
1915            SubmissionWaveDispatchStage::LaneReserveSubmitAndArm,
1916        );
1917        let lane_reserve_stage = SubmissionWaveDispatchStageTimer::start(
1918            timing_sink,
1919            SubmissionWaveDispatchStage::LaneReserve,
1920        );
1921        let mut lane_reservation = lane
1922            .reserve_enqueue()
1923            .map_err(SubmissionWaveDispatchError::Contract)?;
1924        drop(lane_reserve_stage);
1925
1926        let device_submit_stage = SubmissionWaveDispatchStageTimer::start(
1927            timing_sink,
1928            SubmissionWaveDispatchStage::DeviceRuntimeSubmit,
1929        );
1930        completion.mark_submission_started();
1931        let submit_outcome = lane_reservation.submit_with_timing(commands, timing_sink);
1932        drop(lane_reservation);
1933        drop(device_submit_stage);
1934
1935        let outcome = match submit_outcome {
1936            LaneSubmitOutcome::DefinitelyNotSubmitted(error) => {
1937                let retry = completion
1938                    .definitely_not_submitted_wave()
1939                    .map_err(SubmissionWaveDispatchError::Contract)?;
1940                let failures = batch_identity
1941                    .participants()
1942                    .iter()
1943                    .map(|participant| {
1944                        classify_device_error(runtime, participant.identity().clone(), &error)
1945                    })
1946                    .collect::<Result<Vec<_>, _>>()
1947                    .map_err(SubmissionWaveDispatchError::Contract)?;
1948                Err(SubmissionWaveDispatchError::DefinitelyNotSubmitted { failures, retry })
1949            }
1950            LaneSubmitOutcome::PossiblySubmittedPanic => {
1951                let recovery = completion.submission_indeterminate();
1952                Err(SubmissionWaveDispatchError::SubmissionIndeterminate { recovery })
1953            }
1954            LaneSubmitOutcome::Submitted(fence) => {
1955                let device_attribution = runtime.submission_attribution(&fence);
1956                let completion_arm_stage = SubmissionWaveDispatchStageTimer::start(
1957                    timing_sink,
1958                    SubmissionWaveDispatchStage::CompletionArm,
1959                );
1960                let completion = match completion.arm(fence, timing_mode) {
1961                    Ok(completion) => completion,
1962                    Err((error, completion)) => {
1963                        return Err(SubmissionWaveDispatchError::PostSubmitContract {
1964                            error,
1965                            completion,
1966                        });
1967                    }
1968                };
1969                if !lane.current_descriptor_matches_snapshot() {
1970                    lane.fail_closed();
1971                    return Err(SubmissionWaveDispatchError::PostSubmitContract {
1972                        error: invalid_operation("wave submit completion runtime drifted"),
1973                        completion,
1974                    });
1975                }
1976                let attribution = match device_attribution
1977                    .map(|device| {
1978                        BoundDeviceSubmissionAttribution::new(
1979                            batch_identity.clone(),
1980                            completion.receipt().fingerprint().to_owned(),
1981                            device,
1982                        )
1983                    })
1984                    .transpose()
1985                {
1986                    Ok(attribution) => attribution,
1987                    Err(error) => {
1988                        return Err(SubmissionWaveDispatchError::PostSubmitContract {
1989                            error,
1990                            completion,
1991                        });
1992                    }
1993                };
1994                drop(completion_arm_stage);
1995                Ok(ProfiledSubmissionHandle::new(completion, attribution))
1996            }
1997        };
1998        drop(lane_stage);
1999        outcome
2000    }
2001}
2002
2003fn map_backing_initialization_error<R, Retry>(
2004    runtime: &R,
2005    batch_identity: &BatchOperationIdentity,
2006    error: BackingInitializationEncodeError<R::Error>,
2007) -> OperationDispatchError<R, Retry>
2008where
2009    R: DeviceRuntime,
2010    Retry: DispatchRetryAuthority,
2011{
2012    match error {
2013        BackingInitializationEncodeError::Contract(error) => {
2014            OperationDispatchError::Contract(error)
2015        }
2016        BackingInitializationEncodeError::Runtime { participant, error } => {
2017            let identity = batch_identity
2018                .nodes()
2019                .iter()
2020                .flat_map(BatchOperationNodeIdentity::participants)
2021                .find(|candidate| {
2022                    candidate.node_key().sequence_authority() == participant.sequence_authority()
2023                        && candidate.node_key().request_authority()
2024                            == participant.request_authority()
2025                })
2026                .map(BatchOperationParticipantIdentity::identity)
2027                .cloned();
2028            let Some(identity) = identity else {
2029                return OperationDispatchError::Contract(invalid_operation(
2030                    "backing initialization failure has no matching batch participant",
2031                ));
2032            };
2033            match classify_device_error(runtime, identity, &error) {
2034                Ok(failure) => OperationDispatchError::Initialization(failure),
2035                Err(error) => OperationDispatchError::Contract(error),
2036            }
2037        }
2038    }
2039}
2040
2041fn encode_submission_wave_determinism_restore<R>(
2042    runtime: &R,
2043    resolved: &dyn ExecutablePlanView,
2044    batch_identity: &BatchOperationIdentity,
2045    completion: &CompletionReservation<R>,
2046    restore: &SubmissionWaveDeterminismRestore,
2047    commands: &mut DeviceCommandBatch<R::Command>,
2048) -> Result<usize, SubmissionWaveDispatchError<R>>
2049where
2050    R: DeviceRuntime,
2051{
2052    restore
2053        .validate_for(resolved)
2054        .map_err(SubmissionWaveDispatchError::Contract)?;
2055    let participant_count = usize::try_from(restore.participant_count()).map_err(|_| {
2056        SubmissionWaveDispatchError::Contract(invalid_operation(
2057            "determinism restore participant count exceeds host address space",
2058        ))
2059    })?;
2060    let mut command_count = 0_usize;
2061    for (initialization_index, initialization) in restore.initializations().iter().enumerate() {
2062        let location = initialization.location();
2063        if !initialization
2064            .consumer_node_ids()
2065            .iter()
2066            .any(|node_id| node_id == location.node_id())
2067            || initialization.consumer_node_ids().iter().any(|node_id| {
2068                batch_identity
2069                    .node_index(node_id)
2070                    .and_then(|index| batch_identity.node_participant_count(index))
2071                    != Some(participant_count)
2072            })
2073        {
2074            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
2075                "determinism restore consumer coverage differs from its submitted wave",
2076            )));
2077        }
2078        let node_index = batch_identity
2079            .node_index(location.node_id())
2080            .ok_or_else(|| {
2081                SubmissionWaveDispatchError::Contract(invalid_operation(
2082                    "determinism restore anchor node is absent from its submitted wave",
2083                ))
2084            })?;
2085        let node_index_u32 = u32::try_from(node_index).map_err(|_| {
2086            SubmissionWaveDispatchError::Contract(invalid_operation(
2087                "determinism restore node index exceeds u32",
2088            ))
2089        })?;
2090        let node_identity = batch_identity
2091            .materialize_node(node_index)
2092            .map_err(SubmissionWaveDispatchError::Contract)?;
2093        let prepared_node = completion.wave().nodes().get(node_index).ok_or_else(|| {
2094            SubmissionWaveDispatchError::Contract(invalid_operation(
2095                "determinism restore anchor node is absent from its prepared wave",
2096            ))
2097        })?;
2098        for participant_index in 0..participant_count {
2099            let participant_index_u32 = u32::try_from(participant_index).map_err(|_| {
2100                SubmissionWaveDispatchError::Contract(invalid_operation(
2101                    "determinism restore participant index exceeds u32",
2102                ))
2103            })?;
2104            let participant = node_identity
2105                .participants()
2106                .get(participant_index)
2107                .ok_or_else(|| {
2108                    SubmissionWaveDispatchError::Contract(invalid_operation(
2109                        "determinism restore participant is absent from its anchor node",
2110                    ))
2111                })?;
2112            let participant_work = prepared_node
2113                .work_shape()
2114                .participant_work()
2115                .get(participant_index)
2116                .ok_or_else(|| {
2117                    SubmissionWaveDispatchError::Contract(invalid_operation(
2118                        "determinism restore participant lacks exact token work",
2119                    ))
2120                })?;
2121            let logical_work = DeviceCommandLogicalWork::for_participant_range(
2122                DeviceBatchingForm::Scalar,
2123                participant_index_u32,
2124                1,
2125                participant_work.token_span().immediate_tokens(),
2126            )
2127            .map_err(SubmissionWaveDispatchError::Contract)?;
2128            let bytes = restore
2129                .participant_payloads(participant_index_u32)
2130                .and_then(|payloads| payloads.get(initialization_index))
2131                .ok_or_else(|| {
2132                    SubmissionWaveDispatchError::Contract(invalid_operation(
2133                        "determinism restore payload matrix is incomplete",
2134                    ))
2135                })?;
2136            let range = restore
2137                .initialization_range(participant_index_u32, initialization_index)
2138                .ok_or_else(|| {
2139                    SubmissionWaveDispatchError::Contract(invalid_operation(
2140                        "determinism restore range matrix is incomplete",
2141                    ))
2142                })?;
2143            let backing = completion
2144                .backing_view(
2145                    location.node_id(),
2146                    participant_index_u32,
2147                    location.resource_id(),
2148                )
2149                .map_err(SubmissionWaveDispatchError::Contract)?;
2150            let encoded = encode_submission_wave_backing_upload(
2151                runtime,
2152                participant.identity(),
2153                &backing,
2154                location.usage(),
2155                location.element_type(),
2156                range.logical_offset_bytes(),
2157                bytes,
2158                "determinism restore",
2159                |command| {
2160                    commands.push_node_initialization(node_index_u32, logical_work, command);
2161                },
2162            )?;
2163            command_count = command_count.checked_add(encoded).ok_or_else(|| {
2164                SubmissionWaveDispatchError::Contract(invalid_operation(
2165                    "determinism restore command count overflows usize",
2166                ))
2167            })?;
2168        }
2169    }
2170    Ok(command_count)
2171}
2172
2173fn encode_submission_wave_inputs<R>(
2174    runtime: &R,
2175    resolved: &dyn ExecutablePlanView,
2176    batch_identity: &BatchOperationIdentity,
2177    completion: &CompletionReservation<R>,
2178    uploads: &[SubmissionWaveInputUpload],
2179    commands: &mut DeviceCommandBatch<R::Command>,
2180) -> Result<(), SubmissionWaveDispatchError<R>>
2181where
2182    R: DeviceRuntime,
2183{
2184    struct ValidatedInputUpload<'a> {
2185        upload: &'a SubmissionWaveInputUpload,
2186        participant: &'a BatchOperationParticipantIdentity,
2187        destination: std::ops::Range<u64>,
2188    }
2189
2190    let mut upload_cursor = 0_usize;
2191    while upload_cursor < uploads.len() {
2192        let first_upload = &uploads[upload_cursor];
2193        let mut run_end = upload_cursor + 1;
2194        while uploads.get(run_end).is_some_and(|upload| {
2195            upload.node_id() == first_upload.node_id()
2196                && upload.input_ordinal() == first_upload.input_ordinal()
2197        }) {
2198            run_end += 1;
2199        }
2200        let node = resolved
2201            .execution_plan()
2202            .payload()
2203            .nodes()
2204            .iter()
2205            .find(|node| node.id() == first_upload.node_id())
2206            .ok_or_else(|| {
2207                SubmissionWaveDispatchError::Contract(invalid_operation(
2208                    "submission input upload references an unknown plan node",
2209                ))
2210            })?;
2211        let identity_node_index = batch_identity
2212            .node_index(first_upload.node_id())
2213            .ok_or_else(|| {
2214                SubmissionWaveDispatchError::Contract(invalid_operation(
2215                    "submission input upload has no physical node identity",
2216                ))
2217            })?;
2218        let node_identity = batch_identity
2219            .materialize_node(identity_node_index)
2220            .map_err(SubmissionWaveDispatchError::Contract)?;
2221        let value = node
2222            .values()
2223            .iter()
2224            .find(|value| {
2225                value.role() == ResolvedValueRole::Input
2226                    && value.ordinal() == first_upload.input_ordinal()
2227            })
2228            .ok_or_else(|| {
2229                SubmissionWaveDispatchError::Contract(invalid_operation(
2230                    "submission input upload references an unknown node input",
2231                ))
2232            })?;
2233        let [component] = value.storage().components() else {
2234            return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
2235                "submission input upload requires one activation storage component",
2236            )));
2237        };
2238        let descriptor = completion
2239            .wave()
2240            .step_resources()
2241            .dynamic_descriptor(component.resource_id())
2242            .map_err(SubmissionWaveDispatchError::Contract)?;
2243        let participant_packed = descriptor.lifetime() == AllocationLifetime::Step
2244            && descriptor.kind() == &AllocationKind::Value;
2245        let prepared_work_shape = if participant_packed {
2246            Some(
2247                completion
2248                    .wave()
2249                    .nodes()
2250                    .iter()
2251                    .find(|wave_node| wave_node.node_id() == first_upload.node_id())
2252                    .ok_or_else(|| {
2253                        SubmissionWaveDispatchError::Contract(invalid_operation(
2254                            "submission input upload has no prepared wave node",
2255                        ))
2256                    })?
2257                    .work_shape(),
2258            )
2259        } else {
2260            None
2261        };
2262
2263        let mut validated = Vec::with_capacity(run_end - upload_cursor);
2264        for upload in &uploads[upload_cursor..run_end] {
2265            let participant_index = usize::try_from(upload.participant_index()).map_err(|_| {
2266                SubmissionWaveDispatchError::Contract(invalid_operation(
2267                    "submission input upload participant index exceeds host address space",
2268                ))
2269            })?;
2270            let participant = node_identity
2271                .participants()
2272                .get(participant_index)
2273                .ok_or_else(|| {
2274                    SubmissionWaveDispatchError::Contract(invalid_operation(
2275                        "submission input upload participant is absent from its plan node",
2276                    ))
2277                })?;
2278            let byte_len = upload.source_layout().byte_len().map_err(|error| {
2279                SubmissionWaveDispatchError::Contract(invalid_operation(error.to_string()))
2280            })?;
2281            let value_end = upload
2282                .logical_offset_bytes()
2283                .checked_add(byte_len)
2284                .ok_or_else(|| {
2285                    SubmissionWaveDispatchError::Contract(invalid_operation(
2286                        "submission input upload value range overflows",
2287                    ))
2288                })?;
2289            if value.usage() != BufferUsage::Activations
2290                || !matches!(value.access(), TensorAccess::Read | TensorAccess::ReadWrite)
2291                || value.tensor().element_type() != upload.source_layout().element_type()
2292                || component.element_type() != upload.source_layout().element_type()
2293                || value_end > component.length_bytes()
2294            {
2295                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
2296                    "submission input upload differs from its resolved activation binding",
2297                )));
2298            }
2299            let semantic_destination_start = component
2300                .offset_bytes()
2301                .checked_add(upload.logical_offset_bytes())
2302                .ok_or_else(|| {
2303                    SubmissionWaveDispatchError::Contract(invalid_operation(
2304                        "submission input upload destination overflows",
2305                    ))
2306                })?;
2307            let semantic_destination_end = semantic_destination_start
2308                .checked_add(byte_len)
2309                .ok_or_else(|| {
2310                    SubmissionWaveDispatchError::Contract(invalid_operation(
2311                        "submission input upload destination range overflows",
2312                    ))
2313                })?;
2314            let destination = if let Some(work_shape) = prepared_work_shape {
2315                translate_step_participant_upload_range(
2316                    descriptor.demand(),
2317                    work_shape,
2318                    participant_index,
2319                    semantic_destination_start..semantic_destination_end,
2320                )
2321                .map_err(SubmissionWaveDispatchError::Contract)?
2322            } else {
2323                semantic_destination_start..semantic_destination_end
2324            };
2325            if destination.end.checked_sub(destination.start) != Some(byte_len) {
2326                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
2327                    "submission input upload translated range differs from its source layout",
2328                )));
2329            }
2330            let backing = completion
2331                .backing_view(
2332                    upload.node_id(),
2333                    upload.participant_index(),
2334                    component.resource_id(),
2335                )
2336                .map_err(SubmissionWaveDispatchError::Contract)?;
2337            if backing.usage() != BufferUsage::Activations
2338                || backing.element_type() != upload.source_layout().element_type()
2339                || destination.end > backing.size_bytes()
2340            {
2341                return Err(SubmissionWaveDispatchError::Contract(invalid_operation(
2342                    "submission input upload backing differs from its resolved activation",
2343                )));
2344            }
2345            validated.push(ValidatedInputUpload {
2346                upload,
2347                participant,
2348                destination,
2349            });
2350        }
2351
2352        let mut validated_cursor = 0_usize;
2353        while validated_cursor < validated.len() {
2354            let mut contiguous_end = validated_cursor + 1;
2355            if participant_packed {
2356                while contiguous_end < validated.len()
2357                    && validated[contiguous_end - 1].destination.end
2358                        == validated[contiguous_end].destination.start
2359                {
2360                    contiguous_end += 1;
2361                }
2362            }
2363            let first = &validated[validated_cursor];
2364            let backing = completion
2365                .backing_view(
2366                    first.upload.node_id(),
2367                    first.upload.participant_index(),
2368                    component.resource_id(),
2369                )
2370                .map_err(SubmissionWaveDispatchError::Contract)?;
2371            if contiguous_end == validated_cursor + 1 {
2372                encode_submission_wave_backing_upload(
2373                    runtime,
2374                    first.participant.identity(),
2375                    &backing,
2376                    BufferUsage::Activations,
2377                    first.upload.source_layout().element_type(),
2378                    first.destination.start,
2379                    first.upload.bytes(),
2380                    "submission input upload",
2381                    |command| commands.push_dynamic_binding(command),
2382                )?;
2383            } else {
2384                let aggregate_byte_len = validated[validated_cursor..contiguous_end]
2385                    .iter()
2386                    .try_fold(0_usize, |total, input| {
2387                        total
2388                            .checked_add(input.upload.bytes().len())
2389                            .ok_or_else(|| {
2390                                SubmissionWaveDispatchError::Contract(invalid_operation(
2391                                    "submission input upload aggregate byte count overflows usize",
2392                                ))
2393                            })
2394                    })?;
2395                let mut aggregate_bytes = Vec::with_capacity(aggregate_byte_len);
2396                for input in &validated[validated_cursor..contiguous_end] {
2397                    aggregate_bytes.extend_from_slice(input.upload.bytes());
2398                }
2399                encode_submission_wave_backing_upload(
2400                    runtime,
2401                    first.participant.identity(),
2402                    &backing,
2403                    BufferUsage::Activations,
2404                    first.upload.source_layout().element_type(),
2405                    first.destination.start,
2406                    &aggregate_bytes,
2407                    "submission input upload aggregate",
2408                    |command| commands.push_dynamic_binding(command),
2409                )?;
2410            }
2411            validated_cursor = contiguous_end;
2412        }
2413        upload_cursor = run_end;
2414    }
2415    Ok(())
2416}