ores.codegen architecture
Table of Contents
Summary
This document records how ores.codegen is built and how its parts
fit together: where its code and data live, how the generator picks
templates for models, how it handles modelines and licence headers,
and the conventions it enforces.
For what the component is and how to operate it, see ores.codegen (the component model) and the recipes it links to.
Detail
Directory structure
projects/ores.codegen/ ├── library/ │ ├── component_catalogue.org # Component → models-dir/glob/modeling-dir (read by manifest.py) │ ├── data/ # Static data (licences, modelines) │ │ ├── licence-GPL-v3.txt │ │ └── modeline.org # Editor modelines — MASD-style org, read directly by core.py │ └── templates/ # Mustache templates + the ores.* physical-space │ # graph (root -> technical space -> facet -> │ # archetype), one org node per graph element, │ # tangled to the .mustache files alongside them │ ├── ores.*.org # Physical-space graph nodes (root/ts/facet/archetype) │ ├── sql_*.mustache │ └── doc_*.org.mustache ├── models/ # Legacy JSON model files (being migrated to org) │ └── <component>/ # e.g. refdata/, trade/, dq/, iam/ ├── output/ # Default destination for generated files ├── scripts/ # Shell scripts for common operations ├── src/ # Python source │ ├── codegen/ # CLI package (codegen.py entry point) │ │ ├── __init__.py │ │ ├── cli.py # argparse entry point; dispatches subcommands │ │ ├── core.py # Model classification, rendering, output resolution │ │ ├── generate.py # generate / regenerate subcommand implementations │ │ ├── org_loader.py # Parses org-mode model files (entity/junction/...) │ │ ├── physical_space.py # Loads the ores.* graph; computes supported/target sets │ │ ├── manifest.py # Named component registry │ │ ├── list_cmd.py # =list= subcommand │ │ ├── diff_cmd.py # =diff= subcommand │ │ └── migrate_*.py # One-off JSON → org migration scripts, per model type │ ├── doc_generate.py # v2 information-architecture doc generator │ ├── fpml_parser.py # FPML Genericode XML → JSON models │ ├── images_generate_sql.py │ ├── lei_extract_subset.py │ └── iso_generate_metadata_sql.py ├── modeling/ │ └── ores.codegen.org # Component model (the entry point) ├── docs/ │ ├── architecture.org # This document │ ├── cpp_generation_analysis.md │ └── doc_generator.md ├── requirements.txt ├── codegen.sh # Wrapper: activates venv and calls codegen.py ├── generate_doc.sh # Wrapper for doc_generate.py └── generate_*_schema.sh # Legacy per-component schema scripts (being retired)
Internal modules
| File | Purpose |
|---|---|
src/codegen/cli.py |
Argparse entry point; parses subcommands and dispatches |
src/codegen/core.py |
Model classification (get_model_type), rendering, output-path resolution |
src/codegen/generate.py |
generate and regenerate subcommand implementations |
src/codegen/org_loader.py |
Parses org-mode model files (entity, junction, field-group, …) into model data |
src/codegen/physical_space.py |
Loads the ores physical-space graph; computes supported/target archetype sets |
src/codegen/manifest.py |
Named component registry (maps component name → models dir + glob) |
src/codegen/list_cmd.py |
list subcommand implementation |
src/codegen/diff_cmd.py |
diff subcommand implementation |
src/doc_generate.py |
v2 information-architecture document generator (task/story/sprint/…) |
src/fpml_parser.py |
FPML Genericode XML → JSON models |
src/iso_generate_metadata_sql.py |
ISO standards → SQL |
src/images_generate_sql.py |
Image artefacts (flags, crypto icons) → SQL |
src/lei_extract_subset.py |
LEI dataset subset extractor |
| ores physical-space graph | One org node per graph element (root/technical-space/facet/archetype); declares which templates generate for which model types |
library/component_catalogue.org |
Maps component names to discovery roots; read directly by manifest.py |
library/data/modeline.org |
Editor modeline strings per language; read directly by core.py |
library/data/ |
Static data files (licences, modelines) |
library/templates/ |
Mustache templates + the physical-space graph nodes |
models/ |
Legacy JSON model files (component-by-component migration to org is ongoing) |
output/ |
Default destination for generated files |
Main generator functions
In src/codegen/core.py (model classification and rendering) and
src/codegen/physical_space.py (graph traversal):
get_model_type(filename, path=None)— classify a model file's type (domain_entity,junction,schema,field_group, …). Org models are classified via their#+type:frontmatter first; filename-suffix predicates (is_junction_model, …) are the fallback for legacy JSON models with no frontmatter. Thetabletype (and itsis_table_modelpredicate) was retired once every entity migrated todomain_entity— see Retire legacy codegen profile system; add junction support to physical-space codegen.load_graph(templates_dir)(inphysical_space.py) — parse the ores physical-space graph org nodes into aGraphof technical spaces, facets, and archetypes.compute_supported_set(properties, graph, model_type)— the archetypes an entity can generate, from facet#+model_types:plus the entity's:ores.*.enabled:drawer overrides.compute_target_set(address, graph)— the archetypes to generate this run: all facets under an--address, or every facet if none given.resolve_targets(model_path, base_dir, address, properties=)= (ingenerate.py) — the single resolver used by both the CLI and the compass wrapper; combines supported ∩ target into concrete (template, output path) units. See Addressing system below for howaddressnarrows the target set.resolve_output_path(pattern, model_data, model_type)— expand an output path pattern using model fields.render_template(template_path, data)— render a Mustache template with the given data.generate_from_model()— orchestrate generation for one model file.
Template system
- Mustache via the
pystachelibrary. - Templates live in
library/templates/. The.mustachefiles are generated artefacts, tangled from the literate facet docs in the same directory — see the Codegen template library overview for the hierarchy, tangle workflow, and drift checks. - Output is SQL, C++, or org-mode depending on the template family.
Data files
library/data/licence-GPL-v3.txt— full GPL v3 licence text used in generated headers.library/data/modeline.org— per-language editor modeline strings (MASD-style org hierarchy; read directly bycore.pyvia_load_modelines_from_org()).
Model types and file naming
This section covers the legacy JSON model path only — org-mode
models (the current standard; see Codegen input org-file schema
reference) declare their type via #+type: frontmatter instead of a
filename suffix, and get_model_type() checks that frontmatter first.
Filename-suffix detection, described below, is the fallback used only
for JSON models that carry no frontmatter.
Each legacy JSON type has a root JSON key of the same name and is associated with one or more templates through the ores physical-space graph.
| Filename suffix | Model type | Root JSON key | Primary template |
|---|---|---|---|
*_entity.json |
schema |
entity |
sql_schema_table_create.mustache (legacy) |
*_domain_entity.json |
domain_entity |
domain_entity |
C++ templates + sql_schema_domain_entity_create.mustache |
*_junction.json |
junction |
(varies) | sql_schema_junction_create.mustache |
The *_table.json=/=*_table.org table model type (root key table,
sql_schema_create.mustache) is retired — every SQL-only entity table
migrated to domain_entity and the type's dispatch was removed from
the generator entirely.
Model-template mapping
The active mapping is declared in ores physical-space graph, not hard-coded in Python. Each facet entry lists which templates apply to which model types and the output path pattern.
Table schema mappings (retired)
The *_table.json=/=*_table.org table model type and its
sql_schema_create.mustache template are retired; every SQL-only
entity table now expresses the same shape (primary key, columns,
validation function, insert trigger, coding scheme, image id) as a
domain_entity model with no C++/Qt sections, rendered via
sql_schema_domain_entity_create.mustache. The generator still shares
the field-normalisation logic (normalise_sql_table_context() /
domain_entity_to_table_context() in core.py=/=org_loader.py) — only
the separate table model type and its dedicated template are gone.
Domain entity schema mappings (*_domain_entity.json files)
These files drive both C++ generation and SQL for domain entities (party, book, counterparty, etc.). The SQL portion is handled separately from the C++ portion.
| Template | Output file |
|---|---|
sql_schema_domain_entity_create.mustache |
{component}_{entity}_create.sql |
sql_schema_notify_trigger.mustache |
{component}_{entity}_notify_trigger.sql |
sql_schema_artefact_create.mustache |
dq_{entity}_artefact_create.sql |
C++ templates (via --address ores.cpp) |
.hpp / .cpp files |
Standard data mappings
| Model file | Template(s) |
|---|---|
model.json |
sql_batch_execute.mustache |
catalogs.json |
sql_catalog_populate.mustache |
country_currency.json |
sql_flag_populate.mustache, sql_currency_populate.mustache, sql_country_populate.mustache |
datasets.json |
sql_dataset_populate.mustache, sql_dataset_dependency_populate.mustache |
methodologies.json |
sql_methodology_populate.mustache |
tags.json |
sql_tag_populate.mustache |
Entity populate mappings (*_data.json files)
| Template | Output file |
|---|---|
sql_populate_refdata.mustache |
{component}_{entity}_populate.sql |
Addressing system
The physical-space address is the selector: every entity's
generation footprint is its supported set on the ores physical-space
graph (root → technical space → facet → archetype), narrowed by
--address to a subtree of that graph and by the model's own
:ores.*.enabled: drawer overrides. There is no separate profile
declaration to maintain — an entity's ores.* binding is its
generation footprint.
Examples: --address ores.sql.schema generates SQL DDL only;
--address ores.cpp generates every C++ facet (domain, generator,
repository, service, protocol, …); --address ores.cpp.qt generates
just the Qt facet; omitting --address generates an entity's full
supported set.
Component registry
Named components are declared in library/component_catalogue.org, read directly
by src/codegen/manifest.py at startup. See component_catalogue.org for the full
16-component table (name, models_dir, entity_glob, exclude_suffix, modeling_dir).
Retired scripts
The following shell scripts have been deleted and replaced by codegen.sh:
| Deleted script | Replacement command |
|---|---|
generate_refdata_schema.sh |
codegen.sh regenerate --component refdata --address ores.sql.schema |
Modeline configurations
From library/data/modeline.org:
| Language | Modeline |
|---|---|
| SQL | sql-product: postgres; indent-tabs-mode: nil |
| C++ | mode: c++; indent-tabs-mode: nil; c-basic-offset: 4 |
Features
- Licence generation. Generated files carry a licence header with editor modelines, a copyright with the current year, and the appropriate per-language comment formatting.
- Multi-language comment support. SQL and C++ use
/* ... */with a* = line prefix; Python uses =""", JavaScript uses/** */. - Graph-resolved output. Each archetype's output path pattern (on
its ores physical-space graph node) is expanded against the model's
own fields and written project-root-relative; parent directories are
created automatically.
--dry-runprints the resolved paths without writing. - Overall models. A
model.jsoncan orchestrate generation of multiple artefacts in dependency order. - Dynamic prefixing. A
model_nameproperty on an overall model prefixes every output file (for examplesolvaris_). - Automatic sibling loading. JSON models in the same directory are loaded together so a template can cross-reference them.
- Enhanced data context. Subject-area datasets (such as
currencies_dataset,countries_dataset) are surfaced as named variables to templates for direct access.
Example model structure
From models/slovaris/catalogs.json:
[
{
"name": "Slovaris",
"description": "Imaginary world to test all system functions.",
"owner": "Testing Team"
}
]
The sql_catalog_populate.mustache template generates SQL that:
- Includes the enhanced licence header.
- Sets the schema to
ores. - Generates SQL calls to
metadata.upsert_dq_catalogs(). - Includes summary queries.
Extending
To add a new SQL-only entity table (the table model type's retired
role) for an existing component, scaffold a domain_entity model
(compass add entity_org --component <name> ...) with no ** Qt
section instead — see Codegen input org-file schema reference.
To add a new facet or template:
- Add the Mustache template to
library/templates/. - Add an entry to ores physical-space graph under the relevant facet heading,
adding a row to the templates table with
template,outputpattern, and optionallymodel_types. - If adding a new model type, update
get_model_type()insrc/codegen/core.pyand add any preprocessing logic in thegenerate_from_model()dispatch block.
To add a new named component:
- Add a row to
library/component_catalogue.orgwith the component'smodels_dir,entity_glob,exclude_suffix, andmodeling_dir. - The component is then available as
codegen.sh regenerate --component <name>.
See also
- ores.codegen — the component model (entry point).
- Codegen input org-file schema reference — schema for every org-file type consumed by the generator.
- How do I run codegen? — operational recipe.
- How do I create a new doc? — operational recipe for the org-document generator.
- Paste blocks: injecting custom code into generated files — how
hand-written C++ survives codegen regeneration via
:implements UUIDpaste blocks. projects/ores.codegen/docs/cpp_generation_analysis.md— analysis of the C++ code generation paths.projects/ores.codegen/docs/doc_generator.md— full CLI reference forgenerate_doc.sh.