commit 67fc0bf8adf131904f70c6cd45e115b734bd9932
parent f54dd5d07226bfd8d704690df0d489103a036134
Author: triesap <tyson@radroots.org>
Date: Wed, 24 Jun 2026 06:25:52 +0000
dto: add explicit source root sets
Diffstat:
4 files changed, 173 insertions(+), 0 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -1674,6 +1674,7 @@ dependencies = [
name = "radroots_core"
version = "0.1.0-alpha.2"
dependencies = [
+ "dto_bindgen_core",
"rust_decimal",
"rust_decimal_macros",
"serde",
@@ -1703,6 +1704,7 @@ dependencies = [
name = "radroots_events"
version = "0.1.0-alpha.2"
dependencies = [
+ "dto_bindgen_core",
"hex",
"radroots_core",
"serde",
@@ -2046,7 +2048,9 @@ name = "radroots_sdk_xtask"
version = "0.1.0"
dependencies = [
"dto_bindgen_core",
+ "radroots_core",
"radroots_core_bindings",
+ "radroots_events",
"radroots_events_bindings",
"radroots_events_indexed_bindings",
"radroots_identity_bindings",
diff --git a/tools/xtask/Cargo.toml b/tools/xtask/Cargo.toml
@@ -15,7 +15,9 @@ path = "src/main.rs"
[dependencies]
dto_bindgen_core = { workspace = true }
radroots_sdk_binding_model = { path = "../../crates/binding_model" }
+radroots_core = { workspace = true, features = ["dto-bindgen"] }
radroots_core_bindings = { path = "../../crates/core_bindings" }
+radroots_events = { workspace = true, features = ["dto-bindgen"] }
radroots_events_bindings = { path = "../../crates/events_bindings" }
radroots_events_indexed_bindings = { path = "../../crates/events_indexed_bindings" }
radroots_identity_bindings = { path = "../../crates/identity_bindings" }
diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs
@@ -0,0 +1,165 @@
+use dto_bindgen_core::{Registry, RootDescriptor, build_registry};
+
+#[derive(Clone, Copy, Debug)]
+pub struct DtoPackageRootSet {
+ pub package_key: &'static str,
+ roots: fn() -> Vec<RootDescriptor>,
+}
+
+impl DtoPackageRootSet {
+ pub fn roots(&self) -> Vec<RootDescriptor> {
+ (self.roots)()
+ }
+
+ pub fn registry(&self) -> Registry {
+ build_registry(self.roots())
+ }
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct ManualDescriptorFamily {
+ pub package_key: &'static str,
+ pub source_family: &'static str,
+ pub reason: &'static str,
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct SdkLocalWrapperAllowance {
+ pub package_key: &'static str,
+ pub shape_family: &'static str,
+ pub reason: &'static str,
+}
+
+pub const DTO_PACKAGE_ROOTS: &[DtoPackageRootSet] = &[
+ DtoPackageRootSet {
+ package_key: "core",
+ roots: core_roots,
+ },
+ DtoPackageRootSet {
+ package_key: "events",
+ roots: events_roots,
+ },
+];
+
+pub const MANUAL_DESCRIPTOR_FAMILIES: &[ManualDescriptorFamily] = &[
+ ManualDescriptorFamily {
+ package_key: "core",
+ source_family: "decimal, currency, money, quantity, percent, quantity price, unit, and discount value families",
+ reason: "custom serde, string-backed newtypes, aliases, and tagged enum wire forms require source-owned manual descriptors",
+ },
+ ManualDescriptorFamily {
+ package_key: "events",
+ source_family: "event timestamps, counters, and optional metadata fields",
+ reason: "large integers and source-specific optional/null policy must be explicit",
+ },
+ ManualDescriptorFamily {
+ package_key: "events",
+ source_family: "GeoJSON coordinate arrays",
+ reason: "fixed-size Rust arrays must preserve tuple semantics in TypeScript",
+ },
+ ManualDescriptorFamily {
+ package_key: "events_indexed",
+ source_family: "checkpoint and index cursor fields",
+ reason: "custom deserialization and large integers require manual descriptor policy",
+ },
+ ManualDescriptorFamily {
+ package_key: "replica_db_schema",
+ source_family: "untagged query wrappers and serde_json value fields",
+ reason: "schema query shapes are generated and not all source fields map to derive-supported DTOs",
+ },
+ ManualDescriptorFamily {
+ package_key: "types",
+ source_family: "generic result wrapper types",
+ reason: "generic export instantiations must be explicit and package-scoped",
+ },
+];
+
+pub const SDK_LOCAL_WRAPPER_ALLOWANCES: &[SdkLocalWrapperAllowance] = &[
+ SdkLocalWrapperAllowance {
+ package_key: "core",
+ shape_family: "RadrootsCoreCurrency and RadrootsCoreDecimal package aliases",
+ reason: "source descriptors correctly describe fields as strings, while package roots still need stable named TypeScript aliases",
+ },
+ SdkLocalWrapperAllowance {
+ package_key: "replica_db_schema",
+ shape_family: "generated query argument wrappers",
+ reason: "schema operation inputs are generated package shapes rather than source-owned public DTO structs",
+ },
+ SdkLocalWrapperAllowance {
+ package_key: "types",
+ shape_family: "IResult, IResultList, and IResultPass generic envelopes",
+ reason: "generic helper envelopes are SDK package contracts used across generated schema packages",
+ },
+ SdkLocalWrapperAllowance {
+ package_key: "events_indexed",
+ shape_family: "index query result helpers",
+ reason: "indexed package helpers represent SDK query projections rather than source-owned wire events",
+ },
+];
+
+pub fn package_root_set(package_key: &str) -> Option<&'static DtoPackageRootSet> {
+ DTO_PACKAGE_ROOTS
+ .iter()
+ .find(|root_set| root_set.package_key == package_key)
+}
+
+fn core_roots() -> Vec<RootDescriptor> {
+ radroots_core::dto::dto_roots().into_iter().collect()
+}
+
+fn events_roots() -> Vec<RootDescriptor> {
+ radroots_events::dto::dto_roots().into_iter().collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{
+ DTO_PACKAGE_ROOTS, MANUAL_DESCRIPTOR_FAMILIES, SDK_LOCAL_WRAPPER_ALLOWANCES,
+ package_root_set,
+ };
+
+ #[test]
+ fn approved_source_roots_build_registries() {
+ for root_set in DTO_PACKAGE_ROOTS {
+ let registry = root_set.registry();
+ assert!(
+ !registry.has_errors(),
+ "registry for {} has diagnostics: {:?}",
+ root_set.package_key,
+ registry.diagnostics
+ );
+ assert!(!registry.roots.is_empty());
+ }
+ }
+
+ #[test]
+ fn package_roots_are_explicit_not_discovered() {
+ assert!(package_root_set("core").is_some());
+ assert!(package_root_set("events").is_some());
+ assert!(package_root_set("trade").is_none());
+ }
+
+ #[test]
+ fn manual_descriptor_catalog_covers_known_review_families() {
+ assert!(
+ MANUAL_DESCRIPTOR_FAMILIES
+ .iter()
+ .any(|family| family.source_family.contains("GeoJSON"))
+ );
+ assert!(
+ MANUAL_DESCRIPTOR_FAMILIES
+ .iter()
+ .any(|family| family.source_family.contains("generic result"))
+ );
+ assert!(
+ SDK_LOCAL_WRAPPER_ALLOWANCES
+ .iter()
+ .any(|allowance| allowance.shape_family.contains("RadrootsCoreDecimal"))
+ );
+ assert!(
+ SDK_LOCAL_WRAPPER_ALLOWANCES
+ .iter()
+ .any(|allowance| allowance.shape_family.contains("IResult"))
+ );
+ }
+}
diff --git a/tools/xtask/src/main.rs b/tools/xtask/src/main.rs
@@ -4,6 +4,8 @@ mod coverage;
mod coverage_policy;
#[allow(dead_code)]
mod dto_render;
+#[allow(dead_code)]
+mod dto_roots;
mod fs;
mod generate;
mod manifest;