Skip to content

GTS inventory splits when two versions of cf-gears-toolkit-gts are linked #130

Description

@MikeFalcon77

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

  1. 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.
  2. 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.
  3. 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.
  4. If the inventory crate ever needs 2.0, the last 1.x release re-exports the 2.0 types (semver trick).
  5. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions