OvertureMaps / OvertureMaps/schema

[BUG](codegen) Union- or model-rooted RootModel entry points miscompile as scalar aliases

Open
#595 0 comments 0 reactions 1 assignee View on GitHub

@sethfitz is already working on this.

Since Jul 23, 2026.

Dominant language
Python
Stars
213
Forks
22
Avg merge
3d 3h
Merged PRs (30d)
31

Description

Summary

The #593 fix routes every RootModel entry point through the alias path: extract_model_spec returns None for any RootModel, and extract_alias_spec documents it as a NewTypeSpec over its bare root shape. That is correct only when the root is a scalar (or plain container). A RootModel whose root is a discriminated union or a model -- a valid Pydantic shape, RootModel[Annotated[Union[...], Field(discriminator=...)]] -- is silently miscompiled: it documents as a scalar type alias and is skipped from expression generation, when it should generate as a union (per-arm markdown, per-arm PySpark checks) exactly as the bare Annotated[Union] alias does today. There is no error; the output is just wrong.

Why it is latent

The Overture schema declares no union- or model-rooted RootModel entry points today, so nothing currently triggers this. It becomes a live defect the moment such a shape appears -- either an external user running the codegen on their own models, or the in-flight migration of Segment from a bare Annotated[Union] alias to RootModel (the more idiomatic Pydantic spelling for a validated root entity).

Root cause

Discovery classifies entry points by is it a RootModel? rather than by what is the RootModel's root?:

  • extract_model_spec (spec_discovery.py:42): if is_rootmodel(entry): return None
  • extract_alias_spec (spec_discovery.py:64): if is_rootmodel(entry): return extract_rootmodel_alias(entry)

Both branches fire for any RootModel regardless of root shape.

Related type-signature lie

discover_models is annotated -> ModelDict where ModelDict = dict[ModelKey, type[BaseModel]] (discovery/types.py:17), but a discriminated-union entry point stores an Annotated[Union[...], Field(discriminator=...)] alias, which is not a type[BaseModel]. The annotation is already inaccurate for union entry points. Migrating unions to RootModel makes it honest (a RootModel is a BaseModel subclass); short of that, the type should be widened to reflect what discovery actually yields.

Expectation

Condition the entry-point classification on the RootModel's root shape rather than on RootModel-ness:

  • scalar/container root -> alias page, as today
  • discriminated-union or model root -> generate as a union/model (peel the RootModel, extract the inner shape), not an alias

At minimum, a union- or model-rooted RootModel entry point must not be silently documented as a scalar alias. If full support is not built in the same change, detect and raise, matching the self-referential-RootModel precedent from #593.

Related

Follow-up gap in the #593 fix.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.