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:
- (B2)
get_model_type()andload_model()are hard-coupled to filename suffixes — switch to#+type:frontmatter detection. - (B3) Entirely separate parsers — teach
load_org_model()to parse* Validation function,* Insert trigger,has_tenant_id,coding_scheme,image_id. - (B1) Two incompatible SQL templates — extend
sql_schema_domain_entity_create.mustacheto handle the full table-template data shape. - (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--addressdeclares 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--profilefrom the CLI. Subsumes the originally planned#+sql_onlyand#+has_qtflags. - (B4)
refdatavsrefdata-cppcomponent 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 sqlno longer overwrites table-pathway SQL output with the structurally incomplete domain-entity SQL. get_model_type()andload_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_idfrom entity org files that carry them.sql_schema_domain_entity_create.mustachegenerates byte-identical SQL tosql_schema_create.mustachefor 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}]].enabledproperties, 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
--addressargument 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. --profileis 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
refdataandrefdata-cppcomponent catalogue entries are merged; all profiles fire from a single component with one discovery glob. compass codegen entity archetypeslists the full physical space inores.ts.facet.archetypenotation;--entity <name>shows the entity's supported set with per-archetype ✅/❌ status.- All existing regression tests pass;
compass codegen entityproduces 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}]].enabledin 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: truefollowed by:ores.cpp.qt.enabled: falseenables 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
--addressdeclares the target set; what generates is their intersection.--profileis 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--profileinvocations 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.