Skip to main content

bb_compiler/
validate_runtime_complete.rs

1//! Final structural completeness check.
2//!
3//! Walks each per-partition installed graph and asserts every wire
4//! op is paired with the gate chain the engine expects and every
5//! async op carries a `DeadlineCheck`. Catches missing
6//! compiler-inserted ops before the graph reaches `Node::ensure_ready`.
7
8use bb_ir::proto::onnx::GraphProto;
9
10use crate::error::CompileError;
11use crate::partition_by_wire_ops::WIRE_DOMAIN;
12
13const SYSCALL_DOMAIN: &str = "ai.bytesandbrains.syscall";
14const SEND_OP: &str = "Send";
15const RECV_OP: &str = "Recv";
16
17const PEER_HEALTH_GATE_TX_OP: &str = "PeerHealthGateTx";
18const BACKOFF_GATE_TX_OP: &str = "BackoffGateTx";
19const DEDUP_GATE_RX_OP: &str = "DedupGateRx";
20const PEER_HEALTH_GATE_RX_OP: &str = "PeerHealthGateRx";
21const BACKOFF_GATE_RX_OP: &str = "BackoffGateRx";
22const DEADLINE_CHECK_OP: &str = "DeadlineCheck";
23
24const DEADLINE_NS_ATTR: &str = "deadline_ns";
25
26const PEER_ATTR: &str = "peer";
27
28/// Validate that every compiler-required gate / lifecycle op is
29/// present alongside the ops it serves. Returns `Ok(())` on success,
30/// `Err` describing the first missing piece otherwise.
31///
32/// Sends/Recvs that carry an explicit `peer` attribute (peer-specific
33/// routing) are gated by the canonical TX/RX gate chains. Sends/Recvs
34/// without `peer` route via the runtime address book using
35/// `dest_target` metadata and do not require the per-peer gates.
36pub fn validate_runtime_complete(sub_graph: &GraphProto) -> Result<(), CompileError> {
37    let nodes = &sub_graph.node;
38    let has_op = |op_type: &str, domain: &str| -> bool {
39        nodes
40            .iter()
41            .any(|n| n.op_type == op_type && n.domain == domain)
42    };
43
44    // Peer-routed Sends need the TX gate chain.
45    let has_peer_send = nodes.iter().any(|n| {
46        n.domain == WIRE_DOMAIN
47            && n.op_type == SEND_OP
48            && n.attribute.iter().any(|a| a.name == PEER_ATTR)
49    });
50    if has_peer_send {
51        if !has_op(PEER_HEALTH_GATE_TX_OP, SYSCALL_DOMAIN) {
52            return Err(CompileError::Internal {
53                detail: format!(
54                    "validate_runtime_complete: partition `{}` has a peer-routed wire.Send but no PeerHealthGateTx",
55                    sub_graph.name,
56                ),
57            });
58        }
59        if !has_op(BACKOFF_GATE_TX_OP, SYSCALL_DOMAIN) {
60            return Err(CompileError::Internal {
61                detail: format!(
62                    "validate_runtime_complete: partition `{}` has a peer-routed wire.Send but no BackoffGateTx",
63                    sub_graph.name,
64                ),
65            });
66        }
67    }
68
69    // Peer-routed Recvs need the RX gate chain.
70    let has_peer_recv = nodes.iter().any(|n| {
71        n.domain == WIRE_DOMAIN
72            && n.op_type == RECV_OP
73            && n.attribute.iter().any(|a| a.name == PEER_ATTR)
74    });
75    if has_peer_recv {
76        if !has_op(DEDUP_GATE_RX_OP, SYSCALL_DOMAIN) {
77            return Err(CompileError::Internal {
78                detail: format!(
79                    "validate_runtime_complete: partition `{}` has a peer-routed wire.Recv but no DedupGateRx",
80                    sub_graph.name,
81                ),
82            });
83        }
84        if !has_op(PEER_HEALTH_GATE_RX_OP, SYSCALL_DOMAIN) {
85            return Err(CompileError::Internal {
86                detail: format!(
87                    "validate_runtime_complete: partition `{}` has a peer-routed wire.Recv but no PeerHealthGateRx",
88                    sub_graph.name,
89                ),
90            });
91        }
92        if !has_op(BACKOFF_GATE_RX_OP, SYSCALL_DOMAIN) {
93            return Err(CompileError::Internal {
94                detail: format!(
95                    "validate_runtime_complete: partition `{}` has a peer-routed wire.Recv but no BackoffGateRx",
96                    sub_graph.name,
97                ),
98            });
99        }
100    }
101
102    // Every NodeProto carrying `deadline_ns` needs DeadlineCheck.
103    let any_deadline = nodes
104        .iter()
105        .any(|n| n.attribute.iter().any(|a| a.name == DEADLINE_NS_ATTR));
106    if any_deadline && !has_op(DEADLINE_CHECK_OP, SYSCALL_DOMAIN) {
107        return Err(CompileError::Internal {
108            detail: format!(
109                "validate_runtime_complete: partition `{}` carries deadline_ns but no DeadlineCheck",
110                sub_graph.name,
111            ),
112        });
113    }
114
115    // Each gate-insertion pass publishes a `GateContract` via
116    // inventory; iterating them means adding a new gate is "ship
117    // the inserting pass + register its contract" without editing
118    // this validator. Failures surface as
119    // `CompileError::RuntimeIncomplete { missing }`.
120    for reg in crate::gate_contract::contracts() {
121        reg.contract.assert_inserted(sub_graph)?;
122    }
123
124    Ok(())
125}
126