Settings panel — premium macOS/iOS restyle
Phase G is a bench-only visual round on /home/loca/dev/wrdp: the QuizWizz Settings panel restyled to one Apple inset-grouped visual language, driven by a capped vision loop and closed by a keyboard walk and the standing gates. It changes CSS and class attributes only, 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, one page:/wp-admin/admin.php?page=qw-settings - viewports 1280x900 desktop and 390x900 mobile, WordPress
freshcolour scheme - plugin mirror HEAD
715474f, unchanged by this round — nothing was staged or committed ./scripts/qwgit.sh status --porcelaincounts 51Mrows and 0??rows, against 49Mafter round F
- bench
- identity, per the bench law that owner-identity Settings writes destroy operator history:
- every capture, every walk and every gate ran as the disposable administrator
qwvisual-20260914(ID 1171); never user 1 - the admin’s
admin_coloruser meta was switched frommoderntofreshbefore round 0, so every round is scored against the same core chrome. That is WordPress user meta, not a QuizWizz setting, and it is the only deliberate state change of the round - zero QuizWizz Settings saves happened in phase G. The option SHA-256 stayed
89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9fandwp_qwizz_settings_backupsread 94 rows with 10 owned by user 1 after every round, every gate and the deletion below - the disposable admin was deleted after the gates with
wp user delete 1171 --yes, against 0 backup rows and 0 posts owned by 1171 at that moment. Administrators are nowadminalone. Round F had deliberately retained this identity; phase G used it and gave it back - re-read while writing this receipt: option SHA
89877cf6…,total=94 owner1=10, one administrator (1:admin), user 1171 absent
- every capture, every walk and every gate ran as the disposable administrator
- evidence locations:
- private, mode
0700:evidence/2026-09-14-uiux-round/settings/— 130 files (129 plus the self-excluded inventory row),allJsonParsetrue, 48 board PNG/JSON pairs of which 42 are scored and 6 are the final unscored board, 11 auxiliary PNGs, 7 critique records covering 56 vision evaluations, 6 fix lists, the preserved failed and artifact keyboard walks and the rejected experiment’s walk (file-inventory.json) - public-safe copies: board-settings.png, settings-scores.md, settings-keyboard-walk.md
- private, mode
2. Specification as shipped
The binding contract was the phase G design specification: system type stack with helper text never below 12px, iOS/macOS inset-grouped lists with one containment edge per section and a 16px-inset hairline between rows, boolean settings as 40x24 desktop / 51x31 mobile switches whose knob shadow is the one permitted control shadow, segmented controls for the tab and tier choosers, a glass toolbar that keeps its 52px geometry and the superglued-rail stacking, a --qw-canvas page field, motion limited to background-color, border-color, box-shadow, opacity, transform at 150–200ms with a reduced-motion opt-out, and the geometry contract of the design board at :163-198. The three new admin tokens are verbatim, at wp/wp-content/plugins/quizwizz/assets/css/qwizz-tokens.css:91-93:
--qw-radius-group: 12px;
--qw-radius-control: 8px;
--qw-canvas: color-mix(in srgb, var(--qw-line2) 40%, white);The single accent is the second qwizz-tokens.css change, and it is scoped rather than global: .qwizz-settings.qwizz-settings--premium at :398-406 sets --qw-brand: #6d28d9, --qw-brand-dark: #5b21b6, --qw-focus: var(--qw-brand) and a --qw-ring mixed from the same hue at 28%. Every accented state in the panel resolves through that one family — the switch ON track at qwizz-admin-settings-core.css:2429-2430, the selection dots at :2584-2585 and :2651-2652, and accent-color at :2918 — while every other QuizWizz admin surface keeps the WordPress-theme-derived tokens of the shared block at qwizz-tokens.css:39-50, whose ten-selector list includes .qwizz-settings itself and is beaten only on the premium root by specificity. The keyboard walk measured the resulting focus outline as rgb(109, 40, 217), which is that hex.
Six owned files. The SHA-256 values below are the live bytes, re-hashed for this receipt and equal to the staged record /tmp/qwfix/settings/round-7-focus/sha256.txt:
File under wp/wp-content/plugins/quizwizz/ | Live SHA-256 | Rounds that changed it |
|---|---|---|
assets/css/qwizz-tokens.css | f30aefd31a3684f3ae61200e569e3402e991103a74be5428844f42823a0b854b | 1, 2, 3 |
assets/css/qwizz-admin-settings-core.css | 4e93db131f0b57ca7f143ae9ca1a2e4a917f47a67129606950a4e7959daa3d59 | 1, 2, 3, focus amendment |
assets/css/qwizz-admin-settings-layout.css | 109869be46bf725986259fca3928cee6488dd98494f7f8fcf8d0cb762442071a | 1, 2, 3 |
assets/css/qwizz-admin-settings-search-preview.css | 04b7b6a69a78611e101d21dc1306221f17131e6bdeed8d4fbc2cf781bac29cf2 | 1, 2 |
assets/css/qwizz-admin-settings-workspace.css | 74ea11c77c426a62c8764d1c0e7dcdd41e49f05bf806875309859a1899979a8d | 1 through 6, focus amendment |
includes/Admin/views/settings-page.php | c7131d8d02a9814b9d5bdc1f0636f9fee5620aaa6167aee07e24a0ad9f2bb0c3 | 1 only |
Each install went through the bench protocol — stage under /tmp/qwfix/settings/round-<n>/, install -o www-data -g www-data -m 0644, then php -l in the container for the view. No file under vendor/, build/, provenance/ or QUIZWIZZ_VERSION was touched.
The PHP view carries class additions only, and that is measured rather than asserted: stripping every class="…" attribute from the round-F staged pre-G copy (/tmp/qwfix/uiux/save-status/includes/Admin/views/settings-page.php) and from the live file leaves zero differing lines. 85 lines gained class tokens and no line lost one, introducing 12 new tokens — qwizz-settings--premium, qwizz-settings__canvas, qwizz-settings__toolbar--glass, qwizz-settings-cluster, qwizz-settings-group, qwizz-settings-group__body, qwizz-settings-group__eyebrow, qwizz-settings-row, qwizz-admin-switch--ios, qwizz-search--pill, qwizz-segment--control and qwizz-segmented-tabs. The view reached its final bytes in round 1 and no later round changed it.
JavaScript is untouched, also measured: live assets/js/qwizz-admin-settings.js is SHA-256 14cea53d553d3498cb4a7fda8bf34aadb56ed76bba69c4851baa90adc5ea1b84, byte-identical to the round-F staged copy of the same file.
One correction to the round’s own summary: the four Settings sheets are token-driven, but they are not hex-free. qwizz-admin-settings-workspace.css:995-996 uses #000 and rgba(0, 0, 0, .35) as the stops of the segmented strip’s right-edge fade mask-image. Those are mask alpha stops rather than paint colours, and no other hex literal appears in the four sheets.
Shipped state is vision round 6 plus the CSS-only round-7-focus amendment, which was authorised after the six-round cap to repair focus-ring clipping. The amendment was not vision-scored, so it does not contribute to any score in section 3.
Two changes the specification forbids were recorded instead of made, because the plan freezes JavaScript:
- search-result rows concatenate a setting’s label and its value into one string — rendered as
Page numbersDefault,Name / Date / Class linesDefaultandPre-print fine-tune editorDefault. The cause issearchIndexCopyatassets/js/qwizz-admin-settings.js:1012-1018, which clones the row, removes effect sentences, screen-reader text, help and segments, and returns the remainingtextContentwith no separator; the result is consumed for the rendered row at:1434. This was the critic’s top residual from round 4 onward. - the mobile segmented strip does not scroll a focused off-screen segment into view. A fix needs a focus handler calling
scrollIntoView, and the file contains noscrollIntoView, nofocusinand no focus listener at all.
Both are carried as ledger rows in section 9.
3. The vision loop
Six PNGs per round — top, group and search at each of the two viewports — were evaluated with the P-settings prompt verbatim from /tmp/qwfix/uiux/prompts.txt, and the two top-of-page PNGs additionally with P-first5, for 8 evaluations per round and 56 in total across 7 critique records. The seven axes the prompt scores 1–10 are hierarchy, density and rhythm, alignment and spacing consistency, contrast and legibility, apple_feel (inset grouped lists, hairline separators, rounded controls, restrained single accent, system type), discoverability of actions and polish; the min axis column below is the lowest of those seven across all six PNGs of the round.
| round | min axis | P1 | P2 | P3 |
|---|---|---|---|---|
| 0 (baseline, pre-restyle) | 3 | 0 | 96 | 26 |
| 1 | 3 | 0 | 83 | 38 |
| 2 | 3 | 0 | 82 | 33 |
| 3 | 3 | 0 | 81 | 36 |
| 4 | 3 | 0 | 77 | 35 |
| 5 | 4 | 0 | 74 | 33 |
| 6 | 4 | 0 | 86 | 37 |
The round did not converge. Convergence required two consecutive rounds in which every axis on every PNG scored at least 9 with zero P1 and zero P2 findings; verdict.json records qualifiedRounds: [], so the six-round cap decided the outcome instead. The plan’s fallback rule is the highest minimum axis score with ties going to the latest round: rounds 5 and 6 tie at minimum axis 4, so round 6 shipped. Per-round tables are in settings-scores.md; the raw records are critique-round-<n>.json, the fix inputs fixes-round-1..6.json, and the decision verdict.json.
What actually moved the design between rounds was the orchestrator’s own screenshot readback, not the critic. Each item below was observed in the round’s captures and fixed in the next:
| round | readback | where it went |
|---|---|---|
| 1 | boolean settings still painted as WordPress-blue native circles inside nested bordered sub-fieldsets, and the stepper was clipped | switches, single containment edge and stepper repair in round 2 |
| 2 | the shared dashbar rail lost its secondary stat links, caused by a Settings-page stat override | override reverted in round 3, rail restored |
| 3 | on mobile with search expanded, toolbar icons and the Saved pill overlapped | round 4 made the segmented strip scrollable and moved the actions cluster trailing |
| 4 | on desktop with search expanded, the nine-tab strip overlapped its own labels | round 5 gave segments flex-shrink: 0 inside an overflow-x: auto strip; round 6 added the right-edge fade mask at qwizz-admin-settings-workspace.css:995-996 |
| 6 | clean at both viewports in all three states | shipped |
Every score, severity and axis in this section is a model judgement over a static screenshot. They are [INFERENCE], never measurements, and no ledger row moves on them. Two further caveats belong to the record: the desktop top, group and search PNGs are byte-identical between rounds 3 and 4, because round 4 was a mobile-only change, yet the critic scored them differently — 42 scored PNGs carry 39 unique SHA-256 values (settings-scores.md). Score movement on identical bytes is evaluation variance and must not be attributed to CSS. And round 6’s P2 count rises to 86 from round 5’s 74 on a strictly later build, which is the same variance seen from the other side.
4. Keyboard walk
Run at both viewports as the disposable admin after the focus amendment, recorded in keyboard-walk-final.json and summarised in settings-keyboard-walk.md. Scope split: Settings means focus stops inside .qwizz-settings; core means every other stop on the page, including the WordPress admin bar, the admin menu and the shared stats rail. Core stops are out of scope for this round and were left unchanged.
| scope and viewport | stops | missing indicators | clipped rings |
|---|---|---|---|
| Settings, desktop | 36 | 3 → 0 | 8 raw → 0 |
| Settings, mobile | 36 | 3 → 0 | 3 → 2 |
| core, desktop | 68 | 0 → 0 | 11 → 11 |
| core, mobile | 15 | 1 → 1 | 7 → 7 |
Desktop walked 104 stops in total and mobile 51.
- one of the eight raw desktop clips was a collector artifact, not a defect. Step 92 is the opacity-0 checkbox
fieldset#qw-tier-player-sound-default > label > inputforplayer.sound_default: the collector measured its invisible 3px external outline while the visible inset-ring proxy was on screen. The other seven raw clips concern visible elements and are genuinely repaired. Do not present all eight as product defects. - the two remaining mobile clips are the
PlayerandAdvancedsegments of the scrollable strip. Focused, their boxes reach 235.95px and 244.61px against the strip’s clip edge at 210px, so they overhang by 25.95px and 34.61px. The strip reportsscrollLeft: 0,scrollWidth: 394,clientWidth: 169andscrollBehavior: autoboth 80ms after focus and again after the 600ms settle, so the user agent does not scroll a focused segment into view and this is not a smooth-scroll timing artifact (keyboard-final-artifact-check.json). Closing it needs JavaScript, which phase G froze — ledger row in section 9. - the Preview modal passed on both viewports: it opens, focus lands inside it,
Escapecloses it, and focus returns to the exact opener. - search behaves, but the interim assertion did not. Typing
pdfreports 5 matches, and the visible indexed setting rows outside the results panel move 7 → 85 of 87 indexed candidates at both viewports. Search reveals matching rows across tiers rather than hiding non-matches, so the plan’s “filters” wording is satisfied by the results panel while the orchestrator’s interim “row count decreases” assertion was mis-specified. It is recorded as a mis-specified assertion, not as a product defect, and the walk’s own overall verdict therefore reads FAIL. - console errors 0 and page errors 0 in every walk, before and after the amendment.
5. Functional gates
Browser smoke, harness scripts/quizwizz-browser-smoke.js at SHA-256 6d0803b2121ef1d352e5a1b6d606aae915773902257214cc118f303ac7b25289, one bounded chunk at a time on an idle bench with a single harness owner, identity resolved through profile.php only:
| Chunk | Result | Record |
|---|---|---|
legacy | 47/47 | g-legacy.json |
uiux-perfection with QWIZZ_UIUX_STEPS=a-d | 7/7 | g-uiux-a-d.json |
uiux-perfection with QWIZZ_UIUX_STEPS=h-j | 7/7 | g-uiux-h-j.json |
tier-selector,single-column,selection-borders,superglued-rail,welcome | 10/10 | g-admin-settings.json |
Every record reports overallPass true, consoleErrors and pageErrors empty, restoration.complete true, foreignRowsDuringRun=[], and both identityEqual and survivingIdentityEqual true. The harness created writers 1198, 1199, 1200 and 1201, one per chunk, and deleted each; the legacy and admin-selector chunks each removed one auto-draft, the two uiux-perfection chunks none. Records are private under evidence/2026-09-14-uiux-round/smoke/.
Shell harness scripts/quizwizz-probe.sh at SHA-256 eacd72ceef6a1f86…, --wave all on the idle bench: exit 0, TAP 1..98, # assertions=98 failures=0, zero not ok and zero Bail out! lines. Wave 9 printed # admin_tree 2q build 10q attempt_payload 5q settings page 4q / 150490 bytes, inside its 6 / 10 / 8 / 13-query ceilings. logs/debug.log measured 38,699 lines before and 38,699 after. The TAP record is /tmp/qwfix/settings/wave-all-g.tap, SHA-256 b653db020e0787bb95d5a81690a4d47ed41692637d339ec77ee00cb75c9c1d22.
All gates ran against the exact shipped bytes: the focus amendment was installed before them and the scroll-snap candidate of section 6 was installed and reverted afterwards.
Two coverage caveats, because a green chunk is not proof of a contract nobody asserts:
- the
a-dstep group emits exactly three UI/UX assertions —UIUX (a)scroll-spy ownership,UIUX (b)assistive-only effect sentences andUIUX (c)the icon/text gap with itschecked >= 60denominator. There is noUIUX (d)assertion in the harness. The Preview modal appears only as twowaitForbarriers atscripts/quizwizz-browser-smoke.js:3173-3179, which open the modal and close it throughbutton[data-preview-close]; nothing there is a counted assertion, and nothing there checks focus containment,Escapeor focus return. The Preview contract is covered by the keyboard walk of section 4 alone. - the probe harness page and the harness skill still describe the shell plan as
1..76in places, while the installed harness emits1..98. That is documentation drift against installed bytes; it is recorded as a ledger row rather than repaired by editing counts this round did not measure.
6. The rejected scroll-snap candidate
One further attempt was made on the residual mobile clip and it failed, so it is recorded rather than hidden. A round-8 CSS-only candidate added exactly two rules to qwizz-admin-settings-workspace.css: scroll-snap-type: none on .qwizz-workspace-nav, .qwizz-anchor-strip and .qwizz-segmented-tabs under :focus-within, and scroll-snap-align: none on their focused anchors. The staged candidate is /tmp/qwfix/settings/round-8-focus-snap-candidate/, workspace sheet SHA-256 5617a492daebfff0baa76083e4c7bdd09345595a03db7ec7f62ad6ec2691648f.
It was installed at 06:11:51Z, measured ineffective and reverted at 06:14:48Z; the staged record carries its own revert annotation at 06:15:05Z. The measurement is keyboard-walk-snap.json: the Player overhang was unchanged at 25.95px and the Advanced segment measured 280.61px against the same 210px clip edge, a 70.6px overhang, with scrollLeft still 0. That 70.6px figure belongs to the rejected experiment only; the shipped residual is 25.95px and 34.61px as recorded in section 4.
Live qwizz-admin-settings-workspace.css is back at the round-7-focus bytes 74ea11c7…, which is the value in the section 2 table.
7. Board and public evidence
One board, 2400x1120, SHA-256 efa9c79e7ed741d29e7b78d318240f1cf2d289d455395dec319e55d41e6a1d02: two rows of six tiles, round 0 against the final build, in the order top, group, search at desktop then the same three at mobile. Every tile was inspected before publication and none shows a credential, address or private identifier, so no redaction was applied.

