lease_client: vendor the connector lease_v2 byte goldens (ModelConnector c1802d8) and pin the kit to that merged commit

The client decodes every published refusal and the grant and encodes the request
and each message back to the same bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-31 05:41:33 +01:00
commit bd5a50e1d3
10 changed files with 62 additions and 3 deletions

2
Cargo.lock generated
View file

@ -1156,7 +1156,7 @@ dependencies = [
[[package]]
name = "model-connector"
version = "0.1.0"
source = "git+https://eureka.gamecult.org/forge/GameCult/ModelConnector.git?rev=9db62027eb1e6a2f7a47fdfb3cb5f118c5b96da7#9db62027eb1e6a2f7a47fdfb3cb5f118c5b96da7"
source = "git+https://eureka.gamecult.org/forge/GameCult/ModelConnector.git?rev=c1802d85bee3ae04b0c5737563c8343c1fef515d#c1802d85bee3ae04b0c5737563c8343c1fef515d"
dependencies = [
"aes-gcm",
"base64",

View file

@ -33,7 +33,7 @@ cultnet-rs.workspace = true
eureka-pipeline = { path = "../eureka-pipeline" }
eureka-state = { path = "../eureka-state", default-features = false }
huginn-mind = { path = "../huginn-mind" }
model-connector = { git = "https://eureka.gamecult.org/forge/GameCult/ModelConnector.git", rev = "9db62027eb1e6a2f7a47fdfb3cb5f118c5b96da7", package = "model-connector" }
model-connector = { git = "https://eureka.gamecult.org/forge/GameCult/ModelConnector.git", rev = "c1802d85bee3ae04b0c5737563c8343c1fef515d", package = "model-connector" }
rmp-serde = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@ -53,7 +53,7 @@ rustix = { version = "1", default-features = false, features = ["std", "net"] }
[dev-dependencies]
# The kit's serve loop and service, for the test that runs the connector client
# against the real server with a fake provider behind it.
model-connector = { git = "https://eureka.gamecult.org/forge/GameCult/ModelConnector.git", rev = "9db62027eb1e6a2f7a47fdfb3cb5f118c5b96da7", package = "model-connector", features = ["daemon"] }
model-connector = { git = "https://eureka.gamecult.org/forge/GameCult/ModelConnector.git", rev = "c1802d85bee3ae04b0c5737563c8343c1fef515d", package = "model-connector", features = ["daemon"] }
proc-macro2 = "1"
quote = "1"
syn = { version = "2", features = ["full"] }

View file

@ -0,0 +1,16 @@
# lease_v2 fixtures
The exact bytes of the claude lease protocol v2: each file is one whole frame (a u32
big-endian length, then the named-MessagePack map `{kind, value}`).
- `request.bin`: `claude_lease_request`.
- `refusal_unknown_caller.bin`, `refusal_expired.bin`, `refusal_busy.bin`,
`refusal_provider_rejected.bin`: `claude_lease_refusal`; `kind` is the variant name as a
PascalCase string.
- `grant.bin`: `claude_lease_grant` with `lease_id` and `plan_quota` carrying `five_hour` and
`seven_day` windows (utilization_permille, resets_at_unix_ms, status, observed_at_unix_ms).
On the wire the grant travels with one SCM_RIGHTS fd; the file holds the frame only.
Huginn's lease client vendors these files from this repository and tests against the same
bytes. Generator: `tests/lease_wire_golden.rs`; run it with `LEASE_V2_REGENERATE=1`, then
review the diff: a changed byte is a wire change.

Binary file not shown.

Binary file not shown.

View file

@ -259,3 +259,46 @@ mod socket_wire {
served.join().unwrap();
}
}
/// The connector published bytes of lease v2, vendored under `lease_v2/` from
/// ModelConnector `c1802d8` (`crates/claude-connector/tests/fixtures/lease_v2`).
/// The client decodes every one of them and encodes each back to the same bytes.
mod connector_goldens {
use super::*;
const REQUEST: &[u8] = include_bytes!("lease_v2/request.bin");
const GRANT: &[u8] = include_bytes!("lease_v2/grant.bin");
const REFUSALS: [(&[u8], LeaseRefusalKind); 4] = [
(include_bytes!("lease_v2/refusal_unknown_caller.bin"), LeaseRefusalKind::UnknownCaller),
(include_bytes!("lease_v2/refusal_expired.bin"), LeaseRefusalKind::Expired),
(include_bytes!("lease_v2/refusal_busy.bin"), LeaseRefusalKind::Busy),
(include_bytes!("lease_v2/refusal_provider_rejected.bin"), LeaseRefusalKind::ProviderRejected),
];
#[test]
fn the_request_encodes_to_exactly_the_published_bytes() {
let Some(LeaseMessage::Request(request)) = decode_frame(REQUEST) else { panic!("request.bin is a request") };
assert_eq!(request.expires_at_unix_ms, 0x0000_01a1_896d_3cc0);
assert_eq!(encode_frame(&LeaseMessage::Request(LeaseRequest { expires_at_unix_ms: 0x0000_01a1_896d_3cc0 })).unwrap(), REQUEST);
}
#[test]
fn every_published_refusal_decodes_to_its_kind_and_encodes_back_to_its_bytes() {
for (bytes, kind) in REFUSALS {
let message = decode_frame(bytes).unwrap_or_else(|| panic!("{kind:?} decodes"));
let LeaseMessage::Refusal(refused) = &message else { panic!("{kind:?}: a refusal") };
assert_eq!(refused.kind, kind);
assert_eq!(encode_frame(&message).unwrap(), bytes, "{kind:?} re-encodes to the connector bytes");
}
}
#[test]
fn the_published_grant_decodes_with_both_plan_windows_and_encodes_back_to_its_bytes() {
let message = decode_frame(GRANT).expect("grant.bin decodes");
let LeaseMessage::Grant(grant) = &message else { panic!("a grant") };
assert!(!grant.lease_id.is_empty());
let windows: Vec<&str> = grant.plan_quota.iter().map(|plan| plan.window.as_str()).collect();
assert_eq!(windows, ["five_hour", "seven_day"]);
assert_eq!(encode_frame(&message).unwrap(), GRANT);
}
}