Task: Analyze current badge colour determination and design improved storage
Table of Contents
This page documents a task in the Improve badge colour scheme support story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Determine how badge colours are currently determined across the codebase, and whether/how to move toward storing colour schemes in the database — either alongside a "table enum type"'s own row data, or as a system-level property for cases like booleans, per the story's framing.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Improve badge colour scheme support |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-07-15 |
Acceptance
- Establishes, with evidence (grep/file references, not guesswork), whether badge colours are currently hardcoded or data-driven.
- If a data-driven mechanism already exists, assesses how complete its rollout is (adoption coverage, remaining hardcoded stragglers, Qt-vs-Wt parity) rather than assuming it needs to be built from scratch.
- Produces a concrete recommendation: either a design for new storage,
or a scoped list of gaps to close in an already-adequate design —
written into this task's
* Resultand reflected in the story's* Decisions=/=* Tasks.
Plan
- Searched for any existing badge-related infrastructure before
assuming none exists — found a full, already-implemented,
database-driven badge system, designed in
doc/plans/2026-03-28-badge-system-design.org(2026-03-28) and substantially built out since: fourores.dqentities (badge_severity,code_domain,badge_definition,badge_mapping), a client-sideBadgeCache(loaded once at startup, synchronousresolve(code_domain, entity_code)), and codegen support (abadge_keycolumn annotation that generates the delegate wiring automatically — seeores.cpp.qt.mdi_window_impl.org's\{\{#is_badge\}\}section). - Verified the design doc's own success criteria against the current
tree rather than trusting the doc alone:
BadgeColors.hppis gone;ColorConstants.hppno longer has abadge_colorsstruct — Phase 3 cleanup of the old hardcoded path is done.- Sampled every file
grepfound still callingset_badge_color_resolver(the delegate API, ~19 files:BookMdiWindow.cpp,TenantMdiWindow.cpp,ComputeConsoleWindow.cpp,WorkspaceMdiWindow.cpp, others) — every one of them resolves throughBadgeCache::resolve()already; none hardcode a colour inline. The Phase-2 delegate migration described in the design doc is, as far as this sample shows, complete for the entities that have adopted badges at all. - Confirmed
BookMdiWindow.cpp's badge wiring (set_badge_color_resolver(...)callingcache->resolve("book_status", ...),cache->resolve("is_sweepable", ...), etc.) is\{\{#is_badge\}\}codegen output, not hand-written — matches thebadge_keycolumn annotation onores.refdata.book.org.
- Directly tested the story's own hypothesis ("for booleans it is a
system property"):
is_sweepable(a boolean column) already renders as a badge, via the exact same(code_domain, entity_code)mapping mechanism as any enum —code_domain = "is_sweepable",entity_code = "true"/"false", seeded as two ordinarybadge_mappingrows (dq_badge_system_populate.sql:502,504), reusing the sharedactive=/=inactivebadge definitions. There is no separate "system property" mechanism for booleans, and no gap here — the hypothesis in the story's own framing turned out to be already answered, just not the way it assumed. A code comment atdq_badge_system_populate.sql:725documents this as a repeatable convention ("same convention asis_sweepable"), so it is not a one-off hack either. - Checked adoption breadth, not just depth:
badge_keyis used in only 10 of 108domain_entitymodels (book,currency,currency_pair,currency_pair_convention,calendar,tenor,instrument_code,crm_topology_config,crm_driver_pair,crm_enabled_derived_pair). 58 badge definitions are already seeded. This says the infrastructure is done but rollout is early — most status/enum/boolean columns elsewhere in the codebase presumably still render as plain text, not badges, simply because nobody has annotated their model yet (a rollout/toil gap, not a design gap). - Checked Wt parity, since the design doc's own "Open Questions"
flagged this as unscoped:
projects/ores.wt.service/src/app/ account_list_widget.cppis the only Wt file touching badges at all, and it hardcodes Bootstrapcss_classstrings ("badge bg-danger"=/"badge bg-success"/"badge bg-secondary") directly in C++ — it does *not* go through =badge_definition=/ =css_classfrom the DB at all. This is a real, confirmed gap: Wt badge rendering was never actually migrated to the data-driven system the design doc planned for it. - Evaluated the story's other implicit hypothesis — storing colour
directly on a "table enum type"'s own row (e.g. a
colourcolumn onbook_status) instead of the current normalised(code_domain, entity_code) -> badge_definitionindirection. Recommend against changing this: the current design's whole point is that many entity types share onebadge_definition(e.g.active=/=inactiveis reused bybook_status,regulatory_book_type,is_sweepable,tenant_status,workspace_status, …) — moving colour onto each lookup table would fragment that reuse, force every table to duplicate colour choices, and lose the central catalogue (58 definitions, one source of truth) theBadgeSeverityMdiWindow=/ =BadgeDefinitionMdiWindowadmin UI already manages. The existing architecture is the right one; it just needs wider adoption.
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 |
|---|---|
| #1593 | [agile] Scaffold badge colour scheme support story |
Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
Result
Badge colours are already database-driven, not hardcoded — a
complete system (badge_severity=/=code_domain=/=badge_definition=/
=badge_mapping in ores.dq, a client-side BadgeCache, and codegen
support via a badge_key column annotation) was designed
2026-03-28 and has since been substantially built and rolled out for
every entity that uses it. Sampled ~19 files still calling the
delegate's set_badge_color_resolver API and every one resolves
through BadgeCache — no hardcoded stragglers found. The story's own
"booleans need a system property" hypothesis is already answered by
the existing (code_domain, entity_code) mapping (is_sweepable is a
live example, documented as a repeatable convention) — no new storage
design needed there.
Confirmed real gaps instead of a from-scratch design (full writeup in
the conversation that produced this task; distilled into the story's
* Decisions and the four follow-on tasks below):
- An entity that is a badge source (e.g.
book_status) doesn't badge itself on its own list — only consumers do. - Adoption is narrow (10/108
domain_entitymodels usebadge_key) with no audit of where else it should apply. - No visual palette review:
badge_definition=/=badge_severityhave list/detail UI (System > Configuration,AdminPlugin.cpp:182) but colours render as plain hex text, not swatches — misuse of the greyy/green/red/yellow semantic convention can't be eyeballed. badge_mapping(the actual linkage data) has no UI at all — "no management UI, populated via seed scripts" was true then and still is. This is the single highest-leverage gap: a mapping browser would make 1, 2, and 3 reviewable instead of grep-only.- The unmapped-value fallback colour
(
color_constants::badge_fallback, orange) is a Qt-only hardcoded constant, indistinguishable in principle from a legitimate grey "inactive" badge, and would need re-duplicating in any future non-Qt client rather than being inherited from the shared data model.
Explicitly recommend against moving colour storage onto each "table enum type"'s own row — the current normalised mapping's whole value is letting many entity types share one badge definition; per-table colour columns would fragment that and lose the central catalogue. Keep the architecture, close the gaps above.
Wt support is explicitly out of scope for the follow-on tasks (per
explicit instruction) but was checked for architectural soundness:
the data/protocol layer is genuinely client-agnostic already
(badge_definition carries both raw hex and an unused css_class
Wt hint); the one piece that wasn't was the fallback colour (#5
above), folded into its own task so any future client inherits it
automatically instead of re-hardcoding it.