commit beb99b13e992af5593e0255a7229a1a0c09a498b
parent ca443903b9cfbaba3f97ec3826f44a3982075553
Author: triesap <tyson@radroots.org>
Date: Wed, 24 Jun 2026 07:05:52 +0000
dto: guard events registry migration inputs
- inventory current events binding type exports in xtask tests
- verify event inventory against committed package output
- cover integer policy propagation through transparent containers
- validate targeted SDK dto registry tests
Diffstat:
2 files changed, 184 insertions(+), 0 deletions(-)
diff --git a/tools/xtask/src/dto_render.rs b/tools/xtask/src/dto_render.rs
@@ -647,4 +647,72 @@ mod tests {
"large integer field requires explicit numeric policy"
);
}
+
+ #[test]
+ fn propagates_integer_policy_through_transparent_containers_only() {
+ let mut registry = Registry::new();
+ let counter_id = registry.register_type(
+ RustTypeId::new("sdk", "Counter"),
+ TypeDef::Struct(
+ StructDef::new("Counter", "Counter", span()).with_field(
+ field("value", "value", TypeRef::Primitive(Primitive::U64))
+ .with_int_repr(IntRepr::JsonNumberUnsafe),
+ ),
+ ),
+ );
+ registry.register_type(
+ RustTypeId::new("sdk", "TransparentCounters"),
+ TypeDef::Struct(
+ StructDef::new("TransparentCounters", "TransparentCounters", span())
+ .with_field(
+ field(
+ "maybe_count",
+ "maybeCount",
+ TypeRef::option(TypeRef::Primitive(Primitive::U64)),
+ )
+ .with_presence(FieldPresence::optional_nullable())
+ .with_int_repr(IntRepr::JsonString),
+ )
+ .with_field(
+ field(
+ "count_list",
+ "countList",
+ TypeRef::vec(TypeRef::Primitive(Primitive::U64)),
+ )
+ .with_int_repr(IntRepr::JsonString),
+ )
+ .with_field(
+ field(
+ "fixed_counts",
+ "fixedCounts",
+ TypeRef::array(TypeRef::Primitive(Primitive::U64), 2),
+ )
+ .with_int_repr(IntRepr::JsonString),
+ )
+ .with_field(
+ field(
+ "by_key",
+ "byKey",
+ TypeRef::Map {
+ key: Box::new(TypeRef::String),
+ value: Box::new(TypeRef::Primitive(Primitive::U64)),
+ },
+ )
+ .with_int_repr(IntRepr::JsonString),
+ )
+ .with_field(
+ field("named_counter", "namedCounter", TypeRef::Named(counter_id))
+ .with_int_repr(IntRepr::JsonString),
+ ),
+ ),
+ );
+
+ let rendered = render_registry_types(®istry, &DtoRegistryRenderOptions::default())
+ .expect("registry renders");
+
+ assert_eq!(
+ rendered.body_ts(),
+ "export type Counter = { value: number, };\n\nexport type TransparentCounters = { maybeCount?: string | null, countList: Array<string>, fixedCounts: [string, string], byKey: Record<string, string>, namedCounter: Counter, };"
+ );
+ }
}
diff --git a/tools/xtask/src/dto_roots.rs b/tools/xtask/src/dto_roots.rs
@@ -133,6 +133,111 @@ mod tests {
package_root_set,
};
+ const EVENTS_BINDINGS_TYPES_TS: &str =
+ include_str!("../../../packages/events-bindings/src/generated/types.ts");
+ const EVENTS_TYPE_INVENTORY: &[&str] = &[
+ "JobFeedbackStatus",
+ "JobInputType",
+ "JobPaymentRequest",
+ "RadrootsAccountClaim",
+ "RadrootsActiveTradeEnvelope",
+ "RadrootsActiveTradeMessageType",
+ "RadrootsAppData",
+ "RadrootsComment",
+ "RadrootsCoop",
+ "RadrootsCoopLocation",
+ "RadrootsCoopRef",
+ "RadrootsDocument",
+ "RadrootsDocumentSubject",
+ "RadrootsFarm",
+ "RadrootsFarmLocation",
+ "RadrootsFarmRef",
+ "RadrootsFollow",
+ "RadrootsFollowProfile",
+ "RadrootsGcsLocation",
+ "RadrootsGeoChat",
+ "RadrootsGeoJsonPoint",
+ "RadrootsGeoJsonPolygon",
+ "RadrootsGiftWrap",
+ "RadrootsGiftWrapRecipient",
+ "RadrootsJobFeedback",
+ "RadrootsJobInput",
+ "RadrootsJobParam",
+ "RadrootsJobRequest",
+ "RadrootsJobResult",
+ "RadrootsList",
+ "RadrootsListEntry",
+ "RadrootsListSet",
+ "RadrootsListing",
+ "RadrootsListingAvailability",
+ "RadrootsListingBin",
+ "RadrootsListingDeliveryMethod",
+ "RadrootsListingImage",
+ "RadrootsListingImageSize",
+ "RadrootsListingLocation",
+ "RadrootsListingProduct",
+ "RadrootsListingProductTagKeys",
+ "RadrootsListingStatus",
+ "RadrootsMessage",
+ "RadrootsMessageFile",
+ "RadrootsMessageFileDimensions",
+ "RadrootsMessageRecipient",
+ "RadrootsNostrEvent",
+ "RadrootsNostrEventPtr",
+ "RadrootsNostrEventRef",
+ "RadrootsPlot",
+ "RadrootsPlotLocation",
+ "RadrootsPlotRef",
+ "RadrootsPost",
+ "RadrootsProfile",
+ "RadrootsProfileType",
+ "RadrootsReaction",
+ "RadrootsRelayDocument",
+ "RadrootsResourceArea",
+ "RadrootsResourceAreaLocation",
+ "RadrootsResourceAreaRef",
+ "RadrootsResourceHarvestCap",
+ "RadrootsResourceHarvestProduct",
+ "RadrootsSeal",
+ "RadrootsTradeAnswer",
+ "RadrootsTradeDiscountDecision",
+ "RadrootsTradeDiscountOffer",
+ "RadrootsTradeDiscountRequest",
+ "RadrootsTradeDomain",
+ "RadrootsTradeEconomicActor",
+ "RadrootsTradeEconomicEffect",
+ "RadrootsTradeEconomicLineKind",
+ "RadrootsTradeEnvelope",
+ "RadrootsTradeInventoryCommitment",
+ "RadrootsTradeListingCancel",
+ "RadrootsTradeListingParseError",
+ "RadrootsTradeListingValidateRequest",
+ "RadrootsTradeListingValidateResult",
+ "RadrootsTradeListingValidationError",
+ "RadrootsTradeMessagePayload",
+ "RadrootsTradeMessageType",
+ "RadrootsTradeOrderCancelled",
+ "RadrootsTradeOrderChange",
+ "RadrootsTradeOrderDecision",
+ "RadrootsTradeOrderDecisionEvent",
+ "RadrootsTradeOrderEconomicItem",
+ "RadrootsTradeOrderEconomicLine",
+ "RadrootsTradeOrderEconomicTotals",
+ "RadrootsTradeOrderEconomics",
+ "RadrootsTradeOrderItem",
+ "RadrootsTradeOrderRequested",
+ "RadrootsTradeOrderResponse",
+ "RadrootsTradeOrderRevision",
+ "RadrootsTradeOrderRevisionDecision",
+ "RadrootsTradeOrderRevisionDecisionEvent",
+ "RadrootsTradeOrderRevisionProposed",
+ "RadrootsTradeOrderRevisionResponse",
+ "RadrootsTradeOrderStatus",
+ "RadrootsTradePricingBasis",
+ "RadrootsTradeQuestion",
+ "RadrootsTradeTransportLane",
+ ];
+
#[test]
fn approved_source_roots_build_registries() {
for root_set in DTO_PACKAGE_ROOTS {
@@ -177,4 +282,15 @@ mod tests {
.any(|allowance| allowance.shape_family.contains("IResult"))
);
}
+
+ #[test]
+ fn events_type_inventory_matches_current_package_surface() {
+ let actual = EVENTS_BINDINGS_TYPES_TS
+ .lines()
+ .filter_map(|line| line.strip_prefix("export type "))
+ .map(|rest| rest.split([' ', '<']).next().expect("type name"))
+ .collect::<Vec<_>>();
+
+ assert_eq!(actual, EVENTS_TYPE_INVENTORY);
+ }
}