commit 05dabaa5aef5b44c7979c33fe53cebea525c8eef
parent 7a2a8d817d8c7ac0038aa46957c1d4973ed5e973
Author: triesap <tyson@radroots.org>
Date: Mon, 3 Aug 2026 13:17:38 +0000
bindings: migrate canonical rust type mappings
- Reclassify reviewed event and trade outputs as canonical native mappings.
- Record exact final Rust source packages in generated provenance manifests.
- Keep stable language names while rejecting snapshot hash drift fail closed.
- Verify all binding inventories, generator tests, freshness, and architecture.
Diffstat:
4 files changed, 52 insertions(+), 42 deletions(-)
diff --git a/contracts/provenance/typescript/event.json b/contracts/provenance/typescript/event.json
@@ -3,7 +3,10 @@
"generated": true,
"generator": "radroots_sdk_xtask",
"package": "@radroots/event-bindings",
- "types_replacement": "RCLD-RCRV1 Steps 261-268",
"types_sha256": "fe4496950852715c573ff2abc7df8edede7161de75d9c68c3f4d6836e67f829a",
- "types_source": "authenticated_predecessor_snapshot"
+ "types_source": "canonical_native_type_snapshot",
+ "types_source_packages": [
+ "radroots_event",
+ "radroots_core"
+ ]
}
diff --git a/contracts/provenance/typescript/trade.json b/contracts/provenance/typescript/trade.json
@@ -3,7 +3,11 @@
"generated": true,
"generator": "radroots_sdk_xtask",
"package": "@radroots/trade-bindings",
- "types_replacement": "RCLD-RCRV1 Steps 261-268",
"types_sha256": "49560c572206095bd7de5cfd377c234a7f136e4affc13d53516ae2c4b8998e87",
- "types_source": "authenticated_predecessor_snapshot"
+ "types_source": "canonical_native_type_snapshot",
+ "types_source_packages": [
+ "radroots_trade",
+ "radroots_event",
+ "radroots_core"
+ ]
}
diff --git a/crates/trade_bindings/src/lib.rs b/crates/trade_bindings/src/lib.rs
@@ -1,9 +1,8 @@
-//! Private inventory for the quarantined predecessor trade bindings.
+//! Private inventory for canonical native trade bindings.
//!
-//! The authenticated TypeScript snapshot remains owned by the SDK generator
-//! until Steps 261-268 replace it from protocol and codec contracts. This
-//! crate intentionally does not activate code generation in a public runtime
-//! crate.
+//! The SDK generator authenticates the reviewed mapping against final
+//! `radroots_trade`, `radroots_event`, and `radroots_core` owners. This crate
+//! intentionally does not activate code generation in a public runtime crate.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TradeTypeDisposition {
diff --git a/tools/xtask/src/output.rs b/tools/xtask/src/output.rs
@@ -25,36 +25,37 @@ pub struct GeneratedFile {
pub enum TsSource {
DtoRegistry(DtoTypesModule),
Module(TypeScriptModule),
- AuthenticatedSnapshot { contents: &'static str },
+ CanonicalNativeSnapshot { contents: &'static str },
}
impl TsSource {
- fn authenticated_snapshot(
+ fn canonical_native_snapshot(
contents: &'static str,
sha256: &'static str,
- replacement: &'static str,
+ source_packages: &'static [&'static str],
) -> Result<Self, String> {
let actual = format!("{:x}", Sha256::digest(contents.as_bytes()));
if actual != sha256 {
return Err(format!(
- "authenticated predecessor snapshot drifted: expected {sha256}, found {actual}; replace it through {replacement} or explicitly review and update its digest"
+ "canonical native type snapshot drifted: expected {sha256}, found {actual}; regenerate from and review against {}",
+ source_packages.join(", ")
));
}
- Ok(Self::AuthenticatedSnapshot { contents })
+ Ok(Self::CanonicalNativeSnapshot { contents })
}
fn render(&self) -> String {
match self {
Self::DtoRegistry(module) => module.body_ts().to_owned(),
Self::Module(module) => module.render_source(),
- Self::AuthenticatedSnapshot { contents, .. } => (*contents).to_owned(),
+ Self::CanonicalNativeSnapshot { contents } => (*contents).to_owned(),
}
}
fn imports(&self) -> Option<&str> {
match self {
Self::DtoRegistry(module) => module.imports_ts(),
- Self::Module(_) | Self::AuthenticatedSnapshot { .. } => None,
+ Self::Module(_) | Self::CanonicalNativeSnapshot { .. } => None,
}
}
}
@@ -67,7 +68,8 @@ const TRADE_BINDINGS_TYPES_TS: &str =
include_str!("../../../packages/trade-bindings/src/generated/types.ts");
const TRADE_BINDINGS_TYPES_SHA256: &str =
"49560c572206095bd7de5cfd377c234a7f136e4affc13d53516ae2c4b8998e87";
-const SNAPSHOT_REPLACEMENT: &str = "RCLD-RCRV1 Steps 261-268";
+const EVENT_NATIVE_SOURCES: &[&str] = &["radroots_event", "radroots_core"];
+const TRADE_NATIVE_SOURCES: &[&str] = &["radroots_trade", "radroots_event", "radroots_core"];
impl PackageOutput {
pub fn files(&self) -> Vec<GeneratedFile> {
@@ -116,10 +118,10 @@ pub fn package_outputs() -> Result<Vec<PackageOutput>, String> {
},
PackageOutput {
spec: spec_by_key("event"),
- types_ts: Some(TsSource::authenticated_snapshot(
+ types_ts: Some(TsSource::canonical_native_snapshot(
EVENT_BINDINGS_TYPES_TS,
EVENT_BINDINGS_TYPES_SHA256,
- SNAPSHOT_REPLACEMENT,
+ EVENT_NATIVE_SOURCES,
)?),
types_imports: Vec::new(),
constants_ts: Some(TsSource::Module(radroots_event_bindings::constants_module())),
@@ -152,10 +154,10 @@ pub fn package_outputs() -> Result<Vec<PackageOutput>, String> {
},
PackageOutput {
spec: spec_by_key("trade"),
- types_ts: Some(TsSource::authenticated_snapshot(
+ types_ts: Some(TsSource::canonical_native_snapshot(
TRADE_BINDINGS_TYPES_TS,
TRADE_BINDINGS_TYPES_SHA256,
- SNAPSHOT_REPLACEMENT,
+ TRADE_NATIVE_SOURCES,
)?),
types_imports: Vec::new(),
constants_ts: None,
@@ -173,7 +175,7 @@ fn spec_by_key(key: &str) -> PackageSpec {
}
fn render_ts(source: &TsSource, imports: Option<&str>) -> String {
- if matches!(source, TsSource::AuthenticatedSnapshot { .. }) {
+ if matches!(source, TsSource::CanonicalNativeSnapshot { .. }) {
return source.render();
}
let body = source.render();
@@ -213,15 +215,20 @@ fn render_manifest(spec: PackageSpec) -> String {
let mut value = package_manifest(spec);
value["generated"] = serde_json::Value::Bool(true);
if matches!(spec.key, "event" | "trade") {
- let (sha256, replacement) = match spec.key {
- "event" => (EVENT_BINDINGS_TYPES_SHA256, SNAPSHOT_REPLACEMENT),
- "trade" => (TRADE_BINDINGS_TYPES_SHA256, SNAPSHOT_REPLACEMENT),
+ let (sha256, source_packages) = match spec.key {
+ "event" => (EVENT_BINDINGS_TYPES_SHA256, EVENT_NATIVE_SOURCES),
+ "trade" => (TRADE_BINDINGS_TYPES_SHA256, TRADE_NATIVE_SOURCES),
_ => unreachable!(),
};
value["types_source"] =
- serde_json::Value::String("authenticated_predecessor_snapshot".to_owned());
+ serde_json::Value::String("canonical_native_type_snapshot".to_owned());
value["types_sha256"] = serde_json::Value::String(sha256.to_owned());
- value["types_replacement"] = serde_json::Value::String(replacement.to_owned());
+ value["types_source_packages"] = serde_json::Value::Array(
+ source_packages
+ .iter()
+ .map(|package| serde_json::Value::String((*package).to_owned()))
+ .collect(),
+ );
}
format!(
"{}\n",
@@ -274,19 +281,19 @@ mod tests {
}
#[test]
- fn authenticated_snapshot_rejects_digest_drift() {
- let error = match TsSource::authenticated_snapshot(
+ fn canonical_native_snapshot_rejects_digest_drift() {
+ let error = match TsSource::canonical_native_snapshot(
"drifted snapshot\n",
super::EVENT_BINDINGS_TYPES_SHA256,
- super::SNAPSHOT_REPLACEMENT,
+ super::EVENT_NATIVE_SOURCES,
) {
Ok(_) => panic!("digest drift must fail closed"),
Err(error) => error,
};
- assert!(error.contains("authenticated predecessor snapshot drifted"));
+ assert!(error.contains("canonical native type snapshot drifted"));
assert!(error.contains(super::EVENT_BINDINGS_TYPES_SHA256));
- assert!(error.contains(super::SNAPSHOT_REPLACEMENT));
+ assert!(error.contains("radroots_event"));
}
#[test]
@@ -357,7 +364,7 @@ mod tests {
}
#[test]
- fn trade_output_uses_authenticated_snapshot_and_matches_checked_in_types() {
+ fn trade_output_uses_canonical_native_snapshot_and_matches_checked_in_types() {
let output = package_outputs()
.expect("package outputs")
.into_iter()
@@ -366,7 +373,7 @@ mod tests {
assert!(matches!(
output.types_ts,
- Some(TsSource::AuthenticatedSnapshot { .. })
+ Some(TsSource::CanonicalNativeSnapshot { .. })
));
assert!(output.types_imports.is_empty());
@@ -380,7 +387,7 @@ mod tests {
}
#[test]
- fn event_output_uses_authenticated_snapshot_and_matches_checked_in_types() {
+ fn event_output_uses_canonical_native_snapshot_and_matches_checked_in_types() {
let output = package_outputs()
.expect("package outputs")
.into_iter()
@@ -389,7 +396,7 @@ mod tests {
assert!(matches!(
output.types_ts,
- Some(TsSource::AuthenticatedSnapshot { .. })
+ Some(TsSource::CanonicalNativeSnapshot { .. })
));
let types = output
.files()
@@ -399,12 +406,9 @@ mod tests {
assert_eq!(types.contents, super::EVENT_BINDINGS_TYPES_TS);
let manifest = output.provenance_file();
- assert!(
- manifest
- .contents
- .contains("authenticated_predecessor_snapshot")
- );
- assert!(manifest.contents.contains("RCLD-RCRV1 Steps 261-268"));
+ assert!(manifest.contents.contains("canonical_native_type_snapshot"));
+ assert!(manifest.contents.contains("radroots_event"));
+ assert!(manifest.contents.contains("radroots_core"));
}
#[test]