Task: Scaffold model .org files per entity type (regular/enum/junction)
Table of Contents
This page documents a task in the Commission ores.qt.dq — full-stack codegen for the DQ component story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Generate correct, fully-knobbed entity .org model skeletons per entity metatype (domain_entity/junction/lookup_entity — the MASD-established classification, see Plan), with domain_entity further split into named shapes by knob combination, by sampling correctly-modeled reference entities, so new DQ (and future) entity models start from a known-good baseline instead of copy-paste. Also document the fixed set of manual post-generation integration steps (registrar wiring, NATS relay wiring, CMake/plugin wiring, …) so the scaffold — or the LLM using it — knows what still needs doing by hand, with a pointer to the capture/task ID tracking each step not yet automated.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Commission ores.qt.dq — full-stack codegen for the DQ component |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-07-17 |
Acceptance
[X]org_entity_meta_model.orgdocuments every variability knob actually in use (has_change_reason_cache, history_response_data_field, delete_request_id_field, has_uuid_primary_key, badge/coding_scheme wiring, etc.) – today's doc omits all of them.[X]A codegen command/template exists per entity metatype/shape that scaffolds a new model .org with the correct knobs already present – either set from the sampled exemplar or left as an explicit TODO with a one-line reason – so a knob can never be silently omitted.[X]A "Post-generation checklist" is authored (in the scaffolded file or a companion doc, decide during implementation) enumerating every fixed manual integration step (registrar sub-registration, application.cpp NATS-relay wiring, CMakeLists entry, Qt plugin/menu wiring, manual chapter), each linking to a capture/task ID if the step is separately tracked for automation.[ ]Used to author the DQ reference-entity models in the sibling commissioning task (819B050A) – that task's own job, not blocking this one's completion.
Plan
Not "stereotype" (UML mechanism) and not "profile" – metatype: the
MASD term for an entity's classification, per Applied MASD § Metatypes,
facets, archetypes, and transforms (domain_entity, junction,
enumeration, … – "do not use 'stereotype' to mean 'metatype'").
Codegen's #+type: frontmatter already dispatches on exactly this:
ores.codegen.entity (metatype domain_entity), ores.codegen.junction
(metatype junction), ores.codegen.lookup_entity (maps to metatype
enumeration? naming mismatch to confirm during implementation –
the established metatype table in Applied MASD says enumeration,
codegen's doc-type says lookup_entity; reconcile or document why
they differ).
market_observation is #+type: ores.codegen.entity today (metatype
domain_entity) despite being structurally quite different
(TimescaleDB hypertable, immutable observation semantics, no Qt) –
so per the current, established metatype list it is not a distinct
metatype, it is a domain_entity with :ores.cpp.qt.enabled: false
and a different natural-key/temporal shape. The four "regular" rows
below are the same situation: same metatype (domain_entity),
different knob combinations. Calling all five "metatypes" would be
exactly the kind of stretching Applied MASD warns against, so this
task uses shape for that finer, sub-metatype grouping – a shape is
"which optional domain_entity knobs this kind of entity needs", not a
new classification codegen dispatches on. Whether timeseries entities
are common/different enough to eventually warrant becoming their own
metatype (a real #+type: ores.codegen.timeseries, dispatching to a
different archetype set) is a legitimate future question, out of
scope for this task – flag it rather than deciding it here.
Candidate metatypes/shapes and their sampled exemplars (to confirm/revise once we start, these are reconnaissance picks, not final):
| Metatype | Shape | Exemplar(s) | Why |
|---|---|---|---|
| domain_entity | simple text-key | ores.refdata.country.org |
text natural key, has_uuid_primary_key: false, no hierarchy |
| domain_entity | FK-scoped | ores.refdata.book.org |
party_id soft-FK scoping, moderate size |
| domain_entity | hierarchical composite | ores.refdata.party.org, ores.refdata.counterparty.org |
has_parent_id, has_uuid_primary_key: true, composite child-entity tables |
| domain_entity | richest/all-knobs | ores.refdata.currency.org |
every optional knob exercised at least once, custom generator/service code |
| domain_entity | timeseries/hypertable | ores.marketdata.market_observation.org |
TimescaleDB hypertable, (series, observation_datetime, point_id) triple, ores.cpp.qt.enabled: false today (see Notes on future UI/chart work), transaction-time vs financial valid-time distinction |
| lookup_entity | (none needed yet) | ores.iam.tenant_type_lookup_entity.org (candidate) |
small closed code set, minimal knobs |
| junction | (none needed yet) | ores.refdata.party_counterparty_junction.org (candidate) |
two-sided FK association |
Existing doc-type split (ores.codegen.entity=/=lookup_entity=/
=junction) already gives us the metatype boundary; extend within
ores.codegen.entity for the domain_entity shapes rather than adding
new doc types.
Notes
Promoted from a backlog capture (same :ID:, preserved for traceability).
Today every entity's model .org file (e.g.
projects/ores.refdata/modeling/ores.refdata.<entity>.org) is
hand-authored from scratch or copy-pasted from a similar entity, so
variability knobs (has_change_reason_cache,
history_response_data_field, delete_request_id_field,
has_uuid_primary_key, badge wiring for enum-like lookups, junction
wiring for many-to-many association entities, etc.) get set
inconsistently or omitted entirely depending on which entity someone
copied from. In practice there are really only a handful of entity
kinds driving these knobs: a plain domain entity, an enum/lookup
entity (small closed set of codes, usually badge-rendered in list
views), and a junction/association entity (links two entities, often
read-only or list-only). Add a mustache template per kind under
projects/ores.codegen/library/templates/ that scaffolds a new model
.org with the correct knobs for that kind already present and set
to sensible defaults – derived by sampling known-good reference
entities (e.g. ores.refdata.book.org, ores.refdata.currency.org)
that are already proven to fill in every knob correctly, rather than
generic per-kind defaults alone.
This traces back to task AA97E310 (PRs #1571/#1590), which found 8
*_convention entities missing has_change_reason_cache: true
despite their schema requiring change_reason_code (saves silently
failed with an empty change-reason dropdown), and the same 8 missing
history_response_data_field=/=delete_request_id_field overrides
because their protocol field names don't follow the codegen
defaults. All three gaps trace back to the model .org file being
authored without a checklist for "what does an entity of this kind
need". A kind-aware scaffold sampled from correct entities would make
these knobs impossible to silently omit.
See also: Story: Migrate all entities onto the generic HistoryDialog.
Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario, run
through the QA Validation Runner panel) that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
PRs
| PR | Title |
|---|---|
Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | claude-review: 4 of 5 –shape presets' knob bundles didn't match their stated exemplar .org files (richest missing has_tenant_id; simple-text-key had a false has_export_macro and was missing has_insert_trigger_validations/qt_has_change_reason_cache/qt_has_pagination; hierarchical-composite had a false has_foreign_keys/qt_has_export_macro and was missing has_insert_trigger_validations; timeseries had a false has_foreign_keys) | projects/ores.codegen/src/doc_generate.py | Accepted | Verified each finding directly against country.org/currency.org/party.org/counterparty.org/market_observation.org; fixed all four presets to match. |
Result
The documentation half of this task (org_entity_meta_model.org and its segment pages documenting every variability knob in use) shipped in PR #1620. This PR ships the remaining two acceptance criteria:
compass add entity_org --shape <name>(simple-text-key,fk-scoped,hierarchical-composite,richest,timeseries) scaffolds a knobbed entity model instead of the previous bare, unknobbed skeleton. The template itself (doc_entity_org.org.mustache, tangled fromores.doc.modeling.entity_org.org) carries the non-structural variability as mustache section-conditionals gated by the shape's knob bundle (ENTITY_ORG_SHAPE_PRESETSindoc_generate.py) – one template covers every shape, no per-shape file copying. Individual--entity-<knob>flags override any preset value. Anything a shape can't derive (actual columns, FK targets, display fields, …) is left as a visible, one-lineTODOin the scaffolded output, never silently omitted.- Codegen entity — post-generation checklist enumerates the fixed manual integration steps (sub-registrar wiring, event-registrar wiring, CMake wiring, Qt plugin wiring), each explaining why it isn't generated yet and linking the capture/task tracking automation where one exists. Linked from the entity hub and from C++ NATS, replacing a dangling "see the hub's frontmatter" reference that pointed nowhere.
The five shape presets are reconnaissance picks sampled from one exemplar each (per the Plan table above), not a final catalogue – expect to refine them as 819B050A actually uses the scaffold to author the DQ reference entities.