add the Studio element manifest and its window-matching test

ui-layout.md named the arrangement's owners but nothing knew which elements exist, so a
view switch could silently take a running session's tracker reset away: docs/ui-elements.json
now states all 195 by region, pane and view, ui/elements.py loads it, and
tools/ui_elements_dump.py drafts it.
Verified: apps/studio 393 items (13 new) and ui_check 600/0, autocal 358, shared 390 with its
2 known wall-clock failures, lint and doc gates clean; a removed element, a renamed
objectName and a new named widget each fail the suite.
This commit is contained in:
ykcheungab
2026-10-01 15:18:16 +08:00
parent e0156a14c6
commit eb70ac7638
6 changed files with 2013 additions and 0 deletions
+34
View File
@@ -126,3 +126,37 @@ not a prerequisite.
**Golden images, if adopted:** pin the window size, scale factor, font and theme, or they will flake
and be disabled. A flaky render gate is worse than none.
## 7. The element manifest
[`ui-elements.json`](ui-elements.json) is the machine-readable half of this contract. The rules
above say who owns the arrangement; the manifest says **which elements are supposed to exist**, per
region, per pane and per view. Each entry carries a stable `id`, the Qt `objectName` (recorded only
when it is a stable identity — the rail's transport carries a stylesheet token instead, so it is
found by path), the class, a one-line purpose, and the views it appears in. Anything that exists
only in some views, or only while a condition holds, declares `views` or a named `condition`
rather than leaving it ambiguous.
[`ui/elements.py`](../src/orisys_studio/ui/elements.py) loads it and answers the questions a test
needs: `missing()`, `wrong_class()`, `unlisted_named_widgets()` and `validate()`.
[`tests/test_ui_elements.py`](../tests/test_ui_elements.py) runs them against a real
`StudioMainWindow` in each view, and asserts the declared panes are the visible ones.
[`tools/ui_elements_dump.py`](../tools/ui_elements_dump.py) drafts the file from a live window.
**The manifest is authored, not generated.** A generated file accepts whatever the code happens to
contain, which is the drift it exists to catch; the dump is a drafting aid and its output must be
curated by hand. **An element is listed before a test relies on it** — that is what makes the file a
spec rather than a description of what someone found. The drift report (visible named widgets the
manifest accounts for neither as an element identity nor as a declared stylesheet token) is
compared with the record in each view, so new interface names fail until the manifest says what
they are.
Whoever changes the set of elements — adding, renaming or removing a widget the manifest covers —
updates the manifest in the same change, before the test is asked to rely on it.
This is the **element** tier of §6 and nothing more. It does not assert geometry or containment, it
does not run the locale/theme/minimum-size matrix, and it does not compare rendered pixels. Those
extend it rather than replace it: the geometry tier would add the rectangle a listed element is
allowed to occupy, the matrix tier would vary the window states the same list is checked under, and
the rendered tier would pin a reference image for the panes it names. None of that is attempted
here.