types-registry seeds itself from the link-time inventory declared in toolkit-gts. If a process links two semver-incompatible versions of that crate, types and instances declared against the other version never reach types-registry. Nothing fails at compile time or during init.
How registration works now
#[gts_type_schema], gts_instance! and gts_instance_raw! (libs/toolkit-gts-macros) wrap the upstream gts-macros macros and add an inventory::submit! of toolkit_gts::InventoryTypeSchema or toolkit_gts::InventoryInstance.
- Both collectors are declared in
libs/toolkit-gts/src/lib.rs. The entries hold only strings and JSON: type_id, instance_id, schema_fn: fn() -> String, payload_fn: fn() -> serde_json::Value.
- During init, types-registry calls
all_inventory_type_schemas() and all_inventory_instances() and registers whatever they return. It logs the counts at debug level and doesn't compare them against an expected set.
The problem
An inventory registry is keyed by the entry type. toolkit_gts::InventoryTypeSchema from 0.1 and from 0.2 are different types with separate registries. types-registry iterates only the one from the version it was built with.
Example: a gear published against cf-gears-toolkit-gts 0.1 is built into a host whose types-registry uses 0.2. Cargo links both versions. The gear's submit! calls compile and land in the 0.1 registry. types-registry never sees them and starts normally. The gear's types are missing from the registry as if they were never declared.
Cargo unifies semver-compatible versions (0.1.4 and 0.1.6), so patch releases are safe. Every 0.x minor bump splits the registry.
cf-gears-toolkit-gts will get such bumps for reasons unrelated to the inventory:
- Its public API re-exports
gts items (GtsId, GtsInstanceId, GtsSchema, GtsTraitsSchema), and its base types PluginV1 and AuthzPermissionV1 are built with gts-macros. Moving from gts 0.12 to 0.13 is a breaking change for it.
- A breaking change to
PluginV1, AuthzPermissionV1 or the wrapper macros has the same effect.
Registrator (libs/toolkit/src/registry.rs) and ConsumerRegistration (libs/toolkit/src/discovery.rs) in cf-gears-toolkit use the same pattern. This issue covers only the GTS inventory.
Proposal
- Move
InventoryTypeSchema, InventoryInstance and both inventory::collect! calls into a new crate (working name cf-gears-toolkit-gts-inventory). It depends only on inventory and serde_json: no gts, no base types, no macros. Release it as 1.0.
cf-gears-toolkit-gts re-exports the entry types from it. The macros keep emitting toolkit_gts::InventoryTypeSchema paths, so no call sites change. all_inventory_* can stay in cf-gears-toolkit-gts, since any version of it now iterates the same registry.
- Release a 0.1.x patch of
cf-gears-toolkit-gts with the re-export. Gears still on 0.1 join the shared registry after cargo update. Gears pinned to 0.1.6 or earlier stay split.
- If the inventory crate ever needs 2.0, the last 1.x release re-exports the 2.0 types (semver trick).
- Add
multiple-versions = "deny" for the inventory crate to cargo deny, both in gears-rust and in anything that assembles hosts from published gears.
Open questions
- Should types-registry fail init when an expected type is missing? It can't read another version's registry, so it would need the expected ids from somewhere else (config or gear metadata). That would also catch lost registrations with other causes.
- Check whether ready-mode dependency validation already catches a missing type that another registered schema references by
$ref. A leaf type that nothing references would still go unnoticed.
- Whether
Registrator and ConsumerRegistration need the same split in cf-gears-toolkit.
types-registry seeds itself from the link-time inventory declared in toolkit-gts. If a process links two semver-incompatible versions of that crate, types and instances declared against the other version never reach types-registry. Nothing fails at compile time or during init.
How registration works now
#[gts_type_schema],gts_instance!andgts_instance_raw!(libs/toolkit-gts-macros) wrap the upstreamgts-macrosmacros and add aninventory::submit!oftoolkit_gts::InventoryTypeSchemaortoolkit_gts::InventoryInstance.libs/toolkit-gts/src/lib.rs. The entries hold only strings and JSON:type_id,instance_id,schema_fn: fn() -> String,payload_fn: fn() -> serde_json::Value.all_inventory_type_schemas()andall_inventory_instances()and registers whatever they return. It logs the counts at debug level and doesn't compare them against an expected set.The problem
An
inventoryregistry is keyed by the entry type.toolkit_gts::InventoryTypeSchemafrom 0.1 and from 0.2 are different types with separate registries. types-registry iterates only the one from the version it was built with.Example: a gear published against
cf-gears-toolkit-gts0.1 is built into a host whose types-registry uses 0.2. Cargo links both versions. The gear'ssubmit!calls compile and land in the 0.1 registry. types-registry never sees them and starts normally. The gear's types are missing from the registry as if they were never declared.Cargo unifies semver-compatible versions (0.1.4 and 0.1.6), so patch releases are safe. Every 0.x minor bump splits the registry.
cf-gears-toolkit-gtswill get such bumps for reasons unrelated to the inventory:gtsitems (GtsId,GtsInstanceId,GtsSchema,GtsTraitsSchema), and its base typesPluginV1andAuthzPermissionV1are built withgts-macros. Moving fromgts0.12 to 0.13 is a breaking change for it.PluginV1,AuthzPermissionV1or the wrapper macros has the same effect.Registrator(libs/toolkit/src/registry.rs) andConsumerRegistration(libs/toolkit/src/discovery.rs) incf-gears-toolkituse the same pattern. This issue covers only the GTS inventory.Proposal
InventoryTypeSchema,InventoryInstanceand bothinventory::collect!calls into a new crate (working namecf-gears-toolkit-gts-inventory). It depends only oninventoryandserde_json: nogts, no base types, no macros. Release it as 1.0.cf-gears-toolkit-gtsre-exports the entry types from it. The macros keep emittingtoolkit_gts::InventoryTypeSchemapaths, so no call sites change.all_inventory_*can stay incf-gears-toolkit-gts, since any version of it now iterates the same registry.cf-gears-toolkit-gtswith the re-export. Gears still on 0.1 join the shared registry aftercargo update. Gears pinned to 0.1.6 or earlier stay split.multiple-versions = "deny"for the inventory crate tocargo deny, both in gears-rust and in anything that assembles hosts from published gears.Open questions
$ref. A leaf type that nothing references would still go unnoticed.RegistratorandConsumerRegistrationneed the same split incf-gears-toolkit.