Submit an issue View all issues Source
MIR-942

Schemagen: support shared/named enum types to eliminate cross-schema enum conversion bugs

In Progress public
phinze phinze Opened Mar 31, 2026 Updated Sep 1, 2026

Context

MIR-940 exposed a class of bug where the same semantic enum (disk provider: miren | local) is defined inline in two schema paths, causing schemagen to generate two separate Go types with different string constant values:

  • DisksProvider with value "provider.miren"
  • ConfigSpecServicesDisksProvider with value "component.config_spec.services.disks.provider.miren"

Go happily allows type conversion between them since they're both string underneath, but the values silently mismatch. We hit this bug in three separate places across two PRs (#713, #714) before fully fixing it — each boundary between schema layers required a hand-written switch to map between representations.

Proposal

Add support for named, reusable enum definitions in schema YAML:

enums:
  disk_provider:
    choices: [miren, local]
    doc: "Disk provider: 'miren' for network disks, 'local' for node-local"

kinds:
  config_spec:
    services:
      disks:
        provider:
          type: enum
          ref: disk_provider

Schemagen would generate one Go type per named enum, with the semantic values as constants ("miren", "local") rather than path-prefixed strings. The Encode()/Decode() functions would bridge between the shared Go constants and the per-path entity store IDs.

This eliminates the entire class of bug — there's one type, one set of values, and the compiler enforces consistency across schema boundaries.

Migration considerations

  • Entity store data: No change. The fully-qualified entity IDs in etcd stay the same — Encode()/Decode() just map differently.
  • Rolling deploys: Safe, since Decode() maps from entity IDs (unchanged) to Go constants (new values). Old and new code read the same stored data.
  • Code churn: One-shot make generate + fix compile errors. Mechanical but potentially noisy.
  • Wire format: Audit whether any RPC messages serialize Go enum values directly (not via entity store). If so, those would see different on-wire strings during the transition.

References

  • MIR-940 / PR #713 / PR #714 — the bug that motivated this
  • pkg/entity/cmd/schemagen/generator.go lines 636-675 — current enum generation logic
  • api/core/schema.yml — the two inline disk provider enum definitions