Task: Migrate ores.qt.party's history dialogs to the generic HistoryDialog

Table of Contents

This page documents a task in the Migrate ores.qt.refdata onto the generic HistoryDialog story. It captures the goal, current status, acceptance, and any notes or results.

Goal

Retire the 4 hand-rolled *HistoryDialog classes in projects/ores.qt/party (BusinessUnitHistoryDialog, BusinessUnitTypeHistoryDialog, PartyIdSchemeHistoryDialog, PartyStatusHistoryDialog), wiring business_unit, business_unit_type, party_id_scheme, and party_status onto the generic HistoryDialog. Scope expanded substantially mid-task — see Plan — into moving all 4 entities out of ores.qt.party (deleted) into ores.qt.refdata, and then bringing all 4 entities onto full codegen (domain/SQL/repository/service/protocol/generator/Qt/eventing), including authoring a brand-new codegen model for business_unit_type (which never had one) and a new codegen template paste-point.

Status

Field Value
State DONE
Parent story Migrate ores.qt.refdata onto the generic HistoryDialog
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-07-17

Acceptance

  • All 4 entities' history windows use the generic HistoryDialog (no per-entity *HistoryDialog class remains). ✅
  • ores.qt.party plugin is deleted; its 4 entities live in ores.qt.refdata=/=RefdataPlugin instead. ✅
  • All 4 entities have a complete codegen stack (domain/SQL/repository/service/protocol/generator/Qt/eventing), diffed layer-by-layer against the prior hand-written code. ✅
  • Local build passes clean. ✅
  • PR #1609 merged. ✅

Plan

Original scope (per the task title) was a frontend-only rewire, same shape as currency's PR #1553. Investigation and explicit direction mid-task expanded it in three stages:

Stage 1 — backend generic-history support + frontend rewire

No backend generic-history support existed for any of the 4 entities (no entity_type_of, no *_history_field_mapper, no register_history_provider registration in registrar.cpp) — unlike currency, which already had it. Added these by hand initially, and rewired all 4 controllers' showHistoryWindow=/=onOpenVersion=/ =onRevertVersion to the generic HistoryDialog, following CurrencyController's pattern. Deleted the 4 *HistoryDialog classes.

Stage 2 — ores.qt.party is not a real plugin; dissolve it

ores.qt.party's own doc comment says "contributes to the shared Reference Data menu; no standalone menu"; all 4 entities are ores.refdata.api::domain::* with no ores.party backend at all; and the product backlog already had a matching deferred capture (Dissolve ores.qt.party plugin) tracking exactly this. Moved all 4 entities' Qt code into ores.qt.refdata via git mv, wired the 4 controllers into RefdataPlugin, deleted ores.qt.party entirely (plugin class, CMake wiring, modeling docs), and updated the architecture docs.

Stage 3 — full codegen, not hand-wiring

Explicit direction: every entity touched here should have a complete codegen stack, not hand-maintained backend glue. Re-did stage 1's hand-written pieces properly:

  • business_unit, party_id_scheme, party_status: regenerated domain/repository/service/protocol/generator/presentation/Qt layer by layer, diffing each against the prior hand-written code before accepting. SQL regeneration was skipped for party_id_scheme and party_status — both are dual-file entities (a _table.org counterpart already owns their SQL; regenerating from the domain_entity file is a documented unsafe path per codegen-model-unification.org, and neither needed schema changes). business_unit's SQL was regenerated cleanly.
  • business_unit_type: had no codegen model at all. Authored one from scratch (using business_unit.org=/=business_centre.org as templates), including its full stack. Its coding_scheme_code FK is always system-tenant-scoped (unlike ordinary per-tenant soft FKs) and it exports a validator function (ores_refdata_validate_business_unit_type_fn) that business_unit's own trigger depends on — neither fits the standard per-column FK knobs, so both are expressed as trailing-paste-block custom SQL. That required adding a new, backward-compatible trailing paste marker to the shared sql_schema_domain_entity_create template (verified as a no-op against an unrelated already-generated entity, currency, before relying on it).
  • NATS eventing: discovered mid-stage that business_unit_type and party_id_scheme never had eventing wired at all (Qt already subscribed to changed-events that nothing published), and that business_unit's own eventing was hand-wired directly in application.cpp rather than through the generated per-entity *_event_registrar pattern. Generated and wired all three properly (Postgres NOTIFY trigger → generated *_event_registrarevent_registrar.cpp → NATS publish), and removed the hand-written block for business_unit from application.cpp.

