Story: Remove the legacy Qt remnants
Table of Contents
- 1. Goal
- 2. Status
- 3. Acceptance
- 4. Tasks
- 5. Decisions
- 5.1. The first unit takes only the Qt-named keys
- 5.2. The removal is proved output-neutral, not argued
- 5.3. What is left, and what the next unit must decide
- 5.4. The first read analysis was wrong, and the way it was wrong matters
- 5.5. The related codegen code, and its size
- 5.6. This story executes the Component Clean Standard, rules M09 and H02
- 5.7. One toggle is kept on the repository's own precedent
- 5.8. The documentation unit
- 5.9. The independent verifier found a cascade the removal did not finish
- 6. Out of scope
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 deletedsetCreateMode.has_as_of_combo_fieldsand its helper, which gated adatetime.hppinclude and thesetX()/setReadOnly()re-populate calls in the Qt detail-dialog template.view_groupsand its helpercompute_view_groups, which grouped detail fields into Qt detail-dialog tabs.has_uuid_detail_fieldsandhas_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:
- Keys nothing reads, which go.
- Keys read only by another unread key, which go together.
- Keys read by a validator, such as
has_parent_scoped_listthroughvalidate_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/analysisanddoc/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_interfaceandvalidate_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.