2026-09-14 QuizWizz UI/UX repair round
Round F is a bench-only repair round on /home/loca/dev/wrdp: the six reviewer rows that still had a code action, one measured regression the round itself caused and then fixed, and a matched before/after measurement of the surfaces they touch. It closes no product decision and authorises nothing. Every patch on this page is releaseEligible: false; the release owner carries source through the locked pipeline.
1. Scope and identity
- bench and boundary:
- bench
/home/loca/dev/wrdp; plugin mirror HEAD715474f, unchanged by this round — nothing was staged or committed ./scripts/qwgit.sh status --porcelaincounts 49Mrows and 0??rows, against 41Mbefore round F- the product was frozen after the regression fix; the boards, metric tables and this receipt were written against that frozen tree
- bench
- identity, per the bench law that owner-identity Settings writes destroy operator history:
- every browser measurement and every gate ran as the disposable administrator
qwvisual-20260914(ID 1171); never user 1 - the Settings option SHA-256 stayed
89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9fthroughout wp_qwizz_settings_backupsread 94 rows with 10 owned by user 1 after every gate
- every browser measurement and every gate ran as the disposable administrator
- measurement driver:
/tmp/qwfix/uiux/measure.mjs, SHA-256be06ed624df7e512dba4ddde6c5443f6c818efbb71f9260727b112c441ba6aec, byte-identical on the before and the after run — the before/after pair is matched, not a plan-supplied baseline- nine shots: J1 Builder, J2 Builder customised, J3 fine-tune editor, J4 fine-tune with preview, J5 PDF (pdf.js render), Q1 quiz editor, L1 quiz list, D1 dashboard, S1 Settings
- two viewports: desktop 1280x900 and mobile 390x900, so 18 shot/viewport pairs
- evidence locations:
- private, mode
0700:evidence/2026-09-14-uiux-round/{before,after,compare,smoke}/,findings-before.json,findings-after.json - public-safe copies: board-journey.png, board-admin.png, metrics.md, scores.md, findings-after.json, smoke-summary.md
- private, mode
2. Fix wave — slices and files
Five slices installed through the bench protocol: stage under /tmp/qwfix/<slice>/, install -o www-data -g www-data -m 0644, then php -l in the container or node --check for JavaScript. Every changed file linted clean. No file under vendor/, build/, provenance/ or QUIZWIZZ_VERSION was touched.
| Slice | Ledger rows and changes | Anchors in the installed tree |
|---|---|---|
| PubCss | UIUX-REV-04 plus the measured public-editor targets: row tools visible at rest and full on hover or focus-within; outcome-bar end padding derived from a component-local measure; eyebrow and theme-check text raised to at least 12px; disabled buttons unified; 44px mobile targets; a real step title | assets/css/qwizz-finetune.css:705 (opacity: .55 at rest) and :710-713 (opacity: 1 under :hover, :focus-within); :110 and :113 (--qw-editor-outcome-h: 80px, end padding calc(… + 24px)), :805 (124px at the narrow breakpoint); assets/css/qwizz-builder.css:693 (.qwizz-builder__step-title) |
| PubView | UIUX-REV-03 and UIUX-REV-05: translatable source copy Your quiz, the category step promoted to a real h2 with an aria-labelledby association, stepper titles, and the German catalog rebuilt | includes/Frontend/views/builder-view.php:305 (Your quiz), :179-180 (h2.qwizz-builder__step-title#qwizz-builder-step-categories plus aria-labelledby on the grid); languages/quizwizz-de_DE.po, .mo, languages/quizwizz.pot |
| AdminEditor | UIUX-REV-07, UIUX-REV-08 and UIUX-REV-01: the fifth language-name map replaced by a shared helper, REST subject entity-decoded, rail overflow generalised, switch ON recoloured to brand, add-question hint added, list badge raised to 12px, readiness cell stripped of its duplicate Draft, dashboard targets raised to 44px | includes/LanguageFlags.php:30 (public static function label( string $code )), consumed at includes/Frontend/views/builder-view.php:146; includes/Rest/AdminController.php; includes/Admin/ListTables.php; includes/Admin/DashboardPresenter.php; assets/css/qwizz-admin-editor.css, qwizz-admin-dashboard.css, qwizz-admin-shell.css |
| SaveStatus | The [data-save-status] pill restored to the Settings toolbar: markup, seven strings, a five-state JavaScript state machine and its own styling; measured contrast 7.33 | includes/Admin/views/settings-page.php:196-199; includes/Admin/SettingsPage.php:408-420 (saveError, settingsConflict, allSaved, shortSaved, shortSaving, shortError, unsavedSection); assets/js/qwizz-admin-settings.js:218-221 (setSaveStatus, allowed states saved, unsaved, saving, error, conflict), driven at :251-256, :1702, :1746-1749, :1770, :1777; assets/css/qwizz-admin-settings-core.css |
| PubViewCatalog | Six German msgids added and the .mo regenerated | languages/quizwizz-de_DE.po, languages/quizwizz-de_DE.mo |
UIUX-REV-02 and UIUX-REV-06 received no change: the shadowed Settings toolbar declarations and the phantom public --qw-brand branch were both already absent from the installed tree when the slices opened it. That is a measurement, not a repair, and it is recorded as such in the ledger rather than as shipped work.
3. Regression wave — the +N subject chip
The AdminEditor slice made the +N subject-overflow marker focusable, which is what UIUX-REV-08 asked for. The marker was a bare inline span, so becoming focusable turned it into an undersized interactive target: it measured 28x21 and the L1-desktop owned small-target count rose from the baseline 8 to 17, nine of them the new chip and its siblings. The round-F metric run is what caught it; no probe selector did.
- fix:
.qwizz-list-context__moreis now abox-sizing: border-boxinline-flexpill atmin-width: 32px/min-height: 32pxwith centred text —assets/css/qwizz-admin-shell.css:114-134. The focus ring is drawn inside the element (outline-offset: -2px,:141-144) because.qwizz-list-contextclips its overflow and an offset ring would be eaten. - re-measurement: L1-desktop owned small targets back to 8, equal to the baseline; the chip’s client rect reads 32x32; visually verified in the browser.
- companion product change needed by the
superglued-railgate: the@media (max-width: 600px)rail rule inassets/css/qwizz-admin-responsive.css:376was generalised frombody.qwizz_page_qw-settingstobody.qwizz-admin:has(.qwizz-admin-rail) #wpcontent, so the quiz-list and quiz-editor screens no longer reserve 46px under an admin bar that WordPress has made absolute. VerifiedstatsTop0 and no root overflow at 390px on the settings, list and editor screens.
One caveat about the published boards: the L1-desktop tile is a pre-chip-fix capture, and its caption says so. The 32x32 result above comes from the re-measurement, not from that tile.
4. Harness reconciliations
Eight harness items were reconciled before the gates could decide anything, and they are recorded against installed harness bytes in the probe harness rather than restated here. In outline:
- contract changes: the step f opacity predicate; the
legacymobile-Settings tier raise; thesuperglued-railadmin-bar-derivedexpectedTop; thetrivia-htmlboolean answer-key baseline; the step c tier raise, which moved the icon-gap denominator from 26 to 80 pairs; and the step f row count, now read from the Builder’s own[data-qwizz-count]becausecount.defaulthas been 7 since the operator’s 2026-09-09 Settings change. - recorded without action: the
legacysave-status assertion’s EnglishSavedliteral, which would fail under a de_DE admin locale; and the puppeteer utility-world trap, wherepage.evaluateunder puppeteer-core 25.3.0 cannot see page globals, so a non-OMP runner must bindevaluateto a main-worldRuntime.evaluate.
Three of these are why a gate that was red on first pass went green without a product change, so they are contract corrections, not passes. None of them is evidence that the product improved.
5. Gates
Shell harness, idle bench, single harness owner:
| Gate | Result | Record |
|---|---|---|
--wave 1 | 17 assertions, 0 failures | round-F shell run |
--wave all | TAP 1..98, # assertions=98 failures=0, after the fix wave | /tmp/qwfix/uiux/wave-all-after.tap |
logs/debug.log | 38,699 lines; 0 new lines across every run of this round | wc -l logs/debug.log |
Browser smoke, harness SHA-256 6d0803b2121ef1d352e5a1b6d606aae915773902257214cc118f303ac7b25289 at 3,716 lines, one bounded chunk at a time on an idle bench, driver puppeteer-core 25.3.0 on CDP 9333 with a main-world evaluate binding:
| Chunk | Result | Notes |
|---|---|---|
legacy | 47/47 | |
player | 9/9 | recorded earlier in the round |
welcome,superglued-rail,single-column,selection-borders,trivia-html | 13/13 | |
uiux-perfection a-d | 7/7 | |
uiux-perfection e | 5/5 | |
uiux-perfection f | 5/5 | rowCount 7 equals requestedCount 7; toolsRestOpacity .55, hover 1 |
uiux-perfection g | 5/5 | |
uiux-perfection h-j | 7/7 | |
post-chip re-gate, chunk3-admin-regate | 13/13 | the admin chunk re-run at 2026-09-14T04:02:10Z, after the chip fix landed at 03:05:48Z; overallPass true, failed empty |
post-chip re-gate, chunk8-uiux-h-j-regate | 7/7 | uiux-perfection h-j re-run at 2026-09-14T04:05:09Z; overallPass true, failed empty |
Every recorded chunk reports foreignRowsDuringRun=[], restoration complete, and identityEqual and survivingIdentityEqual true. Both re-gate records carry error: null, consoleErrors=[], pageErrors=[], restoration.complete true and restoration.settingsBackup with identityEqual and survivingIdentityEqual true and foreignRowsDuringRun=[]. The cleanupPacket for recorded chunks f and g reports remainingDrafts, remainingArtifacts and remainingPrivateFiles all 0 with 0 failures. One first-pass chunk3 run carried a single console error from a third-party secure.gravatar.com fetch (net::ERR_NETWORK_CHANGED) and was re-run clean; the failure was network, not product.
The two re-gate chunks are the ones that render the +N badge and the list surface the regression hit, and both postdate the fix: the qwizz-admin-shell.css rule was installed at 2026-09-14T03:05:48Z and the re-runs started at 04:02:10Z and 04:05:09Z. Records: evidence/2026-09-14-uiux-round/smoke/chunk3-admin-regate.json and chunk8-uiux-h-j-regate.json (private), summarised in smoke-summary.md.
6. Owned-metric deltas
Both sides of every row below come from the same driver bytes on the same nine shots. Only plugin-owned elements are counted, which is the re-scope the two metric rows asked for: no WordPress admin bar, dashbar or table-cell chrome is inside any *Owned counter. The full 366-row comparison is in metrics.md.
Improved:
| Shot and viewport | Metric | Before | After |
|---|---|---|---|
| J3-desktop | hoverOnly | 1 | 0 |
| J4-desktop | hoverOnly | 1 | 0 |
| J4-mobile | hoverOnly | 1 | 0 |
| J3-mobile | smallPrimaryOwned | 7 | 0 |
| J4-mobile | smallPrimaryOwned | 7 | 0 |
| Q1-mobile | hOverflow | 1 | 0 |
| L1-mobile | hOverflow | 1 | 0 |
| D1-mobile | hOverflow | 1 | 0 |
| D1-mobile | smallPrimaryOwned | 19 | 2 |
| L1-desktop | tinyTextOwned | 49 | 0 |
| J4-desktop | tinyTextOwned | 2 | 0 |
Worse, with the cause established:
| Shot and viewport | Metric | Before | After | What it is |
|---|---|---|---|---|
| L1-desktop | smallTargetsOwned | 8 | 17 | The real regression of section 3. Fixed, re-measured at 8. |
| J4-desktop and J4-mobile | visibleIndicators | 40 | 11 | Driver artifact. The 40-step tab walk started on the outcome bar and entered the PDF preview iframe; 11 of the 13 focused elements had indicators and the 2 misses are iframes, which draw no outline. |
| S1-mobile | tinyTextOwned | 40 | 41 | Measurement artifact. The restored save-status pill hides its long label with font-size: 0 plus ::after { content: attr(data-short) } at 782px and below, so a visible 12px short label is counted as tiny text. No change made. |
Nineteen further rows are tDom or measureMs timings that read worse. They are single-run wall-clock samples from a shared bench, not a benchmark, and no conclusion is drawn from them.
Unchanged baseline debts, retained rather than smoothed away: S1-mobile focusClipped 11; S1 contrastFailsOwned 1; D1-mobile smallPrimaryOwned 2 remaining after the 19 → 2 improvement.
7. Vision critique — severity totals and score movement
The critique re-ran the same two prompts, P-visual and P-first5 from /tmp/qwfix/uiux/prompts.txt, verbatim on both sides.
| Set | Findings | P1 | P2 | P3 |
|---|---|---|---|---|
| Baseline | 172 | 6 | 90 | 76 |
| After | 170 | 7 | 87 | 76 |
Of the 94 P1 and P2 findings on the after side, 88 matched a baseline finding. There are 0 new P1 findings and 6 new P2 findings, which are the UIUX-VIS rows in section 9.
Score movements named in the dossier, on the 1–10 per-shot scale in scores.md:
| Direction | Movements |
|---|---|
| up | D1-mobile alignment 3→5, density 2→3, polish 3→4; L1-mobile alignment 4→5, density 3→4, polish 3→4; S1-mobile alignment 6→7, contrast 4→5; J3-desktop density 3→4; Q1-mobile density 2→3 |
| down | J1-desktop hierarchy 6→5, contrast 7→6, alignment 8→7; J2-mobile hierarchy 5→4, density 5→4; J1-mobile density 5→4; J5-desktop polish 7→6 |
The J5-desktop polish move is uninterpretable as a product signal: J5 renders a fresh random quiz on every run, so the two captures are not the same content. Two further down-moves appear in the published table beyond the dossier’s named list — J3-desktop alignment 6→5 and J4-desktop contrast 6→5 — and are recorded here so the table and this page agree.
Every number in this section is a model judgement over a static screenshot, not a measurement. See section 15.
8. The seven retained P1 findings
All seven after-side P1 findings restate a baseline symptom; none is new, and none is a regression introduced by this round. They group into four symptoms.
| Symptom | Shots | Why it is retained |
|---|---|---|
| Fine-tune sticky outcome bar over content | J3-desktop, J3-mobile, J4-desktop, J4-mobile | The bar is sticky by design. End padding derived from --qw-editor-outcome-h (assets/css/qwizz-finetune.css:110,113, 124px at the narrow breakpoint at :805) keeps every row reachable by scrolling. The critic judges a single static frame and cannot scroll, so it reports occlusion that a user does not experience. Design-accepted. |
| PDF text size | J5-mobile | The PDF page is scaled to a 390px viewport, so the rendered type is small by construction of the capture, not of the product. |
| Sticky Update bar | Q1-mobile | Same class as the fine-tune bar: sticky by design, judged from a static frame. |
| Small text | Q1-mobile | The critic was shown a downscaled image. |
These four are carried as one owner-decidable ledger group, UIUX-P1, because accepting or rejecting a sticky-bar design is a human judgement and no bench measurement settles it.
9. Six new P2 findings
Six after-side P2 findings have no baseline match. They are recorded as ledger ids so they cannot be quietly lost, and they are owner-decidable: each is a design judgement about weight, grouping or repetition, not a measured defect.
| id | Shot | Finding |
|---|---|---|
| UIUX-VIS-01 | J1-desktop | Category tiles all carry equal visual weight, and the Surprise me tile’s dashed treatment reads as disabled or as a placeholder rather than as a distinct choice. |
| UIUX-VIS-02 | J1-mobile | The Surprise me tile again, at the mobile viewport. |
| UIUX-VIS-03 | J1-mobile | The collapsed Customize disclosure gives no indication of what it contains. |
| UIUX-VIS-04 | Q1-mobile | The Answers switches do not read as having a clear on/off state. |
| UIUX-VIS-05 | D1-mobile | Subject names repeat across the dashboard cards. |
| UIUX-VIS-06 | S1-mobile | The imports card composition is called out. |
10. Pixel diff
Full-page and viewport PNG pairs, decoded with the standard library and counted as changed when any channel differs by more than 8:
| Pair | Fraction of pixels changed |
|---|---|
| J3-desktop | 0.0115 |
| J4-desktop | 0.0115 |
| J3-mobile | 0.153 |
| J4-mobile | 0.152 |
| J5-desktop | 0.207 |
| J5-mobile | 0.220 |
| L1-desktop | 0.0089 |
| Q1-mobile viewport | 0.059 |
| S1-desktop | 0.0006 |
| S1-mobile | 0.0016 |
Nine full-page pairs were not diffed because their dimensions differ, which is itself the result:
- height grew as content grew: J1 and J2 desktop 1134 → 1162, J1 and J2 mobile 1372 → 1401, Q1-desktop 1317 → 1339, D1-desktop 2703 → 2705.
- width shrank because the horizontal overflow is gone: the D1, L1 and Q1 mobile full-page captures were 1031px wide before and are 375px after. That is the same defect the
hOverflowrows in section 6 record.
The J5 fractions carry the same caveat as its score: fresh random content on each run.
11. Residue
- an aborted first smoke attempt left harness user
qwharness_browser_smoke(ID 1182) with 2 backup rows and 1qw_questionauto-draft. All were attributed and removed before any gate resumed. This is exactly the leak the bounded-chunk bench law exists to prevent. - two WordPress Quick Draft auto-drafts created by user 1171 during dashboard hops, IDs 12578 and 12614, were removed.
- final bench state:
wp_qwizz_settings_backups94 rows with 10 owned by user 1; Settings option SHA-256 unchanged at89877cf6…; the administrator list isadminandqwvisual-20260914.
The disposable admin qwvisual-20260914 (1171) is deliberately retained, not deleted, so the next round has a non-operator identity available without creating one.
12. Mirror census refresh
Round F changed 21 files, which moves the mirror census from 41 tracked-modified rows to 49. The refreshed class counts, the 21 files by class and the refresh artifact’s own limits are on the mirror decision sheet. In short: post-sep8-unattributed rose from 0 to 13 and post-packet-mutation from 0 to 8, which together are the 21 files; packet-on-drifted-base fell from 13 to 5, inherited-unpacketed from 5 to 3 and inherited-catalog-artifact from 17 to 14.
The refresh did not re-run the canonical apply-check, so the sheet’s exit-1 seven-path result still describes the pre-round-F packet only. Round F makes the release owner’s decision strictly harder, not easier: eight packet paths now carry bytes the sealed packet does not describe.
13. Evidence boards
Two boards, 2400x1272 each, assembled from the after-side captures. Every tile was read and inspected before publication; all 18 after-side top-900px crops were checked for visible secrets or addresses and none was found, so no redaction was applied.


The L1-desktop tile on the admin board predates the chip fix of section 3, as its caption states.
14. What remains
Retained debts, each already a ledger row:
- UIUX-P1 — the four design-accepted P1 symptoms of section 8. Needs a human judgement on the sticky-bar design; no measurement will close it.
- UIUX-VIS-01 through UIUX-VIS-06 — the six new P2 critic findings of section 9. Owner-decidable for the same reason.
- S1-mobile
focusClipped11, S1contrastFailsOwned1, D1-mobilesmallPrimaryOwned2 — unchanged baseline metric debts, not regressions. - S1-mobile
tinyTextOwned41 — the save-status hide technique of section 6. Recorded as a measurement artifact; either the metric or the technique would have to change, and neither is a defect today. - UIUX-BACKUP-01 — owner 1 still holds 11 backup rows against a per-writer cap of 10. Round F did not touch it; the no-operator-write rule stands.
- UIUX-FLAKE-01 and issue #15 — still open, because no loaded run has yet named a failing component.
- the mirror decision — now 49 rows with 21 of them changed after the Sep-8 seal. Release-owner work, unchanged in kind by this round.
15. Explicit non-claims
- no human acceptance. Nobody has reviewed or accepted these surfaces. This receipt records measurements and gates only.
- no release eligibility.
releaseEligible: false. Nothing was staged, committed or pushed; mirror HEAD is still715474f. - the vision critique’s findings, severities and 1–10 scores are model judgements over static screenshots. They are
[INFERENCE], never measurements, and no ledger row moves on them. Four of the seven retained P1 findings are demonstrably artifacts of judging a sticky element in a frame that cannot be scrolled. - the post-chip re-gate covers the admin and
uiux-perfectionh-jchunks only. The other six chunks were not re-run after the chip fix, so their records describe the pre-fixqwizz-admin-shell.cssbytes; nothing on the surfaces they cover changed in that fix, but they are not post-fix proof. - no production wiki build or deployment was run by this writer, and no page on this round is claimed live.
- three of the browser chunks went green only after a harness contract was corrected. A corrected contract is not a product improvement, and none of those three is cited as one.
- the mirror apply-check was not re-run against the round-F tree.