Skip to content

Commit f2d5b6c

Browse files
AndrewSazonovclaude
andcommitted
Add audit knowledge base from the 2026-07 GUI base audit
Full audit of EasyApplication as the GUI foundation for the future enhantica/edi desktop + WASM application, structured like the enhantica/crysta knowledge base: - audit/issues: 33 rated issues (I-0001..I-0033) with evidence in audit/issues/audit-2026-07 (incl. a round-2 verification log) - audit/roadmap: status.yml + 26 junior-agent-ready task packets across 9 milestones (M01 WASM/CMake revival, M02 render-everywhere, M03 decoupling, M04-M09 hardening/docs/handoff) - audit/milestones: Phase-I milestone pages - audit/design: strategy, target architecture, modern-Qt/QML guidelines, owner-ratified decision record (QtGraphs; dual build) - audit/process: operator playbook + junior-agent writing guide Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent c55d01c commit f2d5b6c

82 files changed

Lines changed: 6344 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

audit/README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# gui-components audit knowledge base
2+
3+
This directory is the in-repo, git-tracked **audit, roadmap and design
4+
record** for `easyscience/gui-components` (the `EasyApplication` Qt/QML
5+
component library). It was opened by the **2026-07 GUI base audit**,
6+
whose purpose is to turn this library into _"a very solid, robust,
7+
sustainable and maintainable base for GUI"_ that the new
8+
diffraction-analysis product
9+
[`enhantica/edi`](https://github.com/enhantica/edi) can build its
10+
**desktop (PySide6) and web (WASM/C++)** front-ends on.
11+
12+
It deliberately mirrors the structure of the
13+
[`enhantica/crysta`](https://github.com/enhantica/crysta) knowledge base
14+
(issues · roadmap · milestones · design · process), so the same agents
15+
and playbooks can operate on both repos.
16+
17+
## Why this exists
18+
19+
`gui-components` is the shared GUI foundation. Two consumers depend on
20+
it:
21+
22+
- The current reference app
23+
[`easydiffractionbeta`](https://github.com/easyscience/easydiffractionbeta)
24+
(Qt/QML + PySide6, QMake) — the app whose look-and-feel we are
25+
keeping.
26+
- The **future** product `edi` — desktop **and** WASM web app,
27+
implemented by less-advanced agents who need an unambiguous,
28+
well-documented, tested base to work against.
29+
30+
The audit found the base is **functional on desktop-Python but
31+
structurally fragile, is broken on the web/WASM target it claims to
32+
support, and is entangled with EasyDiffraction specifics** that block
33+
reuse. This knowledge base records every finding with evidence, rates
34+
it, and lays out an ordered plan to fix it.
35+
36+
## Layout
37+
38+
```
39+
audit/
40+
├── README.md ← this file
41+
├── issues/
42+
│ ├── about.md ← issue-tracker process (priorities, format, workflow)
43+
│ ├── index.md ← THE single source of truth: one rated row per issue
44+
│ ├── open/ ← one file per OPEN issue: I-NNNN-slug.md
45+
│ ├── closed/ ← resolved issues move here (git keeps history)
46+
│ └── audit-2026-07/ ← the raw evidence (file:line proofs) backing each issue
47+
├── roadmap/
48+
│ ├── index.md ← phases, milestone ordering, how a task is run
49+
│ ├── status.yml ← single source of truth for milestone/task progress
50+
│ └── tasks/ ← one packet per one-session task: M##-T##-slug.md
51+
├── milestones/ ← externally-checkable capability deliverables
52+
├── design/ ← the analysis, target architecture, Qt best-practices, decisions
53+
└── process/ ← operator playbook + how to write for junior agents
54+
```
55+
56+
## Start here
57+
58+
1. **See the problems, rated:** [`issues/index.md`](issues/index.md).
59+
2. **Understand the strategy & long-term improvements:**
60+
[`design/audit-2026-07-strategy.md`](design/audit-2026-07-strategy.md).
61+
3. **See the plan (milestones/tasks):**
62+
[`roadmap/index.md`](roadmap/index.md).
63+
4. **Confirm the big forks before coding:**
64+
[`design/decisions-to-confirm.md`](design/decisions-to-confirm.md).
65+
5. **If you are the implementing agent:** read
66+
[`process/operator-playbook.md`](process/operator-playbook.md) and
67+
[`design/modern-qt-guidelines.md`](design/modern-qt-guidelines.md)
68+
first.
69+
70+
## Audit headline
71+
72+
| Verdict | |
73+
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
74+
| **Desktop-Python (PySide6)** | Works today; maintainability & test debt is high. |
75+
| **Web (WASM/C++)** | **Broken.** The C++ example's `resources.qrc` still points at the pre-rename `src/EasyApp/…` tree and lists deleted files; charts/reports need `QtWebEngine` (unavailable in WASM); `Settings{ location }` throws in the browser. |
76+
| **Reusable base for a _new_ product** | **Not yet.** App-specific concepts (`EasyDiffraction`, page enums, auto-updater) are hard-wired into the "generic" library. |
77+
| **Modern-Qt hygiene** | Classic-only: no CMake/`qt_add_qml_module`, no QML linting/tests, private `QtQuick.Controls.impl` used in 21 files, mixed versioned imports, zero real tests. |
78+
79+
The good news: the visual design system (Style singletons,
80+
Elements/Components layering, theming and animations) is coherent and
81+
worth preserving. The work is **hardening and decoupling**, not a
82+
rewrite.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Target architecture — the hardened GUI base
2+
3+
Where the base should land after Phase I–II, so `edi` can build a
4+
desktop and a WASM app on it. This is the "north star" the milestones
5+
move toward; it is intentionally incremental from today's tree (the
6+
visual design system is kept).
7+
8+
## Layering (keep, clarify, enforce)
9+
10+
```
11+
EasyApplication.Gui
12+
├── Style singletons: Colors, Sizes, Fonts, Times (design tokens — no logic)
13+
├── Globals Vars (app-agnostic runtime flags), AppSettings, ApplicationInfo (NEW seams)
14+
├── Animations ThemeChange, TranslationChange, ColorReset
15+
├── Elements primitives: Button, Label, TextField, ComboBox, … (one type/file, T.* based)
16+
├── Components composed: AppShell/ApplicationWindow, AppBar, ContentArea, SideBar, TableView, …
17+
├── Charts façade: Chart1D, Chart2DHeatmap, Chart3DSurface (native backend, NO WebEngine)
18+
└── Logic (js) pure helpers: Translate, Utils, ProjectConfig
19+
```
20+
21+
Rules (enforced by CI grep + qmllint, documented in
22+
[modern-qt-guidelines.md](modern-qt-guidelines.md)):
23+
24+
- **Elements** are primitives (extend `QtQuick.Templates`), no app
25+
knowledge, no cross-Element composition beyond Style/Animations.
26+
- **Components** compose Elements into reusable app furniture. The
27+
window apps use is `Components.ApplicationWindow` (the base primitive
28+
is renamed `ApplicationWindowBase`, I-0028).
29+
- **No product literals, no named app pages** anywhere in `Gui`. App
30+
specifics enter only through the injected seams below.
31+
32+
## The three injection seams (this is what makes it generic)
33+
34+
Everything app-specific that is _currently baked in_ becomes
35+
host-injected:
36+
37+
1. **`ApplicationInfo`** — organization, applicationName, version,
38+
settings namespace (optionally a changelog URL / update service). Set
39+
once in the host `main` (Python or C++). Logging and settings derive
40+
identity from it. Replaces the hard-coded `EasyDiffraction`
41+
(I-0006/I-0022).
42+
2. **Page model** — the app supplies a list
43+
`[{ title, icon, source|component, enabled }]`; the app bar and
44+
content area render from it. Replaces `Vars.AppBarIndexEnum`
45+
(I-0006).
46+
3. **Optional services**`updateService` (I-0007), and any other
47+
platform/host capability the app opts into. The library ships none by
48+
default.
49+
50+
## Platform-divergent façades (write app code once)
51+
52+
For anything that differs between desktop and WASM, a small façade with
53+
a fixed property API and a target-aware backend (detect
54+
`Qt.platform.pluginName === "wasm"`):
55+
56+
| Façade | Desktop backend | WASM backend | Issue |
57+
| ------------------------------------- | ----------------------------- | ------------------------------------------------ | ------ |
58+
| `AppSettings` | `QSettings`/`Settings` (file) | `Settings``localStorage` (no file `location`) | I-0003 |
59+
| `Charts.Chart*` | QtGraphs/Qt Charts | same (native, GPU) — **no WebEngine** | I-0002 |
60+
| `updateService` (opt-in) | QtIFW / host | absent (web self-updates via redeploy) | I-0007 |
61+
| file open/save, clipboard (as needed) | native dialogs | browser file API / no-op | future |
62+
63+
The point: platform `#ifdef`-style logic lives in **one** file per
64+
capability, not scattered (today the `Settings` bug is copy-pasted 11×).
65+
66+
## Build & distribution (dual, one source tree)
67+
68+
```
69+
src/EasyApplication/Gui/**.qml (ONE source of truth)
70+
71+
┌───────────┴────────────┐
72+
▼ ▼
73+
PySide6 path CMake path (qt_add_qml_module)
74+
(interpreted QML, (compiled QML via qmlsc,
75+
desktop-Python) generated qmldir+resources)
76+
│ │
77+
▼ ┌─────┴─────┐
78+
pip wheel ▼ ▼
79+
(easydiffraction desktop WASM
80+
desktop app) C++ app web app
81+
```
82+
83+
- **CMake `qt_add_qml_module` is the source of truth** for module
84+
identity (URI == import path, I-0009), resources (generated, so no
85+
I-0001 drift), and compiled QML.
86+
- **PySide6 consumes the same raw `.qml`** for the desktop-Python app
87+
(kept working throughout).
88+
- Distribution: a Python wheel for the PySide desktop path; a CMake
89+
package (`find_package` / `add_subdirectory`) for the C++/WASM path.
90+
(Ratify the exact split in
91+
[decisions-to-confirm.md](decisions-to-confirm.md) §B.)
92+
93+
## Quality gates (the product is gated, not just the shell)
94+
95+
- `qmllint` + `qmlformat --check` over every module (pre-commit + CI).
96+
- Qt Quick Test **smoke-load** (every Element/Component instantiates
97+
cleanly) + interactive units, headless in CI on desktop and WASM.
98+
- CI grep gates: no `easydiffraction`, no `QtQuick.Controls.impl`
99+
outside wrappers, no `Settings{location}` in screens, no dangling
100+
manifest paths, no spaces in `src/` filenames.
101+
- A component **gallery** example that renders everything (light+dark) —
102+
living docs + visual smoke.
103+
104+
## edi consumption (the payoff)
105+
106+
`enhantica/edi` (product monorepo) builds:
107+
108+
- **`edi` desktop app** — QML/PySide, declares its pages +
109+
`ApplicationInfo`, styles via `Style` tokens, uses
110+
`Components`/`Elements`/`Charts` façades. Ready after M03
111+
(decoupled) + M04 (gated).
112+
- **`edi` web app** — the same QML compiled for WASM via CMake. Ready
113+
after M01 + M02 (renders on WASM).
114+
- **`edi` shared session layer** — theme/settings/page-model/undo state,
115+
injected through the seams above; a single place both surfaces share.
116+
Formalised in M09.
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
# Strategy & long-term improvements — 2026-07 GUI base audit
2+
3+
The analysis behind the [issue tracker](../issues/index.md) and
4+
[roadmap](../roadmap/index.md): what state the base is in, where it
5+
should go, and the long-term improvements beyond the immediate fixes.
6+
Written to brief the owner and the implementing agents on _why_ the plan
7+
is ordered as it is.
8+
9+
## Executive summary
10+
11+
`gui-components` (`EasyApplication`) is a mature-looking Qt/QML
12+
component library with a genuinely good **visual design system**
13+
(coherent Style tokens, a clean Elements→Components layering, theming
14+
with animated transitions, a broad control set). It works today as the
15+
desktop-Python GUI base for `easydiffractionbeta`.
16+
17+
But measured against the goal — _a solid, robust, sustainable,
18+
maintainable base for a **new** product (`edi`) shipping on **desktop
19+
and web/WASM**_, built by **less-advanced agents** — it has three
20+
structural gaps:
21+
22+
1. **The web/WASM target is broken and architecturally blocked.** The
23+
C++ build's resource manifest rotted at the
24+
`EasyApp``EasyApplication` rename (I-0001); the charts/report need
25+
`QtWebEngine`, which does not exist on WASM (I-0002); settings
26+
persistence throws in the browser (I-0003); and the WASM CI never
27+
runs, so none of this was caught (I-0005).
28+
2. **It is entangled with EasyDiffraction.** App page names, the product
29+
name, an auto-updater pointing at EasyDiffraction's servers, and a
30+
`QtTest`-based tutorial harness are compiled into the "generic"
31+
library (I-0006, I-0007, I-0012). A second product cannot adopt it
32+
cleanly.
33+
3. **The engineering foundation is classic-only and ungated.** No
34+
CMake/`qt_add_qml_module`, no QML linting/formatting, no real tests
35+
(all `test_dummy.py`), reliance on private Qt internals in 33 files,
36+
and a repo scaffolded from a generic _Python-library_ template that
37+
checks the thin Python shell while the thick QML core goes ungated
38+
(I-0004, I-0009, I-0010, I-0011, I-0018, I-0026).
39+
40+
None of this requires a rewrite. It requires **hardening + decoupling**
41+
on top of the good design system, in a deliberate order: unbreak the web
42+
target on a drift-proof build, decouple from EasyDiffraction, then gate
43+
quality so the hardening sticks.
44+
45+
## The three-phase plan (and why this order)
46+
47+
- **Phase I — Unbreak & stabilise (M01–M03).** Restore the web target on
48+
a CMake module build that _cannot_ drift (M01), make it actually
49+
render and persist on WASM (M02), and decouple it from EasyDiffraction
50+
(M03). After Phase I, `edi` can start building its surfaces on a base
51+
that builds everywhere and isn't someone else's app. M01 and M03
52+
parallelise (build vs decoupling).
53+
- **Phase II — Sustainable engineering (M04–M06).** Gate the _actual
54+
product_: `qmllint`, `qmlformat`, Qt Quick Test required in CI (M04);
55+
retire private-API reliance and modernise imports (M05); define a real
56+
distribution model and prune deps/fonts (M06). This is what makes the
57+
base _maintainable_ by many hands.
58+
- **Phase III — Solid base for edi (M07–M09).** i18n/a11y (M07),
59+
documentation + a component gallery + an enforced style guide (M08),
60+
and the `edi` handoff seam + semver (M09). This is what makes the base
61+
_followable_ by less-advanced agents.
62+
63+
## Long-term improvements (beyond the issue fixes)
64+
65+
These are not individual bugs; they are the direction that keeps the
66+
base healthy for years.
67+
68+
1. **One build system, generated artifacts.** Standardise on CMake
69+
`qt_add_qml_module` as the source of truth for module identity,
70+
resources, and compiled QML. Hand-maintained `.qrc`/`.pro` is how
71+
I-0001 happened; generated manifests make that class of bug
72+
impossible. Keep the PySide interpreted path as a thin consumer of
73+
the same source tree (dual distribution — see
74+
[architecture-target.md](architecture-target.md)).
75+
2. **A stable façade layer for anything platform-divergent.** Charts,
76+
settings, file dialogs, clipboard, update-check, and audio behave
77+
differently (or don't exist) on WASM. Put each behind a small QML
78+
façade with a fixed property API and a target-aware backend, so app
79+
code is written once and the platform difference lives in one file.
80+
(M02 does charts + settings; extend the pattern.)
81+
3. **Decoupling by construction, enforced.** The library must contain
82+
**zero** product literals and **zero** named app pages. Make that a
83+
CI grep gate, not a convention — so it can't regress as new agents
84+
contribute. Everything app-specific enters via injected data
85+
(`ApplicationInfo`, a page model, an optional update service).
86+
4. **Compiled, type-safe QML.** Move from context-property injection
87+
(`typeof pyX !== "undefined"` in `Vars.qml`) and `var` properties
88+
toward `required property`, typed properties, and
89+
`QML_ELEMENT`/singleton registration, so `qmlsc` can compile QML to
90+
C++ (startup + WASM wins) and `qmllint` can actually check it.
91+
5. **A test pyramid whose base is a smoke-load.** The single
92+
highest-value test is "does every component instantiate without a QML
93+
error", run headless in CI on desktop and WASM. It would have caught
94+
I-0001/I-0013/I-0020 for near-zero cost. Build up from there
95+
(interactive Qt Quick Test, Python backend units, a visual gallery).
96+
6. **The library documents itself.** A component gallery that renders
97+
every Element/Component (in light+dark) doubles as living
98+
documentation _and_ a visual smoke test. Junior agents building `edi`
99+
should be able to browse "what exists and how to use it" without
100+
reading source.
101+
7. **Design tokens as a first-class, exportable system.** The Style
102+
singletons are already a de facto design system; formalise them
103+
(documented token names, light/dark, the sizing scale) so they can be
104+
shared with non-Qt surfaces (web docs, marketing) and evolved
105+
deliberately.
106+
8. **Accessibility and i18n as defaults, not retrofits.** Establish
107+
`qsTr()`-everywhere and `Accessible` roles as conventions now, while
108+
the base is ~90 components, rather than across a grown `edi`.
109+
9. **Version and support the base like a product.** Semver, a changelog,
110+
and a documented support window for Qt versions — so `edi` can pin a
111+
known-good base and upgrade deliberately.
112+
113+
## What to preserve (do not "improve" away)
114+
115+
- The **Style token system** (`Colors`/`Sizes`/`Fonts`/`Times`) and the
116+
dark/light palette — it is hand-tuned and coherent.
117+
- The **Elements (primitive) → Components (composed)** layering — it is
118+
the right shape; just rename the ambiguous base window (I-0028) and
119+
document it (I-0030).
120+
- The **animated theming/translation transitions**
121+
(`Behavior on color { ThemeChange {} }`) — a nice touch that gives the
122+
app polish; keep them target-aware.
123+
- The **breadth of controls** — the library already covers most of what
124+
an analysis app needs.
125+
126+
## Risks & mitigations
127+
128+
- **Chart migration is the biggest single effort** (10 files + report,
129+
plus a library choice). De-risk by validating the ratified library
130+
choice (Decision A: QtGraphs) on a measured 1-D prototype in M02-T1
131+
before doing 2-D/3-D.
132+
- **CMake migration could disturb the working PySide path.** Mitigate by
133+
keeping the raw `.qml` in place and treating CMake as an additional
134+
consumer (dual build), landing modules incrementally (M01-T1 beachhead
135+
first).
136+
- **Decoupling churns many files.** Mitigate with the smoke-load test
137+
(M04-T2) landed early so the churn is caught, and CI grep gates so
138+
decoupling can't silently regress.
139+
- **Less-advanced implementing agents.** Mitigate with explicit task
140+
packets (done), an enforced style guide (I-0030/M08), and the
141+
[writing-for-junior-agents](../process/writing-for-junior-agents.md)
142+
conventions.
143+
144+
## Open decisions (ratify before Phase I code)
145+
146+
See [decisions-to-confirm.md](decisions-to-confirm.md): the chart
147+
library, the build/distribution model, the template framing, and how far
148+
to split app-specific screens out of the library. These change _how_
149+
Phase I is executed and are cheap to decide now, expensive to reverse
150+
later.

0 commit comments

Comments
 (0)