1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! The contract primitive traits (D60/D61): the API-version marker and the
//! version-local wire body.
//!
//! These are the two traits the bus client is generic over - the ABI floor every
//! contract body and api-version marker implements. The concrete versioned API
//! versions (`phoxal::api`, …) and the `phoxal_api_tree!` macro that
//! generates their `ApiVersion` / `ContractBody` impls live in the `phoxal-api`
//! crate, which re-exports these traits - so they are reachable as
//! `phoxal_api::ApiVersion` / `phoxal_api::ContractBody`. The `phoxal` engine
//! re-exports this bus crate at `phoxal::bus`, so they are also reachable as
//! `phoxal::bus::ApiVersion` / `phoxal::bus::ContractBody`.
/// Marker trait identifying one API version (D60).
///
/// Implemented only by the zero-variant `enum Api {}` that
/// [`phoxal_api_tree!`] generates inside each revision module. The [`ID`] is the
/// dotted wire revision (`"v0.1"`) and is carried in bus metadata as
/// informational provenance, never in the wire body or the topic key (D62).
///
/// [`ID`]: ApiVersion::ID
/// [`phoxal_api_tree!`]: https://docs.rs/phoxal
/// The semantic **and temporal** role a topic plays in its owning service's
/// contract.
///
/// Every topic in a [`phoxal_api_tree!`] declares one of these (D63, plan #00).
/// The role records *intent*, separate from the wire shape: a `Command` and a
/// `State` topic are both pub/sub on the wire, but the owner subscribes a
/// `Command` (it is the service's control input) and publishes a `State` (it is
/// the service's telemetry output).
///
/// The role drives two things:
///
/// - the **side branding** (L1): the api tree's builders read it to pick each
/// leaf's side-branded topic kind
/// (`Publish`/`Subscribe`/`AskQuery`/`ServeQuery`), so taking the wrong side
/// of a topic is a compile error;
/// - the **temporal capability** (#952 section D): the role decides which robot
/// time a publisher of that contract can express at all. A `State` is
/// published at a logical step, a `Measurement` carries a capture stamp, and
/// a `Command` or `Diagnostic` expresses no robot time. The generated body
/// implements exactly one of [`StateContract`] / [`MeasurementContract`] /
/// [`CommandContract`] / [`DiagnosticContract`], and each publisher handle is
/// bounded by its own marker, so reaching for the wrong publisher is a
/// compile error rather than a review question.
///
/// [`phoxal_api_tree!`]: https://docs.rs/phoxal
/// Marker for a body whose topic role is [`TopicRole::State`].
///
/// Generated by `phoxal_api_tree!`; it is the bound on
/// [`StatePublisher`](crate::handle::StatePublisher), whose only publish path
/// requires a runner- or authority-minted step token.
/// Marker for a body whose topic role is [`TopicRole::Measurement`].
///
/// Generated by `phoxal_api_tree!`; it is the bound on
/// [`MeasurementPublisher`](crate::handle::MeasurementPublisher), whose publish
/// path requires a capture stamp the driver derived from its device clock.
/// Marker for a body whose topic role is [`TopicRole::Command`].
///
/// Generated by `phoxal_api_tree!`; it is the bound on
/// [`CommandPublisher`](crate::handle::CommandPublisher), which expresses no
/// robot time at all.
/// Marker for a body whose topic role is [`TopicRole::Diagnostic`].
///
/// Generated by `phoxal_api_tree!`; it is the bound on
/// [`DiagnosticPublisher`](crate::handle::DiagnosticPublisher), which expresses
/// no robot time at all.
/// A version-local wire body: a plain serde type bound to exactly one
/// [`ApiVersion`] and one contract topic (D61/D1).
///
/// Every body declared inside a `phoxal_api_tree!` node gets a generated impl.
/// Each body carries its own [`Api`](ContractBody::Api) version marker and
/// version-qualified [`TOPIC`](ContractBody::TOPIC).
/// Participant `Api` derives record contract bodies field by field, and setup
/// builders require the requested handle body to be declared by that struct.
///
/// The serde encoding of an implementor *is* the wire payload; there is no version
/// envelope (D62).
///
/// **Wire identity is the key, not a hash (D1).** The version is folded into
/// [`TOPIC`](ContractBody::TOPIC), so `v0.1::drive::Target` and a
/// hypothetically re-minted `v0.2::drive::Target` publish on different Zenoh
/// keys and physically cannot collide. There is therefore no `SCHEMA_ID`/`FAMILY`
/// axis: two participants interoperate on a contract iff they use the exact same
/// version-qualified name, which is realized on the wire by the key.
/// A receiver's per-key Zenoh subscription is the
/// whole fast-reject; the bus decode path validates only the codec.