Story: Implement temporal composite entity versioning
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
Land the SQL/codegen mechanism for child writes to bump a parent's version in the same transaction, the as-of read-side composition query, and the Qt composite history dialog, proven against party and counterparty as the reference entities.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent sprint | Sprint 22 |
| Now | Core mechanism (SQL touch-function, as-of query, architecture decisions) shipped. |
| Waiting on | Nothing. |
| Next | None — the 2 remaining Qt/doc tasks moved to Commission party, counterparty, and party_status together, since both are gated on that story's own binding prerequisite. |
| Last touched | 2026-07-10 |
Acceptance
- Child writes to party_identifier/party_contact_information (and counterparty equivalents) bump the parent's version in the same transaction, with a standardized change-reason comment. A read-side as-of query composes parent+children by matching valid_from/valid_to windows. The Qt history dialog shows composite state as of a selected parent version. Zero-diff regen where codegen already covers the entity; hand-patched first for party (not yet under codegen), matching the established pattern.
Tasks
| Task | State | Start | End | Description |
|---|---|---|---|---|
| Resolve open decisions from the versioning architecture doc | DONE | 2026-07-07 | 2026-07-07 | Sign off on: whether child DELETE also bumps the parent version, the actual codegen flag names (bump_parent_version, list_by_as_of), and whether reason-code stamping on the touch function is mandatory. Record decisions in the architecture doc and this story. |
| SQL touch-function mechanism: child writes bump parent version | DONE | 2026-07-07 | 2026-07-08 | Hand-patch party_identifier/party_contact_information (and generate the equivalent for counterparty via the codegen facet) so their insert trigger and soft-delete rule call a shared touch function that bumps the parent's version in the same transaction, with a standardized change-reason comment. |
| As-of window-join read-side composition query | DONE | 2026-07-08 | 2026-07-08 | Add the parent as-of-version fetch and the child as-of-window list query (interval overlap against the parent's valid_from/valid_to), plus a service-level helper composing parent+children as of a given parent version. |
| Qt composite history/version dialog | (moved) | 2026-07-08 | 2026-07-10 | Moved to Commission party, counterparty, and party_status together — blocked on that story's own party/counterparty binding prerequisite. |
| Document the composite versioning approach and codegen recipe | (moved) | 2026-07-10 | Moved to Commission party, counterparty, and party_status together — gated on the Qt dialog task above landing for real. |
Decisions
- Child DELETE bumps the parent version, symmetric with insert/update.
- Codegen FK flag:
:bump_parent_version:(alongside:list_by:); read-side counterpart:list_by_as_of:. - Reason-code stamping on the touch function is mandatory.
- This is codegen-driven from the start, not a hand-patch-only
affair: both flags are variability knobs on the entity
.orgmodel — enabling them on any FK generates the full mechanism (touch function call from the trigger and delete rule, the as-of query). Party is hand-patched first only because party itself isn't yet under codegen; counterparty gets it purely by flipping the flags. - Composite tab UX finding (from the test scenario's first step,
marked FAIL by the author): showing a flat "identifiers/contacts as
of this version" list is not the right end-state UX — a tester
wants to know which child changed at a version and drill into
that child's own history (old value → new value), not re-derive
the diff by eye against the previous version's flat list.
- That drill-down needs a per-child-entity history dialog
(
PartyIdentifierHistoryDialog,PartyContactInformationHistoryDialog, and counterparty equivalents), which doesn't exist yet. - Per-child history dialogs must be codegen-generated (the same
facet that generates
HistoryDialogBase-derived dialogs for top-level entities today), not hand-built one-off for this task. - That commissioning is exactly task 3 ("Bind composite child-entity and hierarchy widgets to party and counterparty") of the sibling Composite child-entity and hierarchy Qt widgets for codegen story — so the Composite tab's flat-list view here is a deliberate interim, blocked from reaching its real end-state UX until that story's task 3 lands. Not a defect to chase further in this task.
- That drill-down needs a per-child-entity history dialog
(