Skip to main content

hanzo_client/apis/
label_api.rs

1/*
2 * Hanzo Cloud API
3 *
4 * The Hanzo Cloud API as a customer calls it: every operation under /v1/ except the operator's admin product, relay routes, legacy spellings and capabilities still reached by flag. Tagged by product: the first path segment after /v1/.
5 *
6 * The version of the OpenAPI document: v1
7 * 
8 * Generated by: https://openapi-generator.tech
9 */
10
11
12use reqwest;
13use serde::{Deserialize, Serialize, de::Error as _};
14use crate::{apis::ResponseContent, models};
15use super::{Error, configuration, ContentType};
16
17
18/// struct for typed errors of method [`risk_dispose_labels`]
19#[derive(Debug, Clone, Serialize, Deserialize)]
20#[serde(untagged)]
21pub enum RiskDisposeLabelsError {
22    UnknownValue(serde_json::Value),
23}
24
25/// struct for typed errors of method [`risk_hold_labels`]
26#[derive(Debug, Clone, Serialize, Deserialize)]
27#[serde(untagged)]
28pub enum RiskHoldLabelsError {
29    UnknownValue(serde_json::Value),
30}
31
32/// struct for typed errors of method [`risk_label`]
33#[derive(Debug, Clone, Serialize, Deserialize)]
34#[serde(untagged)]
35pub enum RiskLabelError {
36    UnknownValue(serde_json::Value),
37}
38
39/// struct for typed errors of method [`risk_label_coverage`]
40#[derive(Debug, Clone, Serialize, Deserialize)]
41#[serde(untagged)]
42pub enum RiskLabelCoverageError {
43    UnknownValue(serde_json::Value),
44}
45
46/// struct for typed errors of method [`risk_label_vocabulary`]
47#[derive(Debug, Clone, Serialize, Deserialize)]
48#[serde(untagged)]
49pub enum RiskLabelVocabularyError {
50    UnknownValue(serde_json::Value),
51}
52
53/// struct for typed errors of method [`risk_labels`]
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum RiskLabelsError {
57    UnknownValue(serde_json::Value),
58}
59
60/// struct for typed errors of method [`risk_resolve_labels`]
61#[derive(Debug, Clone, Serialize, Deserialize)]
62#[serde(untagged)]
63pub enum RiskResolveLabelsError {
64    UnknownValue(serde_json::Value),
65}
66
67
68/// Applies this tenant's retention, and only this tenant's.  It is bounded three ways, each a compliance property rather than a convenience. It refuses a boundary younger than the platform floor, because a label can be the input to an adverse action and five years is what the retention ledger holds such a record for. It never touches a record under litigation hold. And it disposes of whole records rather than redacting fields.  It removes the derived columnar copy BEFORE the record, and refuses the whole disposal if the warehouse cannot be reached. The other order would leave rows in the warehouse that nothing can identify any more, which is a disposal that did not happen and says it did.
69pub async fn risk_dispose_labels(configuration: &configuration::Configuration, risk_dispose_in: models::RiskDisposeIn) -> Result<models::RiskDisposeOut, Error<RiskDisposeLabelsError>> {
70    // add a prefix to parameters to efficiently prevent name collisions
71    let p_risk_dispose_in = risk_dispose_in;
72
73    let uri_str = format!("{}/v1/label/dispose", configuration.base_path);
74    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
75
76    if let Some(ref user_agent) = configuration.user_agent {
77        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
78    }
79    if let Some(ref token) = configuration.bearer_access_token {
80        req_builder = req_builder.bearer_auth(token.to_owned());
81    };
82    req_builder = req_builder.json(&p_risk_dispose_in);
83
84    let req = req_builder.build()?;
85    let resp = configuration.client.execute(req).await?;
86
87    let status = resp.status();
88    let content_type = resp
89        .headers()
90        .get("content-type")
91        .and_then(|v| v.to_str().ok())
92        .unwrap_or("application/octet-stream");
93    let content_type = super::ContentType::from(content_type);
94
95    if !status.is_client_error() && !status.is_server_error() {
96        let content = resp.text().await?;
97        match content_type {
98            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
99            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskDisposeOut`"))),
100            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskDisposeOut`")))),
101        }
102    } else {
103        let content = resp.text().await?;
104        let entity: Option<RiskDisposeLabelsError> = serde_json::from_str(&content).ok();
105        Err(Error::ResponseError(ResponseContent { status, content, entity }))
106    }
107}
108
109/// Places or releases a litigation hold on named records.  A hold is a fact about the RECORD, not about the world: it says retention may not dispose of this row, and it asserts nothing about what happened. So it is not a field on an assertion and it is not folded into the content digest — carried there it was silently a no-op on any record that already existed, since re-filing the same assertion with a hold flag produced the same digest, the insert was ignored, and the caller was answered `duplicate` while the hold it asked for was never placed. This op is the one way a hold moves, in either direction, and the move is written to the audit log.  Every named id is this tenant's or is nothing. The statement runs against the tenant's own file, which holds no other tenant's rows and has no column that could name one.
110pub async fn risk_hold_labels(configuration: &configuration::Configuration, risk_hold_in: models::RiskHoldIn) -> Result<models::RiskHoldOut, Error<RiskHoldLabelsError>> {
111    // add a prefix to parameters to efficiently prevent name collisions
112    let p_risk_hold_in = risk_hold_in;
113
114    let uri_str = format!("{}/v1/label/hold", configuration.base_path);
115    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
116
117    if let Some(ref user_agent) = configuration.user_agent {
118        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
119    }
120    if let Some(ref token) = configuration.bearer_access_token {
121        req_builder = req_builder.bearer_auth(token.to_owned());
122    };
123    req_builder = req_builder.json(&p_risk_hold_in);
124
125    let req = req_builder.build()?;
126    let resp = configuration.client.execute(req).await?;
127
128    let status = resp.status();
129    let content_type = resp
130        .headers()
131        .get("content-type")
132        .and_then(|v| v.to_str().ok())
133        .unwrap_or("application/octet-stream");
134    let content_type = super::ContentType::from(content_type);
135
136    if !status.is_client_error() && !status.is_server_error() {
137        let content = resp.text().await?;
138        match content_type {
139            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
140            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskHoldOut`"))),
141            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskHoldOut`")))),
142        }
143    } else {
144        let content = resp.text().await?;
145        let entity: Option<RiskHoldLabelsError> = serde_json::from_str(&content).ok();
146        Err(Error::ResponseError(ResponseContent { status, content, entity }))
147    }
148}
149
150/// Records a batch of ground truth against the entities it judges.  Each assertion carries TWO times — when the judged event happened, and when the assertion became knowable — and both are required. The second is what keeps a chargeback that landed in June out of a model that had to decide in February.  It is idempotent on the CONTENT of an assertion, so a webhook that redelivers is safe. It never overwrites: a source that corrects itself later files a NEW assertion, which wins from the moment it became knowable and leaves every earlier observation instant seeing exactly what it saw.  The asserter is stamped from the validated credential and is not a body field.
151pub async fn risk_label(configuration: &configuration::Configuration, risk_label_in: models::RiskLabelIn) -> Result<models::RiskLabelOut, Error<RiskLabelError>> {
152    // add a prefix to parameters to efficiently prevent name collisions
153    let p_risk_label_in = risk_label_in;
154
155    let uri_str = format!("{}/v1/label", configuration.base_path);
156    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
157
158    if let Some(ref user_agent) = configuration.user_agent {
159        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
160    }
161    if let Some(ref token) = configuration.bearer_access_token {
162        req_builder = req_builder.bearer_auth(token.to_owned());
163    };
164    req_builder = req_builder.json(&p_risk_label_in);
165
166    let req = req_builder.build()?;
167    let resp = configuration.client.execute(req).await?;
168
169    let status = resp.status();
170    let content_type = resp
171        .headers()
172        .get("content-type")
173        .and_then(|v| v.to_str().ok())
174        .unwrap_or("application/octet-stream");
175    let content_type = super::ContentType::from(content_type);
176
177    if !status.is_client_error() && !status.is_server_error() {
178        let content = resp.text().await?;
179        match content_type {
180            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
181            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskLabelOut`"))),
182            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskLabelOut`")))),
183        }
184    } else {
185        let content = resp.text().await?;
186        let entity: Option<RiskLabelError> = serde_json::from_str(&content).ok();
187        Err(Error::ResponseError(ResponseContent { status, content, entity }))
188    }
189}
190
191/// Reports how much of a window has matured and how much of that is judged, per source.  It is the gate on training. A supervised fit over a window whose judged count is near zero produces a number, and the number is meaningless; this op is what lets that be stated before the fit rather than discovered after it.  It reads the RECORD plane and folds every assertion at that event's OWN as-of, so the counts obey exactly the leakage rule a materialisation would. It counts only what was ASSERTED: what share of the whole event STREAM carries a label is a question about the feature plane's denominator and is not answerable here.
192pub async fn risk_label_coverage(configuration: &configuration::Configuration, from: Option<&str>, to: Option<&str>, horizon: Option<i32>) -> Result<models::RiskLabelCoverage, Error<RiskLabelCoverageError>> {
193    // add a prefix to parameters to efficiently prevent name collisions
194    let p_from = from;
195    let p_to = to;
196    let p_horizon = horizon;
197
198    let uri_str = format!("{}/v1/label/coverage", configuration.base_path);
199    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
200
201    if let Some(ref param_value) = p_from {
202        req_builder = req_builder.query(&[("from", &param_value.to_string())]);
203    }
204    if let Some(ref param_value) = p_to {
205        req_builder = req_builder.query(&[("to", &param_value.to_string())]);
206    }
207    if let Some(ref param_value) = p_horizon {
208        req_builder = req_builder.query(&[("horizon", &param_value.to_string())]);
209    }
210    if let Some(ref user_agent) = configuration.user_agent {
211        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
212    }
213    if let Some(ref token) = configuration.bearer_access_token {
214        req_builder = req_builder.bearer_auth(token.to_owned());
215    };
216
217    let req = req_builder.build()?;
218    let resp = configuration.client.execute(req).await?;
219
220    let status = resp.status();
221    let content_type = resp
222        .headers()
223        .get("content-type")
224        .and_then(|v| v.to_str().ok())
225        .unwrap_or("application/octet-stream");
226    let content_type = super::ContentType::from(content_type);
227
228    if !status.is_client_error() && !status.is_server_error() {
229        let content = resp.text().await?;
230        match content_type {
231            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
232            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskLabelCoverage`"))),
233            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskLabelCoverage`")))),
234        }
235    } else {
236        let content = resp.text().await?;
237        let entity: Option<RiskLabelCoverageError> = serde_json::from_str(&content).ok();
238        Err(Error::ResponseError(ResponseContent { status, content, entity }))
239    }
240}
241
242/// Publishes the closed vocabularies and the precedence rule that resolves a conflict between two sources.  A precedence rule nobody can read is a rule nobody can audit or dispute, and the whole defensibility of a contested label rests on being able to say why one assertion beat another. The order returned here is derived from the same declaration the resolver reads — it is not a description of it.
243pub async fn risk_label_vocabulary(configuration: &configuration::Configuration, ) -> Result<models::RiskLabelVocabulary, Error<RiskLabelVocabularyError>> {
244
245    let uri_str = format!("{}/v1/label/vocabulary", configuration.base_path);
246    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
247
248    if let Some(ref user_agent) = configuration.user_agent {
249        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
250    }
251    if let Some(ref token) = configuration.bearer_access_token {
252        req_builder = req_builder.bearer_auth(token.to_owned());
253    };
254
255    let req = req_builder.build()?;
256    let resp = configuration.client.execute(req).await?;
257
258    let status = resp.status();
259    let content_type = resp
260        .headers()
261        .get("content-type")
262        .and_then(|v| v.to_str().ok())
263        .unwrap_or("application/octet-stream");
264    let content_type = super::ContentType::from(content_type);
265
266    if !status.is_client_error() && !status.is_server_error() {
267        let content = resp.text().await?;
268        match content_type {
269            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
270            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskLabelVocabulary`"))),
271            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskLabelVocabulary`")))),
272        }
273    } else {
274        let content = resp.text().await?;
275        let entity: Option<RiskLabelVocabularyError> = serde_json::from_str(&content).ok();
276        Err(Error::ResponseError(ResponseContent { status, content, entity }))
277    }
278}
279
280/// Reads the assertions this tenant has recorded, newest event first.  It reads the RECORD — the tenant's own store — and not the columnar copy, so what it returns is what would be produced in an audit. Narrow it by entity, by asserter, or by event window.
281pub async fn risk_labels(configuration: &configuration::Configuration, kind: Option<&str>, subject: Option<&str>, source: Option<&str>, from: Option<&str>, to: Option<&str>, limit: Option<i32>) -> Result<models::RiskLabelsOut, Error<RiskLabelsError>> {
282    // add a prefix to parameters to efficiently prevent name collisions
283    let p_kind = kind;
284    let p_subject = subject;
285    let p_source = source;
286    let p_from = from;
287    let p_to = to;
288    let p_limit = limit;
289
290    let uri_str = format!("{}/v1/label", configuration.base_path);
291    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
292
293    if let Some(ref param_value) = p_kind {
294        req_builder = req_builder.query(&[("kind", &param_value.to_string())]);
295    }
296    if let Some(ref param_value) = p_subject {
297        req_builder = req_builder.query(&[("subject", &param_value.to_string())]);
298    }
299    if let Some(ref param_value) = p_source {
300        req_builder = req_builder.query(&[("source", &param_value.to_string())]);
301    }
302    if let Some(ref param_value) = p_from {
303        req_builder = req_builder.query(&[("from", &param_value.to_string())]);
304    }
305    if let Some(ref param_value) = p_to {
306        req_builder = req_builder.query(&[("to", &param_value.to_string())]);
307    }
308    if let Some(ref param_value) = p_limit {
309        req_builder = req_builder.query(&[("limit", &param_value.to_string())]);
310    }
311    if let Some(ref user_agent) = configuration.user_agent {
312        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
313    }
314    if let Some(ref token) = configuration.bearer_access_token {
315        req_builder = req_builder.bearer_auth(token.to_owned());
316    };
317
318    let req = req_builder.build()?;
319    let resp = configuration.client.execute(req).await?;
320
321    let status = resp.status();
322    let content_type = resp
323        .headers()
324        .get("content-type")
325        .and_then(|v| v.to_str().ok())
326        .unwrap_or("application/octet-stream");
327    let content_type = super::ContentType::from(content_type);
328
329    if !status.is_client_error() && !status.is_server_error() {
330        let content = resp.text().await?;
331        match content_type {
332            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
333            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskLabelsOut`"))),
334            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskLabelsOut`")))),
335        }
336    } else {
337        let content = resp.text().await?;
338        let entity: Option<RiskLabelsError> = serde_json::from_str(&content).ok();
339        Err(Error::ResponseError(ResponseContent { status, content, entity }))
340    }
341}
342
343/// Answers, for each named event, which assertion was in force AS OF that event's own horizon — and what disagreed with it.  This is the join surface: the dataset materialiser calls it to attach ground truth to training rows, and the evaluator calls it to score a past decision against what was knowable when the decision had to be made. One mechanism for both, so a model can never be trained under one leakage rule and scored under another.  Three answers are distinct and all three are honest: a resolved label, an event that has not matured, and a matured event nobody has judged. The last is never reported as unproductive.
344pub async fn risk_resolve_labels(configuration: &configuration::Configuration, risk_resolve_in: models::RiskResolveIn) -> Result<models::RiskResolveOut, Error<RiskResolveLabelsError>> {
345    // add a prefix to parameters to efficiently prevent name collisions
346    let p_risk_resolve_in = risk_resolve_in;
347
348    let uri_str = format!("{}/v1/label/resolve", configuration.base_path);
349    let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
350
351    if let Some(ref user_agent) = configuration.user_agent {
352        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
353    }
354    if let Some(ref token) = configuration.bearer_access_token {
355        req_builder = req_builder.bearer_auth(token.to_owned());
356    };
357    req_builder = req_builder.json(&p_risk_resolve_in);
358
359    let req = req_builder.build()?;
360    let resp = configuration.client.execute(req).await?;
361
362    let status = resp.status();
363    let content_type = resp
364        .headers()
365        .get("content-type")
366        .and_then(|v| v.to_str().ok())
367        .unwrap_or("application/octet-stream");
368    let content_type = super::ContentType::from(content_type);
369
370    if !status.is_client_error() && !status.is_server_error() {
371        let content = resp.text().await?;
372        match content_type {
373            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
374            ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::RiskResolveOut`"))),
375            ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RiskResolveOut`")))),
376        }
377    } else {
378        let content = resp.text().await?;
379        let entity: Option<RiskResolveLabelsError> = serde_json::from_str(&content).ok();
380        Err(Error::ResponseError(ResponseContent { status, content, entity }))
381    }
382}
383