Story: Codegen unified model — Phase 3: unify temporal/non-temporal templates
Table of Contents
This page documents a story in Sprint 22. It captures the goal, current status, acceptance criteria, and the tasks that compose it.
Goal
The C++ template library has two parallel families for domain types:
| Temporal (versioned, full audit trail) | Non-temporal (read-only, no audit columns) |
|---|---|
cpp_domain_type_entity.hpp.mustache |
cpp_domain_type_entity_non_temporal.hpp.mustache |
cpp_domain_type_entity.cpp.mustache |
cpp_domain_type_entity_non_temporal.cpp.mustache |
cpp_domain_type_mapper.hpp.mustache |
cpp_domain_type_mapper_non_temporal.hpp.mustache |
cpp_domain_type_mapper.cpp.mustache |
cpp_domain_type_mapper_non_temporal.cpp.mustache |
cpp_domain_type_repository.hpp.mustache |
cpp_domain_type_repository_non_temporal.hpp.mustache |
cpp_domain_type_repository.cpp.mustache |
cpp_domain_type_repository_non_temporal.cpp.mustache |
Six template pairs, 12 files total. Every bug fix or enhancement must be applied twice. When one family diverges from the other, non-temporal entities silently get outdated patterns.
This story merges each pair into a single template controlled by an
is_temporal boolean in the unified model. Temporal behaviour is enclosed
in {{#is_temporal}} / {{/is_temporal}} Mustache conditional blocks.
The profiles non-temporal-domain, non-temporal-repository, and
non-temporal are retired; the domain, repository, and all-cpp
profiles handle both.
This story can run in parallel with Phase 2: single model file per entity because it touches templates and profiles, not model files.
See Codegen architecture analysis and unified model roadmap for context.
Status
| Field | Value |
|---|---|
| State | ABANDONED |
| Parent sprint | Sprint 22 |
| Now | Superseded by deletion: the entire non-temporal family (SQL + C++ facets, archetypes, templates) was removed during the single-model consolidation because no entity used it. Nothing to merge. |
| Waiting on | A real non-temporal entity to be commissioned — at which point temporality returns as an is_temporal variability point, verifiable against that entity. |
| Next | Re-add is_temporal variability to the unified create/domain/repository templates when first needed (not before — an unverifiable branch is worse than its absence). |
| Last touched | 2026-06-28 |
Acceptance
- Six
_non_temporaltemplate files are deleted. - The corresponding temporal templates each contain
{{#is_temporal}}blocks covering audit-column generation,version-bump logic, and history queries. - All existing temporal entities produce zero diff against their current output.
- All existing non-temporal entities produce zero diff against their current output.
profiles.jsonno longer containsnon-temporal-domain,non-temporal-repository, ornon-temporalprofiles.- The
all-cppprofile correctly generates both temporal and non-temporal entities based on theis_temporalfield (defaulting totrueif absent). - All models that previously required
non-temporalprofiles haveis_temporal: falsein their model file. - CI passes. Site builds cleanly.
Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Task: Diff temporal and non-temporal template pairs; write merge plan | ABANDONED | Moot: the non-temporal family was deleted (unused), so there are no pairs to merge. | ||
| Task: Merge template pairs and add is_temporal conditionals | ABANDONED | Moot: superseded by deletion. The is_temporal variability point will be added when a non-temporal entity is first commissioned (see Decisions). |
||
| Task: Verify zero diff and retire non-temporal profiles | ABANDONED | Superseded: the non-temporal* profiles and the six (in fact 21) non-temporal template/archetype/facet files were removed during the single-model consolidation. |
Decisions
- Delete-first, not merge-first (2026-06-28). The non-temporal family was
entirely unused: no model declared it, nothing generated the
created_atshape, and under--addressthe non-temporal facets were silently default-enabled for every domain entity (a latent collision). Rather than merge two families where one had no users, the whole non-temporal family was deleted during the single-model consolidation (21 template/archetype/facet files + thenon-temporal*profile entries ingenerate.py). Temporality becomes anis_temporalvariability point on the single model + unified templates, added only when a genuinely non-temporal entity is first commissioned and theis_temporal=falsebranch can be verified against it. This story's original "merge six pairs" plan is therefore moot; the residual work is the deferredis_temporalvariability above. is_temporaldefaults totrue. All existing temporal models are unaffected — they do not need the field added. Only non-temporal models needis_temporal: false. This is the safer default because temporal is the common case.- Merge into the temporal template, not a neutral template. The temporal template
is the superset. Wrapping temporal-only sections in
{{#is_temporal}}is simpler than creating a third neutral template and routing both families to it.
Out of scope
cpp_domain_type_class_non_temporal.hpp.mustache— the non-temporal domain class template. Evaluate during Task 1 whether to include in the merge.sql_schema_non_temporal_create.mustache— a separate SQL concern, not part of the C++ template family.- Qt templates — Qt does not have a temporal/non-temporal split.