Story: Resolve codegen model unification blockers

Table of Contents

This page documents a story in Sprint 23. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

Merged into Retire legacy codegen profile system; add junction support to physical-space codegen on 2026-07-15: the remaining BACKLOG blockers (B4, B6/archetypes subcommand, B7, B9, B10, B11, plus the two content-migration/table-retirement tasks) are all "retire legacy codegen cruft" work overlapping that story's own scope (in particular B10/B11 duplicated its tasks 1 and 5 almost exactly), so they were relocated there via compass task move rather than tracked in two places. This story is closed with the 6 blockers it actually completed (B1, B2, B3, B5, B8, plus the populate-archetypes task); nothing further will land against it.

Carried from Sprint 22, where 8 of 15 tasks were completed (one abandoned, superseded).

Goal

The codegen model unification analysis identifies six concrete blockers that prevent merging the dual domain_entity + table org files into a single entity file per entity. This story resolves five of them (B6 is abandoned — subsumed by B5's generic mechanism), leaving the generator in a state where the content migration (moving _table.org sections into entity files and deleting the table files) can proceed safely and mechanically.

The blockers, in implementation order:

  1. (B2) get_model_type() and load_model() are hard-coupled to filename suffixes — switch to #+type: frontmatter detection.
  2. (B3) Entirely separate parsers — teach load_org_model() to parse * Validation function, * Insert trigger, has_tenant_id, coding_scheme, image_id.
  3. (B1) Two incompatible SQL templates — extend sql_schema_domain_entity_create.mustache to handle the full table-template data shape.
  4. (B5) No element-level physical-space binding; profile concept leaked to CLI — introduce the supported/target set model: the entity's ores.* drawer declares its supported set (what it is capable of generating); the optional CLI --address declares the target set (what to generate this run; defaults to the full supported set). What actually generates = target ∩ supported. Target outside supported → warning for that entity. Remove --profile from the CLI. Subsumes the originally planned #+sql_only and #+has_qt flags.
  5. (B4) refdata vs refdata-cpp component split — collapse into a single component.

Status

Field Value
State DONE
Parent sprint Sprint 23
Now B1, B2, B3, B5, and B8 done. Remaining backlog (B4, B6, B7, B9, B10, B11, content migration, table retirement) moved to Retire legacy codegen profile system; add junction support to physical-space codegen.
Waiting on Nothing.
Next Nothing — see the target story.
Last touched 2026-07-15

Acceptance

  • Running compass codegen entity --component refdata-cpp --profile sql no longer overwrites table-pathway SQL output with the structurally incomplete domain-entity SQL.
  • get_model_type() and load_model() resolve model type from #+type: frontmatter; the filename-suffix fallback remains for any model without a #+type: header.
  • load_org_model() correctly parses * Validation function, * Insert trigger, #+has_tenant_id, #+coding_scheme, and #+image_id from entity org files that carry them.
  • sql_schema_domain_entity_create.mustache generates byte-identical SQL to sql_schema_create.mustache for any dual-file entity when given the merged entity model.
  • Each entity's :PROPERTIES: drawer declares its supported set: the archetypes it can produce. ores.{ts}[.{facet}[.{archetype}]].enabled properties, resolved with specificity-ordered override semantics (more-specific wins), produce the supported set. Absent properties leave the model-types filter as the sole gate (backward-compatible).
  • The CLI accepts an optional --address argument that declares the target set; absent, the target set equals the full supported set. What generates = target ∩ supported. Target ∩ supported = ∅ for an entity → warning "nothing to generate for <entity>"; the run still succeeds for other entities in the component.
  • --profile is removed from the CLI. The entity's binding IS the profile.
  • A SQL-only entity is expressed as :ores.cpp.enabled: false; an entity without Qt as :ores.cpp.qt.enabled: false. No ad-hoc boolean flags required.
  • The supported/target set resolution logic is isolated in a dedicated Python module with unit tests covering: empty properties (backward compat), TS-level disable, facet-level disable, combined TS-enable + facet-disable override, target ⊆ supported (normal filter), target ∩ supported = ∅ (warn), unknown address (error).
  • The refdata and refdata-cpp component catalogue entries are merged; all profiles fire from a single component with one discovery glob.
  • compass codegen entity archetypes lists the full physical space in ores.ts.facet.archetype notation; --entity <name> shows the entity's supported set with per-archetype ✅/❌ status.
  • All existing regression tests pass; compass codegen entity produces zero diff vs HEAD for all currently registered components.

Tasks

Task State Start End Description
Scaffold story: Resolve codegen model unification blockers DONE 2026-06-27 2026-06-27 Story scaffolding rides this task: documents, sprint wiring, and the scaffold PR. Close it before merging that PR.
B2: Switch model-type detection from filename suffix to #+type: frontmatter DONE 2026-06-27 2026-06-27 Change get_model_type() and load_model() in core.py to resolve the model type from the #+type: frontmatter key rather than filename suffix; keep suffix fallback for files without #+type:.
B3: Teach load_org_model() to parse table-only sections DONE 2026-06-27 2026-06-27 Extend load_org_model() in org_loader.py to parse * Validation function, * Insert trigger / ** Validations, and the #+has_tenant_id, #+coding_scheme, #+image_id frontmatter keys that currently only load_org_table_model() handles.
B1: Extend entity SQL template to cover full table-template data shape DONE 2026-06-27 2026-06-27 Extend sql_schema_domain_entity_create.mustache to render coding_scheme columns, image_id, the validation_fn block, and insert_trigger.validations — the sections that previously only sql_schema_create.mustache (table pathway) produced — so a merged entity model generates byte-identical SQL to the table pathway.
B5: Implement element-level physical space binding via ores.* property drawer DONE 2026-06-27 2026-06-29 Implement ores.{ts}[.{facet}].enabled property-drawer activation with hierarchical override semantics. The generator reads these from each entity's :PROPERTIES: drawer, resolves specificity (more-specific address wins), and skips matching facets. Replaces the ad-hoc #+sql_only and #+has_qt flags. Resolution logic isolated and unit-tested.
B6: Make C++/Qt section optional with #+has_qt: false guard ABANDONED     Superseded by B5: the generic ores.* property-drawer mechanism covers this use case via :ores.cpp.qt.enabled: false.
B8: Fold component-scaffolding archetypes into the physical-space graph DONE 2026-06-28 2026-06-28 Migrate the component-scope archetypes (cmake_*, cpp_component_*, cpp_service_app_*, sql_service_*, shell_*, the * Component archetypes) into the ores.* physical-space doc graph, after B5 lands the entity-facet graph.
Generate data-scope populate archetypes from dataset org-models DONE 2026-06-28 2026-06-29 Migrate populate/seed generation into the ores.* graph: each seeder dataset becomes a literate org model declaring its enabled ores.sql.populate archetypes via the drawer; retire get_template_mappings and the scattered data JSON.

Decisions

  • Implement in order B2 → B3 → B1 → B5 → B4: frontmatter detection must come first (B3, B1 depend on it); parsers before templates (template needs the richer data shape); physical-space binding before component collapse (collapse relies on binding to handle SQL-only entities); component collapse last.
  • The five active tasks share one feature branch (feature/codegen-unification-blockers) and one PR, since each is a prerequisite for the next and none produces a shippable intermediate state. B6 (#+has_qt) is ABANDONED — superseded by B5.
  • Originally scoped B5 and B6 as separate boolean flags (#+sql_only, #+has_qt). Replaced with a single MASD-aligned mechanism: ores.{ts}[.{facet}[.{archetype}]].enabled in the entity's :PROPERTIES: drawer, following Dogen's variability model (cf. :masd.cpp.enabled:, :masd.csharp.enabled:) and ORE Studio Variability Model. Resolution is specificity-ordered: :ores.cpp.enabled: true followed by :ores.cpp.qt.enabled: false enables all C++ except Qt. Any future per-element activation need is handled by the same mechanism — no new flags.
  • Physical space is a "set of sets" (TS → facet → archetype). The entity declares its supported set; the CLI --address declares the target set; what generates is their intersection. --profile is removed: the entity's binding IS the profile, and the CLI address is only a filter, never an expansion. Updating all existing compass commands and skills to remove --profile invocations is part of B5's scope.

Out of scope

(Both items below were originally deferred to a follow-on story, Decommission ores.codegen.table model type; that story closed at sprint 22's end without doing them, so they were pulled in here as real tasks instead of tracked twice — see the Tasks table.)

  • ~Content migration (Step 5 of the migration path): moving =_table.org= sections into entity files and deleting the table files.~ Now tracked as a task above.
  • ~Retiring the =ores.codegen.table= type from =get_model_type()= (Step 7): deferred until all table files are gone.~ Now tracked as a task above.

Result

Closed with the 6 blockers actually completed this story (B1, B2, B3, B5, B8, the populate-archetypes migration). The remaining backlog — B4, B6 (archetypes subcommand), B7, B9, B10, B11, the _table.org content migration, and table-model-type retirement — was relocated (via compass task move, UUIDs intact) to Retire legacy codegen profile system; add junction support to physical-space codegen on 2026-07-15, since both stories were converging on the same "retire legacy codegen cruft" work — B10 and B11 in particular duplicated that story's tasks 1 and 5 almost exactly.

Emacs 29.3 (Org mode 9.6.15)