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 HEAD 715474f, unchanged by this round — nothing was staged or committed
    • ./scripts/qwgit.sh status --porcelain counts 49 M rows and 0 ?? rows, against 41 M before round F
    • the product was frozen after the regression fix; the boards, metric tables and this receipt were written against that frozen tree
  • 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 89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9f throughout
    • wp_qwizz_settings_backups read 94 rows with 10 owned by user 1 after every gate
  • measurement driver:
    • /tmp/qwfix/uiux/measure.mjs, SHA-256 be06ed624df7e512dba4ddde6c5443f6c818efbb71f9260727b112c441ba6aec, 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:

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.

SliceLedger rows and changesAnchors in the installed tree
PubCssUIUX-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 titleassets/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)
PubViewUIUX-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 rebuiltincludes/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
AdminEditorUIUX-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 44pxincludes/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
SaveStatusThe [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.33includes/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
PubViewCatalogSix German msgids added and the .mo regeneratedlanguages/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__more is now a box-sizing: border-box inline-flex pill at min-width: 32px / min-height: 32px with 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-context clips 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-rail gate: the @media (max-width: 600px) rail rule in assets/css/qwizz-admin-responsive.css:376 was generalised from body.qwizz_page_qw-settings to body.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. Verified statsTop 0 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 legacy mobile-Settings tier raise; the superglued-rail admin-bar-derived expectedTop; the trivia-html boolean 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] because count.default has been 7 since the operator’s 2026-09-09 Settings change.
  • recorded without action: the legacy save-status assertion’s English Saved literal, which would fail under a de_DE admin locale; and the puppeteer utility-world trap, where page.evaluate under puppeteer-core 25.3.0 cannot see page globals, so a non-OMP runner must bind evaluate to a main-world Runtime.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:

GateResultRecord
--wave 117 assertions, 0 failuresround-F shell run
--wave allTAP 1..98, # assertions=98 failures=0, after the fix wave/tmp/qwfix/uiux/wave-all-after.tap
logs/debug.log38,699 lines; 0 new lines across every run of this roundwc -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:

ChunkResultNotes
legacy47/47
player9/9recorded earlier in the round
welcome,superglued-rail,single-column,selection-borders,trivia-html13/13
uiux-perfection a-d7/7
uiux-perfection e5/5
uiux-perfection f5/5rowCount 7 equals requestedCount 7; toolsRestOpacity .55, hover 1
uiux-perfection g5/5
uiux-perfection h-j7/7
post-chip re-gate, chunk3-admin-regate13/13the 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-regate7/7uiux-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 viewportMetricBeforeAfter
J3-desktophoverOnly10
J4-desktophoverOnly10
J4-mobilehoverOnly10
J3-mobilesmallPrimaryOwned70
J4-mobilesmallPrimaryOwned70
Q1-mobilehOverflow10
L1-mobilehOverflow10
D1-mobilehOverflow10
D1-mobilesmallPrimaryOwned192
L1-desktoptinyTextOwned490
J4-desktoptinyTextOwned20

Worse, with the cause established:

Shot and viewportMetricBeforeAfterWhat it is
L1-desktopsmallTargetsOwned817The real regression of section 3. Fixed, re-measured at 8.
J4-desktop and J4-mobilevisibleIndicators4011Driver 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-mobiletinyTextOwned4041Measurement 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.

SetFindingsP1P2P3
Baseline17269076
After17078776

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:

DirectionMovements
upD1-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
downJ1-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.

SymptomShotsWhy it is retained
Fine-tune sticky outcome bar over contentJ3-desktop, J3-mobile, J4-desktop, J4-mobileThe 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 sizeJ5-mobileThe 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 barQ1-mobileSame class as the fine-tune bar: sticky by design, judged from a static frame.
Small textQ1-mobileThe 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.

idShotFinding
UIUX-VIS-01J1-desktopCategory 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-02J1-mobileThe Surprise me tile again, at the mobile viewport.
UIUX-VIS-03J1-mobileThe collapsed Customize disclosure gives no indication of what it contains.
UIUX-VIS-04Q1-mobileThe Answers switches do not read as having a clear on/off state.
UIUX-VIS-05D1-mobileSubject names repeat across the dashboard cards.
UIUX-VIS-06S1-mobileThe 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:

PairFraction of pixels changed
J3-desktop0.0115
J4-desktop0.0115
J3-mobile0.153
J4-mobile0.152
J5-desktop0.207
J5-mobile0.220
L1-desktop0.0089
Q1-mobile viewport0.059
S1-desktop0.0006
S1-mobile0.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 hOverflow rows 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 1 qw_question auto-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_backups 94 rows with 10 owned by user 1; Settings option SHA-256 unchanged at 89877cf6…; the administrator list is admin and qwvisual-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.

Round F journey board: the J1 to J5 public Builder, fine-tune and PDF surfaces at desktop and mobile, after the fix wave

Round F admin board: the Q1 quiz editor, L1 quiz list, D1 dashboard and S1 Settings surfaces at desktop and mobile, after the fix wave

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 focusClipped 11, S1 contrastFailsOwned 1, D1-mobile smallPrimaryOwned 2 — unchanged baseline metric debts, not regressions.
  • S1-mobile tinyTextOwned 41 — 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 still 715474f.
  • 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-perfection h-j chunks only. The other six chunks were not re-run after the chip fix, so their records describe the pre-fix qwizz-admin-shell.css bytes; 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.