You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A field.enum that reaches its values through two levels of extends generates nothing. Concretely: when a projection field extends an entity field, and that entity field itself extends a shared abstract enum, the projection's generated enum type disappears entirely and every consumer fails to resolve it.
Sibling of #246 (same feature area, different failure). #246 is "the shared enum generates but isn't imported"; this is "a second extends hop and it doesn't generate at all".
NpcCharacterViewStatus.kt is not generated at all.
Every consumer of the projection's status column then fails to compile: Unresolved reference 'NpcCharacterViewStatus', plus knock-on Argument type mismatch: actual type is 'List<partylore.common.CharacterStatusValue>', but 'Iterable<T>' was expected at each call site.
Before the shared-enum change, the same projection field generated NpcCharacterViewStatus correctly from the entity's own inline values. So the regression is specifically the second hop.
Expected
A projection field extending an entity field whose values are themselves inherited should resolve transitively, and generate exactly as it does when the entity declares values inline.
Suggested fix
Likely an own-vs-effective accessor read when collecting enum values during codegen. Your own guidance calls this out (metaobjects-authoring skill, "Abstracts + extends"):
Always read a property or iterate a member set via the resolving/effective accessor … never an own*() accessor — an own-only read silently drops everything inherited via extends.
One hop works because the entity field's own node still carries values. Two hops fails because the middle node has none of its own — it inherits them. So the enum generator very likely reads own-values at the projection layer and finds an empty set, then skips emission.
Two asks beyond the fix itself:
Fail loudly rather than silently. An enum field that resolves to zero values should be a load error (ERR_MISSING_REQUIRED_ATTR-style), not a silent no-emit. @values is documented as required on field.enum; a chain that resolves to none currently violates that invariant quietly. This is what made the failure expensive to diagnose — generate-sources was green and only a full compile revealed it.
Conformance fixture for depth ≥ 2, covering projection→entity→shared. A one-hop fixture passes today and pins nothing about the chain.
Impact
Blocks adopting a shared enum in any project that also uses projections over the same entity — which is the common case, since a projection usually exists precisely to expose that entity's columns. In our tree it blocked converging three drifted copies of one status vocabulary; we shipped identical inline value sets plus a build-time equality test as the workaround, which is strictly worse than the type-level guarantee extends was going to provide.
Summary
A
field.enumthat reaches itsvaluesthrough two levels ofextendsgenerates nothing. Concretely: when a projection field extends an entity field, and that entity field itself extends a shared abstract enum, the projection's generated enum type disappears entirely and every consumer fails to resolve it.Sibling of #246 (same feature area, different failure). #246 is "the shared enum generates but isn't imported"; this is "a second
extendshop and it doesn't generate at all".Reproduction
Two-level chain —
Projection.status→Entity.status→Shared— allfield.enum:mvn generate-sourcesreports BUILD SUCCESS.Actual
CharacterStatusValue.ktgenerates correctly with all 12 values, andActiveNpcTable/GameCharacterTablereference it (that part works — modulo Kotlin codegen: generated *Table / *RepositoryBase reference a cross-package shared field.enum without importing it #246's missing import).NpcCharacterViewStatus.ktis not generated at all.Unresolved reference 'NpcCharacterViewStatus', plus knock-onArgument type mismatch: actual type is 'List<partylore.common.CharacterStatusValue>', but 'Iterable<T>' was expectedat each call site.Before the shared-enum change, the same projection field generated
NpcCharacterViewStatuscorrectly from the entity's own inlinevalues. So the regression is specifically the second hop.Expected
A projection field extending an entity field whose values are themselves inherited should resolve transitively, and generate exactly as it does when the entity declares
valuesinline.Suggested fix
Likely an own-vs-effective accessor read when collecting enum
valuesduring codegen. Your own guidance calls this out (metaobjects-authoringskill, "Abstracts +extends"):One hop works because the entity field's own node still carries
values. Two hops fails because the middle node has none of its own — it inherits them. So the enum generator very likely reads own-values at the projection layer and finds an empty set, then skips emission.Two asks beyond the fix itself:
ERR_MISSING_REQUIRED_ATTR-style), not a silent no-emit.@valuesis documented as required onfield.enum; a chain that resolves to none currently violates that invariant quietly. This is what made the failure expensive to diagnose —generate-sourceswas green and only a full compile revealed it.Impact
Blocks adopting a shared enum in any project that also uses projections over the same entity — which is the common case, since a projection usually exists precisely to expose that entity's columns. In our tree it blocked converging three drifted copies of one status vocabulary; we shipped identical inline value sets plus a build-time equality test as the workaround, which is strictly worse than the type-level guarantee
extendswas going to provide.Environment: metaobjects 7.8.0 (Maven), Kotlin/Exposed codegen, reproduced 2026-08-01.