Story: Remove the legacy Qt remnants

Table of Contents

This page documents a story in Sprint 26. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

1. Goal

Nothing in the tree computes, documents or names a Qt concept that no longer exists. The generator produces byte-identical output for every component, and every page that described the Qt layer states it as history or is gone.

2. Status

Field Value
State STARTED
Parent sprint Sprint 26
Now Not yet started.
Waiting on Nothing.
Next Break the story into tasks.
Last touched 2026-09-23

3. Acceptance

  • No presentation key is written that no template, render path or validator reads.
  • The helpers that existed only to compute unread keys are gone, with their tests.
  • Regenerating a component produces no diff, so the removal is proved output-neutral.
  • Every document that named the Qt layer as live is corrected or marked historical.

4. Tasks

Task State Start End Description
Scaffold story: Remove the legacy Qt remnants DONE 2026-09-23 2026-09-23 Story scaffolding rides this task: documents, sprint wiring, and the scaffold PR. Close it before merging that PR.
Remove the presentation keys no template reads STARTED 2026-09-23   Initial task for: Remove the legacy Qt remnants

5. Decisions

5.1. The first unit takes only the Qt-named keys

Removed in the first pass, because each is Qt-specific in name and purpose and each is written to the presentation dict that no template, render path or validator reads:

  • qt_settings_version, a QSettings concept.
  • key_widget, the key field's Qt widget class, for the deleted setCreateMode.
  • has_as_of_combo_fields and its helper, which gated a datetime.hpp include and the setX()/setReadOnly() re-populate calls in the Qt detail-dialog template.
  • view_groups and its helper compute_view_groups, which grouped detail fields into Qt detail-dialog tabs.
  • has_uuid_detail_fields and has_date_detail_fields.

Both helpers went with their only caller, along with test_view_groups.py and test_as_of_combo_fields.py.

5.2. The removal is proved output-neutral, not argued

presentation is never put into the render data. The generator's own drift gate regenerates a component and compares, so it answers the question directly: iam is byte-identical after the removal, and refdata, the largest component, produces the same 806 diff headers before and after against its own pre-existing drift. Nothing that reaches a template changed.

5.3. What is left, and what the next unit must decide

The presentation dict carries 54 keys. 44 are written and read by nothing. The first pass took the Qt-named handful. The rest are Qt-era too (needs_item_delegate, metadata_start_row, export_macro, hidden_columns, changed_event_class, flag_icon_column, has_dynamic_combo_fields, and so on), but some are read by other keys inside the same block, and a few are read by validators rather than templates.

The next unit has to separate three cases that look alike:

  1. Keys nothing reads, which go.
  2. Keys read only by another unread key, which go together.
  3. Keys read by a validator, such as has_parent_scoped_list through validate_parent_scoped_list. A validator fails fast on a bad model, so removing the key means removing the guard, and the guard may still earn its place. Decide these one at a time.

Take one key, remove it, re-run the drift gate. The gate is the authority, because it compares rendered output rather than reading code.

5.4. The first read analysis was wrong, and the way it was wrong matters

The first pass counted a write that reads its own key as a write only, so presentation['has_pagination'] = presentation.get('has_pagination', False) looked unread. It is not a read in any useful sense: it defaults a value that nothing consumes. The same shape applies to item_var.

The distinction to keep straight is between a self-default and a consumed read. A self-default writes a key from itself and proves nothing. A consumed read is another expression, or another key, reading the value.

Both keys are dead in substance. item_var went with the Qt list-window chrome in a later pass, once the models were swept. has_pagination is kept, because its feature document records it as a retired toggle that stays accepted as documentation.

5.5. The related codegen code, and its size

The keys are the visible part. What carries them is larger:

Layer Size File
The generator 35 keys src/codegen/core.py
Profile flags routed into presentation 12, of which has_csv_xml_io and has_version_navigation are read by nothing src/codegen/org_loader.py
Profile features declaring those flags 12 features under projects/modeling/variability_feature_*.org  
Entity models with a Presentation drawer 115 models, 67 distinct drawer properties projects/*/modeling/*.org
Validators reading the dict validate_explorer_interface, validate_parent_scoped_list src/codegen/core.py

5.6. This story executes the Component Clean Standard, rules M09 and H02

M09 asks that no Qt or Wt presentation drawer or property remain in a model, and names its check as a grep over the modeling directories. H02 asks the same of code. That grep stood at 656 hits at the start of this work and at 94 after it, and what remains is documentation rather than models.

5.7. One toggle is kept on the repository's own precedent

variability_feature_has_pagination.org records that has_pagination was retired as a behavioural toggle on 2026-09-04, and that the literal stays accepted on entity orgs and profiles as documentation only. It is left exactly as it is, loader routing included, because deleting it would reverse a documented decision rather than remove a remnant.

has_csv_xml_io and has_version_navigation carry no such note, and their stated effects name Qt artefacts the retirement deleted: the MDI window import dialog with its csv_export_class and xml_export_class helpers, and the detail dialog's version navigation controls. They are marked retired the same way has_pagination is, rather than deleted, so that a model or a profile still declaring one does not begin failing model drift for a reason that has nothing to do with Qt.

5.8. The documentation unit

Corrected here. The README's Qt6 badge is gone, so the project no longer advertises a dependency it does not have. The icon inventory's 118 links into the deleted ores.qt tree are either repointed at the surviving icon set, 40 of them, or marked as removed, 78. The user manual carries a status note saying it documents the retired client and that its chapters are the record and the domain source. The qt tag is marked retired rather than deleted, so historical documents keep a defined tag. qt left the component vocabulary, because no such component exists to file work under.

Naming what is left rather than hiding it. About fourteen user manual chapters still describe Qt screens in their body text, and projects/ores.codegen/modeling/entity_meta_model_cpp_qt.org still documents drawer properties this branch deleted. Both are prose rewrites rather than mechanical edits, and no gate verifies them, so neither is attempted in this pass. The manual note makes both survivable for a reader in the meantime.

5.9. The independent verifier found a cascade the removal did not finish

Reviewed before landing. The verifier reproduced the central claim more strongly than the branch did: it rendered refdata from both revisions, 2788 files each with no difference, and marketdata, 234 each with no difference. Both sit outside the drift gate, which covers iam only.

It also falsified the claim that the loops went. hidden_columns is still built and marked in core.py while its write to presentation is gone. has_badge_columns and has_self_colour_columns are still written with no reader left, because the needs_item_delegate consumer went. parent_pascal is assigned once and never used.

That is a cascade rather than three separate misses: each removal orphans the next, and the same is true of has_parent_relationship and then parent_entity_singular, which four models still declare. The method is the one already proven here, key by key with the drift gate between each, and it belongs to this task rather than to a rushed pass before a merge.

6. Out of scope

  • The name of projects/ores.codegen/modeling/entity_meta_model_cpp_qt.org, a Qt-named page whose content is corrected here but whose filename and ID stay.
  • doc/analysis and doc/plans, which hold most of the Qt references in the tree. They read as history. Confirm that before touching them.
  • The two validators, validate_explorer_interface and validate_parent_scoped_list. Each guards a knob that still exists, so removing the guard would remove a check on a model author rather than a fragment of the Qt client.

Emacs 29.3 (Org mode 9.6.15)