fix: preserve notification uncertainty and target provenance
This commit is contained in:
@@ -33,6 +33,16 @@ pub enum NotificationDiagnosticStage {
|
|||||||
RuntimeAccepted,
|
RuntimeAccepted,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum NotificationTargetResolution {
|
||||||
|
Unresolved,
|
||||||
|
Reserved,
|
||||||
|
RequestPersisted,
|
||||||
|
RuntimeAccepted,
|
||||||
|
MultipleAuthorizedTargets,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct NotificationDiagnostic {
|
pub struct NotificationDiagnostic {
|
||||||
@@ -51,6 +61,11 @@ pub struct NotificationDiagnostic {
|
|||||||
pub purpose: Option<String>,
|
pub purpose: Option<String>,
|
||||||
pub delivery_id: Option<String>,
|
pub delivery_id: Option<String>,
|
||||||
pub stage: NotificationDiagnosticStage,
|
pub stage: NotificationDiagnosticStage,
|
||||||
|
/// Conservative: a persisted request without ACK is enough; this does not prove a send occurred.
|
||||||
|
/// Can remain true alongside a later preflight failure, rejection or historical recipient.
|
||||||
|
pub acceptance_outcome_unknown: bool,
|
||||||
|
/// Failure records do not identify a particular authorized replacement target.
|
||||||
|
pub target_resolution: NotificationTargetResolution,
|
||||||
pub target_runtime_id: Option<String>,
|
pub target_runtime_id: Option<String>,
|
||||||
pub target_worker_id: Option<String>,
|
pub target_worker_id: Option<String>,
|
||||||
pub last_failure_code: Option<String>,
|
pub last_failure_code: Option<String>,
|
||||||
|
|||||||
@@ -1,4 +1,51 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn notification_wip_executes_same_read_and_honors_profile_denial() {
|
||||||
|
for denied in [false, true] {
|
||||||
|
let client = Arc::new(Client {
|
||||||
|
requests: Mutex::new(vec![]),
|
||||||
|
status: 200,
|
||||||
|
body: json!({"items":[],"next_cursor":null,"source_checks":[]}).to_string(),
|
||||||
|
});
|
||||||
|
let tools = native_ticket_tools(client.clone(), TicketFeatureAccess::read_only()).unwrap();
|
||||||
|
let handler = TicketCollectionWipHandler {
|
||||||
|
tools: operation_map(
|
||||||
|
tools
|
||||||
|
.into_iter()
|
||||||
|
.filter(|t| t.projection.surface == NativeTicketSurface::Collection)
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
permissions: denied.then_some(ToolPermissionConfig {
|
||||||
|
default_action: ToolPermissionAction::Deny,
|
||||||
|
rules: vec![],
|
||||||
|
}),
|
||||||
|
collection_route: "/tickets".into(),
|
||||||
|
observations: Arc::new(Mutex::new(TicketObservationState::default())),
|
||||||
|
};
|
||||||
|
let args = BTreeMap::from([("ticket".into(), WipValue::String("T-755".into()))]);
|
||||||
|
let result = handler
|
||||||
|
.call(
|
||||||
|
"notification_diagnostics",
|
||||||
|
&args,
|
||||||
|
WipCallContext {
|
||||||
|
execution: ToolExecutionContext::direct(),
|
||||||
|
security_context: "worker".into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert_eq!(result.is_err(), denied);
|
||||||
|
let requests = client.requests.lock().unwrap();
|
||||||
|
assert_eq!(requests.len(), usize::from(!denied));
|
||||||
|
if !denied {
|
||||||
|
assert_eq!(requests[0].method, WorkspaceRequestMethod::Get);
|
||||||
|
assert_eq!(
|
||||||
|
requests[0].path,
|
||||||
|
"/api/w/workspace/notification-diagnostics?ticket=T-755"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
use crate::worker::{WorkspaceClientError, WorkspaceRequest, WorkspaceResponse};
|
use crate::worker::{WorkspaceClientError, WorkspaceRequest, WorkspaceResponse};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Client {
|
struct Client {
|
||||||
@@ -32,15 +79,23 @@ async fn notification_tool_and_wip_share_bounded_read_contract() {
|
|||||||
let client = Arc::new(Client {
|
let client = Arc::new(Client {
|
||||||
requests: Mutex::new(vec![]),
|
requests: Mutex::new(vec![]),
|
||||||
status: 200,
|
status: 200,
|
||||||
body: json!({"items":[],"next_cursor":null,"source_checks":[]}).to_string(),
|
body: json!({"items":[{"source_id":"notification-source:5","source_event_id":"mr-event:m:e","event_kind":"mr_review","recipient_role":"orchestrator","stage":"acceptance_unknown","acceptance_outcome_unknown":true,"target_resolution":"multiple_authorized_targets","retry_candidate":true,"model_processing_confirmed":false}],"next_cursor":null,"source_checks":[]}).to_string(),
|
||||||
});
|
});
|
||||||
let (meta, tool) = definition(client.clone())();
|
let (meta, tool) = definition(client.clone())();
|
||||||
let schema = jsonschema::validator_for(&meta.input_schema).unwrap();
|
let schema = jsonschema::validator_for(&meta.input_schema).unwrap();
|
||||||
let input = json!({"ticket":"T-755","merge_request_id":"mr/1?","job_id":"job","cursor":"notification-source:4","limit":10});
|
let input = json!({"ticket":"T-755","merge_request_id":"mr/1?","job_id":"job","cursor":"notification-source:4","limit":10});
|
||||||
assert!(schema.is_valid(&input));
|
assert!(schema.is_valid(&input));
|
||||||
tool.execute(&input.to_string(), ToolExecutionContext::direct())
|
let output = tool
|
||||||
|
.execute(&input.to_string(), ToolExecutionContext::direct())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let page: Value = serde_json::from_str(output.content.as_deref().unwrap()).unwrap();
|
||||||
|
assert_eq!(page["items"][0]["acceptance_outcome_unknown"], true);
|
||||||
|
assert_eq!(
|
||||||
|
page["items"][0]["target_resolution"],
|
||||||
|
"multiple_authorized_targets"
|
||||||
|
);
|
||||||
|
assert!(page["items"][0]["target_worker_id"].is_null());
|
||||||
let requests = client.requests.lock().unwrap();
|
let requests = client.requests.lock().unwrap();
|
||||||
assert_eq!(requests.len(), 1);
|
assert_eq!(requests.len(), 1);
|
||||||
assert_eq!(requests[0].method, WorkspaceRequestMethod::Get);
|
assert_eq!(requests[0].method, WorkspaceRequestMethod::Get);
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ fn source_checks(
|
|||||||
.and_then(|v| v.parse::<i64>().ok()),
|
.and_then(|v| v.parse::<i64>().ok()),
|
||||||
) {
|
) {
|
||||||
Some(conn.query_row("SELECT EXISTS(SELECT 1 FROM typed_ticket_events e LEFT JOIN workspace_resource_keys k ON k.workspace_id=e.workspace_id AND k.resource_kind='ticket' AND k.resource_id=e.ticket_id WHERE e.workspace_id=?1 AND (e.ticket_id=?2 OR k.resource_key=?2) AND e.event_index=?3)",params![workspace,ticket,index],|r|r.get(0))?)
|
Some(conn.query_row("SELECT EXISTS(SELECT 1 FROM typed_ticket_events e LEFT JOIN workspace_resource_keys k ON k.workspace_id=e.workspace_id AND k.resource_kind='ticket' AND k.resource_id=e.ticket_id WHERE e.workspace_id=?1 AND (e.ticket_id=?2 OR k.resource_key=?2) AND e.event_index=?3)",params![workspace,ticket,index],|r|r.get(0))?)
|
||||||
|
} else if let Some((mr, event)) =
|
||||||
|
id.strip_prefix("mr-event:").and_then(|v| v.split_once(':'))
|
||||||
|
{
|
||||||
|
Some(conn.query_row("SELECT EXISTS(SELECT 1 FROM merge_request_thread_events WHERE workspace_id=?1 AND merge_request_id=?2 AND event_id=?3)",params![workspace,mr,event],|r|r.get(0))?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -157,7 +161,9 @@ pub(super) fn page_with_connection(
|
|||||||
COALESCE(json_extract(a.target_json,'$.worker.runtime_id'),json_extract(aa.source_json,'$.runtime_id'),json_extract(r.target_json,'$.worker.runtime_id'),json_extract(ar.reserved_source_json,'$.runtime_id')),
|
COALESCE(json_extract(a.target_json,'$.worker.runtime_id'),json_extract(aa.source_json,'$.runtime_id'),json_extract(r.target_json,'$.worker.runtime_id'),json_extract(ar.reserved_source_json,'$.runtime_id')),
|
||||||
COALESCE(json_extract(a.target_json,'$.worker.worker_id'),json_extract(aa.source_json,'$.worker_id'),json_extract(r.target_json,'$.worker.worker_id'),json_extract(ar.reserved_source_json,'$.worker_id')),
|
COALESCE(json_extract(a.target_json,'$.worker.worker_id'),json_extract(aa.source_json,'$.worker_id'),json_extract(r.target_json,'$.worker.worker_id'),json_extract(ar.reserved_source_json,'$.worker_id')),
|
||||||
f.code,f.recorded_at,
|
f.code,f.recorded_at,
|
||||||
CASE WHEN s.role IN ('orchestrator','worker') AND s.assignment_id!='' THEN EXISTS(SELECT 1 FROM ticket_current_worker_assignments c WHERE c.workspace_id=s.workspace_id AND c.ticket_id=s.ticket_id AND c.role=s.role AND c.assignment_id=s.assignment_id) END
|
CASE WHEN s.role IN ('orchestrator','worker') AND s.assignment_id!='' THEN EXISTS(SELECT 1 FROM ticket_current_worker_assignments c WHERE c.workspace_id=s.workspace_id AND c.ticket_id=s.ticket_id AND c.role=s.role AND c.assignment_id=s.assignment_id) END,
|
||||||
|
EXISTS(SELECT 1 FROM notification_failures uf WHERE uf.workspace_id=s.workspace_id AND uf.delivery_id=d.delivery_id AND uf.code IN ('acceptance_unknown','acknowledgement_failed')),
|
||||||
|
(SELECT COUNT(*) FROM (SELECT DISTINCT at.runtime_id,at.worker_id FROM notification_assignment_targets at WHERE at.workspace_id=s.workspace_id AND at.delivery_id=d.delivery_id))
|
||||||
{joins}
|
{joins}
|
||||||
LEFT JOIN notification_requests r ON r.workspace_id=s.workspace_id AND r.delivery_id=d.delivery_id
|
LEFT JOIN notification_requests r ON r.workspace_id=s.workspace_id AND r.delivery_id=d.delivery_id
|
||||||
LEFT JOIN notification_acknowledgements a ON a.workspace_id=s.workspace_id AND a.delivery_id=d.delivery_id
|
LEFT JOIN notification_acknowledgements a ON a.workspace_id=s.workspace_id AND a.delivery_id=d.delivery_id
|
||||||
@@ -176,6 +182,31 @@ pub(super) fn page_with_connection(
|
|||||||
let accepted: bool = row.get(14)?;
|
let accepted: bool = row.get(14)?;
|
||||||
let failure: Option<String> = row.get(17)?;
|
let failure: Option<String> = row.get(17)?;
|
||||||
let recipient_current: Option<bool> = row.get(19)?;
|
let recipient_current: Option<bool> = row.get(19)?;
|
||||||
|
let unresolved_send: bool = row.get(20)?;
|
||||||
|
let multiple_targets = row.get::<_, i64>(21)? > 1;
|
||||||
|
let acceptance_outcome_unknown = !accepted && (prepared || unresolved_send);
|
||||||
|
use server_api::NotificationTargetResolution as Target;
|
||||||
|
let target_resolution = if accepted {
|
||||||
|
Target::RuntimeAccepted
|
||||||
|
} else if multiple_targets {
|
||||||
|
Target::MultipleAuthorizedTargets
|
||||||
|
} else if prepared {
|
||||||
|
Target::RequestPersisted
|
||||||
|
} else if reserved {
|
||||||
|
Target::Reserved
|
||||||
|
} else {
|
||||||
|
Target::Unresolved
|
||||||
|
};
|
||||||
|
let target_runtime_id = if multiple_targets && !accepted {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
bounded(row.get(15)?)
|
||||||
|
};
|
||||||
|
let target_worker_id = if multiple_targets && !accepted {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
bounded(row.get(16)?)
|
||||||
|
};
|
||||||
let stage = if accepted {
|
let stage = if accepted {
|
||||||
Stage::RuntimeAccepted
|
Stage::RuntimeAccepted
|
||||||
} else if recipient_current == Some(false) {
|
} else if recipient_current == Some(false) {
|
||||||
@@ -186,7 +217,7 @@ pub(super) fn page_with_connection(
|
|||||||
Stage::Suppressed
|
Stage::Suppressed
|
||||||
} else if disposition.as_deref() == Some("defer") {
|
} else if disposition.as_deref() == Some("defer") {
|
||||||
Stage::Deferred
|
Stage::Deferred
|
||||||
} else if failure.as_deref() == Some("acceptance_unknown") {
|
} else if unresolved_send {
|
||||||
Stage::AcceptanceUnknown
|
Stage::AcceptanceUnknown
|
||||||
} else if failure.as_deref() == Some("runtime_rejected") {
|
} else if failure.as_deref() == Some("runtime_rejected") {
|
||||||
Stage::RuntimeRejected
|
Stage::RuntimeRejected
|
||||||
@@ -218,8 +249,10 @@ pub(super) fn page_with_connection(
|
|||||||
purpose: bounded(row.get(10)?),
|
purpose: bounded(row.get(10)?),
|
||||||
delivery_id: bounded(row.get(11)?),
|
delivery_id: bounded(row.get(11)?),
|
||||||
stage,
|
stage,
|
||||||
target_runtime_id: bounded(row.get(15)?),
|
acceptance_outcome_unknown,
|
||||||
target_worker_id: bounded(row.get(16)?),
|
target_resolution,
|
||||||
|
target_runtime_id,
|
||||||
|
target_worker_id,
|
||||||
last_failure_code: bounded(failure),
|
last_failure_code: bounded(failure),
|
||||||
last_failure_at: bounded(row.get(18)?),
|
last_failure_at: bounded(row.get(18)?),
|
||||||
retry_candidate,
|
retry_candidate,
|
||||||
|
|||||||
@@ -1,5 +1,55 @@
|
|||||||
// Production Store and SQLite. No Runtime/model side effects are required for diagnostics.
|
// Production Store and SQLite. No Runtime/model side effects are required for diagnostics.
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
async fn notification_diagnostics_preserves_unknown_acceptance_and_marks_replacement_ambiguity() {
|
||||||
|
use server_api::{NotificationDiagnosticsQuery as Q,NotificationDiagnosticStage as S,NotificationTargetResolution as T};
|
||||||
|
for initial_failure in [NotificationFailureCode::AcceptanceUnknown,NotificationFailureCode::AcknowledgementFailed] {
|
||||||
|
let (_dir,store)=tracking_store_fixture().await;
|
||||||
|
tracking_store_assign(&store,"a","assign-a");
|
||||||
|
let source=tracking_store_source();
|
||||||
|
let delivery=delivery_store_reserve_initial(&store,&source);
|
||||||
|
store.prepare_ticket_assignment_delivery_content("w",&delivery.delivery_id,"frozen body",&source).unwrap();
|
||||||
|
let key=NotificationDeliveryKey::AssignmentInput{assignment_id:"a".into(),input_event_id:delivery.input_event_id.clone()};
|
||||||
|
store.record_notification_delivery_failure("w",&key,initial_failure).unwrap();
|
||||||
|
store.record_notification_delivery_failure("w",&key,NotificationFailureCode::TargetStopped).unwrap();
|
||||||
|
let query=Q{delivery_id:Some(delivery.delivery_id.clone()),..Default::default()};
|
||||||
|
let read=||store.notification_diagnostics("w",&query).unwrap().items.remove(0);
|
||||||
|
assert_eq!(read().stage,S::AcceptanceUnknown);
|
||||||
|
assert!(read().acceptance_outcome_unknown);
|
||||||
|
assert_eq!(read().last_failure_code.as_deref(),Some("target_stopped"));
|
||||||
|
store.with_conn(|conn|{conn.execute("UPDATE worker_singleton_owners SET worker_id='replacement' WHERE workspace_id='w'",[])?;Ok(())}).unwrap();
|
||||||
|
let replacement=TicketAssignmentTrackingSourceContext{worker_id:"replacement".into(),..source};
|
||||||
|
store.prepare_ticket_assignment_delivery_content("w",&delivery.delivery_id,"ignored new body",&replacement).unwrap();
|
||||||
|
let ambiguous=read();
|
||||||
|
assert_eq!(ambiguous.target_resolution,T::MultipleAuthorizedTargets);
|
||||||
|
assert!(ambiguous.target_runtime_id.is_none() && ambiguous.target_worker_id.is_none());
|
||||||
|
store.ack_ticket_assignment_delivery("w",&delivery.delivery_id,&replacement).unwrap();
|
||||||
|
let accepted=read();
|
||||||
|
assert_eq!(accepted.target_resolution,T::RuntimeAccepted);
|
||||||
|
assert_eq!(accepted.target_worker_id.as_deref(),Some("replacement"));
|
||||||
|
assert!(!accepted.acceptance_outcome_unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn notification_diagnostics_detects_exact_missing_mr_event_after_earlier_capture() {
|
||||||
|
use server_api::NotificationDiagnosticsQuery as Q;
|
||||||
|
let (_dir,store)=tracking_store_fixture().await;
|
||||||
|
tracking_store_assign(&store,"a","assign-a");
|
||||||
|
store.with_conn(|conn| {
|
||||||
|
conn.execute("INSERT INTO merge_requests(workspace_id,merge_request_id,repository_id,state,selector_to,created_at,updated_at) SELECT workspace_id,'mr-diagnostic',repository_id,'open','develop','1','1' FROM repositories WHERE workspace_id='w' LIMIT 1",[])?;
|
||||||
|
for (event,seq) in [("first",1),("missing",2)] {
|
||||||
|
conn.execute("INSERT INTO merge_request_thread_events(workspace_id,merge_request_id,event_id,sequence,kind,payload_json,created_at) VALUES('w','mr-diagnostic',?1,?2,'review','{}','1')",params![event,seq])?;
|
||||||
|
}
|
||||||
|
conn.execute("INSERT INTO notification_sources(workspace_id,ticket_id,input_event_id,role,assignment_id,kind,facts_json) SELECT workspace_id,ticket_id,'mr-event:mr-diagnostic:first',role,assignment_id,'mr_review',json_set(facts_json,'$.merge_request_id','mr-diagnostic') FROM notification_sources WHERE assignment_id='a' LIMIT 1",[])?;
|
||||||
|
Ok(())
|
||||||
|
}).unwrap();
|
||||||
|
let page=store.notification_diagnostics("w",&Q{merge_request_id:Some("mr-diagnostic".into()),source_event_id:Some("mr-event:mr-diagnostic:missing".into()),..Default::default()}).unwrap();
|
||||||
|
assert!(page.items.is_empty());
|
||||||
|
assert!(page.source_checks[0].captured);
|
||||||
|
assert_eq!(page.source_checks[1].origin_present,Some(true));
|
||||||
|
assert!(!page.source_checks[1].captured);
|
||||||
|
}
|
||||||
|
#[tokio::test]
|
||||||
async fn notification_diagnostics_bounds_saved_reasons_without_returning_source_payloads() {
|
async fn notification_diagnostics_bounds_saved_reasons_without_returning_source_payloads() {
|
||||||
use server_api::NotificationDiagnosticsQuery as Q;
|
use server_api::NotificationDiagnosticsQuery as Q;
|
||||||
let (_dir,store)=tracking_store_fixture().await;
|
let (_dir,store)=tracking_store_fixture().await;
|
||||||
|
|||||||
+21
-1
@@ -5635,6 +5635,10 @@
|
|||||||
"NotificationDiagnostic": {
|
"NotificationDiagnostic": {
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"acceptance_outcome_unknown": {
|
||||||
|
"description": "Conservative: a persisted request without ACK is enough; this does not prove a send occurred.\nCan remain true alongside a later preflight failure, rejection or historical recipient.",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"assignment_id": {
|
"assignment_id": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -5719,6 +5723,10 @@
|
|||||||
"stage": {
|
"stage": {
|
||||||
"$ref": "#/components/schemas/NotificationDiagnosticStage"
|
"$ref": "#/components/schemas/NotificationDiagnosticStage"
|
||||||
},
|
},
|
||||||
|
"target_resolution": {
|
||||||
|
"$ref": "#/components/schemas/NotificationTargetResolution",
|
||||||
|
"description": "Failure records do not identify a particular authorized replacement target."
|
||||||
|
},
|
||||||
"target_runtime_id": {
|
"target_runtime_id": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -5744,6 +5752,8 @@
|
|||||||
"event_kind",
|
"event_kind",
|
||||||
"recipient_role",
|
"recipient_role",
|
||||||
"stage",
|
"stage",
|
||||||
|
"acceptance_outcome_unknown",
|
||||||
|
"target_resolution",
|
||||||
"retry_candidate",
|
"retry_candidate",
|
||||||
"model_processing_confirmed"
|
"model_processing_confirmed"
|
||||||
],
|
],
|
||||||
@@ -5884,6 +5894,16 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
|
"NotificationTargetResolution": {
|
||||||
|
"enum": [
|
||||||
|
"unresolved",
|
||||||
|
"reserved",
|
||||||
|
"request_persisted",
|
||||||
|
"runtime_accepted",
|
||||||
|
"multiple_authorized_targets"
|
||||||
|
],
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"Nullable_string": {
|
"Nullable_string": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -17487,7 +17507,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"title": "Yoi Server API",
|
"title": "Yoi Server API",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"x-yoi-source-digest": "sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04"
|
"x-yoi-source-digest": "sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3"
|
||||||
},
|
},
|
||||||
"openapi": "3.1.0",
|
"openapi": "3.1.0",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
|
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04)
|
// Input contract: 0.1.0 (sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3)
|
||||||
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/companion-api.ts
|
// Output: web/workspace/src/lib/generated/companion-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04)
|
// Input contract: 0.1.0 (sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3)
|
||||||
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/repository-api.ts
|
// Output: web/workspace/src/lib/generated/repository-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
|
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04)
|
// Input contract: 0.1.0 (sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3)
|
||||||
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/runtime-api.ts
|
// Output: web/workspace/src/lib/generated/runtime-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
|
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04)
|
// Input contract: 0.1.0 (sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3)
|
||||||
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/ticket-api.ts
|
// Output: web/workspace/src/lib/generated/ticket-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
|
||||||
@@ -61,7 +61,7 @@ export type MergeStrategy = "fast_forward" | "merge";
|
|||||||
|
|
||||||
export type NewTicket = { assignee?: string | null; author?: string | null; body: MarkdownText; kind: string; labels: Array<string>; priority: string; queued_at?: string | null; queued_by?: string | null; readiness?: string | null; risk_flags: Array<string>; slug?: string | null; targets?: Array<TicketTarget>; title: string; workflow_state?: TicketState | null; };
|
export type NewTicket = { assignee?: string | null; author?: string | null; body: MarkdownText; kind: string; labels: Array<string>; priority: string; queued_at?: string | null; queued_by?: string | null; readiness?: string | null; risk_flags: Array<string>; slug?: string | null; targets?: Array<TicketTarget>; title: string; workflow_state?: TicketState | null; };
|
||||||
|
|
||||||
export type NotificationDiagnostic = { assignment_id?: string | null; delivery_id?: string | null; disposition?: string | null; event_kind: string; job_id?: string | null; last_failure_at?: string | null; last_failure_code?: string | null; merge_request_id?: string | null; model_processing_confirmed: boolean; purpose?: string | null; reason?: string | null; recipient_current?: boolean | null; recipient_role: string; retry_candidate: boolean; source_event_id: string; source_id: string; stage: NotificationDiagnosticStage; target_runtime_id?: string | null; target_worker_id?: string | null; ticket?: string | null; };
|
export type NotificationDiagnostic = { acceptance_outcome_unknown: boolean; assignment_id?: string | null; delivery_id?: string | null; disposition?: string | null; event_kind: string; job_id?: string | null; last_failure_at?: string | null; last_failure_code?: string | null; merge_request_id?: string | null; model_processing_confirmed: boolean; purpose?: string | null; reason?: string | null; recipient_current?: boolean | null; recipient_role: string; retry_candidate: boolean; source_event_id: string; source_id: string; stage: NotificationDiagnosticStage; target_resolution: NotificationTargetResolution; target_runtime_id?: string | null; target_worker_id?: string | null; ticket?: string | null; };
|
||||||
|
|
||||||
export type NotificationDiagnosticStage = "historical" | "awaiting_routing" | "suppressed" | "deferred" | "pending" | "reserved" | "request_persisted" | "runtime_rejected" | "acceptance_unknown" | "delivery_failed" | "runtime_accepted";
|
export type NotificationDiagnosticStage = "historical" | "awaiting_routing" | "suppressed" | "deferred" | "pending" | "reserved" | "request_persisted" | "runtime_rejected" | "acceptance_unknown" | "delivery_failed" | "runtime_accepted";
|
||||||
|
|
||||||
@@ -69,6 +69,8 @@ export type NotificationDiagnosticsPage = { items: Array<NotificationDiagnostic>
|
|||||||
|
|
||||||
export type NotificationSourceCheck = { captured: boolean; origin_present?: boolean | null; reference: string; resource_kind: string; };
|
export type NotificationSourceCheck = { captured: boolean; origin_present?: boolean | null; reference: string; resource_kind: string; };
|
||||||
|
|
||||||
|
export type NotificationTargetResolution = "unresolved" | "reserved" | "request_persisted" | "runtime_accepted" | "multiple_authorized_targets";
|
||||||
|
|
||||||
export type ObjectiveDetail = { body: string; body_truncated: boolean; created_at?: string | null; event_page: QueryPage; events: Array<ObjectiveEventDetail>; id: string; linked_ticket_summaries: Array<ObjectiveLinkedTicketSummary>; linked_tickets: Array<string>; record_source: string; resource_key: string; resources: Array<ObjectiveResourceSummary>; state: string; title: string; updated_at?: string | null; };
|
export type ObjectiveDetail = { body: string; body_truncated: boolean; created_at?: string | null; event_page: QueryPage; events: Array<ObjectiveEventDetail>; id: string; linked_ticket_summaries: Array<ObjectiveLinkedTicketSummary>; linked_tickets: Array<string>; record_source: string; resource_key: string; resources: Array<ObjectiveResourceSummary>; state: string; title: string; updated_at?: string | null; };
|
||||||
|
|
||||||
export type ObjectiveEventDetail = { body?: string | null; created_at: string; event_ref: string; kind: string; };
|
export type ObjectiveEventDetail = { body?: string | null; created_at: string; event_ref: string; kind: string; };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
|
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
|
||||||
// Input: openapi/server-api.json
|
// Input: openapi/server-api.json
|
||||||
// Input contract: 0.1.0 (sha256:ba0b73fac609dc65712a95c3b96f1044b16f82a5775f591813c02e8f392b5a04)
|
// Input contract: 0.1.0 (sha256:d3f51c6f6b7091ca393c9d197309e280a18357889e9e6df69bbdfcaeb13d0cc3)
|
||||||
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
|
||||||
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
|
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
|
||||||
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
|
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check
|
||||||
|
|||||||
Reference in New Issue
Block a user