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. The table type (and its is_table_model predicate) was retired once every entity migrated to domain_entity — see Retire legacy codegen profile system; add junction support to physical-space codegen.
  • load_graph(templates_dir) (in physical_space.py) — parse the ores physical-space graph org nodes into a Graph of 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=)= (in generate.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 how address narrows 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 pystache library.
  • Templates live in library/templates/. The .mustache files 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 by core.py via _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-run prints the resolved paths without writing.
  • Overall models. A model.json can orchestrate generation of multiple artefacts in dependency order.
  • Dynamic prefixing. A model_name property on an overall model prefixes every output file (for example solvaris_).
  • 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:

  1. Includes the enhanced licence header.
  2. Sets the schema to ores.
  3. Generates SQL calls to metadata.upsert_dq_catalogs().
  4. 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:

  1. Add the Mustache template to library/templates/.
  2. Add an entry to ores physical-space graph under the relevant facet heading, adding a row to the templates table with template, output pattern, and optionally model_types.
  3. If adding a new model type, update get_model_type() in src/codegen/core.py and add any preprocessing logic in the generate_from_model() dispatch block.

To add a new named component:

  1. Add a row to library/component_catalogue.org with the component's models_dir, entity_glob, exclude_suffix, and modeling_dir.
  2. The component is then available as codegen.sh regenerate --component <name>.

See also

Emacs 29.3 (Org mode 9.6.15)