diff --git a/AGENTS.md b/AGENTS.md index e6b9f51d..496242a9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -138,9 +138,6 @@ Swarm-level: with **no identity** and a TLS failure that names no cause. - **`swarm-queue-client/`** — the one authenticated connect to the swarm NATS queue. -- **`swarm-wire/`** — serde-only request and reply contracts services - exchange over the queue (builder, claude login), so naming one links - neither the queue client nor the store client. - **`swarm-nats-auth/`** — NATS auth-callout responder; without it the queue is fail-closed and admits nobody. - **`swarm-agent-verify/`** — checks a `swarm-agent..` diff --git a/Cargo.lock b/Cargo.lock index b6674478..8ecce245 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4811,7 +4811,6 @@ dependencies = [ "serde_json", "swarm-queue-client", "swarm-secret-client", - "swarm-wire", "tokio", "tracing", ] @@ -4847,7 +4846,6 @@ dependencies = [ "serde_json", "swarm-queue-client", "swarm-secret-client", - "swarm-wire", "tokio", "tracing", ] @@ -4891,7 +4889,6 @@ dependencies = [ "swarm-matrix-client", "swarm-queue-client", "swarm-secret-client", - "swarm-wire", "tempfile", "tokio", "tower", @@ -5013,7 +5010,6 @@ dependencies = [ "swarm-agent-verify", "swarm-queue-client", "swarm-secret-client", - "swarm-wire", "tokio", "tracing", "tracing-subscriber", @@ -5080,14 +5076,6 @@ dependencies = [ "vaultrs", ] -[[package]] -name = "swarm-wire" -version = "0.1.0" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "swarmctl" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index a1f718b8..ed69dd19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ members = [ "swarm-logs-auth", "swarm-metrics-auth", "swarm-secret-client", - "swarm-wire", "swarmctl", ] @@ -119,7 +118,6 @@ swarm-controller-api = { path = "swarm-controller-api" } swarm-matrix-client = { path = "swarm-matrix-client" } swarm-queue-client = { path = "swarm-queue-client" } swarm-secret-client = { path = "swarm-secret-client" } -swarm-wire = { path = "swarm-wire" } thiserror = "2" vaultrs = "0.8" # vaultrs's transport crates. Direct dependencies because one endpoint is diff --git a/swarm-builder/Cargo.toml b/swarm-builder/Cargo.toml index bbb5d424..4275fee9 100644 --- a/swarm-builder/Cargo.toml +++ b/swarm-builder/Cargo.toml @@ -15,11 +15,10 @@ async-nats.workspace = true futures-util.workspace = true hive-log.workspace = true serde_json.workspace = true +# The build subject and the shapes the controller sends and reads back. swarm-queue-client.workspace = true # The forge token and queue client secret paths, and the store login. swarm-secret-client.workspace = true -# The build subject and the shapes the controller sends and reads back. -swarm-wire.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/swarm-builder/src/archetypes.rs b/swarm-builder/src/archetypes.rs index cf35081f..76222ade 100644 --- a/swarm-builder/src/archetypes.rs +++ b/swarm-builder/src/archetypes.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use std::process::Stdio; use std::time::Duration; -use swarm_wire::builder::ArchetypesReply; +use swarm_queue_client::builder::ArchetypesReply; /// What every evaluation is run with, fixed at start. pub struct Evaluator { @@ -105,7 +105,7 @@ mod tests { nix: PathBuf::from("nix"), hyperhive: "/nix/store/h-source".to_owned(), nixpkgs: "/nix/store/n-source".to_owned(), - deadline: swarm_wire::builder::ARCHETYPES_DEADLINE, + deadline: swarm_queue_client::builder::ARCHETYPES_DEADLINE, } } diff --git a/swarm-builder/src/main.rs b/swarm-builder/src/main.rs index 5c835f37..bf0cfe2b 100644 --- a/swarm-builder/src/main.rs +++ b/swarm-builder/src/main.rs @@ -1,11 +1,11 @@ //! The swarm builder's build service. //! //! Connects to the swarm queue as its own OIDC client, takes build requests -//! from swarm-controller on [`swarm_wire::builder::SUBJECT`], builds +//! from swarm-controller on [`swarm_queue_client::builder::SUBJECT`], builds //! each agent config at its commit, answers on the request's reply subject, //! and logs one line per build. It writes nothing to the forge: the //! controller turns the reply into a commit status. It also answers -//! [`swarm_wire::builder::ARCHETYPES_SUBJECT`] with the agent +//! [`swarm_queue_client::builder::ARCHETYPES_SUBJECT`] with the agent //! archetypes its hyperhive source declares, which the controller stores. //! //! The store identity comes from the `BAO_*` environment. The queue client @@ -19,13 +19,13 @@ use std::time::Duration; use anyhow::{Context, Result, anyhow, bail}; use futures_util::StreamExt as _; -use swarm_queue_client::{ClientSecret, QueueConfig}; -use swarm_secret_client::forge::Credential; -use swarm_secret_client::stored_secret::StoredSecret; -use swarm_wire::builder::{ +use swarm_queue_client::builder::{ ARCHETYPES_DEADLINE, ARCHETYPES_SUBJECT, BUILD_DEADLINE, BuildAgent, QUEUE_GROUP, REPLY_DEADLINE, Reply, SUBJECT, }; +use swarm_queue_client::{ClientSecret, QueueConfig}; +use swarm_secret_client::forge::Credential; +use swarm_secret_client::stored_secret::StoredSecret; mod archetypes; mod nix_build; @@ -168,10 +168,10 @@ async fn answer_evaluations( }; let reply = evaluator.eval().await; match &reply { - swarm_wire::builder::ArchetypesReply::Evaluated { archetypes, .. } => { + swarm_queue_client::builder::ArchetypesReply::Evaluated { archetypes, .. } => { tracing::info!(count = archetypes.len(), "archetypes evaluated"); } - swarm_wire::builder::ArchetypesReply::Failed { error_tail } => { + swarm_queue_client::builder::ArchetypesReply::Failed { error_tail } => { tracing::warn!(%error_tail, "archetype evaluation failed"); } } diff --git a/swarm-builder/src/nix_build.rs b/swarm-builder/src/nix_build.rs index b6937378..099a28de 100644 --- a/swarm-builder/src/nix_build.rs +++ b/swarm-builder/src/nix_build.rs @@ -16,7 +16,7 @@ use std::path::PathBuf; use std::process::Stdio; use std::time::Duration; -use swarm_wire::builder::{BuildAgent, Reply}; +use swarm_queue_client::builder::{BuildAgent, Reply}; use tokio::io::AsyncReadExt as _; /// The most of `nix`'s stderr a failed build's reply carries, from its end. @@ -293,7 +293,7 @@ pub(crate) fn tail(stderr: &str, status: std::process::ExitStatus) -> String { #[cfg(test)] mod tests { use super::*; - use swarm_wire::builder::BUILD_DEADLINE; + use swarm_queue_client::builder::BUILD_DEADLINE; fn job() -> BuildAgent { BuildAgent { diff --git a/swarm-claude-login/Cargo.toml b/swarm-claude-login/Cargo.toml index b1af0ca1..68238712 100644 --- a/swarm-claude-login/Cargo.toml +++ b/swarm-claude-login/Cargo.toml @@ -21,8 +21,6 @@ hive-types.workspace = true swarm-queue-client.workspace = true # The credentials and queue client secret paths, and the store login. swarm-secret-client.workspace = true -# The login subject and the requests and replies it carries. -swarm-wire.workspace = true tokio.workspace = true tracing.workspace = true diff --git a/swarm-claude-login/src/login.rs b/swarm-claude-login/src/login.rs index 1b504623..17246354 100644 --- a/swarm-claude-login/src/login.rs +++ b/swarm-claude-login/src/login.rs @@ -14,8 +14,8 @@ use std::process::Stdio; use std::sync::Arc; use std::time::Duration; +use swarm_queue_client::claude_login::Reply; use swarm_secret_client::claude_login::Credentials; -use swarm_wire::claude_login::Reply; use tokio::io::{AsyncBufReadExt as _, AsyncRead, AsyncWriteExt as _, BufReader}; use tokio::process::{Child, ChildStdin, Command}; use tokio::sync::{Mutex, watch}; diff --git a/swarm-claude-login/src/main.rs b/swarm-claude-login/src/main.rs index 1efcf0b0..36bcdf3f 100644 --- a/swarm-claude-login/src/main.rs +++ b/swarm-claude-login/src/main.rs @@ -2,7 +2,7 @@ //! //! Connects to the swarm queue as its own OIDC client, takes an operator's //! login steps from swarm-controller on -//! [`swarm_wire::claude_login::SUBJECT`], runs `claude auth login` +//! [`swarm_queue_client::claude_login::SUBJECT`], runs `claude auth login` //! for the agent named ([`login`]), and writes the credentials it produces to //! that agent's store leaf, a new version over any stored before. The agent's //! harness takes a version newer than the one it last installed. @@ -16,10 +16,10 @@ use std::sync::Arc; use anyhow::{Context, Result, bail}; use futures_util::StreamExt as _; +use swarm_queue_client::claude_login::{Reply, Request, SESSION_DEADLINE, STEP_DEADLINE, SUBJECT}; use swarm_queue_client::{ClientSecret, QueueConfig}; use swarm_secret_client::claude_login::{Credentials, client_secret_path, credentials_path}; use swarm_secret_client::stored_secret::StoredSecret; -use swarm_wire::claude_login::{Reply, Request, SESSION_DEADLINE, STEP_DEADLINE, SUBJECT}; mod login; @@ -190,7 +190,7 @@ mod tests { use std::sync::Arc; use std::time::Duration; - use swarm_wire::claude_login::{Reply, Request}; + use swarm_queue_client::claude_login::{Reply, Request}; use super::{handle, login}; diff --git a/swarm-controller/Cargo.toml b/swarm-controller/Cargo.toml index 14204773..f1e40ade 100644 --- a/swarm-controller/Cargo.toml +++ b/swarm-controller/Cargo.toml @@ -118,8 +118,6 @@ swarm-queue-client = { workspace = true, features = [ # name and the object's shape are agreements between the two ends, and a # second spelling here would be a store this hive could not read. swarm-secret-client.workspace = true -# The builder and claude login subjects, requests and replies it sends. -swarm-wire.workspace = true # The appservice calls `matrix_account::agent_token` mints agents' accounts # with — shared with `swarm-matrix-ctl`, which pins the same device id. swarm-matrix-client.workspace = true diff --git a/swarm-controller/src/archetypes.rs b/swarm-controller/src/archetypes.rs index 6c755a9f..1507e57e 100644 --- a/swarm-controller/src/archetypes.rs +++ b/swarm-controller/src/archetypes.rs @@ -16,7 +16,7 @@ use hive_sh4re::permissions::Permission; use problem_details::ProblemDetails; use serde::{Deserialize, Serialize}; use swarm_queue_client::archetypes::{ArchetypeMeta, BUILTIN_SOURCE, SourceRecord}; -use swarm_wire::builder::{ +use swarm_queue_client::builder::{ ARCHETYPES_DEADLINE, ARCHETYPES_SUBJECT, ArchetypesReply, EvalArchetypes, }; use utoipa::ToSchema; @@ -361,7 +361,7 @@ mod tests { let mut requests = builder .queue_subscribe( ARCHETYPES_SUBJECT, - swarm_wire::builder::QUEUE_GROUP.to_owned(), + swarm_queue_client::builder::QUEUE_GROUP.to_owned(), ) .await .expect("subscribe"); diff --git a/swarm-controller/src/builder.rs b/swarm-controller/src/builder.rs index 88323bca..cef00653 100644 --- a/swarm-controller/src/builder.rs +++ b/swarm-controller/src/builder.rs @@ -16,7 +16,7 @@ use std::future::Future; use forgejo_api::structs::CommitStatusState; use hive_jobq::scheduler::Outcome; -use swarm_wire::builder::{BuildAgent, REPLY_DEADLINE, Reply, SUBJECT}; +use swarm_queue_client::builder::{BuildAgent, REPLY_DEADLINE, Reply, SUBJECT}; use crate::agent_renewal::unix_now; use crate::forge::{self, CONFIG_ORG}; @@ -534,7 +534,7 @@ mod tests { let builder = nats.client().await; let mut requests = builder - .queue_subscribe(SUBJECT, swarm_wire::builder::QUEUE_GROUP.to_owned()) + .queue_subscribe(SUBJECT, swarm_queue_client::builder::QUEUE_GROUP.to_owned()) .await .expect("subscribe"); // A message the builder sends itself and receives back proves the diff --git a/swarm-controller/src/claude_login.rs b/swarm-controller/src/claude_login.rs index 857a9c58..10425785 100644 --- a/swarm-controller/src/claude_login.rs +++ b/swarm-controller/src/claude_login.rs @@ -21,7 +21,7 @@ use axum::extract::{Path, State}; use axum::http::{HeaderMap, StatusCode}; use problem_details::ProblemDetails; use serde::{Deserialize, Serialize}; -use swarm_wire::claude_login::{REPLY_DEADLINE, Reply, Request, SUBJECT}; +use swarm_queue_client::claude_login::{REPLY_DEADLINE, Reply, Request, SUBJECT}; use utoipa::ToSchema; use crate::{AppState, error_problem}; @@ -243,7 +243,7 @@ mod tests { use std::sync::Mutex; use axum::http::StatusCode; - use swarm_wire::claude_login::{Reply, Request}; + use swarm_queue_client::claude_login::{Reply, Request}; use super::{LoginSink, relay}; diff --git a/swarm-controller/src/main.rs b/swarm-controller/src/main.rs index ed5499a3..ce88efd3 100644 --- a/swarm-controller/src/main.rs +++ b/swarm-controller/src/main.rs @@ -601,7 +601,7 @@ async fn build_agent( rev: String, pr: u64, ) -> hive_jobq::scheduler::Outcome { - let job = swarm_wire::builder::BuildAgent { agent, rev, pr }; + let job = swarm_queue_client::builder::BuildAgent { agent, rev, pr }; let builds = builder::runs::Builds::Live(deps.queue.clone()); let link_base = std::env::var(PUBLIC_URL_ENV).ok(); builder::run( diff --git a/swarm-nats-auth/Cargo.toml b/swarm-nats-auth/Cargo.toml index 0bf8e78b..7ba2da59 100644 --- a/swarm-nats-auth/Cargo.toml +++ b/swarm-nats-auth/Cargo.toml @@ -33,8 +33,6 @@ swarm-queue-client = { workspace = true, features = ["notices"] } # credentials `swarm-agent-verify` checks a presented token against. swarm-secret-client.workspace = true swarm-agent-verify.workspace = true -# The builder and login subjects it grants. -swarm-wire.workspace = true tokio.workspace = true tracing.workspace = true tracing-subscriber.workspace = true diff --git a/swarm-nats-auth/src/policy.rs b/swarm-nats-auth/src/policy.rs index 088be44b..c18b1153 100644 --- a/swarm-nats-auth/src/policy.rs +++ b/swarm-nats-auth/src/policy.rs @@ -281,11 +281,11 @@ impl Policy { Permissions { publish: vec![Self::inbox(client_id)], subscribe: Some(vec![ - swarm_wire::builder::SUBJECT.to_owned(), - swarm_wire::builder::ARCHETYPES_SUBJECT.to_owned(), + swarm_queue_client::builder::SUBJECT.to_owned(), + swarm_queue_client::builder::ARCHETYPES_SUBJECT.to_owned(), Self::inbox(client_id), ]), - responses: Some(swarm_wire::builder::REPLY_DEADLINE), + responses: Some(swarm_queue_client::builder::REPLY_DEADLINE), } } @@ -296,10 +296,10 @@ impl Policy { Permissions { publish: vec![Self::inbox(client_id)], subscribe: Some(vec![ - swarm_wire::claude_login::SUBJECT.to_owned(), + swarm_queue_client::claude_login::SUBJECT.to_owned(), Self::inbox(client_id), ]), - responses: Some(swarm_wire::claude_login::REPLY_DEADLINE), + responses: Some(swarm_queue_client::claude_login::REPLY_DEADLINE), } } @@ -661,11 +661,11 @@ impl Policy { // back on this client's inbox, which it already subscribes to. swarm_queue_client::review_classifier::SUBJECT.to_owned(), // A build of an agent config, sent as a request the same way. - swarm_wire::builder::SUBJECT.to_owned(), + swarm_queue_client::builder::SUBJECT.to_owned(), // An archetype evaluation, sent as a request the same way. - swarm_wire::builder::ARCHETYPES_SUBJECT.to_owned(), + swarm_queue_client::builder::ARCHETYPES_SUBJECT.to_owned(), // An operator's claude login step, sent as a request the same way. - swarm_wire::claude_login::SUBJECT.to_owned(), + swarm_queue_client::claude_login::SUBJECT.to_owned(), // The wanted-state buckets — one per hive, all created and written // by this single client. // @@ -1532,8 +1532,8 @@ mod tests { #[test] fn the_builder_hears_its_subject_and_inbox_only_and_answers_by_reply() { + use swarm_queue_client::builder::{ARCHETYPES_SUBJECT, REPLY_DEADLINE, SUBJECT}; use swarm_queue_client::client_inbox_prefix; - use swarm_wire::builder::{ARCHETYPES_SUBJECT, REPLY_DEADLINE, SUBJECT}; let p = policy() .with_builders(vec![BUILDER.to_owned()]) @@ -1562,7 +1562,7 @@ mod tests { #[test] fn only_the_reader_may_send_a_build() { - use swarm_wire::builder::{ARCHETYPES_SUBJECT, SUBJECT}; + use swarm_queue_client::builder::{ARCHETYPES_SUBJECT, SUBJECT}; let p = with_classifier().with_builders(vec![BUILDER.to_owned()]); let reader = p.permissions("swarm-controller").expect("the reader"); @@ -1589,8 +1589,8 @@ mod tests { #[test] fn the_claude_login_minter_hears_its_subject_and_inbox_only_and_answers_by_reply() { + use swarm_queue_client::claude_login::{REPLY_DEADLINE, SUBJECT}; use swarm_queue_client::client_inbox_prefix; - use swarm_wire::claude_login::{REPLY_DEADLINE, SUBJECT}; let p = policy() .with_claude_logins(vec![CLAUDE_LOGIN.to_owned()]) @@ -1602,7 +1602,7 @@ mod tests { for refused in [ ">".to_owned(), "$SWARM.>".to_owned(), - swarm_wire::builder::SUBJECT.to_owned(), + swarm_queue_client::builder::SUBJECT.to_owned(), reply(&client_inbox_prefix("swarm-controller")), ] { assert!( @@ -1618,7 +1618,7 @@ mod tests { #[test] fn only_the_reader_may_send_a_login_step() { - use swarm_wire::claude_login::SUBJECT; + use swarm_queue_client::claude_login::SUBJECT; let p = with_classifier() .with_builders(vec![BUILDER.to_owned()]) diff --git a/swarm-queue-client/src/archetypes.rs b/swarm-queue-client/src/archetypes.rs index e99984a5..519a9a4e 100644 --- a/swarm-queue-client/src/archetypes.rs +++ b/swarm-queue-client/src/archetypes.rs @@ -4,7 +4,7 @@ //! //! **swarm-controller is the only writer and the only reader.** The swarm //! builder evaluates the source and answers on -//! `swarm_wire::builder::ARCHETYPES_SUBJECT`; the controller checks each +//! [`crate::builder::ARCHETYPES_SUBJECT`]; the controller checks each //! archetype's settings the way `POST /api/agents` checks them and writes the //! result here, so the create screen lists archetypes from a value that a //! create would accept. diff --git a/swarm-wire/src/builder.rs b/swarm-queue-client/src/builder.rs similarity index 56% rename from swarm-wire/src/builder.rs rename to swarm-queue-client/src/builder.rs index aeb66f54..9ba1e6bd 100644 --- a/swarm-wire/src/builder.rs +++ b/swarm-queue-client/src/builder.rs @@ -82,97 +82,40 @@ pub enum ArchetypesReply { #[cfg(test)] mod tests { - use serde_json::json; - use super::*; #[test] - fn the_build_request_serializes_as_pinned() { - let req = BuildAgent { - agent: "atlas".to_owned(), - rev: "abc".to_owned(), - pr: 7, - }; - let value = serde_json::to_value(&req).expect("encodes"); - assert_eq!(value, json!({"agent": "atlas", "rev": "abc", "pr": 7})); - assert_eq!( - serde_json::from_value::(value).expect("decodes"), - req - ); - } - - #[test] - fn the_reply_serializes_as_pinned() { - for (reply, wire) in [ - ( - Reply::Built { - out_path: "/nix/store/x".to_owned(), - }, - json!({"state": "built", "out_path": "/nix/store/x"}), - ), - ( - Reply::Failed { - error_tail: "e".to_owned(), - }, - json!({"state": "failed", "error_tail": "e"}), - ), - ] { - assert_eq!(serde_json::to_value(&reply).expect("encodes"), wire); - assert_eq!( - serde_json::from_value::(wire).expect("decodes"), - reply - ); - } - } - - #[test] - fn the_archetypes_request_and_reply_serialize_as_pinned() { - let req = EvalArchetypes::default(); - let value = serde_json::to_value(&req).expect("encodes"); - assert_eq!(value, json!({})); - assert_eq!( - serde_json::from_value::(value).expect("decodes"), - req - ); - - let mut archetypes = serde_json::Map::new(); - archetypes.insert("coder".to_owned(), json!({"description": "d"})); - for (reply, wire) in [ - ( - ArchetypesReply::Evaluated { - source: "/nix/store/h".to_owned(), - archetypes, - }, - json!({ - "state": "evaluated", - "source": "/nix/store/h", - "archetypes": {"coder": {"description": "d"}}, - }), - ), - ( - ArchetypesReply::Failed { - error_tail: "e".to_owned(), - }, - json!({"state": "failed", "error_tail": "e"}), - ), - ] { - assert_eq!(serde_json::to_value(&reply).expect("encodes"), wire); - assert_eq!( - serde_json::from_value::(wire).expect("decodes"), - reply - ); - } - } - - #[test] - fn the_subjects_are_pinned() { - assert_eq!(SUBJECT, "$SWARM.builder.build"); - assert_eq!(ARCHETYPES_SUBJECT, "$SWARM.builder.archetypes"); - assert_eq!(QUEUE_GROUP, "builder"); + fn the_wire_tags_the_reply_by_state() { + let json = serde_json::to_value(Reply::Built { + out_path: "/nix/store/x".to_owned(), + }) + .expect("encodes"); + assert_eq!(json["state"], "built"); + assert_eq!(json["out_path"], "/nix/store/x"); + let json = serde_json::to_value(Reply::Failed { + error_tail: "e".to_owned(), + }) + .expect("encodes"); + assert_eq!(json["state"], "failed"); } #[test] fn the_reply_deadline_outlasts_the_build() { assert!(REPLY_DEADLINE > BUILD_DEADLINE); } + + #[test] + fn the_archetypes_reply_is_tagged_by_state() { + let json = serde_json::to_value(ArchetypesReply::Evaluated { + source: "/nix/store/h".to_owned(), + archetypes: serde_json::Map::new(), + }) + .expect("encodes"); + assert_eq!(json["state"], "evaluated"); + let json = serde_json::to_value(ArchetypesReply::Failed { + error_tail: "e".to_owned(), + }) + .expect("encodes"); + assert_eq!(json["state"], "failed"); + } } diff --git a/swarm-wire/src/claude_login.rs b/swarm-queue-client/src/claude_login.rs similarity index 59% rename from swarm-wire/src/claude_login.rs rename to swarm-queue-client/src/claude_login.rs index bac6d6ce..d1242cec 100644 --- a/swarm-wire/src/claude_login.rs +++ b/swarm-queue-client/src/claude_login.rs @@ -6,9 +6,9 @@ //! each. //! //! A login is two requests for one agent: -//! [`Request::Start`] runs +//! [`Request::Start`](crate::claude_login::Request::Start) runs //! `claude auth login` and answers with the URL it printed, and -//! [`Request::Code`] hands it the code the +//! [`Request::Code`](crate::claude_login::Request::Code) hands it the code the //! operator pasted and answers once the credentials are in the agent's store //! leaf. The running login lives in the minter's memory between the two, so //! the swarm runs one minter. @@ -71,68 +71,19 @@ pub enum Reply { #[cfg(test)] mod tests { - use serde_json::json; - use super::*; #[test] - fn the_request_serializes_as_pinned() { - for (req, wire) in [ - ( - Request::Start { - agent: "atlas".to_owned(), - operator: "mara".to_owned(), - }, - json!({"step": "start", "agent": "atlas", "operator": "mara"}), - ), - ( - Request::Code { - agent: "atlas".to_owned(), - code: "c".to_owned(), - }, - json!({"step": "code", "agent": "atlas", "code": "c"}), - ), - ( - Request::Cancel { - agent: "atlas".to_owned(), - }, - json!({"step": "cancel", "agent": "atlas"}), - ), - ] { - assert_eq!(serde_json::to_value(&req).expect("encodes"), wire); - assert!(serde_json::from_value::(wire).expect("decodes") == req); - } - } - - #[test] - fn the_reply_serializes_as_pinned() { - for (reply, wire) in [ - ( - Reply::Started { - url: "https://u".to_owned(), - }, - json!({"state": "started", "url": "https://u"}), - ), - (Reply::Stored, json!({"state": "stored"})), - (Reply::Cancelled, json!({"state": "cancelled"})), - ( - Reply::Failed { - error: "e".to_owned(), - }, - json!({"state": "failed", "error": "e"}), - ), - ] { - assert_eq!(serde_json::to_value(&reply).expect("encodes"), wire); - assert_eq!( - serde_json::from_value::(wire).expect("decodes"), - reply - ); - } - } - - #[test] - fn the_subject_is_pinned() { - assert_eq!(SUBJECT, "$SWARM.claude-login.request"); + fn the_wire_tags_the_request_by_step_and_the_reply_by_state() { + let json = serde_json::to_value(Request::Code { + agent: "atlas".to_owned(), + code: "c".to_owned(), + }) + .expect("encodes"); + assert_eq!(json["step"], "code"); + assert_eq!(json["agent"], "atlas"); + let json = serde_json::to_value(Reply::Stored).expect("encodes"); + assert_eq!(json["state"], "stored"); } #[test] diff --git a/swarm-queue-client/src/lib.rs b/swarm-queue-client/src/lib.rs index 534e933e..ee0ef4ea 100644 --- a/swarm-queue-client/src/lib.rs +++ b/swarm-queue-client/src/lib.rs @@ -494,6 +494,13 @@ pub mod review_classifier; mod startup_read; pub use startup_read::read_with_startup_retry; +/// The builder's build subject and the request and reply it carries. +pub mod builder; + +/// The claude login minter's subject and the requests and replies it +/// carries. +pub mod claude_login; + /// Only the fields this needs; authelia returns several. #[derive(serde::Deserialize)] struct TokenResponse { diff --git a/swarm-wire/Cargo.toml b/swarm-wire/Cargo.toml deleted file mode 100644 index ee968020..00000000 --- a/swarm-wire/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "swarm-wire" -version.workspace = true -edition.workspace = true - -[dependencies] -serde.workspace = true -serde_json.workspace = true - -[lints] -workspace = true diff --git a/swarm-wire/src/lib.rs b/swarm-wire/src/lib.rs deleted file mode 100644 index 10c4c562..00000000 --- a/swarm-wire/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! The request and reply shapes swarm services exchange over the queue: the -//! subjects, their deadlines and the serde types that travel each way. -//! -//! Serde only, with no queue client and no secret-store client. A crate that -//! names a contract (the sender, the answerer, the auth-callout responder that -//! grants the subject) depends on this one without linking either. - -pub mod builder; -pub mod claude_login;