connector-usage-only: regenerate v4 goldens and schemas, format, fix tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-31 04:51:05 +01:00
commit bb8909f2c2
24 changed files with 206 additions and 201 deletions

1
Cargo.lock generated
View file

@ -144,6 +144,7 @@ dependencies = [
"libc", "libc",
"model-connector", "model-connector",
"rmp-serde", "rmp-serde",
"rmpv",
"serde", "serde",
"serde_json", "serde_json",
"sha2", "sha2",

View file

@ -5,8 +5,9 @@ use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use model_connector::{ use model_connector::{
CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition, TransportAdmission, TransportDisposition, TransportInvocation, CallerAdmission, PlanQuotaSnapshot, ReasoningEffort, StopReason, ToolDefinition,
TransportKey, TransportReceipt, TransportService, decrypt_result, encrypt_invocation, TransportAdmission, TransportDisposition, TransportInvocation, TransportKey, TransportReceipt,
TransportService, decrypt_result, encrypt_invocation,
}; };
use super::*; use super::*;
@ -480,8 +481,7 @@ impl Door {
.unwrap() .unwrap()
}); });
let service = let service =
TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000) TransportService::open(&dir.join("replay.cc"), PROVIDER, callers, 5_000).unwrap();
.unwrap();
Self { dir, service } Self { dir, service }
} }
@ -498,13 +498,13 @@ impl Door {
request: ProviderRequest, request: ProviderRequest,
) -> (model_connector::ExecutionClaim, TransportInvocation) { ) -> (model_connector::ExecutionClaim, TransportInvocation) {
let key = TransportKey::from_connection_secret(&format!("{caller}-key")).unwrap(); let key = TransportKey::from_connection_secret(&format!("{caller}-key")).unwrap();
let invocation = let invocation = TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
TransportInvocation::new(caller, 2_000, [7; 32], request).unwrap();
let envelope = encrypt_invocation(&invocation, &key).unwrap(); let envelope = encrypt_invocation(&invocation, &key).unwrap();
match self match self
.service .service
.begin(&envelope, 1_000, &PlanQuotaSnapshot::default(), FRAME) .begin(&envelope, 1_000, &PlanQuotaSnapshot::default(), FRAME)
.unwrap() { .unwrap()
{
TransportAdmission::Execute(claim) => (*claim, invocation), TransportAdmission::Execute(claim) => (*claim, invocation),
TransportAdmission::Reply(_) => panic!("the door answered instead of admitting"), TransportAdmission::Reply(_) => panic!("the door answered instead of admitting"),
} }

View file

@ -11,8 +11,8 @@ use std::time::Duration;
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore}; use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
use model_connector::{ use model_connector::{
CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend, CallerAdmission, CallerConfig, LeaseTurn, MIN_PAYLOAD_BYTES, ProviderBackend, ServeError,
ServeError, ServeLimits, ServiceError, TransportService, load_admissions, serve_service, ServeLimits, ServiceError, TransportService, load_admissions, serve_service,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@ -230,9 +230,7 @@ impl ClaudeConnectorConfig {
} }
let mut seen = BTreeSet::new(); let mut seen = BTreeSet::new();
for model in &caller.allowed_models { for model in &caller.allowed_models {
if !has_model_id_form(model) if !has_model_id_form(model) || !seen.insert(model.as_str()) {
|| !seen.insert(model.as_str())
{
return Err(ConfigError::Invalid("allowed_models")); return Err(ConfigError::Invalid("allowed_models"));
} }
} }
@ -344,7 +342,6 @@ fn has_model_id_form(model: &str) -> bool {
&& after_ok && after_ok
} }
/// One file name under `$CREDENTIALS_DIRECTORY`, never a path. /// One file name under `$CREDENTIALS_DIRECTORY`, never a path.
fn is_credential_name(name: &str) -> bool { fn is_credential_name(name: &str) -> bool {
!name.is_empty() !name.is_empty()

View file

@ -671,9 +671,9 @@ mod tests {
fn a_frame_that_trickles_past_its_deadline_is_refused_however_small_each_read() { fn a_frame_that_trickles_past_its_deadline_is_refused_however_small_each_read() {
let (mut reader, mut writer) = UnixStream::pair().unwrap(); let (mut reader, mut writer) = UnixStream::pair().unwrap();
let frame = encode_frame(&LeaseMessage::ClaudeLeaseRefusal(LeaseRefused { let frame = encode_frame(&LeaseMessage::ClaudeLeaseRefusal(LeaseRefused {
kind: LeaseRefusalKind::Busy, kind: LeaseRefusalKind::Busy,
detail: "lease:x".to_string(), detail: "lease:x".to_string(),
})); }));
let trickle = thread::spawn(move || { let trickle = thread::spawn(move || {
for byte in frame { for byte in frame {
if writer.write_all(&[byte]).is_err() { if writer.write_all(&[byte]).is_err() {

View file

@ -28,8 +28,8 @@ pub use launch::ChildEnv;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub use lease::{ pub use lease::{
LeaseCaller, LeaseGranted, LeaseLimits, LeaseMessage, LeaseRefusalKind, LeaseRefused, LeaseCaller, LeaseGranted, LeaseLimits, LeaseMessage, LeaseRefusalKind, LeaseRefused,
LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit, LeaseRequest, MAX_LEASE_FRAME_BYTES, PeerCredentials, PeerUnit, PeerUnits, decode_frame,
PeerUnits, decode_frame, encode_frame, peer_credentials, serve_leases, user_uid, encode_frame, peer_credentials, serve_leases, user_uid,
}; };
#[cfg(unix)] #[cfg(unix)]
pub use process::StdProcessPort; pub use process::StdProcessPort;

View file

@ -280,6 +280,9 @@ fn the_dollar_flags_are_not_flags() {
let scratch = Scratch::new(); let scratch = Scratch::new();
let made = init(&scratch, &init_flags(&scratch, extra)); let made = init(&scratch, &init_flags(&scratch, extra));
assert!(!made.status.success(), "{extra:?} was accepted"); assert!(!made.status.success(), "{extra:?} was accepted");
assert!(!Path::new(&scratch.path("connector.cc")).exists(), "{extra:?}"); assert!(
!Path::new(&scratch.path("connector.cc")).exists(),
"{extra:?}"
);
} }
} }

View file

@ -279,7 +279,12 @@ fn start(setup: Setup) -> Harness {
}); });
let quota = Arc::new(QuotaCell::new()); let quota = Arc::new(QuotaCell::new());
let listener = UnixListener::bind(&socket).unwrap(); let listener = UnixListener::bind(&socket).unwrap();
let serving = (service.clone(), quota.clone(), tokens.clone(), units.clone()); let serving = (
service.clone(),
quota.clone(),
tokens.clone(),
units.clone(),
);
let caller = LeaseCaller { let caller = LeaseCaller {
uid: setup.uid, uid: setup.uid,
caller_id: CALLER.to_string(), caller_id: CALLER.to_string(),
@ -343,7 +348,10 @@ fn ask_until_granted(harness: &Harness, first_invocation: u64) -> Answer {
fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() { fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
let harness = start(setup()); let harness = start(setup());
let mut answer = ask(&harness, 60_000); let mut answer = ask(&harness, 60_000);
assert_eq!(granted(&answer).lease_id, format!("lease:{}", invocation(1))); assert_eq!(
granted(&answer).lease_id,
format!("lease:{}", invocation(1))
);
assert_eq!(answer.fds.len(), 1); assert_eq!(answer.fds.len(), 1);
let mut read = Vec::new(); let mut read = Vec::new();
File::from(answer.fds.remove(0)) File::from(answer.fds.remove(0))
@ -351,7 +359,10 @@ fn a_grant_passes_one_fd_holding_the_token_then_end_of_file() {
.unwrap(); .unwrap();
assert_eq!(read, TOKEN.as_bytes()); assert_eq!(read, TOKEN.as_bytes());
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 1); assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 1);
assert!(!contains(&answer.raw, TOKEN), "the token is in the pipe only"); assert!(
!contains(&answer.raw, TOKEN),
"the token is in the pipe only"
);
} }
#[test] #[test]
@ -416,7 +427,10 @@ fn a_rejected_window_refuses_the_lease_until_its_reset() {
.quota .quota
.observe([window("five_hour", 1_000, "rejected", reset)]); .observe([window("five_hour", 1_000, "rejected", reset)]);
let refused = ask(&harness, 60_000); let refused = ask(&harness, 60_000);
assert_eq!(refusal_of(&refused), Some(LeaseRefusalKind::ProviderRejected)); assert_eq!(
refusal_of(&refused),
Some(LeaseRefusalKind::ProviderRejected)
);
assert!(refused.fds.is_empty()); assert!(refused.fds.is_empty());
assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 0); assert_eq!(harness.tokens.reads.load(Ordering::SeqCst), 0);
// At the provider's own reset the refusal lifts, with no one lifting it. // At the provider's own reset the refusal lifts, with no one lifting it.

View file

@ -762,8 +762,15 @@ mod tests {
#[test] #[test]
fn the_invocations_identity_covers_its_request() { fn the_invocations_identity_covers_its_request() {
let one = invocation(); let one = invocation();
let mut other = one.clone(); let mut request = one.request.clone();
other.request.max_output_tokens += 1; request.max_output_tokens += 1;
let other = TransportInvocation::new(
one.caller_runtime_id.clone(),
one.expires_at_unix_ms,
one.native_request_sha256,
request,
)
.unwrap();
assert_ne!( assert_ne!(
canonical_invocation_bytes(&one).unwrap(), canonical_invocation_bytes(&one).unwrap(),
canonical_invocation_bytes(&other).unwrap() canonical_invocation_bytes(&other).unwrap()

View file

@ -67,14 +67,6 @@ impl FlakyStore {
pub(crate) fn allowance(&self) -> Arc<AtomicUsize> { pub(crate) fn allowance(&self) -> Arc<AtomicUsize> {
self.pushes_allowed.clone() self.pushes_allowed.clone()
} }
/// A store over the same records that accepts `pushes_allowed` more writes.
pub(crate) fn reopened(&self, pushes_allowed: usize) -> Self {
Self {
held: self.held.clone(),
pushes_allowed: Arc::new(AtomicUsize::new(pushes_allowed)),
}
}
} }
#[cfg(feature = "daemon")] #[cfg(feature = "daemon")]
@ -133,7 +125,6 @@ pub(crate) fn request() -> ProviderRequest {
request request
} }
pub(crate) fn invocation() -> TransportInvocation { pub(crate) fn invocation() -> TransportInvocation {
TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], request()).unwrap() TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], request()).unwrap()
} }

View file

@ -9,7 +9,6 @@ use crate::contract::ContractError;
pub const USAGE_READOUT_SCHEMA_ID: &str = "gamecult.model.usage_readout.v1"; pub const USAGE_READOUT_SCHEMA_ID: &str = "gamecult.model.usage_readout.v1";
/// One window of the subscription plan, as the provider reported it. /// One window of the subscription plan, as the provider reported it.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]

View file

@ -382,10 +382,7 @@ mod tests {
FailureKind, Refusal, TransportDisposition, TransportEvent, TransportEventPayload, FailureKind, Refusal, TransportDisposition, TransportEvent, TransportEventPayload,
TransportInvocation, TransportOutcome, TransportResult, TransportInvocation, TransportOutcome, TransportResult,
}; };
use crate::fixtures::{ use crate::fixtures::{TestStore, caller, invocation_for, receipt, request};
TestStore, caller, invocation_for, receipt,
request,
};
const CALLER: &str = "epiphany-yggdrasil"; const CALLER: &str = "epiphany-yggdrasil";
const KEY: &str = "epiphany-distinct-test-key"; const KEY: &str = "epiphany-distinct-test-key";
@ -461,13 +458,7 @@ mod tests {
let (sender, receiver) = std::sync::mpsc::channel(); let (sender, receiver) = std::sync::mpsc::channel();
let path = path.to_path_buf(); let path = path.to_path_buf();
thread::spawn(move || { thread::spawn(move || {
let _ = sender.send(serve( let _ = sender.send(serve(listener, limits, admissions, &path, backend));
listener,
limits,
admissions,
&path,
backend,
));
}); });
receiver.recv_timeout(Duration::from_secs(2)).ok() receiver.recv_timeout(Duration::from_secs(2)).ok()
} }
@ -493,15 +484,7 @@ mod tests {
let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let listener = TcpListener::bind("127.0.0.1:0").unwrap();
let endpoint = listener.local_addr().unwrap(); let endpoint = listener.local_addr().unwrap();
let path = store.path.clone(); let path = store.path.clone();
thread::spawn(move || { thread::spawn(move || serve(listener, limits(), admissions, &path, backend));
serve(
listener,
limits(),
admissions,
&path,
backend,
)
});
let client = let client =
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap(); ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
(client, endpoint) (client, endpoint)
@ -770,10 +753,9 @@ mod tests {
let envelope = let envelope =
crate::envelope::encrypt_invocation(&invocation, &crate::fixtures::security(KEY)) crate::envelope::encrypt_invocation(&invocation, &crate::fixtures::security(KEY))
.unwrap(); .unwrap();
let TransportAdmission::Execute(claim) = let TransportAdmission::Execute(claim) = service
service .begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20) .unwrap()
.unwrap()
else { else {
panic!("a fresh request must execute"); panic!("a fresh request must execute");
}; };
@ -881,12 +863,7 @@ mod tests {
fn the_smallest_frame_also_carries_the_failure_that_stands_in_for_a_result() { fn the_smallest_frame_also_carries_the_failure_that_stands_in_for_a_result() {
let long = "x".repeat(crate::envelope::MAX_IDENTITY_BYTES); let long = "x".repeat(crate::envelope::MAX_IDENTITY_BYTES);
let plaintext = crate::contract::wire_encode(&crate::service::result_size_failure( let plaintext = crate::contract::wire_encode(&crate::service::result_size_failure(
&long, &long, &long, &long, [0xff; 32], [0xff; 32], 0,
&long,
&long,
[0xff; 32],
[0xff; 32],
0,
)) ))
.unwrap() .unwrap()
.len(); .len();
@ -994,16 +971,7 @@ mod tests {
} }
fn admission(id: &str, key: &str, slots: usize, payload: usize) -> CallerAdmission { fn admission(id: &str, key: &str, slots: usize, payload: usize) -> CallerAdmission {
CallerAdmission::new( CallerAdmission::new(id, key, 1, ["gpt-5.4".to_string()], slots, payload, 32_768).unwrap()
id,
key,
1,
["gpt-5.4".to_string()],
slots,
payload,
32_768,
)
.unwrap()
} }
/// `Some(field)` when serve refused the configuration, `None` while it serves. /// `Some(field)` when serve refused the configuration, `None` while it serves.
@ -1233,10 +1201,9 @@ mod tests {
&crate::fixtures::security(KEY), &crate::fixtures::security(KEY),
) )
.unwrap(); .unwrap();
let TransportAdmission::Execute(claim) = let TransportAdmission::Execute(claim) = service
service .begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20)
.begin(&envelope, now_ms(), &PlanQuotaSnapshot::default(), 1 << 20) .unwrap()
.unwrap()
else { else {
panic!("a fresh request must execute"); panic!("a fresh request must execute");
}; };
@ -1385,15 +1352,7 @@ mod tests {
let backend = CountingBackend::new(true); let backend = CountingBackend::new(true);
let path = store.path.clone(); let path = store.path.clone();
let served = backend.clone(); let served = backend.clone();
thread::spawn(move || { thread::spawn(move || serve(listener, limits(), admissions, &path, served));
serve(
listener,
limits(),
admissions,
&path,
served,
)
});
let client = let client =
ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap(); ConnectorClient::new(endpoint, KEY, FRAME, Some(Duration::from_secs(5))).unwrap();
client.execute(&fresh("request-key")).unwrap(); client.execute(&fresh("request-key")).unwrap();

View file

@ -524,7 +524,8 @@ impl TransportService {
.get::<ReplayRecord>(&replay_key(&identity)) .get::<ReplayRecord>(&replay_key(&identity))
.map_err(replay_store_error)? .map_err(replay_store_error)?
.ok_or(ServiceError::NoActiveRequest)?; .ok_or(ServiceError::NoActiveRequest)?;
if active.state != ReplayState::Active || active.invocation_sha256 != claim.invocation_sha256 if active.state != ReplayState::Active
|| active.invocation_sha256 != claim.invocation_sha256
{ {
return Err(ServiceError::ActiveRequestMismatch); return Err(ServiceError::ActiveRequestMismatch);
} }
@ -897,13 +898,9 @@ mod tests {
let mut changed_request = request(); let mut changed_request = request();
changed_request.instructions.push_str(" Different cargo."); changed_request.instructions.push_str(" Different cargo.");
let conflicting = TransportInvocation::new( let conflicting =
"epiphany-yggdrasil", TransportInvocation::new("epiphany-yggdrasil", 2_000, [7; 32], changed_request)
2_000, .unwrap();
[7; 32],
changed_request,
)
.unwrap();
let refusal = match service let refusal = match service
.begin_unplanned( .begin_unplanned(
&encrypt_invocation(&conflicting, &security).unwrap(), &encrypt_invocation(&conflicting, &security).unwrap(),
@ -932,7 +929,9 @@ mod tests {
let mut service = open_service(&store, 1); let mut service = open_service(&store, 1);
let first_envelope = encrypt_invocation(&first, &security).unwrap(); let first_envelope = encrypt_invocation(&first, &security).unwrap();
assert!(matches!( assert!(matches!(
service.begin_unplanned(&first_envelope, 1_000, FRAME).unwrap(), service
.begin_unplanned(&first_envelope, 1_000, FRAME)
.unwrap(),
TransportAdmission::Execute(_) TransportAdmission::Execute(_)
)); ));
@ -1035,10 +1034,12 @@ mod tests {
) -> (TransportAdmission, TransportInvocation) { ) -> (TransportAdmission, TransportInvocation) {
let mut request = invocation_for(CALLER, request_id).request; let mut request = invocation_for(CALLER, request_id).request;
edit(&mut request); edit(&mut request);
let invocation = let invocation = TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
TransportInvocation::new(CALLER, 2_000, [7; 32], request).unwrap();
let envelope = encrypt_invocation(&invocation, &security(KEY)).unwrap(); let envelope = encrypt_invocation(&invocation, &security(KEY)).unwrap();
(service.begin_unplanned(&envelope, 1_000, FRAME).unwrap(), invocation) (
service.begin_unplanned(&envelope, 1_000, FRAME).unwrap(),
invocation,
)
} }
fn refusal_of(admission: TransportAdmission, invocation: &TransportInvocation) -> Refusal { fn refusal_of(admission: TransportAdmission, invocation: &TransportInvocation) -> Refusal {
@ -1118,14 +1119,9 @@ mod tests {
32_768, 32_768,
) )
.unwrap(); .unwrap();
TransportService::open( TransportService::open(&store.path, "fixture-sse", [admission], 5_000)
&store.path, .unwrap()
"fixture-sse", .begin_unplanned(&envelope, 1_000, FRAME)
[admission],
5_000,
)
.unwrap()
.begin_unplanned(&envelope, 1_000, FRAME)
}; };
assert!(matches!(admit(size), Ok(TransportAdmission::Execute(_)))); assert!(matches!(admit(size), Ok(TransportAdmission::Execute(_))));
let refused = admit(size - 1).unwrap(); let refused = admit(size - 1).unwrap();
@ -1272,15 +1268,7 @@ mod tests {
#[test] #[test]
fn identities_are_bounded_at_admission_and_on_the_request() { fn identities_are_bounded_at_admission_and_on_the_request() {
let admit = |caller_id: String, model: String| { let admit = |caller_id: String, model: String| {
CallerAdmission::new( CallerAdmission::new(caller_id, KEY, 1, [model], 4, 64 * 1024, 32_768)
caller_id,
KEY,
1,
[model],
4,
64 * 1024,
32_768,
)
}; };
let at = "i".repeat(MAX_IDENTITY_BYTES); let at = "i".repeat(MAX_IDENTITY_BYTES);
let over = "i".repeat(MAX_IDENTITY_BYTES + 1); let over = "i".repeat(MAX_IDENTITY_BYTES + 1);
@ -1298,7 +1286,9 @@ mod tests {
let mut service = open_service(&store, 8); let mut service = open_service(&store, 8);
let ok = invocation_for(CALLER, &at); let ok = invocation_for(CALLER, &at);
assert!(matches!( assert!(matches!(
service.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME).unwrap(), service
.begin_unplanned(&raw_envelope(&ok), 1_000, FRAME)
.unwrap(),
TransportAdmission::Execute(_) TransportAdmission::Execute(_)
)); ));
} }
@ -1315,8 +1305,9 @@ mod tests {
let mut service = open_service(&store, 1); let mut service = open_service(&store, 1);
let id = "i".repeat(length); let id = "i".repeat(length);
let long = invocation_for(CALLER, &id); let long = invocation_for(CALLER, &id);
let TransportAdmission::Reply(reply) = let TransportAdmission::Reply(reply) = service
service.begin_unplanned(&raw_envelope(&long), 1_000, FRAME).unwrap() .begin_unplanned(&raw_envelope(&long), 1_000, FRAME)
.unwrap()
else { else {
panic!("an over-long id must be refused, not executed ({length})"); panic!("an over-long id must be refused, not executed ({length})");
}; };
@ -1353,7 +1344,9 @@ mod tests {
let store = TestStore::new(); let store = TestStore::new();
let mut service = open_service(&store, 1); let mut service = open_service(&store, 1);
assert!(matches!( assert!(matches!(
service.begin_unplanned(&raw_envelope(&long), 1_000, frame_cap).unwrap(), service
.begin_unplanned(&raw_envelope(&long), 1_000, frame_cap)
.unwrap(),
TransportAdmission::Reply(_) TransportAdmission::Reply(_)
)); ));
assert_eq!( assert_eq!(
@ -1543,7 +1536,9 @@ mod tests {
let big = text_result(claim.call(), "y"); let big = text_result(claim.call(), "y");
service.complete(*claim, big, FRAME).unwrap(); service.complete(*claim, big, FRAME).unwrap();
assert_eq!( assert_eq!(
service.begin_unplanned(&raw_envelope(&invocation), 1_000, 10).err(), service
.begin_unplanned(&raw_envelope(&invocation), 1_000, 10)
.err(),
Some(ServiceError::FrameBound) Some(ServiceError::FrameBound)
); );
} }
@ -1758,25 +1753,15 @@ mod tests {
for tag in ["", " ", STAND_IN_PROVIDER] { for tag in ["", " ", STAND_IN_PROVIDER] {
assert!( assert!(
matches!( matches!(
TransportService::open( TransportService::open(&store.path, tag, [caller(CALLER, KEY, 1)], 5_000),
&store.path,
tag,
[caller(CALLER, KEY, 1)],
5_000
),
Err(ServiceError::InvalidAdmission) Err(ServiceError::InvalidAdmission)
), ),
"{tag:?}" "{tag:?}"
); );
} }
assert!( assert!(
TransportService::open( TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000)
&store.path, .is_ok()
"fixture-sse",
[caller(CALLER, KEY, 1)],
5_000
)
.is_ok()
); );
} }
@ -2060,12 +2045,7 @@ mod tests {
.unwrap(); .unwrap();
} }
assert!(matches!( assert!(matches!(
TransportService::open( TransportService::open(&store.path, "fixture-sse", [caller(CALLER, KEY, 1)], 5_000),
&store.path,
"fixture-sse",
[caller(CALLER, KEY, 1)],
5_000
),
Err(ServiceError::ReplayStore(_)) Err(ServiceError::ReplayStore(_))
)); ));
} }

View file

@ -128,16 +128,10 @@ mod tests {
TransportService::open( TransportService::open(
&store.path, &store.path,
"fixture-sse", "fixture-sse",
[CallerAdmission::new( [
CALLER, CallerAdmission::new(CALLER, KEY, 1, ["gpt-5.4".to_string()], 1, 65_536, 32_768)
KEY, .unwrap(),
1, ],
["gpt-5.4".to_string()],
1,
65_536,
32_768,
)
.unwrap()],
5_000, 5_000,
) )
.unwrap() .unwrap()
@ -185,7 +179,10 @@ mod tests {
fn a_lease_is_named_by_its_invocation() { fn a_lease_is_named_by_its_invocation() {
let store = TestStore::new(); let store = TestStore::new();
let mut service = open(&store); let mut service = open(&store);
assert_eq!(granted(lease(&mut service, "run-1")).lease_id, "lease:run-1"); assert_eq!(
granted(lease(&mut service, "run-1")).lease_id,
"lease:run-1"
);
} }
#[test] #[test]
@ -231,14 +228,28 @@ mod tests {
); );
assert_eq!( assert_eq!(
service service
.begin_lease(CALLER, LeaseTurn::SelfRun, "run-2", NOW + 99, NOW + 9, &none()) .begin_lease(
CALLER,
LeaseTurn::SelfRun,
"run-2",
NOW + 99,
NOW + 9,
&none()
)
.unwrap(), .unwrap(),
LeaseAdmission::Refused(LeaseRefusal::Busy), LeaseAdmission::Refused(LeaseRefusal::Busy),
"one millisecond before its expiry the lease still holds" "one millisecond before its expiry the lease still holds"
); );
granted( granted(
service service
.begin_lease(CALLER, LeaseTurn::SelfRun, "run-2", NOW + 99, NOW + 10, &none()) .begin_lease(
CALLER,
LeaseTurn::SelfRun,
"run-2",
NOW + 99,
NOW + 10,
&none(),
)
.unwrap(), .unwrap(),
); );
} }
@ -249,7 +260,14 @@ mod tests {
let mut service = open(&store); let mut service = open(&store);
assert_eq!( assert_eq!(
service service
.begin_lease("stranger", LeaseTurn::SelfRun, "run-1", NOW + 1, NOW, &none()) .begin_lease(
"stranger",
LeaseTurn::SelfRun,
"run-1",
NOW + 1,
NOW,
&none()
)
.unwrap(), .unwrap(),
LeaseAdmission::Refused(LeaseRefusal::UnknownCaller) LeaseAdmission::Refused(LeaseRefusal::UnknownCaller)
); );
@ -286,8 +304,7 @@ mod tests {
let call = |service: &mut TransportService, now: u64, plan: &PlanQuotaSnapshot| { let call = |service: &mut TransportService, now: u64, plan: &PlanQuotaSnapshot| {
let mut asked = request(); let mut asked = request();
asked.request_id = format!("call-{now}"); asked.request_id = format!("call-{now}");
let invocation = let invocation = TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
TransportInvocation::new(CALLER, now + 1_000, [7; 32], asked).unwrap();
let sealed = crate::envelope::encrypt_message( let sealed = crate::envelope::encrypt_message(
CALLER, CALLER,
invocation.request_id(), invocation.request_id(),
@ -301,7 +318,8 @@ mod tests {
else { else {
return None; return None;
}; };
let result = crate::envelope::decrypt_result(&reply, &security(KEY), &invocation).unwrap(); let result =
crate::envelope::decrypt_result(&reply, &security(KEY), &invocation).unwrap();
match result.disposition { match result.disposition {
TransportDisposition::Refused(refusal) => Some(refusal), TransportDisposition::Refused(refusal) => Some(refusal),
other => panic!("unexpected {other:?}"), other => panic!("unexpected {other:?}"),
@ -361,7 +379,12 @@ mod tests {
let store = TestStore::new(); let store = TestStore::new();
let mut service = open(&store); let mut service = open(&store);
let longest = "r".repeat(MAX_IDENTITY_BYTES - LEASE_PREFIX.len() - PERSONA_SUFFIX.len()); let longest = "r".repeat(MAX_IDENTITY_BYTES - LEASE_PREFIX.len() - PERSONA_SUFFIX.len());
let grant = granted(lease_in(&mut service, LeaseTurn::PersonaTurn, &longest, &none())); let grant = granted(lease_in(
&mut service,
LeaseTurn::PersonaTurn,
&longest,
&none(),
));
assert_eq!(grant.lease_id.len(), MAX_IDENTITY_BYTES); assert_eq!(grant.lease_id.len(), MAX_IDENTITY_BYTES);
assert!(lease_try(&mut service, LeaseTurn::PersonaTurn, &format!("{longest}r")).is_err()); assert!(lease_try(&mut service, LeaseTurn::PersonaTurn, &format!("{longest}r")).is_err());
} }

View file

@ -1 +1 @@
<EFBFBD>messageIdョgolden-requestゥoperationヲinvokeァpayloadレDhqlzY2hlbWFfaWTZJGdhbWVjdWx0Lm1vZGVsLnRyYW5zcG9ydF9lbnZlbG9wZS52M7FjYWxsZXJfcnVudGltZV9pZK1nb2xkZW4tY2FsbGVyqnJlcXVlc3RfaWSuZ29sZGVuLXJlcXVlc3SsbWVzc2FnZV9raW5kqkludm9jYXRpb26lbm9uY2WczO7MxRrMxw7MhTh7SMzwzNB2qmNpcGhlcnRleHTFA0d65EskLG6kIwJ/G+XDK03gZOGtLFi6vZHJbI+/KpRLwnLT0TPF7RQa0KD98CrW+VwkKY3sRa4+Z9+/5OdPq1YmDFwbxvMVjZsFjXXw84tzvuLKHsb/3kQSEvAlFE4K6FXHvznLcMo4CnGUzoXwNGALf+xDTqFG0aFbdG4xGynV/kttsL6f34F4+l6xiXMUy87Q8/1UyOK/YaVxMMmlT3tdTllhq8YU8Dvfq0KuMaj/f9Anya8A5bJwlxafZPtc53RoH1/oNjLdaDqvwrTEnTB9TvKlnEOxKyyKhmmwGaC03qqPJXRaj8cDQO6EHDbML4J0zMN8TvssQISd5UCeVMkvDGjmvEOmRUoPk1/SnSrIHdha4+6rU4lUSumloLmlx5vv++Mq4AqzOdd/vPB6Ov/AoF32X27o4RI6H3xCKKHjKC4m3+cVjXCrOcGojuRf9yeDFkgbiPaC31hmSc8rAm6HO/NcaIHvx+G+6AaurAEhDLdF6DdrXb4xwjuv6yWQKihNvLXpnwmhRFkSeD5lS6FHW+CoOIdq/RBnFFyDrboTPWFoxQYIrBuqFoHDOajIz7dXYif0sf9sB9JBrDhlcbTpiGcyURfzDhW55NOPqKFGi6ropaJ1/SyLP3f7E57kA22aQ2Op7o36Tu06Pnzo2wI7UsL/Qz27F+AGAukQCvTJyjxARiGr3TRpChjVXx6GXhLrG1T9P+Mrhyrt9vwwhboN8qz1uvDZwKhGWBKXPXkxluq/NY1DwB3JTCCZfEwukWjMZbqiINLEKvW9BStcBR1kfXcK6sQvn/F0g9r81e9brbe+w3U24GERnHwgruOqytTeax/xPbQ7uISV48g5L8DAYf788KhUXwI43QDHNBdBUyo0rCsgoWJKeO05fcAgKgYYGsyLtMW10Vstw3q4POyn3o7rrBz4S2cnl2iZgr0ixg/KgF0V+loEVuj/6rYrcW0SLCHwV1+w1ClFMn0ZPsrz28EoZMA617G0Rrch66cS5uI9/Zf/wLX3z6n7xoPLNXk51ZsLSZ2bqEQkcBJbW/dT5MdH6anWVogRDvIW1coUbkIq9l+pkQSuelWsfakX4UQwYuUD0UwNbqxHiGwlEFj0f1bdhEj26Q==ッpayloadEncodingイmessagepack-base64ュpayloadSchemaル$gamecult.model.transport_envelope.v3ュschemaVersionシcultnet.operation_request.v0ゥserviceIdクgamecult.model.connector <EFBFBD>messageIdョgolden-requestゥoperationヲinvokeァpayloadレ(hqlzY2hlbWFfaWTZJGdhbWVjdWx0Lm1vZGVsLnRyYW5zcG9ydF9lbnZlbG9wZS52NLFjYWxsZXJfcnVudGltZV9pZK1nb2xkZW4tY2FsbGVyqnJlcXVlc3RfaWSuZ29sZGVuLXJlcXVlc3SsbWVzc2FnZV9raW5kqkludm9jYXRpb26lbm9uY2WcXSbMzU3MhsyCzLAtzKLMhcy8zMSqY2lwaGVydGV4dMUDMY816tn0FGQ9jqxE+KyDVcxmhufaQI7vzEXO8NXTQPOYpRuMcRDM/j/QzNF2Lb3Fak0G+hHRKrXDxJ3MeKpoELNYOEyxbKfxn88mjAyyc7BVPM7+0Bk9ye3m5oBF6hoyCgOHSTwESIfq0bim+9oQh1IDp+HdFjztK/XjM731GRzKJmGgxsKqQsz42zq8y9mjAXl3V1RR9ssdKvk2k5U56/3liOeHDU96kOa7IlVCBm6qnn06hg2DTtnBF4xGj6PihHj4KufVkAcuQhRCZWOKsploToXo7wy+jcQDrnhHIUCMN6sk3P9YJh1ejuleDM9rp3RYiXcnzRwMNXK1AGpNraTgWn91d6L/1Ff+gaQBgPxSjW6FATshJf9Iqk9pEhT8xeCQMmNj40CdlVFYNz/TsRJYW45BXm8g83Jnh3Wj0Z90WJ80bwwgZbjPWx6wCOCID6Jo8wiubF6411ygi+GUHTR9rZFhrsGo6TSmsbvIAuabUJcskqKHW7tqVkfpz5JdjyeSSDvKcZ3PQyVne7Lyo8nzNh0g06a7CEUvq9kvr4zfTCfwk/1YVSrZ+7U8ePGj27V3D8+BH/pafiLR5FxxBKWBTYe7n5irVP5gLw4WlzOrSriXpolmaPWujCm3apml45mhlYARdfJJbpQxnQGb6cI3D/vAxxI50BPLB82JqCjNFex9xwfP5jSRDYah9wLm4yVymBqZ8Wvn0maLz4OvF2EonJBwEtN73UBULkdeX6g9GTiu2MKtCjSMm33SkwiHfvDdwMDS11sINK+YQLF/3HobbnAk2n963JahlddNRg79T96GksjN0br8u1PNMC+/uBUHEQvUBfRnR4tKp+SeLF6zMn228orgHgWr7sxilMwTOP1DgXpbEE19M0P8XC0CA/pTeHr4eFHzakPLotxF8avQfPKAXbXWgNGK6uWj1NGPshD6EN3pLvePOc4uObqHMKz/dg52/7m1VTHhYMivSRenG6H/BrWfUXQvcgCPalg7C4KCPYINb3nnRxP0NIOBP+KJ4S2haU94ZNHVr2HB038xNzUm2HrONVBsxuuTckYDmHfCa6FmvVJv4she5wyuPHk=ッpayloadEncodingイmessagepack-base64ュpayloadSchemaル$gamecult.model.transport_envelope.v4ュschemaVersionシcultnet.operation_request.v0ゥserviceIdクgamecult.model.connector

View file

@ -1 +1 @@
„©schema_idÙ"gamecult.model.transport_result.v3ªrequest_id®golden-request±caller_runtime_id­golden-caller«disposition<6F>§Refused«OutputBound „©schema_idÙ"gamecult.model.transport_result.v4ªrequest_id®golden-request±caller_runtime_id­golden-caller«disposition<6F>§Refused«OutputBound

View file

@ -11,12 +11,6 @@
"format": "uint64", "format": "uint64",
"minimum": 0 "minimum": 0
}, },
"max_cost_micro_usd": {
"description": "The most this request may cost, in micro-USD: the caller's own bound\non it. Required nonzero. It is part of the invocation's identity, so a\nchanged budget under a recorded request id is a `ReplayConflict`.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"native_request_sha256": { "native_request_sha256": {
"type": "array", "type": "array",
"items": { "items": {
@ -53,7 +47,6 @@
"expires_at_unix_ms", "expires_at_unix_ms",
"native_request_sha256", "native_request_sha256",
"provider_request_sha256", "provider_request_sha256",
"max_cost_micro_usd",
"request" "request"
], ],
"$defs": { "$defs": {

View file

@ -6,12 +6,6 @@
"caller_runtime_id": { "caller_runtime_id": {
"type": "string" "type": "string"
}, },
"cost_micro_usd": {
"description": "What the request cost, in micro-USD. The service derives it from the\noutcome's usage and its price table; a backend never writes it.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"foreign_reasoning_dropped": { "foreign_reasoning_dropped": {
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.", "description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
"type": "integer", "type": "integer",
@ -35,12 +29,6 @@
"outcome": { "outcome": {
"$ref": "#/$defs/TransportOutcome" "$ref": "#/$defs/TransportOutcome"
}, },
"overrun_micro_usd": {
"description": "How far `cost_micro_usd` exceeds what the service reserved for the\nrequest: zero unless the backend reported usage above the worst case\nthe request allowed, which is a breach of the backend's contract. The\ncost is still the true one and the caller's window is charged all of\nit. The service derives this; a backend never writes it.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"provider": { "provider": {
"type": "string" "type": "string"
}, },
@ -72,8 +60,6 @@
"model", "model",
"provider", "provider",
"foreign_reasoning_dropped", "foreign_reasoning_dropped",
"cost_micro_usd",
"overrun_micro_usd",
"outcome" "outcome"
], ],
"$defs": { "$defs": {
@ -174,7 +160,7 @@
] ]
}, },
"Usage": { "Usage": {
"description": "Token accounting for one request, as the backend reports it; the service\nprices it. Cache reads and writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never priced apart.", "description": "Token accounting for one request, as the backend reports it. Cache reads\nand writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never counted apart.",
"type": "object", "type": "object",
"properties": { "properties": {
"cache_read_tokens": { "cache_read_tokens": {

View file

@ -46,15 +46,13 @@
"ModelNotAllowed", "ModelNotAllowed",
"OutputBound", "OutputBound",
"PayloadBound", "PayloadBound",
"CostBound",
"SpendCeiling",
"Capacity", "Capacity",
"InFlight", "InFlight",
"Indeterminate", "Indeterminate",
"ReplayConflict", "ReplayConflict",
"Malformed", "Malformed",
"ForeignReasoningState", "ForeignReasoningState",
"ClockBehindAdmissionWindow" "ProviderRejected"
] ]
}, },
"StopReason": { "StopReason": {
@ -286,12 +284,6 @@
"caller_runtime_id": { "caller_runtime_id": {
"type": "string" "type": "string"
}, },
"cost_micro_usd": {
"description": "What the request cost, in micro-USD. The service derives it from the\noutcome's usage and its price table; a backend never writes it.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"foreign_reasoning_dropped": { "foreign_reasoning_dropped": {
"description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.", "description": "How many foreign `ReasoningState` items the service removed from the\nrequest before the backend saw it.",
"type": "integer", "type": "integer",
@ -315,12 +307,6 @@
"outcome": { "outcome": {
"$ref": "#/$defs/TransportOutcome" "$ref": "#/$defs/TransportOutcome"
}, },
"overrun_micro_usd": {
"description": "How far `cost_micro_usd` exceeds what the service reserved for the\nrequest: zero unless the backend reported usage above the worst case\nthe request allowed, which is a breach of the backend's contract. The\ncost is still the true one and the caller's window is charged all of\nit. The service derives this; a backend never writes it.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"provider": { "provider": {
"type": "string" "type": "string"
}, },
@ -352,13 +338,11 @@
"model", "model",
"provider", "provider",
"foreign_reasoning_dropped", "foreign_reasoning_dropped",
"cost_micro_usd",
"overrun_micro_usd",
"outcome" "outcome"
] ]
}, },
"Usage": { "Usage": {
"description": "Token accounting for one request, as the backend reports it; the service\nprices it. Cache reads and writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never priced apart.", "description": "Token accounting for one request, as the backend reports it. Cache reads\nand writes are counted apart from plain input.\n`output_tokens` includes reasoning tokens: `reasoning_tokens` is a detail\n(absent when the provider does not report it) and is never counted apart.",
"type": "object", "type": "object",
"properties": { "properties": {
"cache_read_tokens": { "cache_read_tokens": {

View file

@ -0,0 +1,68 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UsageReadout",
"type": "object",
"properties": {
"at_unix_ms": {
"type": "integer",
"format": "uint64",
"minimum": 0
},
"plan_quota": {
"type": "array",
"items": {
"$ref": "#/$defs/PlanQuota"
}
},
"schema_id": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"schema_id",
"at_unix_ms",
"plan_quota"
],
"$defs": {
"PlanQuota": {
"description": "One window of the subscription plan, as the provider reported it.",
"type": "object",
"properties": {
"observed_at_unix_ms": {
"description": "When this window was last reported. Its age in a readout is the\nreadout's `at_unix_ms` minus this.",
"type": "integer",
"format": "uint64",
"minimum": 0
},
"resets_at_unix_ms": {
"type": "integer",
"format": "uint64",
"minimum": 0
},
"status": {
"type": "string"
},
"utilization_permille": {
"description": "How much of the window was used when it was observed, in thousandths;\n`None` once the window has reset (`status` is then `expired`), because\nthe old reading says nothing about the new window.",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0
},
"window": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"window",
"resets_at_unix_ms",
"status",
"observed_at_unix_ms"
]
}
}
}