Real pre-existing bugs found and fixed while regenerating (not introduced by this task, surfaced by actually exercising codegen for the first time on stale/never-generated models):

  • Old hand-written repositories had no tenant_id filtering at all on any query — a multi-tenancy isolation gap; the current template scopes every query by tenant.
  • A model generator snippet assigned a raw boost::uuids::uuid() (nil, but an engaged optional) to an optional-uuid field instead of std::nullopt, which would have failed FK validation on every synthetic-data insert.
  • Two models had a wrong include path (ores.refdata/domain/... missing .api), never caught because their Qt facet had never actually been generated before.
  • Regenerating BusinessUnitController silently dropped IBusinessUnitBrowser, a cross-plugin interface TradingPlugin's Org Explorer view depends on for its business-unit edit/history actions — restored by hand after each regen (the interface isn't representable in the model). Also found that wiring was already passing nullptr for it before this task — a separate, older pre-existing gap, now fixed for real.
  • party_id_scheme.org had a * Check constraints heading that the domain_entity SQL template silently ignores (the real heading is * SQL / ** Checks); moot here since SQL regen was skipped for that entity, but worth knowing.
  • default "" (double-quoted empty string) is invalid SQL string literal syntax; fixed to omit the default entirely.
  • A faker API rename (faker::company::name() doesn't exist; companyName() does) in business_unit.org's generator snippet — pre-existing, never caught because the generator had never run.

Deliberately accepted, disclosed simplifications: the old BusinessUnitDetailDialog showed a read-only "level" label next to the unit-type picker as a side effect of selection; the regenerated dynamic_combo doesn't support that auxiliary display. Not restored (minor UX nicety, not core functionality).

Notes

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
#1609 [refdata,qt,codegen] Migrate ores.qt.party entities to generic HistoryDialog + full codegen

Review

# Comment summary File Decision Notes
1 Stale ores.qt.party links break site build component_overview.org (refdata, application) Accepted Fixed in 3a0d4ae3, before this round.
2 No test coverage for new repository methods business_unit(_type)_repository tests Accepted Added repository_business_unit_repository_tests.cpp (new file) and new cases (pagination, count, at-version, batch remove) to the existing business_unit_type test file.
3 Dropped !empty() guard before lexical_cast<uuid> business_unit_mapper.cpp Declined Matches existing convention — verified identical pattern in portfolio_mapper.cpp (has_value() only, no empty check); DB columns are typed uuid null, not text, so an empty string can't reach this path.
4 Stale prose "ores.qt.party contributes party-related items" ores.qt/refdata component_overview.org Accepted Reworded to describe the party-domain entities directly, no more reference to the deleted plugin.

Result

All 4 entities (business_unit, business_unit_type, party_id_scheme, party_status) now use the generic HistoryDialog, live in ores.qt.refdata=/=RefdataPlugin (ores.qt.party deleted entirely), and have complete, codegen-generated stacks rather than hand-maintained backend glue — including a brand-new model for business_unit_type and a new backward-compatible trailing paste point added to the shared SQL create template. Several real pre-existing bugs (missing tenant scoping, a nil-vs-nullopt generator bug, two wrong include paths, a silently-dropped cross-plugin interface, missing/hand-wired NATS eventing for 3 entities) were found and fixed along the way. Local build (linux-clang-debug-make) passes clean. PR #1609 merged 2026-07-17.

Emacs 29.3 (Org mode 9.6.15)