Entity commissioning process reference
Table of Contents
- 1. Purpose
- 2. Entity meta-types
- 3. Commissioning criteria by layer
- 3.1. DB layer
- 3.2. Codegen layer
- 3.3. Domain layer (C++)
- 3.4. Repository layer (C++)
- 3.5. Service layer (C++)
- 3.6. Messaging / JSON IO layer (C++)
- 3.7. Qt layer
- 3.8. Shell layer (
ores.shellinteractive REPL) - 3.9. Scripted shell layer (
ores.shell) - 3.10. HTTP layer
- 3.11. Wt web UI layer
- 3.12. Manual
- 3.13. Criteria provenance
- 4. Codegen system overview
- 5. Codegen output map
- 6. Drift classification
- 7. Known open path issues (as of 2026-06-25)
- 8. Standard commission story structure
- 9. See also
1. Purpose
Commissioning an entity means bringing it to a fully operational and trustworthy
state across every access layer: the generated code must match what the
templates produce, the hand-written code must satisfy the per-layer criteria
in the * Commissioning criteria by layer section, and the operator must be
able to interact with the entity through
every supported interface (Qt, shell) without regression.
The commission stories in sprint planning exist to drive this work to completion, one entity at a time. This reference document defines what "done" means at each layer and how to structure the work so it can be tracked mechanically.
The retired manual-tracking docs (Entity Coverage Matrix, Domain entity evaluation checklist, Entity Catalogue) were folded into this reference and into the per-component drift stories in 2026-09-03.
2. Entity meta-types
Two meta-types exist. They share most layers but differ in expected UI surface.
| Meta-type | Examples | Characteristic |
|---|---|---|
| Domain entity | currency, party, book | Full CRUD UI, own MDI window, shell commands, manual chapter |
| Auxiliary type | rounding_type, monetary_nature, party_type | Lookup table; appears as a dropdown in a domain entity's detail dialog; may have its own MDI window but that is secondary |
The * Commissioning criteria by layer section below documents which items
apply to each meta-type (Always / If applicable / N/A per meta-type per
item).
3. Commissioning criteria by layer
What done means at each layer. Ported whole from the retired Domain entity evaluation
checklist (2026-09-03) so the criteria stay in one place. The Domain/Aux columns show
whether an item applies to a domain entity or to an auxiliary (lookup) type:
Always / Usually / If applicable / N/A. The What to look for column names the artefact or
the check. See the criteria provenance notes at the end of this section.
3.1. DB layer
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Table exists | DDL file exists for the entity | Always | Always | projects/ores.sql/create/refdata/refdata_<entity>s_create.sql |
tenant_id column |
Multi-tenancy isolation | Usually | Always | tenant_id uuid not null — omit only for truly global domain entities (currencies, countries) |
version column |
Optimistic locking | Always | Always | version integer not null |
modified_by column |
Audit: who edited | Always | Always | modified_by text not null |
performed_by column |
Audit: which service performed it | Always | Always | performed_by text not null; set by trigger to ores_iam_current_service_fn() |
change_reason_code column |
Change tracking | Always | Always | change_reason_code text not null |
change_commentary column |
Change tracking | Always | Always | change_commentary text not null |
valid_from / valid_to |
Temporal history | Always | Always | valid_from timestamp with time zone not null, valid_to timestamp with time zone not null |
| CHECK: temporal order | Prevents invalid ranges | Always | Always | check ("valid_from" < "valid_to") |
| CHECK: natural key not empty | Data integrity | Always | Always | check ("iso_code" <> '') or equivalent |
| GIST exclusion constraint | Prevents temporal overlaps | Always | Always | exclude using gist (tenant_id WITH =, <key> WITH =, tstzrange(valid_from, valid_to) WITH &&) |
| Primary key | Uniqueness | Always | Always | (tenant_id, <natural_key>, valid_from, valid_to) |
| Version unique index | Fast lookup of current version | Always | Always | UNIQUE (tenant_id, <key>, version) WHERE valid_to = ores_utility_infinity_timestamp_fn() |
| Natural key unique index | Fast lookup of current record | Always | Always | UNIQUE (tenant_id, <key>) WHERE valid_to = ores_utility_infinity_timestamp_fn() |
| Tenant index | Tenant-scoped scans | Always | Always | INDEX (tenant_id) WHERE valid_to = ores_utility_infinity_timestamp_fn() |
display_order column |
Dropdown ordering | N/A | Always | display_order integer not null default 0 |
description column |
Human-readable meaning of code | N/A | Always | description text not null |
| Insert trigger | Version management + validation | Always | Always | create or replace function ores_refdata_<entity>s_insert_fn() |
Insert trigger: security definer + set search_path |
Prevents search-path injection attacks | Always | Always | Function header must carry security definer and set search_path = public, pg_temp. Without both, a service role with a manipulated search path can shadow ores_*_tbl references and bypass validation. See Commission: country § Analysis; rule is in PostgreSQL architecture § Insert trigger patterns. |
| Soft-delete rule | History-preserving delete | Always | Always | on delete to ... do instead update ... set valid_to = current_timestamp |
| Validation function | Allows parent entities to validate soft-FK | Always | Always | create or replace function ores_refdata_validate_<entity>_fn(p_tenant_id uuid, p_value text) |
Validation function: security definer + set search_path |
Independently secure for direct-call use | Always | Always | Validate functions must carry both attributes independently of their callers. security definer does not propagate from caller to callee. See Commission: country § Analysis. |
| Validation function: bootstrap checks active rows | Bootstrap pass-through must use valid_to filter |
Always | Always | The not exists bootstrap guard must include and valid_to = ores_utility_infinity_timestamp_fn(). Without it, a table with only soft-deleted rows skips the pass-through and fails with a misleading "Must be one of: (empty list)" error. See Commission: country § Analysis. |
| Entity-specific soft-FK validations | Trigger validates referenced lookup values | Always | N/A | new.rounding_type : ores_refdata_validate_rounding_type_fn(…)= |
party_id soft-reference |
Party-scoped entity | If applicable | N/A | Domain only; check party_id uuid not null and trigger validation |
workspace_id soft-reference |
Workspace-scoped entity | If applicable | N/A | Domain only |
coding_scheme_code column |
Optional DQ coding scheme link | If applicable | N/A | coding_scheme_code text (nullable); validated in trigger if present |
3.2. Codegen layer
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Domain entity model | Codegen model for the C++ domain struct | Always | Always | projects/ores.refdata/modeling/ores.refdata.<entity>.org, * C++ section |
| Entity model | Codegen model for the ODB entity + mapper | Always | Always | projects/ores.refdata/modeling/ores.refdata.<entity>.org, * SQL and * Repository sections |
| Both models consistent with DB schema | Model fields match DB columns | Always | Always | Compare model field names/types against DDL columns |
| No hand-crafted divergence | Generated files match what codegen would produce | Always | Always | If a generated file has been edited manually, flag as drift risk |
3.3. Domain layer (C++)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Domain struct | Plain-data C++ struct | Always | Always | projects/ores.refdata.api/include/ores.refdata.api/domain/<entity>.hpp |
| All business columns represented | No column missing from struct | Always | Always | Compare struct fields against DDL columns (temporal managed by trigger, not struct) |
display_order field |
Present for aux types | N/A | Always | int display_order = 0; |
description field |
Present for aux types | N/A | Always | std::string description; |
recorded_at or equivalent |
Exposes insert timestamp (maps to DB valid_from) |
Always | Always | std::chrono::system_clock::time_point recorded_at; |
| Canonical C++ types | No raw pointers, no inheritance | Always | Always | std::string, std::optional<T>, boost::uuids::uuid, int, bool |
| No logic in struct | Plain data only | Always | Always | No methods beyond constructors; no business logic |
3.4. Repository layer (C++)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Entity class | ODB-annotated wrapper | Always | Always | ores.refdata.core/include/.../repository/<entity>_entity.hpp |
| Mapper class | DB row ↔ domain struct conversion | Always | Always | repository/<entity>_mapper.hpp |
| Repository class | Data access object | Always | Always | repository/<entity>_repository.hpp |
| list, count, save, delete, get | Core CRUD operations | Always | Always | All five methods present in repository header |
| get_history | Temporal history query | Always | Always | Method returning all versions for a given key |
| list_for_party | Party-scoped list | If applicable | N/A | Only for party-scoped domain entities |
| Tenant-scoped queries | Queries filtered by tenant_id | Usually | Always | WHERE clause includes tenant_id condition |
3.5. Service layer (C++)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Service class | Business logic + authorization wrapper | Always | Always | ores.refdata.core/include/.../service/<entity>_service.hpp |
| list, count, save, delete, get, get_history | Full CRUD + history | Always | Always | All six methods present in service header |
| list_for_party | Party-scoped list | If applicable | N/A | Domain only |
| Authorization checks | Caller permission validated | Always | Always | Authorization call before data access |
| NATS event firing on mutation | Events published on save and delete | Always | Always | NATS publish calls in save and delete implementations |
| Registered in the LISTEN/NOTIFY→NATS relay | Entity's DB notify channel is republished to NATS | Always | Always | grep <entity> projects/ores.<component>/service/src/app/application.cpp — expect an include, a register_mapping<...>, and a subscribe<...> block; this file is hand-maintained (no AUTO-GENERATED marker) and is easy to miss when commissioning a new entity. See Commission: party_type — party_type (and ~14 other entities) had a generated _changed_event.hpp but was never wired into this file, so eventing silently never fired despite the SQL trigger and service-layer publish call both being correct. |
3.6. Messaging / JSON IO layer (C++)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| JSON struct | rfl-based serialisation struct | Always | Always | ores.refdata.api/include/.../domain/<entity>_json.hpp |
| IO handler | domain ↔ JSON conversion | Always | Always | domain/<entity>_json_io.hpp |
| Protocol header | NATS message type definitions | Always | Always | messaging/<entity>_protocol.hpp |
| Mutation message types | Save/delete request + saved/deleted event | Always | Always | save_<entity>, delete_<entity>, <entity>_saved, <entity>_deleted in protocol header |
| Query message types | List, count, get, history | Always | Always | list_<entity>s, count_<entity>s, get_<entity>, get_<entity>_history in protocol header |
3.7. Qt layer
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| MDI list window | Top-level window in MDI area | Always | If applicable | ores.qt.refdata/include/ores.qt/<Entity>MdiWindow.hpp |
| Detail dialog | Single-record edit/view | Always | If applicable | <Entity>DetailDialog.hpp |
| History dialog | Temporal history for a record | Always | If applicable | <Entity>HistoryDialog.hpp |
| Controller | Wires windows to service | Always | If applicable | <Entity>Controller.hpp |
| Client model | Qt model/view data model | Always | If applicable | Client<Entity>Model.hpp |
| Dropdown populated in parent dialog | Aux type appears as a combo box choice | N/A | Always | Check parent entity's DetailDialog.cpp for a combo box loading this type |
| Import dialog | Bulk import support | If applicable | N/A | Import<Entity>Dialog.hpp — not all entities have this |
| List window loads post-NATS | Manual verification | Always | If applicable | Open app, navigate to entity MDI window, records appear |
| Detail dialog edit + save round-trip | Manual verification | Always | If applicable | Edit a field, save, reopen — change persisted |
| History dialog shows correct history | Manual verification | Always | If applicable | After edit, history dialog shows two versions |
| Delete preserves history | Manual verification | Always | If applicable | Delete record; history dialog still shows prior versions |
| NATS eventing cross-session | Manual verification | Always | If applicable | Mutation in client A appears in client B without refresh |
3.8. Shell layer (ores.shell interactive REPL)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Submenu registered | Entity has a dedicated submenu in the REPL | Always | If applicable | projects/ores.shell/src/app/commands/<entity>s_commands.cpp registered in menu |
list command |
Lists records from service | Always | If applicable | list case in the commands file |
add / save command |
Creates or updates a record | Always | If applicable | add or save case |
remove / delete command |
Deletes a record | Always | If applicable | remove or delete case |
history command |
Shows temporal history | Always | If applicable | history case |
| Post-NATS service wiring | Commands call service via NATS, not directly | Always | If applicable | Service calls use NATS client, not direct repository |
3.9. Scripted shell layer (ores.shell)
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
list subcommand |
Non-interactive list | Always | If applicable | Subcommand registered and implemented |
add / save subcommand |
Non-interactive create/update | Always | If applicable | Subcommand registered and implemented |
remove / delete subcommand |
Non-interactive delete | Always | If applicable | Subcommand registered and implemented |
| Post-NATS service wiring | Commands call service via NATS | Always | If applicable | Same as REPL |
3.10. HTTP layer
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| GET list route | REST list endpoint | Always | If applicable | GET /refdata/<entity>s in routes file |
| POST save route | REST create/update endpoint | Always | If applicable | POST /refdata/<entity>s |
| DELETE batch route | REST batch delete endpoint | Always | If applicable | DELETE /refdata/<entity>s |
| GET history route | REST history endpoint | Always | If applicable | GET /refdata/<entity>s/:id/history |
| Routes registered | Routes wired into the HTTP server | Always | If applicable | Entry in projects/ores.http.core/src/routes/ |
3.11. Wt web UI layer
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| List widget | Wt list component | Always | If applicable | projects/ores.wt.service/include/.../app/<entity>_list_widget.hpp |
| Detail dialog | Wt edit component | Always | If applicable | <entity>_dialog.hpp |
| Wired into Wt app | Widget registered in application | Always | If applicable | Reference in Wt app class |
| List + edit round-trip | Manual verification | Always | If applicable | Open Wt app, list entity, edit, save — change persisted |
3.12. Manual
| Item | Description | Domain | Aux | What to look for |
|---|---|---|---|---|
| Entity chapter | Dedicated chapter in user guide | Always | If applicable | doc/manual/user_guide/<entity>.org or equivalent |
| What and why | Entity described for a user, not a developer | Always | If applicable | First section: what this entity is, when to use it |
| Qt MDI window documented | List window walkthrough | Always | If applicable | Screenshot or description of columns and actions |
| Qt detail dialog documented | Field-by-field documentation | Always | If applicable | Table of fields with type, validation, and meaning |
| Qt history dialog documented | History usage explained | Always | If applicable | How to view and interpret change history |
| Shell commands documented | All shell commands with examples | Always | If applicable | #+begin_example blocks showing command + output |
| Aux type documented in parent chapter | Valid values listed and explained | N/A | Always | Subsection in parent entity chapter: table of codes + descriptions |
| Indexed from manual root | Chapter reachable from table of contents | Always | If applicable | Entry in doc/manual/user_guide/index.org or equivalent |
| Site builds cleanly | No broken links or missing files | Always | Always | make site passes without error |
3.13. Criteria provenance
- Commission: currency – reference domain entity used to derive these criteria
- Commission: country – extended the DB-layer criteria:
security defineron insert and validate functions; active-rows bootstrap guard; full rationale in the story's* Analysissection - PostgreSQL: Database Architecture and Conventions – canonical rules for insert trigger patterns, validate function security, and bootstrap pass-through
4. Codegen system overview
Every entity in ores.refdata (and other components) has an org model file in
projects/ores.refdata/modeling/ores.refdata.{entity}.org. The codegen system
reads these models and, for each profile requested, renders Mustache templates
and writes the output to the corresponding project directory.
The three critical variables that determine output paths are set in the entity
model (* C++ / ** Flags section):
| Variable | Set in | Example (refdata) | What it controls |
|---|---|---|---|
component |
top-level #+component: |
refdata |
SQL output, Qt component dir |
component_include |
:component_include: |
refdata.api |
API/include paths for domain, generator, protocol, nats-eventing |
component_core |
:component_core: |
refdata.core |
Core paths for repository, service, nats-handler |
Critical rule: if component_include or component_core is missing from the
entity model, generator.py silently falls back to component (e.g. refdata).
This resolves to projects/ores.refdata/ (not an active project directory) and
writes files into an untracked directory. Git sees no diff against HEAD — a
false-clean result. Every entity model must have both fields set explicitly.
See Codegen model safety guardrails for the planned guard.
4.1. How to run codegen
# Run a single profile for one entity (recommended for targeted sync) ./projects/ores.codegen/codegen.sh regenerate \ --component refdata --profile qt \ --entity rounding_type # Run a single profile for all entities in a component (generates everything) ./projects/ores.codegen/codegen.sh regenerate \ --component refdata --profile qt
When running --component without --entity (once that flag lands; see
Codegen developer experience improvements):
- 13 spurious
ERRORlines appear fortableandjunctionmodels under theqtprofile. These are expected skips, not real failures — see Downgrade profile/model-type incompatibility from error to skip. - Files for all 25+ entities are written to disk. Scope the diff to the target entities and discard the rest.
4.2. Post-run cleanup
After running --component mode, discard out-of-scope generated files:
# Revert tracked files modified for non-target entities git checkout HEAD -- projects/ores.qt/refdata/ # Remove untracked new files generated for entities not in target set git status --short | grep '^?' | awk '{print $2}' | xargs rm -f
5. Codegen output map
Complete map of profile → template → output file, using rounding_type in
refdata as the reference (component=refdata, component_include=refdata.api,
component_core=refdata.core).
5.1. sql profile
Supported model types: domain_entity, junction, schema, table
| Template | Output path |
|---|---|
| sql_schema_domain_entity_create | projects/ores.sql/create/refdata/refdata_rounding_types_create.sql |
| sql_schema_notify_trigger | projects/ores.sql/create/refdata/refdata_rounding_types_notify_trigger_create.sql |
| sql_schema_domain_entity_drop | projects/ores.sql/drop/refdata/refdata_rounding_types_drop.sql |
| sql_schema_notify_trigger_drop | projects/ores.sql/drop/refdata/refdata_rounding_types_notify_trigger_drop.sql |
⚠ Known issue (open): The sql profile also fires sql_schema_domain_entity_create for
domain_entity models alongside the newer sql_schema_create for table models.
Entities that have both a _table.json and a domain_entity model have two codegen
paths to the same file. See Codegen model safety guardrails (C1 concern).
5.2. domain profile
Supported model types: schema, domain_entity
| Template | Output path |
|---|---|
| cpp_domain_type_class.hpp | projects/ores.refdata/api/include/ores.refdata.api/domain/rounding_type.hpp |
| cpp_domain_type_json_io.hpp | projects/ores.refdata.api/include/ores.refdata.api/domain/rounding_type_json_io.hpp |
| cpp_domain_type_json_io.cpp | projects/ores.refdata.api/src/domain/rounding_type_json_io.cpp |
| cpp_domain_type_table.hpp | projects/ores.refdata.api/include/ores.refdata.api/domain/rounding_type_table.hpp |
| cpp_domain_type_table.cpp | projects/ores.refdata.api/src/domain/rounding_type_table.cpp |
| cpp_domain_type_table_io.hpp | projects/ores.refdata.api/include/ores.refdata.api/domain/rounding_type_table_io.hpp |
| cpp_domain_type_table_io.cpp | projects/ores.refdata.api/src/domain/rounding_type_table_io.cpp |
⚠ Known path inconsistency (open): The class template uses projects/ores.{component}/api/ →
projects/ores.refdata/api/ (correct, follows the actual directory layout). The six
secondary templates use projects/ores.{component_include}/ → projects/ores.refdata.api/
(a non-existent top-level directory). Git sees those six files as untracked, giving a
false-clean diff. Status: pre-existing bug; deferred to Refactor ores.codegen C++ generation.
5.3. generator profile
Supported model types: schema, domain_entity
| Template | Output path |
|---|---|
| cpp_domain_type_generator.hpp | projects/ores.refdata.api/include/ores.refdata.api/generators/rounding_type_generator.hpp |
| cpp_domain_type_generator.cpp | projects/ores.refdata.api/src/generators/rounding_type_generator.cpp |
5.4. repository profile
Supported model types: schema, domain_entity
| Template | Output path |
|---|---|
| cpp_domain_type_entity.hpp | projects/ores.refdata.core/include/ores.refdata.core/repository/rounding_type_entity.hpp |
| cpp_domain_type_entity.cpp | projects/ores.refdata.core/src/repository/rounding_type_entity.cpp |
| cpp_domain_type_mapper.hpp | projects/ores.refdata.core/include/ores.refdata.core/repository/rounding_type_mapper.hpp |
| cpp_domain_type_mapper.cpp | projects/ores.refdata.core/src/repository/rounding_type_mapper.cpp |
| cpp_domain_type_repository.hpp | projects/ores.refdata.core/include/ores.refdata.core/repository/rounding_type_repository.hpp |
| cpp_domain_type_repository.cpp | projects/ores.refdata.core/src/repository/rounding_type_repository.cpp |
5.5. service profile
Supported model types: schema, domain_entity
| Template | Output path |
|---|---|
| cpp_service.hpp | projects/ores.refdata.core/include/ores.refdata.core/service/rounding_type_service.hpp |
| cpp_service.cpp | projects/ores.refdata.core/src/service/rounding_type_service.cpp |
5.6. protocol profile
Supported model types: domain_entity, schema
| Template | Output path |
|---|---|
| cpp_protocol.hpp | projects/ores.refdata.api/include/ores.refdata.api/messaging/rounding_type_protocol.hpp |
5.7. nats-eventing profile
Supported model types: domain_entity, schema
| Template | Output path |
|---|---|
| cpp_nats_changed_event.hpp | projects/ores.refdata.api/include/ores.refdata.api/eventing/rounding_type_changed_event.hpp |
5.8. nats-handler profile
Supported model types: domain_entity, schema
| Template | Output path |
|---|---|
| cpp_nats_handler.hpp | projects/ores.refdata.core/include/ores.refdata.core/messaging/rounding_type_handler.hpp |
5.9. qt profile
Supported model types: domain_entity only
| Template | Output path |
|---|---|
| cpp_qt_client_model.hpp | projects/ores.qt/refdata/include/ores.qt/ClientRoundingTypeModel.hpp |
| cpp_qt_client_model.cpp | projects/ores.qt/refdata/src/ClientRoundingTypeModel.cpp |
| cpp_qt_mdi_window.hpp | projects/ores.qt/refdata/include/ores.qt/RoundingTypeMdiWindow.hpp |
| cpp_qt_mdi_window.cpp | projects/ores.qt/refdata/src/RoundingTypeMdiWindow.cpp |
| cpp_qt_detail_dialog.hpp | projects/ores.qt/refdata/include/ores.qt/RoundingTypeDetailDialog.hpp |
| cpp_qt_detail_dialog.cpp | projects/ores.qt/refdata/src/RoundingTypeDetailDialog.cpp |
| cpp_qt_history_dialog.hpp | projects/ores.qt/refdata/include/ores.qt/RoundingTypeHistoryDialog.hpp |
| cpp_qt_history_dialog.cpp | projects/ores.qt/refdata/src/RoundingTypeHistoryDialog.cpp |
| cpp_qt_controller.hpp | projects/ores.qt/refdata/include/ores.qt/RoundingTypeController.hpp |
| cpp_qt_controller.cpp | projects/ores.qt/refdata/src/RoundingTypeController.cpp |
| qt_detail_dialog_ui | projects/ores.qt/refdata/ui/RoundingTypeDetailDialog.ui |
| qt_history_dialog_ui | projects/ores.qt/refdata/ui/RoundingTypeHistoryDialog.ui |
6. Drift classification
Every difference between what codegen produces and what is in the repository must be classified before any fix is applied. The direction of the fix depends on the category.
| Category | Definition | Fix direction | Examples |
|---|---|---|---|
| Template gap | Template does not support a feature that the code correctly has | Fix template | has_change_reason_cache not in controller template; UiPersistence missing; version history method not generated |
| Template bug | Template produces structurally wrong output | Fix template | Wrong include guard prefix; wrong NATS channel name; wrong field name |
| Code bug | Code diverged from what the template produces, incorrectly | Fix code | Wrong field name in protocol access (result->rounding_types vs result->types); typo in string literal |
| Cosmetic drift | Formatting difference only; no semantic difference | Accept drift | Include ordering (user before system); constructor initialiser style; connect() arg alignment |
| Model-driven improvement | Template update from org model produces better output (doc, naming) | Accept new output | @brief rewrite from model; example values capitalised; display_order = 0 default init |
| Out-of-scope | Drift in a file belonging to a different entity or component | Discard | Files for entities not in the target set generated by --component run |
Rule: never accept drift silently. Every category must be recorded in the task's
* Review or * Notes table with a "Decision" column entry.
7. Known open path issues (as of 2026-06-25)
| Issue | Status | Owner story |
|---|---|---|
Domain secondary templates (json_io, table, table_io) write to projects/ores.refdata.api/ (untracked) instead of projects/ores.refdata/api/ |
Open — false-clean diffs; files untracked so git shows no diff | Refactor ores.codegen C++ generation |
sql profile dual-fires old and new SQL templates on domain_entity models |
Open — parallel SQL codegen paths exist | Codegen model safety guardrails |
No guard in generator.py when component_include falls back to component |
Open — produces false-clean untracked output | Codegen model safety guardrails |
13 spurious ERROR lines when running qt profile against refdata-cpp (table + junction models) |
Open — noise but not a real failure | Codegen developer experience improvements |
--component runs generate all entities; no --entity filter |
Open — requires manual cleanup | Codegen developer experience improvements |
Qt output paths used dot notation (ores.qt.{component}) instead of slash |
Fixed in PR #1311 | Closed |
Entity models missing .api segment in domain_include=/=protocol_include |
Fixed in PR #1311 for the 3 auxiliary entities | Closed |
8. Standard commission story structure
A commission story should have exactly the following tasks. The table below is the canonical task list; mark N/A for items genuinely not applicable to the entity with a brief reason.
| # | Task | Applies to | Notes |
|---|---|---|---|
| 1 | Appraise: score all layers using the evaluation checklist | Always | First task; findings drive the rest |
| 2 | Verify and fix SQL | Always | DDL criteria from checklist; security-definer, bootstrap guard, GIST exclusion |
| 3 | Sync codegen: sql profile | Always | Zero-diff or sign-off every delta |
| 4 | Sync codegen: domain profile | Always | Watch for false-clean (secondary templates write to untracked path) |
| 5 | Sync codegen: repository profile | Always | |
| 6 | Sync codegen: service profile | Always | |
| 7 | Sync codegen: generator profile | Always | |
| 8 | Sync codegen: protocol profile | Always | |
| 9 | Sync codegen: nats-eventing profile | Always | |
| 10 | Sync codegen: nats-handler profile | Always | |
| 11 | Sync codegen: qt profile | Domain always; Aux if Qt window exists | 12 output files per entity |
| 12 | Verify and fix shell commands | Always | list, add/save, remove, history; post-NATS wiring |
| 13 | Verify Qt UI end-to-end | Domain always; Aux if Qt window exists | MDI list, detail, history, delete, eventing |
| 14 | Write documentation | Always | Manual chapter, shell recipe, NATS message reference |
| 15 | File Wt and HTTP gap captures | Always | Backlog only — not in-sprint tasks |
Tasks 3–11 (codegen sync) are often grouped into one or two tasks per sprint for efficiency, but must each produce a signed-off diff table (zero diff or explicit accept/fix decision per file).
8.1. Codegen sync task acceptance criteria
A codegen sync task for any profile is complete when:
Output location check (do this first, before diffing): every generated file lands in the correct split project directory, not in the monolith:
Profile Expected root Wrong root (monolith — do NOT write here) domain(class template)projects/ores.{component}/api/(same path, check secondary templates) domain(secondary: json_io, table, table_io)projects/ores.{component_include}/projects/ores.{component}/api/generatorprojects/ores.{component_include}/projects/ores.{component}/api/repositoryprojects/ores.{component_core}/projects/ores.{component}/core/serviceprojects/ores.{component_core}/projects/ores.{component}/core/protocolprojects/ores.{component_include}/projects/ores.{component}/api/nats-eventingprojects/ores.{component_include}/projects/ores.{component}/api/nats-handlerprojects/ores.{component_core}/projects/ores.{component}/core/qtprojects/ores.qt/{component}/(no split variant; single path) For
refdata(component_include=refdata.api,component_core=refdata.core):- API headers →
projects/ores.refdata.api/include/ores.refdata.api/ - Core headers →
projects/ores.refdata.core/include/ores.refdata.core/
If a file appears as untracked under
projects/ores.refdata/after running codegen, the output went to the wrong location. Checkcomponent_include/component_corein the entity model (* C++ / ** Flags).- API headers →
- Every generated file either:
a. Produces zero diff against the corresponding hand-written file in the monolith
(
projects/ores.{component}/{api,core}/), or b. Has its delta classified (category from the drift table above) and the decision recorded (fix template / fix code / accept). - All "fix template" decisions have a corresponding template commit.
- All "fix code" decisions have a corresponding code commit with justification.
- All "accept" decisions are recorded in the task's
* Notesor* Reviewtable. - No generated files for non-target entities have been left modified.
- The build passes (no C++ regressions).
8.2. Commit discipline
- One commit per logical fix (template fix, code fix, or model update).
- Never amend commits on a branch under review.
- Never use
git add -A— add files individually to avoid committing generated files for unrelated entities.
9. See also
- Codegen architecture analysis and unified model roadmap — structural concerns C1–C9 and 4-phase roadmap
- ores physical-space graph — authoritative profile → template → output path definitions (consumed by generator.py)
- Commission: currency — reference commission story; most complete example