Task: Retire per-entity history dialog templates for the generic HistoryDialog
This page documents a task in the Consolidate history dialogs onto HistoryDialogBase story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Implement History Diff Architecture end to end, replacing every one
of the 67 *HistoryDialog classes (the 6 hand-rolled ones migrated
onto HistoryDialogBase earlier in this story, plus the 61
codegen-generated ones this task was originally scoped to) with a
single, non-templated HistoryDialog widget. This supersedes the
original "adopt HistoryDialogBase in the template" scope: rather
than migrating per-entity generated dialogs onto a shared base class,
the per-entity dialog classes and their generating templates are
retired outright.
Was gated on the codegen org-model migration: that migration (Codegen unified model — org-mode migration) completed 2026-06-11 — the gate is clear. This task additionally depended on Redesign server-side history-diff architecture (DONE 2026-07-11) for the design it implements.
Status
| Field | Value |
|---|---|
| State | ABANDONED |
| Parent story | Consolidate history dialogs onto HistoryDialogBase |
| Now | Split into six finer-grained sibling tasks below; this umbrella task closed with no code changes. |
| Waiting on | Nothing. |
| Next | Pick up ores.diff: intra-value diff spans first (nothing else depends on it, and everything downstream needs it). |
| Last touched | 2026-07-11 |
Acceptance
- One generic NATS history subject (
history.v1.get) exists, with a server-side dispatch table keyed byentity_type_of(); every entity's typedget_<entity>_historysubject is removed. - Every entity has a codegen'd, plain (not hand-written, not generic- reflection) field-to-string mapper, registered as a history provider.
ores.diff::diff_entrycarriesold_spans=/=new_spans; the test coverage list in the redesign task's Notes is satisfied.HistoryDialogBaseand all per-entity*HistoryDialogclasses are deleted, along withcpp_qt_history_dialog.{hpp,cpp}.mustacheandqt_history_dialog_ui.mustache; a singleHistoryDialogwidget replaces them, taking(entity_type, entity_id).Open=/=Revertdispatch through a codegen'd per-entity action registry (client side); no typed domain payload flows throughHistoryDialogsignals.ores.shell's disabledcurrencies history-diffcommand is replaced by one generic entity-parameterised shell renderer, re-enabled for every entity.- History responses carry no full domain payload; open/revert fetch the typed entity by id/version through each entity's existing typed request when needed.
- Zero-diff regeneration checks green for whatever codegen facets remain (field mapper, history-provider/action registrations); no facet still emits a per-entity dialog class.
Plan
- ores.diff: add
diff_spantodiff_entry; implement span computation inengine::compute(prefix/suffix for single-line, line-LCS + per-line token diff for multiline); cover the test list from the redesign task's Notes. - Entity identifier: add the
entity_type_of()codegen facet, generating the free-function trait per entity. - Server side: add the per-entity field-mapper codegen facet;
introduce the generic
history.v1.getsubject and its dispatch-table handler (reapplying Entity-composed registrars); register each entity's mapper as a history provider; remove the per-entityget_<entity>_historysubjects and handlers as each entity migrates. - Qt: build the single
HistoryDialogwidget (version list, async load, toolbar, changes-tab rendering withdiff_spancolour highlighting per the GitHub-style capture); add the codegen'd per-entityOpen=/=Revertaction registry; wire callers (list windows/controllers) to constructHistoryDialog(entity_type, entity_id)instead of a typed dialog subclass. - Retire the old shape: delete
HistoryDialogBase, every per-entity*HistoryDialogclass, andcpp_qt_history_dialog.{hpp,cpp}.mustache=/=qt_history_dialog_ui.mustacheonce every entity has migrated; zero-diff guardrails confirm no facet still emits them. - Shell: replace the disabled
currencies history-diffcommand with the generic entity-parameterised renderer, re-enabled for every entity. - Composite entities: wire the "Details" affordance for
child-driven versions (per the architecture doc's composite
section) — opens another
HistoryDialoginstance with the child's(entity_type, entity_id).
Given the size, this likely wants splitting into sub-tasks by phase (ores.diff spans; server dispatch; Qt widget; shell; retirement sweep) once implementation starts — revisit before diving in.
Notes
PRs
| PR | Title |
|---|---|
Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
Result
Split into six finer-grained sibling tasks, one per Plan phase, before any implementation started — this task's own scope was too large to track as a single unit of work:
- ores.diff: intra-value diff spans
- Codegen the entity_type_of() identifier trait
- Generic server-side history dispatch: one subject, per-entity handlers
- Single generic HistoryDialog widget in ores.qt
- Retire HistoryDialogBase, per-entity dialogs, and their templates
- Generic unified-diff history renderer in ores.shell
Dependency order: (1) and (2) are independent and can run in either order; (3) needs both; (4) and (6) each need (3); (5) needs (4) and (6) — it retires the old shape only once nothing still depends on it. This task closes with no code changes; its Plan and Acceptance were distributed into the six tasks above.