The two published companions are settings-scores.md, 219 lines carrying the per-round axis tables, the final keyboard table and the bench-invariant lines, and settings-keyboard-walk.md, 66 lines carrying the walk as recorded, including its overall_pass: false.
8. Mirror census after G
Phase G changed six files, two of which were not tracked-modified before, so the mirror census moves from 49 rows to 51 at the same head 715474f, with 0 ??. The refresh artifact is evidence/2026-09-14-mirror-decision/census-refresh-g.json, created 2026-09-14T06:15:40Z, and it carries the same two limits as the round-F refresh: it bypassed the original 41-row assertion, and it did not re-run the canonical apply-check.
| Class | Rows after round F | Rows after phase G |
|---|---|---|
post-sep8-unattributed | 13 | 16 |
post-packet-mutation | 8 | 9 |
packet-clean-base | 6 | 6 |
packet-on-drifted-base | 5 | 4 |
inherited-unpacketed | 3 | 2 |
inherited-catalog-artifact | 14 | 14 |
| total | 49 | 51 |
Four movements account for the whole delta:
assets/css/qwizz-admin-settings-layout.cssmovedpacket-on-drifted-base→post-packet-mutation, because its live bytes no longer equal the sealed Sep-8afterSha256.assets/css/qwizz-admin-settings-workspace.cssmovedinherited-unpacketed→post-sep8-unattributed.assets/css/qwizz-admin-settings-search-preview.cssis a new row,post-sep8-unattributed.assets/css/qwizz-tokens.cssis a new row,post-sep8-unattributed.
The other two owned files were already carried by the round-F refresh: qwizz-admin-settings-core.css as post-packet-mutation and includes/Admin/views/settings-page.php as post-sep8-unattributed. Per-file detail and the owner’s options per class are on the mirror decision sheet. Phase G makes the release owner’s decision harder in the same direction round F did: nine packet paths now carry bytes the sealed packet does not describe, and one more Settings sheet has left the inherited classes.
9. What remains
Eight new ledger ids, all recorded in the open-work ledger so none can be quietly lost. One of them, UIUX-SET-02, no longer remains: the operator-approved JavaScript focus fix recorded in section 11 closed it after this receipt was first written, and it stays in the table with its closing evidence rather than being deleted.
| id | residual | class |
|---|---|---|
| UIUX-SET-01 | search-result rows concatenate label and value (Page numbersDefault). Needs a JavaScript change, and the phase G freeze was lifted only for the section 11 focus fix, so this one is still recorded rather than made. | bench-actionable |
| UIUX-SET-02 | closed 2026-09-14 by the approved focus listener of section 11. The mobile strip now scrolls a focused off-screen segment into view and both viewports measure 0 clipped Settings-owned rings. | shipped |
| UIUX-SET-03 | partially visible scroll-strip tabs on mobile read as truncated labels rather than as an affordance. | owner-decidable |
| UIUX-SET-04 | helper, eyebrow and secondary-text density at both viewports. | owner-decidable |
| UIUX-SET-05 | section-header insets and supporting-text alignment differ across Available experiences, Quiz size and Content languages. | owner-decidable |
| UIUX-SET-06 | the core Screen Options control sits outside the plugin’s content frame on mobile and precedes the settings title. | owner-decidable |
| UIUX-SET-07 | the harness has no UIUX (d) assertion and no counted Preview-modal assertion. | bench-actionable |
| UIUX-SET-08 | documentation drift: 1..76 still appears where the installed harness emits 1..98. | bench-actionable |
UIUX-SET-03 through UIUX-SET-06 are round-6 critic judgements over static screenshots, so they are [INFERENCE] and owner-decidable by construction; no bench measurement moves them. Two of them were summarised more sharply than the record supports, and the difference is stated on the ledger rows: round 6 records a header-inset and supporting-text-alignment inconsistency rather than a missing helper line under Quiz size, and it records Screen Options as consuming height and following its own alignment rather than floating over the mobile rail. Nothing in critique-round-6.json or the final measurement JSONs establishes an overlap with the rail.
Debts carried from earlier rounds are unchanged by phase G: UIUX-P1 and UIUX-VIS-01 through UIUX-VIS-06 from round F, UIUX-BACKUP-01 for owner 1’s 11 backup rows against a per-writer cap of 10, and the mirror decision itself.
10. Explicit non-claims
- not converged. The loop hit its six-round cap with
qualifiedRounds: []; round 6 shipped on a tie-break, and the focus amendment was never vision-scored. - no human acceptance. Nobody has reviewed or accepted this surface. This receipt records measurements, gates and model judgements only.
- no release eligibility.
releaseEligible: false. Nothing was staged, committed or pushed; mirror HEAD is still715474f. - every axis score, severity and finding in section 3 is a model judgement over a static screenshot. They are
[INFERENCE], and the round-3/round-4 identical-byte scoring shows the variance directly. - the keyboard walk’s overall verdict is FAIL, and this page does not present it as a pass. The core failures are out of scope and unchanged, and the mis-specified row-decrease assertion is recorded as mis-specified. Section 4’s two remaining mobile Settings clips are the shipped-round reading; they are closed by section 11, whose own walk still records the same
visibleRowsDecreasedfailure and therefore the same FAIL verdict. - the browser chunks cover no Preview-modal assertion and no
UIUX (d); that contract rests on the keyboard walk alone. - the mirror apply-check was not re-run against the phase G tree, so the exit-1 seven-path result on the decision sheet still describes the pre-round-F packet.
- no production wiki build or deployment was run by this writer, and no page from this round is claimed live.
11. Amendment — approved JavaScript focus fix (2026-09-14)
After the keyboard gate of section 4 was reported blocked on the mobile strip residual, the operator explicitly approved the smallest bounded JavaScript correction in assets/js/qwizz-admin-settings.js. The phase G freeze on JavaScript was lifted for that one change only: UIUX-SET-01 was not touched and stays recorded rather than made. Sections 1 through 10 remain the round’s own record; where they measure the pre-amendment bytes they are superseded here rather than rewritten, including section 2’s live JavaScript reading 14cea53d… and section 4’s two remaining mobile clips.
The change is one focus listener per [data-workspace-tab], inserted immediately before the existing click listener inside the workspaceTabs.forEach at wp/wp-content/plugins/quizwizz/assets/js/qwizz-admin-settings.js:1479. The listener occupies :1485-1491: it returns unless the segment’s strip (tab.parentElement) is horizontally scrollable — strip.scrollWidth <= strip.clientWidth returns at :1487 — and unless the segment’s rect lies outside the strip’s rect, which returns at :1488-1489; otherwise it calls tab.scrollIntoView({ block: 'nearest', inline: 'start', behavior: 'auto' }) at :1490. The in-file rationale is at :1480-1484, the click listener still begins at :1492, and no other file changed.
The first attempt was measured ineffective and is recorded rather than hidden. Both attempts were installed from the same staging directory, /tmp/qwfix/settings/round-9-js/, with install -o www-data -g www-data -m 0644 after a clean node --check; the retained staged copy and its sha256.txt carry the final bundle only, at a7b6768e7fa555019936564552fc8bc9edd1d329bb3499f9248b935519ccbe77, which equals the live file. The live file reads www-data www-data 644.
| attempt | inline argument | live SHA-256 | measured outcome on mobile |
|---|---|---|---|
| first | inline: 'nearest' | 1a3792befba2415e8ed0894b68173707915974af81e68bcfa631e58d9b043bd0 | ineffective. Player still clipped, 1 clipped Settings ring; the strip stayed at scrollLeft: 0 at the 80ms probe and at the settled measurement, segment 144.28–235.95 against strip 41–210 (keyboard-walk-js-1a3792be.json) |
| final | inline: 'start' | a7b6768e7fa555019936564552fc8bc9edd1d329bb3499f9248b935519ccbe77 | effective at both viewports, 0 clipped Settings rings (keyboard-walk-js.json, confirmed by keyboard-walk-js-confirm.json) |
nearest failed because the strip declares scroll-snap-type: x proximity at wp/wp-content/plugins/quizwizz/assets/css/qwizz-admin-settings-workspace.css:194: proximity snapping returns a small nearest scroll to the previous snap point, which is why the durable reading is scrollLeft: 0 at both probes. The probe-runner also observed the requested 26px scroll being pulled back to 0; that transient value is not preserved in an artifact, so the table above carries the measurement and not the transient. inline: 'start' targets the segment’s own snap point — every tab measures scroll-snap-align: start in keyboard-walk-js-confirm.json — so the snap holds the scroll instead of undoing it. The browser re-fetched the served bundle and matched the final SHA, which the walk records as expectedJsSha256; re-hashing the live file for this amendment returns the same value.
Keyboard walk on the final bundle, same collector and same scope split as section 4, run as the disposable admin at 390x900 and 1280x900 (keyboard-walk-js.json, captured 2026-09-14T11:27:28.964Z; mobile confirmation pass keyboard-walk-js-confirm.json at 11:44:12.998Z). Before is the shipped-round reading of section 4; after is this walk:
| scope and viewport | stops | missing indicators | clipped rings |
|---|---|---|---|
| Settings, mobile | 36 of 51 | 0 → 0 | 2 → 0 |
| Settings, desktop | 36 of 104 | 0 → 0 | 0 → 0 |
| core, mobile | 15 | 1 → 1 | 7 → 7 |
| core, desktop | 68 | 0 → 0 | 11 → 11 |
- mobile geometry, measured per segment after the settle:
PlayeratscrollLeft: 87with the segment at 54.28–145.95 inside a strip of 38–207,DataatscrollLeft: 180andAdvancedatscrollLeft: 225with 2.39px of clearance at the strip’s right edge. All four workspace tab stops reportinsideStriptrue andclippedOutsideStripis empty. - desktop is a deliberate no-op: the strip measures
stripScrollWidth: 672againststripClientWidth: 672, so it is not scrollable, the listener’s first guard returns and all four tab stops measure inside the strip unchanged. - core chrome is untouched by the change and unchanged in the measurement: 1 missing indicator and 7 clipped rings on mobile, 0 and 11 on desktop, exactly the section 4 readings.
- the Preview modal passes at both viewports: it opens with focus inside on
Close guest preview,Escapehides it, and focus returns tobutton.qwizz-preview-open. Search typedpdfreports 5 matches and passes. Console errors 0 and page errors 0 in every walk. - the walk’s own
passis still false, on the same single assertion as the shipped round:visibleRowsDecreasedrecordsbefore: 7, after: 85at both viewports. That is the pre-existing artifact of the interim mis-specified assertion described in section 4, identical on the shipped round, and not a regression introduced here. - the plan’s line 210 acceptance — 100% visible focus indicators and 0 clipped rings across Settings-owned stops — is now met at both viewports. It was not met on the shipped round.
- the failed first-bundle walks are preserved as
keyboard-walk-js-1a3792be.jsonandkeyboard-walk-js-1a3792be-confirm.jsonbeside the passing pair, under the private corpusevidence/2026-09-14-uiux-round/settings/.
Gates re-run on the new bundle, one bounded chunk at a time on an idle bench with a single harness owner, at the unchanged harness bytes 6d0803b2…:
| Chunk | Result | Record |
|---|---|---|
legacy | 47/47 | js-legacy.json |
uiux-perfection with QWIZZ_UIUX_STEPS=a-d | 7/7 | js-uiux-a-d.json |
uiux-perfection with QWIZZ_UIUX_STEPS=h-j | 7/7 | js-uiux-h-j.json |
tier-selector,single-column,selection-borders,superglued-rail,welcome | 10/10 | js-admin-settings.json |
Every record reports overallPass true, consoleErrors and pageErrors empty, restoration.complete true, and the backup-table identity digests equal on both readings — equal and survivingIdentityEqual true, with the harness rows it created tracked, requested and removed. Shell scripts/quizwizz-probe.sh --wave all on the same idle bench exited 0 at TAP 1..98 with # assertions=98 failures=0 (/tmp/qwfix/settings/wave-all-js.tap:288-289). logs/debug.log measured 38,703 lines before and 38,703 after; that is the current bench figure and supersedes nothing in section 5, which measured 38,699 at its own time.
Bench invariants after the amendment, re-verified read-only for this page: wp_qwizz_settings_backups holds 94 rows with 10 owned by user 1, qw_exposure_settings hashes to 89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9f unchanged, admin is the only administrator and auto-drafts count 0. No QuizWizz Settings save was made by this amendment. The disposable administrator was re-created as ID 1208 for the walk and deleted afterwards against 0 backup rows and 0 posts; a single Quick Draft auto-draft (post 12640) created by a login redirect was attributed and removed, and user 1208 no longer resolves.
The mirror census was refreshed rather than assumed: evidence/2026-09-14-mirror-decision/census-refresh-js.json, created 2026-09-14T11:45:45+00:00 at head 715474f, reads 51 rows with the same class counts as the phase G refresh — 16 post-sep8-unattributed, 9 post-packet-mutation, 6 packet-clean-base, 4 packet-on-drifted-base, 2 inherited-unpacketed and 14 inherited-catalog-artifact. No class moved, because assets/js/qwizz-admin-settings.js was already a round-F post-packet-mutation row; the only row-level change is that row’s own current_sha256, from 14cea53d… to a7b6768e…, with numstat moving from 54 added / 43 deleted to 66 / 43 against the same packet_after_sha256 70a0a621…. Like the earlier refreshes it carries apply_check: null, so no canonical apply-check was run against this tree either.
Non-claims for this amendment, in addition to section 10: it was not vision-scored, no human has accepted the surface, the freeze lift covers this one change only, the walk’s overall verdict is still false on the mis-specified assertion, and nothing was staged, committed or pushed — mirror HEAD is still 715474f and the patch is releaseEligible: false. No production wiki build or deploy was run by this writer.