feat: migrate protocol and HTTP to structured interface references

T-20: identify interfaces by exact scope/name pairs; add optional opaque scope_ref metadata and separate shape validation from path-dependent scope compatibility. Preserve call error precedence, strict JSON, validators and transport boundaries. Mechanically migrate consumers and document API/wire compatibility and deferred lifecycle semantics.

Validation: cargo fmt --all --check; git diff --check; cargo check --workspace --all-targets; cargo test -p wip-protocol -p wip-http; cargo test --workspace (221 passing tests including doctests); cargo test --workspace --all-targets; nix develop --command cargo clippy --workspace --all-targets -- -D warnings; RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps. All pass. cargo/rustc 1.95.0; development-shell Clippy/rustc 1.97.1.
This commit is contained in:
2026-10-07 18:29:51 +09:00
parent bf5fa54f44
commit 8ecc307fc9
34 changed files with 2124 additions and 263 deletions
+4 -1
View File
@@ -98,6 +98,7 @@ fn real_listener_serves_three_core_interactions_and_write() {
validator: file.validator.clone(),
},
interface: InterfaceTarget {
scope_ref: None,
reference: file.interfaces[0].clone(),
validator: None,
},
@@ -141,6 +142,7 @@ fn real_listener_serves_three_core_interactions_and_write() {
validator: file.validator,
},
interface: InterfaceTarget {
scope_ref: None,
reference: file.interfaces[1].clone(),
validator: None,
},
@@ -412,7 +414,7 @@ fn call_argument_decoding_does_not_mask_missing_target() {
let config = ServerConfig::for_root(temporary.path());
let server = WipFsServer::new(config).expect("build server");
let endpoint = Endpoint::parse("http://localhost/wip").expect("endpoint");
let body = br#"{"target":{"path":"/missing"},"interface":{"reference":"unknown"},"operation":"missing","arguments":{"bytes":"not-base64"}}"#;
let body = br#"{"target":{"path":"/missing"},"interface":{"reference":{"scope":"/","name":"unknown"}},"operation":"missing","arguments":{"bytes":"not-base64"}}"#;
let request = http::Request::builder()
.method(http::Method::POST)
.uri(endpoint.route(Route::CallOperation).as_str())
@@ -490,6 +492,7 @@ fn read_response_size_failure_is_transport_local() {
validator: file.validator,
},
interface: InterfaceTarget {
scope_ref: None,
reference: file.interfaces[0].clone(),
validator: None,
},
+17 -12
View File
@@ -576,7 +576,7 @@ fn observation_and_fetch_policy_panics_remain_sanitized_read_failures() {
let mut registry = InterfaceRegistry::new();
let defaults = DefaultInterfaces::register(&mut registry).unwrap();
let custom = registry.register(MemoryOperationsDefinition, None).unwrap();
let reference = custom.reference().as_str().to_owned();
let reference = custom.reference().protocol_reference();
let engine = Projection::new(
MemoryBackend(fixture.shared.clone()),
registry,
@@ -616,8 +616,8 @@ type Engine = Projection<MemoryBackend, MemoryComposition, Policy>;
struct Fixture {
engine: Engine,
shared: Arc<Shared>,
custom: String,
read: String,
custom: wip_protocol::InterfaceReference,
read: wip_protocol::InterfaceReference,
limits: ResourceLimits,
}
impl Fixture {
@@ -696,8 +696,8 @@ impl Fixture {
limits,
),
shared,
custom: custom_ref.as_str().into(),
read: read_ref.as_str().into(),
custom: custom_ref.protocol_reference(),
read: read_ref.protocol_reference(),
limits,
}
}
@@ -707,7 +707,11 @@ impl Fixture {
.observe(&ExecutionContext::new(), &observe_request(path, depth))
.unwrap()
}
fn descriptor(&self, principal: &Principal, reference: &str) -> InterfaceDescriptor {
fn descriptor(
&self,
principal: &Principal,
reference: &wip_protocol::InterfaceReference,
) -> InterfaceDescriptor {
self.engine
.view(principal)
.fetch_interface(&fetch_request(reference))
@@ -717,7 +721,7 @@ impl Fixture {
fn request(
&self,
path: &str,
reference: &str,
reference: &wip_protocol::InterfaceReference,
operation: &str,
validator: Option<Vec<u8>>,
) -> CallOperationRequest {
@@ -727,7 +731,8 @@ impl Fixture {
validator,
},
interface: InterfaceTarget {
reference: reference.into(),
scope_ref: None,
reference: reference.clone(),
validator: None,
},
operation: operation.into(),
@@ -866,9 +871,9 @@ fn observe_request(path: &str, depth: u32) -> ObserveRequest {
depth,
}
}
fn fetch_request(reference: &str) -> FetchInterfaceRequest {
fn fetch_request(reference: &wip_protocol::InterfaceReference) -> FetchInterfaceRequest {
FetchInterfaceRequest {
interface: reference.into(),
interface: reference.clone(),
}
}
fn success<T: std::fmt::Debug>(response: DecodedResponse<T>) -> T {
@@ -1804,8 +1809,8 @@ fn policy_panics_and_guessed_operation_diagnostics_do_not_leak_to_http() {
// This valid metadata names a nonexistent operation; bypass client-side
// descriptor validation to exercise server diagnostics for untrusted names.
let body = format!(
r#"{{"target":{{"path":"/added"}},"interface":{{"reference":"{}"}},"operation":"{}","arguments":{{}}}}"#,
fixture.custom, POLICY_SECRET
r#"{{"target":{{"path":"/added"}},"interface":{{"reference":{{"scope":"{}","name":"{}"}}}},"operation":"{}","arguments":{{}}}}"#,
fixture.custom.scope, fixture.custom.name, POLICY_SECRET
);
let request = http::Request::builder()
.method(http::Method::POST)