Changelog

2026-09-14 - Settings premium panel restyle (phase G)

The Settings premium restyle rebuilt the QuizWizz Settings panel as one Apple inset-grouped visual language on the bench: groups with a single containment edge and 16px-inset hairlines, switches and segmented controls instead of native WordPress form chrome, a glass toolbar that keeps its 52px geometry and superglued-rail stacking, a --qw-canvas page field and one purple accent scoped to the premium Settings root. Three new admin tokens sit at wp/wp-content/plugins/quizwizz/assets/css/qwizz-tokens.css:91-93 and the scoped accent block at :398-406 (--qw-brand: #6d28d9, --qw-focus: var(--qw-brand)), so nothing outside the Settings root inherits the hue. Six owned files, installed through stage, install as www-data and in-container lint: qwizz-tokens.css, qwizz-admin-settings-core.css, qwizz-admin-settings-layout.css, qwizz-admin-settings-search-preview.css, qwizz-admin-settings-workspace.css and includes/Admin/views/settings-page.php. The view carries class attributes only, which is measured rather than asserted: stripping every class="…" attribute from the pre-round copy and the live file leaves zero differing lines across 85 changed lines and 12 new class tokens, and it reached its final bytes in round 1. assets/js/qwizz-admin-settings.js was byte-identical to its pre-round copy at SHA-256 14cea53d… when the round closed; the amendment sub-entry below supersedes that reading for live bytes.

  • The vision loop ran six scored rounds against a hard cap and did not converge. Minimum axis per round was 3, 3, 3, 3, 3, 4, 4 from baseline through round 6, with 0 P1 throughout and P2 moving 96 → 83 → 82 → 81 → 77 → 74 → 86; verdict.json records qualifiedRounds: [], rounds 5 and 6 tied at minimum axis 4, and the plan’s latest-round tie-break shipped round 6. Every axis and severity is a model judgement over a static screenshot: the desktop PNGs are byte-identical between rounds 3 and 4 and were still scored differently, so 42 scored images carry 39 unique digests. What actually drove the fixes was the orchestrator’s screenshot readback — native blue circles and nested fieldsets in round 1, the dashbar rail losing its secondary stat links in round 2, mobile toolbar overlap in round 3, desktop nine-tab label overlap in round 4 — each repaired in the following round, with the right-edge fade mask landing in round 6 at qwizz-admin-settings-workspace.css:995-996.
  • Shipped state is round 6 plus a CSS-only round-7-focus amendment, which was not vision-scored. The keyboard walk after it covers 104 desktop and 51 mobile tab stops, of which 36 are Settings-owned at each viewport: desktop Settings missing indicators 3 → 0 and clipped rings 8 raw → 0, mobile Settings missing 3 → 0 and clipped 3 → 2. One of the eight raw desktop clips was a collector artifact — an opacity-0 checkbox whose invisible outline was measured while its visible inset-ring proxy was on screen — so seven, not eight, were product defects. The two remaining mobile clips are the Player and Advanced segments overhanging the 210px strip edge by 25.95px and 34.61px with scrollLeft stuck at 0 and scrollBehavior: auto after 600ms. The Preview modal passes open, focus-inside, Escape and exact opener restoration at both viewports. Search typed pdf reports 5 matches while visible indexed rows move 7 → 85 of 87 candidates, so search reveals rows rather than hiding them and the interim “row count decreases” assertion is recorded as mis-specified, not as a defect; the walk’s own verdict stays FAIL. Zero console and page errors in every walk.
  • Gates ran on the exact shipped bytes, on an idle bench with one harness owner, as the disposable administrator qwvisual-20260914 (ID 1171) and never user 1: shell --wave all exit 0 at TAP 1..98 with # assertions=98 failures=0, Wave 9 printing admin_tree 2q build 10q attempt_payload 5q settings page 4q / 150490 bytes inside its 6/10/8/13 ceilings, logs/debug.log at 38,699 lines before and after, TAP record SHA-256 b653db02…. Browser smoke at harness SHA-256 6d0803b2…, one bounded chunk at a time: legacy 47/47, uiux-perfection a-d 7/7 and h-j 7/7, and tier-selector,single-column,selection-borders,superglued-rail,welcome 10/10, every record with zero console and page errors, foreignRowsDuringRun=[], complete restoration and both identity checks true; harness writers 1198-1201 were created and deleted one per chunk.
  • Two coverage caveats are recorded rather than smoothed away: the a-d group emits only UIUX (a), (b) and (c) — there is no UIUX (d), and the Preview modal exists in the harness only as two waitFor barriers at scripts/quizwizz-browser-smoke.js:3173-3179, so the Preview contract rests on the keyboard walk alone; and the probe page and harness skill still describe the shell plan as 1..76 where the installed harness emits 1..98.
  • A round-8 scroll-snap candidate was installed at 06:11:51Z, measured ineffective and reverted at 06:14:48Z. It added exactly two rules, suspending scroll-snap-type on :focus-within and scroll-snap-align on the focused anchor; the Player overhang was unchanged and Advanced measured a 70.6px overhang with scrollLeft still 0. Live qwizz-admin-settings-workspace.css is back at the round-7-focus bytes 74ea11c7…; the rejected walk is preserved as keyboard-walk-snap.json.
  • Zero QuizWizz Settings saves happened in the round. Option SHA-256 89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9f and 94 backup rows with 10 owned by user 1 held after every round, every gate and the identity deletion. The disposable admin’s admin_color user meta was switched from modern to fresh before round 0 so every round was scored against the same core chrome, and the identity itself was deleted afterwards with wp user delete 1171 --yes against 0 backup rows and 0 posts, leaving admin as the only administrator.
  • The open-work ledger now contains 169 ids: 34 shipped, 14 bench-actionable, 61 owner-decidable, 49 terminal-blocked and 11 deferred. Eight ids are new: UIUX-SET-01 and UIUX-SET-02 for the two JavaScript residuals, UIUX-SET-07 for the harness coverage gap and UIUX-SET-08 for the documentation drift, all bench-actionable on arrival; UIUX-SET-03 through UIUX-SET-06 for the round-6 critic residuals, all owner-decidable. UIUX-SET-02 moved to shipped the same day — see the amendment sub-entry below — which is why the class split reads 34/14. Detail is in new section 13. Two of the critic rows also record where the round’s own summary outran the record: round 6 logged a header-inset and supporting-text inconsistency rather than a missing helper line under Quiz size, and it logged Screen Options as consuming height and following its own alignment rather than floating over the mobile rail.
  • Mirror drift widened again: ./scripts/qwgit.sh status --porcelain reads 51 M and 0 ??, against 49 after round F. qwizz-admin-settings-layout.css moved packet-on-drifted-basepost-packet-mutation, qwizz-admin-settings-workspace.css moved inherited-unpacketedpost-sep8-unattributed, and qwizz-admin-settings-search-preview.css and qwizz-tokens.css are new rows. The refreshed class table is on the mirror decision sheet; no canonical apply-check exists for this tree.

Public-safe evidence was copied to q5vault/assets/evidence/2026-09-14-uiux-round/: one 2400x1120 board of round 0 against the final build (SHA-256 efa9c79e…), the 219-line score record and the 66-line keyboard-walk record. The private corpus under evidence/2026-09-14-uiux-round/settings/ holds 130 files including the preserved failed, artifact and rejected-experiment walks. Nothing was staged, committed or pushed; mirror HEAD is still 715474f. The loop did not converge, no human has accepted the surface, and no production wiki build or deploy ran for this round — releaseEligible: false.

2026-09-14 — approved JavaScript focus fix, phase G amendment

The keyboard gate above was reported blocked on the mobile strip clip, and 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, so UIUX-SET-01 stays recorded rather than made. The change is one focus listener per [data-workspace-tab], inserted just before the existing click listener at wp/wp-content/plugins/quizwizz/assets/js/qwizz-admin-settings.js:1485-1491: when the segment’s strip is horizontally scrollable and the segment’s rect lies outside the strip’s rect, it calls tab.scrollIntoView({ block: 'nearest', inline: 'start', behavior: 'auto' }) at :1490.

The first bundle used inline: 'nearest' (live SHA-256 1a3792be…) and was measured ineffective: mobile Player stayed clipped with the strip at scrollLeft: 0 at both probes, because the strip declares scroll-snap-type: x proximity at qwizz-admin-settings-workspace.css:194 and proximity snapping returns a small nearest scroll to the previous snap point. Corrected to inline: 'start', which lands on the segment’s own snap point; final live SHA-256 a7b6768e7fa555019936564552fc8bc9edd1d329bb3499f9248b935519ccbe77, node --check clean, staged at /tmp/qwfix/settings/round-9-js/ and installed www-data 0644, with the browser re-fetching the served bundle and matching that digest.

  • The keyboard walk on the final bundle clears the gate at both viewports. Mobile 51 stops with 36 Settings-owned: 0 missing indicators and 0 clipped rings, Player at scrollLeft: 87 with its segment at 54.28–145.95 inside a strip of 38–207 and Advanced at scrollLeft: 225 with 2.39px of clearance. Desktop 104 stops with 36 Settings-owned: 0 and 0, the strip measuring scrollWidth === clientWidth === 672 so the listener’s guard returns and it no-ops. Core chrome is unchanged at 1 missing / 7 clipped on mobile and 0 / 11 on desktop. Preview opens with focus inside, Escape closes it and focus returns to the opener at both viewports; search typed pdf reports 5 matches; console and page errors 0. The walk’s own verdict stays false on the pre-existing mis-specified visibleRowsDecreased 7 → 85 assertion, identical to the shipped round and not a regression. The plan’s line 210 acceptance — 100% visible indicators and 0 clipped rings across Settings-owned stops — is met for the first time. Records are keyboard-walk-js.json and keyboard-walk-js-confirm.json, with the failed first-bundle pair preserved as keyboard-walk-js-1a3792be*.json.
  • Gates re-ran on the amended bundle at unchanged harness bytes 6d0803b2…, one bounded chunk at a time on an idle bench: legacy 47/47 (js-legacy.json), uiux-perfection a-d 7/7 (js-uiux-a-d.json) and h-j 7/7 (js-uiux-h-j.json), and tier-selector,single-column,selection-borders,superglued-rail,welcome 10/10 (js-admin-settings.json), every record overallPass true with zero console and page errors, restoration complete and the backup-table identity digests equal. Shell --wave all 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 after.
  • Bench invariants held and were re-verified read-only for the amendment: 94 Settings-backup rows with 10 owned by user 1, qw_exposure_settings SHA-256 89877cf6… unchanged, admin the only administrator and 0 auto-drafts. No Settings save was made. The disposable administrator was re-created as ID 1208 for the walk and deleted afterwards against 0 rows and 0 posts; one Quick Draft auto-draft (post 12640) from a login redirect was attributed and removed.
  • The mirror census was refreshed rather than assumed: census-refresh-js.json reads 51 rows at head 715474f with the same class counts as the phase G refresh, because the JavaScript file was already a round-F post-packet-mutation row. No class moved, apply_check is null, and UIUX-SET-02 is now shipped in the ledger.

The amendment is section 11 of the phase G receipt, appended rather than rewritten into the round’s own measurements. It was not vision-scored, no human has accepted the surface, nothing was staged, committed or pushed, and mirror HEAD is still 715474freleaseEligible: false. No production wiki build or deploy was run by its writer.

2026-09-14 - UI/UX repair round (round F)

UX repair round closed the whole 2026-09-02 reviewer and metric block on the bench. Six rows were installed across five slices through stage, install as www-data and in-container lint: UIUX-REV-01 (shared LanguageFlags::label helper at wp/wp-content/plugins/quizwizz/includes/LanguageFlags.php:30, consumed at includes/Frontend/views/builder-view.php:146, plus the REST entity decode), UIUX-REV-03, UIUX-REV-04, UIUX-REV-05 (Your quiz as translatable source copy at builder-view.php:305), UIUX-REV-07 and UIUX-REV-08. UIUX-REV-02 and UIUX-REV-06 were closed on their own measurement: both preconditions were already absent from the installed tree, so no byte changed. UIUX-METRIC-01 and UIUX-METRIC-02 were closed by retiring the stale ≤290px and ≤40px chrome-inclusive targets and re-scoping acceptance to the plugin-owned counter set the round’s driver measures. The Settings save-status pill was restored at includes/Admin/views/settings-page.php:196-199 with seven strings at includes/Admin/SettingsPage.php:408-420 and a five-state setSaveStatus machine at assets/js/qwizz-admin-settings.js:218-221, measured contrast 7.33.

The round caused and then repaired one measured regression. Making the +N subject-overflow marker focusable for UIUX-REV-08 turned a bare span into a 28x21 interactive target and raised L1-desktop owned small targets from the baseline 8 to 17. It is now a 32x32 border-box inline-flex pill with the focus ring drawn inside at assets/css/qwizz-admin-shell.css:114-134,141-144, re-measured at 8 with a 32x32 client rect. A companion rail rule was generalised to body.qwizz-admin:has(.qwizz-admin-rail) #wpcontent at assets/css/qwizz-admin-responsive.css:376 so the quiz-list and quiz-editor screens stop reserving 46px under an admin bar WordPress has made absolute.

  • Gates on an idle bench with a single harness owner, every measurement and run as the disposable administrator qwvisual-20260914 (ID 1171) and never user 1: shell --wave 1 17/0 and --wave all TAP 1..98 with # assertions=98 failures=0 (/tmp/qwfix/uiux/wave-all-after.tap); logs/debug.log at 38,699 lines with 0 new lines across every run. Browser smoke at harness SHA-256 6d0803b2121ef1d352e5a1b6d606aae915773902257214cc118f303ac7b25289 (3,716 lines), one bounded chunk at a time: legacy 47/47, player 9/9, the admin chunk 13/13, and uiux-perfection a-d 7/7, e 5/5, f 5/5, g 5/5, h-j 7/7. Post-chip re-gate: chunk3-admin-regate 13/13 at 04:02:10Z and chunk8-uiux-h-j-regate 7/7 at 04:05:09Z, both after the chip rule landed at 03:05:48Z, both with error: null, empty console and page error arrays, restoration.complete true and foreignRowsDuringRun=[].
  • Three chunks went green only after a harness contract was corrected, not after a product change; the eight reconciliations are recorded against installed harness bytes in the probe harness under 2026-09-14 harness contract update. Two are recorded as known limitations with no change made: the legacy save-status assertion’s English Saved literal, and the puppeteer utility-world trap where page.evaluate cannot see page globals.
  • Matched measurement, same driver bytes (/tmp/qwfix/uiux/measure.mjs, SHA-256 be06ed624df7e512dba4ddde6c5443f6c818efbb71f9260727b112c441ba6aec) on both sides across 18 shot/viewport pairs. Eleven owned-metric rows improved, among them L1-desktop tinyTextOwned 49 → 0, D1-mobile smallPrimaryOwned 19 → 2, J3-mobile and J4-mobile smallPrimaryOwned 7 → 0, and hOverflow 1 → 0 on Q1-mobile, L1-mobile and D1-mobile. Two worse rows are disclosed as artifacts rather than explained away: J4 visibleIndicators 40 → 11 because the tab walk entered the PDF preview iframe, which draws no outline, and S1-mobile tinyTextOwned 40 → 41 because the restored pill hides its long label with font-size: 0 and a ::after short label. Nineteen worse tDom/measureMs rows are single-run timings and carry no conclusion.
  • The re-run vision critique moved 172 findings (6 P1 / 90 P2 / 76 P3) to 170 (7 P1 / 87 P2 / 76 P3), with 88 of the 94 after-side P1 and P2 findings matching a baseline finding, 0 new P1 and 6 new P2. All seven retained P1 findings restate baseline symptoms and reduce to four: the fine-tune sticky outcome bar on J3 and J4 at both viewports, the J5-mobile PDF scaled to 390px, the Q1-mobile sticky Update bar, and Q1-mobile small text read off a downscaled image. Three of the four are artifacts of judging a sticky element in a frame that cannot be scrolled. These are model judgements over static screenshots, never measurements, and no row moves on them.
  • Residue: an aborted first smoke attempt left harness user qwharness_browser_smoke (ID 1182) with two backup rows and one qw_question auto-draft, and two Quick Draft auto-drafts by user 1171 (IDs 12578 and 12614) came from dashboard hops. All were attributed and removed before gates resumed. Final bench: 94 Settings-backup rows with 10 owned by user 1, option SHA-256 89877cf601ca195bf0ff75c936637e485d8b6de454c301934bff54ab0838ff9f unchanged, administrators admin and qwvisual-20260914. The disposable admin is deliberately retained.
  • The open-work ledger now contains 161 ids: 33 shipped, 11 bench-actionable, 57 owner-decidable, 49 terminal-blocked and 11 deferred. Ten rows changed class and seven ids are new — UIUX-P1 for the four retained P1 symptoms and UIUX-VIS-01 through UIUX-VIS-06 for the six new P2 findings, all owner-decidable. Round-F evidence is in new section 12.
  • Mirror drift widened: ./scripts/qwgit.sh status --porcelain reads 49 M and 0 ??, against 41 before the round. 21 of the 49 are round-F files — 13 post-sep8-unattributed and 8 post-packet-mutation — and the eight mutated packet paths now carry bytes the sealed Sep-8 packet does not describe. The canonical apply-check was not re-run against the round-F tree; the refreshed class table is on the mirror decision sheet.

Public-safe evidence was copied to q5vault/assets/evidence/2026-09-14-uiux-round/: two 2400x1272 boards, the metric and score comparisons, the after-side findings and a smoke summary. Nothing was staged, committed or pushed; mirror HEAD is still 715474f. No human acceptance, no release eligibility, and no production wiki build or deploy ran for this round — releaseEligible: false.

2026-09-14 - Backup exposure cleanup

The backup exposure cleanup removed 58 untracked editor droppings (32 .bak, 26 .bak-20260904-cutover; assets 10, config 2, includes 12, languages 34) from wp/wp-content/plugins/quizwizz/ after copying each to evidence/2026-09-14-bak-exposure-cleanup/files/ and proving SHA-256 parity for all 58 (manifest SHA-256 43a12f5e04663327619c8d79ee533cde3a2805460779c90fc4cc1e2c7f490cb5). Before the change the public vhost served includes/Settings/SettingsSchema.php.bak-20260904-cutover (200, 17,979 bytes) and includes/ExposureSettings.php.bak-20260904-cutover (200, 32,392 bytes) because its droppings deny matched only exact extensions; the rule in /etc/nginx/sites-available/wrdp.loca.zone is now suffix-aware for the bak, old, orig and save families, nginx -t exit 0, reload exit 0, and all sampled plus artificial suffixed URLs return 404. Health 7/7; qwgit.sh status --short shows 41 inherited tracked-modified files and 0 untracked. No plugin source, database or Sep-8 mirror/packet boundary changed. Validated with --check-only only; releaseEligible: false. Same day, §7 of the receipt closed the trailing-slash and swp/swo edges of the deny ((?:/.*)?$ path-info tail, suffix-aware swap families), mutation-proved on a throwaway uploads fixture that was served raw before and returns nginx’s 146-byte 404 after; fixture removed, health 7/7.

The mirror decision sheet gives the release owner a per-file 3-way census of the 41 tracked-modified plugin files against mirror HEAD 715474f — 13 packet-on-drifted-base, 6 packet-clean-base, 5 inherited-unpacketed, 17 inherited-catalog-artifact, 0 unattributed — plus the first canonical apply-check of the final packet (exit 1; the same seven paths the v3 assessment recorded) and the concrete options per class. Read-only; nothing staged or committed.

Wave 5 residue diagnostics closes ledger row UIUX-FLAKE-01 as diagnostics: Wave 5 assertion 12 now prints # wave5 residue jobs= files= chunks= cron= markers= option_drift= and a :: detail suffix on failure (mutation-proved red→green); six idle, six 4×-loop and six 8×-loop loaded runs all passed, verdict not reproduced at 4×/8× loops; hypothesis remains unverified. The all-wave gate was found red (98/7) in Waves 7-9 because the operator’s 2026-09-09 02:56–03:02 UTC Settings reconfiguration (play_page_id 0→2, politics and science-mathematics off, 40 leaves in all) had outrun two pinned contracts; the harness now pins player.play_page_id=0 for Waves 7-9 with a byte-exact restore (Bail out! on mismatch, mutation-proved) and re-pins the Wave 9 tree digest to 9f4c1bbb… after proving in memory that the delta is exactly those two toggles. Second all-wave 1..98, failures 0. Harness only; no plugin byte, no Settings saved.

2026-09-08 - Live punchlist repairs and surviving evidence boundaries

The Sep-8 live punchlist receipt is the newest dated audit-as-of record, with its local public-safe evidence integration complete. Main’s sole final /home/loca/dev/wikis/build.sh wrdp --check-only validation passed on 2026-09-09: exit 0 in 166.80 seconds, SSOT passed, 89 Markdown files parsed, 945 files emitted to scratch, and only the expected no-git warning; the execution timestamp was not supplied. No production publication followed. The receipt is not planning authority or blanket acceptance. It records installed Builder, editor, Settings and PDF repairs separately from scoped runtime observations and human decisions. All 39 working identities remain visible; September S03 picks are not the August canonical S03 findings, and this census does not replace canonical issue, ledger or cluster totals. Planning authority remains the remediation masterplan.

  • The local public-safe corpus is 50 assets — 28 JSON and 22 PNG — plus its manifest, not 50 passes. The first 47 entry objects remain unchanged and one Editor projection plus two paint-masked Editor viewport frames were appended. All 50 match recorded digests/lengths, every JSON parses, every public asset is mode 0644, and all 22 PNG stored-byte and decoded-RGBA digests are distinct. The Editor frames show visible geometry/control chrome after verified temporary paint masking; they do not delete DOM/value content or establish interaction/human acceptance. Three inline-only original mobile images never persisted. This is local evidence, not production publication.
  • The final 19-file plugin-source packet was sealed on 2026-09-09 at status PLUGIN_SOURCE_PACKET_OFFLINE_PROVED_RUNTIME_GATE_INCOMPLETE. Its 152,039-byte patch is SHA-256 d1bc84e75939f5fa449b8127c58f271bb59c0e26a7bfb03443d75a4e3083a93c; strict apply-check, apply, recursive byte comparison and live-freeze hashes pass against exact dirty before images. It is not canonically applicable or release eligible. The separate after-only harness/worker supplement is now sealed: manifest SHA-256 a7d8d50ba93dfe807070c435bc669b46dac6ebe53a7616321c63a8f56fbe6eb4, 39 source files and 39/39 copy/current parity. It excludes fixtures, raw results, capabilities, config and PDF copies, so it is source preservation rather than runtime authority. Separately, reconciled Wave 9 1..21 and all-wave 1..98 are green.
  • The read-only database comparison records the 14:14:54 UTC snapshot matching the later 12:57:39 primary-tool-transcript baseline for raw Settings/stored JSON, 94 complete backup rows and quiz/draft fixtures. Independent pre-task archive replay at 14:42:13.916009 UTC establishes all 94 seven-column backup rows, including 10 operator backups, exactly matching the Sep-8 pre-task nightly dump. No task-era backup loss or restoration is needed; older 95-total/11-operator wording does not establish loss today.
  • Final original a-d passes 7/7 and original e 5/5 with complete restoration. Pre-repair original f remains 4/5 and the first post-sticky lifecycle 5/6 red, but corrected response-observer f passes 5/5 with in-viewport Cancel/Preview PDF/Print and exact current-run cleanup. Corrected g passes 5/5 after awaiting initial preview capture; the correction is a harness barrier, not a product fix. The first authorized Editor lifecycle remains red because its oracle ignored Hidden theme policy; the corrected policy-aware lifecycle passes 8/8 for E03-08/10/11/12 across desktop/mobile. Each current f/g/Editor transaction removes exactly one draft, one artifact and one private file. Earlier unknown capabilities remain unresolved; no global cleanup or human acceptance is claimed.
  • The earlier mobile Settings lifecycle passes S03-01/04/07/08 at 390×900 but remains red on operator-auth restoration. Its shallow BEFORE and deep AFTER are counterfactual install evidence, not matched same-depth A/B. A later Fresh-Surfaces lifecycle passes 9/9 for S03-02/03/05/06 with singular AX/DOM Search and Preview controls, trusted keyboard behavior and scoped cleanup. The same-HTML tooltip fixture proves readable hints and native controls under conditional exposure only; stored Hidden exposure remains unchanged.
  • Mirror commit is NOT PERFORMED and blocked: 13/19 dirty-baseline before files differ from canonical 715474f, and disposable canonical apply-check fails on 7 paths. The release owner must decide inherited prerequisites and the canonical target/port, then approve narrow staging after checking the real index for unrelated work.

The linked receipt supplies the evidence and limits for these statements. No release, production wiki publication or human acceptance is claimed. No canonical package was built, signed, published or deployed by this navigation update; source changes remain subject to the release owner’s locked pipeline and releaseEligible: false. The Sep-1–3 records below remain dated history, not current final-gate authority.

2026-09-03 - Standing handover page and durable evidence copy

  • Added 🤝 Handover: bench state at pushed HEAD 715474f, the seven rules learned during the 2026-09-02 round (operator-identity Settings writes, stage/install, idle-bench gates, bounded browser runs, symptom-measuring gates with a denominator guard, browser authority, vault hygiene), the bench-actionable ledger rows in pickup order with file:line pointers and the gate to run after each, the verification commands, and the re-handoff checklist. Linked from the root index, the QuizWizz audit hub, Now and the open-work ledger.
  • Copied the round’s small durable evidence (before/after JSON, measure.js, icongap.js, mutation matrix, dossier, recovery record, TAP records, the SET-07 before screenshot; 108 KB) to q5vault/assets/evidence/2026-09-02-uiux/ so receipts no longer depend on /tmp/qwux/* surviving a reboot. The /tmp citations in dated pages remain correct for their date.

2026-09-03 - SET-07 post-publication correction and Wave 5 reliability bound

The 2026-09-02 UI/UX-perfection receipt now carries a visible amendment rather than silently rewriting its original result. The amendment remains bench-only and releaseEligible: false.

  • The original SET-07 closure was wrong. Both the A8 rule and assertion (c) used #qwizz-settings svg.qwizz-icon:first-child:not(:only-child). In a heading such as Difficulty choices, the label is a text node rather than an element sibling; the SVG is therefore :only-child, so the CSS matched nothing and the gate skipped the same broken icons. Before repair, the cache-disabled operator probe checked 77 icon/text pairs and found 23 violations, including a 0px computed margin and coincident right/left edges on that heading. Evidence: /tmp/qwux/icongap.js; /tmp/omp-sshots-15704bf48cf1b420.webp; wp/wp-content/plugins/quizwizz/assets/css/qwizz-admin-settings-core.css:294-303; agent://SliceA:11-25; receipt amendment.
  • Mirror commit 715474f, settings: restore icon and label spacing, repairs direct-text and element-sibling cases while preserving icon-only controls. The widened operator probe moved from 77 checked / 23 violations to 77 / 0; Available experiences and Use site theme both measured 8px, while undo, redo and mobile search remained 36×44px and preview close remained 44×44px with zero horizontal padding. The installed CSS SHA-256 is 92d09a8e7c60784e36e2eb999ab51f74e26bc466f83707602f9ee8593d23f88a. Evidence: agent://SliceA:1-64; agent://SliceE3:183-195.
  • Browser assertion (c), harness SHA-256 be619c00ac67d076b517f8703da578147fbf76d05cd292c18a4fe769165e9ac6, now walks every visible Settings SVG, excludes screen-reader and ≤1px text rectangles, names each {gap,text,host} violation, and requires checked >= 60 plus zero violations. Mutation 15 restored the old selector and made only (c) fail at 76 checked / 22 violations; mutation 16 deleted the spacing rule and made only (c) fail at 76 / 34. Both restored SHA-exact and replayed 76 / 0. The operator sees 77 pairs while the disposable harness administrator sees 76 because only the operator has the otherwise control-less Protected backups card. Evidence: scripts/quizwizz-browser-smoke.js:3088-3148; /tmp/qwux/e3-row15-{red,green}.json; /tmp/qwux/e3-row16-{red,green}.json; agent://SliceE3:1-116.
  • Final post-repair authority is shell TAP 1..94, # assertions=94 failures=0, plus browser chunks 47/47, 9/9, 13/13, 8/8, 7/7 and 7/7. All browser records report complete restoration, empty console/page-error arrays and foreignRowsDuringRun=[]. Residue remains 95 Settings-backup rows at ordered SHA 86100bbc…, with zero disposable users, smoke posts, quiz-99 attempts and portability jobs. Evidence: /tmp/qwux/wave-all-final2.tap:265-268; /tmp/qwux/e3-final-{legacy,player,admin,uiux-ad,uiux-eg,uiux-hj}.json; agent://SliceE3:117-215.
  • Wave 5 assertion 12, portability fixtures leave no jobs files chunks schedules posts or option drift, measured 0 failures in 6 idle runs and 1 in 6 under a concurrent loop over Settings plus page 57; the failure is /tmp/qwux/w5c-4.tap. Immediate readback found zero jobs, the last-error option unset and zero scheduled events. Of the six ANDed sub-conditions, only $residue_cron / wp_next_scheduled() at scripts/quizwizz-probe.sh:1331 is timing-dependent enough to be a plausible cause, but that attribution is unverified because the assertion emits only portability probe failed, not the failed sub-condition. Full gates therefore require an idle bench; diagnosis is tracked in loca/quizwizz #15. Evidence: /tmp/qwux/w5-{1..6}.tap; /tmp/qwux/w5c-{1..6}.tap; scripts/quizwizz-probe.sh:1324-1361; orchestrator read-only observation using sudo -n docker compose --profile cli run --rm wpcli: wp option get qwizz_portability_last_error → empty, SELECT COUNT(*) FROM wp_qwizz_portability_jobs0, and wp cron event list --hook=qw_process_portability_job --format=count0.
  • The open-work ledger now contains 154 ids: 23 shipped, 21 bench-actionable, 50 owner-decidable, 49 terminal-blocked and 11 deferred. The two amendment rows are shipped gate hardening UIUX-GATE-01 and open diagnostic follow-up UIUX-FLAKE-01. Evidence: open-work completion classes and UI and UX follow-ups.
  • Source-only amendment validation on 2026-09-03 passed /home/loca/dev/wikis/build.sh wrdp --check-only: SSOT validation passed, 87 Markdown inputs parsed and 876 check files emitted, ending Check-only completed successfully. No production build or deploy ran. Evidence: command output; receipt E9.

No canonical package was built, signed, published or deployed by this amendment. The orchestrator owns publication.

2026-09-02 - UI/UX-perfection round accepted with explicit waivers

This section is the original acceptance record; its current-authority language, SET-07 closure, 14-row mutation total and 152-row ledger total are superseded by the 2026-09-03 amendment above. The installed bench result remained ACCEPT-WITH-WAIVERS, zero blockers; every patch remained releaseEligible: false, and issue #14 was only the coordinating issue until the orchestrator changed its state. Evidence: /tmp/qwux/evidence-dossier.md:56-63; agent://FinalReviewer-2; agent://FinalAuditor3.

  • six ordered plugin commits moved the clean mirror from d61d98c to 54c54c8: c80cb89 fine-tune, 94827de Craft builder, 3dd0860 admin surfaces, 19d8906 Settings, 220ee53 Settings follow-up, and 54c54c8 review-copy correction. Evidence: /tmp/qwux/evidence-dossier.md:35-42; slice and commit receipt.
  • final shell evidence is 94/94 on idle-bench bytes. The earlier full run’s transient Wave 5 portability-residue failure, isolated 12/12 rerun and authoritative final 94/94 rerun all remain recorded rather than smoothing the first run away. Evidence: /tmp/qwux/wave-all.tap; /tmp/qwux/wave-5-rerun.tap; /tmp/qwux/wave-all-final.tap; shell receipt.
  • browser evidence is six serial bounded selectors: legacy 47/47, player 9/9, admin 13/13, then uiux-perfection separately as QWIZZ_UIUX_STEPS=a-d 8/8, e-g 7/7 and h-j 7/7. Every invocation reported overall pass, complete restoration, empty console/page-error arrays and no foreign Settings-backup rows. Evidence: /tmp/qwux/evidence-dossier.md:47; agent://SliceE2; browser receipt.
  • fourteen mutation rows reproduced the named defect or assertion failure and returned green after exact restoration. Rows 1–3 are cited predecessor evidence; rows 4–14 ran on the final gate extension. Two widened mutants are disclosed: builder markup alone was not load-bearing because state cleared hidden, and a bare <br> was inert in the flex row. Evidence: local://qwizz-mutation-matrix.md; mutation receipt.
  • the measurement pass confirms the intended compression and reachability changes, including Settings toolbar 122/208px→52/52px, builder 1,831px/2 columns→1,222px/4 columns, fine-tune Print bottom 2,825px→874px and resting controls 11→1. Two target numbers remain explicit waivers: first Settings control 505px rather than ≤290px, and the enclosing WordPress Details cell 75px rather than ≤40px while its owned inner content is one line at 26px. Evidence: /tmp/qwux/before.json; /tmp/qwux/after.json; agent://FinalAuditor3; measurement table.
  • independent review found zero blockers. The wrong trivia-export guidance was corrected in 54c54c8; eight grouped P3 judgments remain open as UIUX-REV-01 through UIUX-REV-08, alongside the backup hazard and two metric rows. Evidence: /tmp/qwux/evidence-dossier.md:56-59; agent://FinalReviewer-2; agent://FinalAuditor3; open-work ledger §11.
  • four attributable owner-1 Settings-backup rows were deleted and three displaced rows restored byte-exact from /home/loca/backups/wrdp/20260902T013032Z/db.sql.gz. Final residue is 95 rows at ordered SHA 86100bbc…, Settings semantic SHA 874bb4f7…, with zero disposable users, smoke posts, quiz-99 attempts and portability jobs. Owner 1 still has 11 rows against cap 10, so operator-identity Settings verification is prohibited and tracked as UIUX-BACKUP-01. Evidence: /tmp/qwux/backup-recovery.json; /tmp/qwux/evidence-dossier.md:51-54; recovery receipt.
  • at the original close, the open-work ledger contained 152 ids: 22 shipped, 20 bench-actionable, 50 owner-decidable, 49 terminal-blocked and 11 deferred. TOUR-19’s rendered gap closed without adding an id; the eleven new rows preserved every accepted waiver and review follow-up. The 2026-09-03 amendment above supersedes that census with 154. Evidence: open-work completion classes; UX follow-ups.
  • source-only vault validation passed: /home/loca/dev/wikis/build.sh wrdp --check-only reported SSOT validation passed, wiki-lint passed, 87 Markdown inputs, 876 emitted check files and successful completion. No production wiki build or deploy ran in this evidence session.

No canonical package was built, signed, published or deployed by this evidence round. The release owner applies source changes through the locked pipeline. Evidence: acceptance boundary.

2026-09-01 - Mega-polish S0a–S10: final ACCEPT with waived residuals

Authority for the dated 2026-09-01 close is its final receipt. It remains correct for that date but is superseded as current mirror, browser and residue authority by the 2026-09-02 receipt. ACCEPT with waived residuals — all four review P1s resolved. Bench-only, releaseEligible: false.

  • nine ordered drive commits landed through catalog close d61d98c; commit 2da4b577 then resolved the transient-resume and per-question Trivia authorization P1s in exactly two plugin files. The plugin mirror is clean at 2da4b577.
  • post-review shell evidence is 94/94: TAP 1..94, # assertions=94 failures=0, waves 1–11 (/tmp/s10-post-review-wave-all.tap).
  • browser authority is three serial bounded cache-disabled chunks: 46/46 legacy + 8/8 player + 12/12 admin/Trivia = 60/60 unique, with zero failed assertions, zero console/page errors and restoration complete. Never use one monolithic all.
  • final-harness-byte mutations 2, 10 and 11 each reproduced only the intended red, restored the exact source SHA and replayed green; all six had complete restoration and empty console/page errors (/tmp/s10-final-harness-row{2,10,11}-{red,green}.json).
  • German catalog authority remains catalog commit d61d98c: 1,697 translated, zero fuzzy and zero untranslated, with 11 named-handle plus three hash-named JSON catalogs. Current plugin HEAD is the later 2da4b577.
  • at that close, the open-work ledger contained 141 rows: 22 shipped + 9 bench-actionable + 50 owner-decidable + 49 terminal-blocked + 11 deferred. The original 2026-09-02 census was 152; the post-publication amendment now sets the standing census at 154.
  • operator-approved recovery corrected the earlier false “no backup existed” conclusion. The root backup /home/loca/backups/wrdp/20260901T013013Z supplied ten recoverable pre-drive rows: payload SHAs were verified before any live write, nine leaked harness rows were deleted, ten rows were restored byte-exact and the legitimate later survivor was preserved. The accepted baseline is 95 rows, ordered-JSON SHA 86100bbc…, identity SHA 270478b9… (/tmp/s10-post-recovery-baseline.json). Intermediate post-backup displaced rows remain unrecoverable.
  • final harness bytes SHA-256 deb5266f… resolve blocker 3: exact accepted-head predecessor refusal, sealed-response attribution, follow-up equality and guarded restore are at scripts/quizwizz-browser-smoke.js:887-907,991-1015,1094-1140,1180-1220. One adversarial refusal left autostart=false / auto_advance_ms=0; both were repaired to documented values. Endpoint response atomicity is a pre-existing product limitation, not introduced or fixed by the drive, and remains open as #13 (includes/Rest/SettingsController.php:101-107,148-157).

Historical pickup recorded at that close:

./scripts/qwgit.sh status --short             # expect no output
./scripts/qwgit.sh log --oneline -1           # expect 2da4b577 plugin review fixes
./scripts/quizwizz-probe.sh --wave all        # expect 1..94; assertions=94 failures=0
/home/loca/dev/wikis/build.sh wrdp --check-only

The last command validates source only. It does not build or deploy the production wiki.

2026-08-31 - Completion drive reconciled: final gates, pushed mirror, one decision sheet

Quickstart - where the drive finished and what still moves:

  • accepted bench state is recorded on the corpus-repair execution record: shell 1..93, assertions=93 failures=0 across waves 1-11; authenticated browser smoke 37/37 with overallPass=true, settings and editor restoration green, zero console errors and zero page errors. The final shell observation followed accepted block-editor commit 33989f9 and catalog commit f79feb6.
  • mirror main is pushed through f79feb6; ./scripts/qwgit.sh status -sb reports ## main...origin/main. Bench work is still releaseEligible: false: pushed mirror state is not a canonical release.
  • the drive’s seven issue-spine rows end five closed and two open. Closed: #1 fixed, #3 refuted/not reproduced, #4 fixed, #7 fixed, #8 fixed. Open: #2 deferred because the corpus replacement is inbound; #5 owner-decidable because signed-in provider order is intentionality, not an observable defect, and this bench has no OpenRouter key. Issue #6 was already closed by the 2026-08-30 choice-card repair.
  • FL-001 was never fixed: source inspection and the browser reproduction refuted its request-path premise, the proposed guard changed no observable behaviour, and no FL-001 code was installed.
  • every question-content, taxonomy-content and census row — including 3.2.3, TOUR-21 and TOUR-22 — is deferred — corpus replacement inbound. The current corpus was not remeasured into a claim that would be stale on arrival.
  • all design and owner choices remain on the single batched sheet in 2026-08-31 corpus triage. TOUR-03, TOUR-09, TOUR-15’s canonical name and TOUR-24a remain decisions; only the literal Wizzard → provisional QuizWizz repair shipped on the bench.
  • both vault gates passed with 79 files parsed, 840 emitted, exit 0 — the W5 one and the end-of-W6 one. The first approved production build then ran, swapped current to dist-1788151241.661169809-3726447 with wrdp/current/index.html readable at -rw-r--r--, and returned HTTP 200 on all 72 audits/qwizz/ routes with every named needle present — yet it failed its live no-leak assertion, because /audits/qwizz/masterplan served one genuine unresolved table-cell wikilink from its W9-07 row. current was rolled back to the pre-drive dist-1788129513.061920758-1839651 per plan and the W9-07 row was repaired in source as a Markdown link. That attempt, its dist and its repair cause stay on the record as history.
  • the owner then recorded a fresh approval for exactly one second production build, and that build has run and succeeded. Its pre-build --check-only and the production run each reported 79 Markdown inputs → 840 emitted files, and current now names dist-1788153309.461633591-3913543 with wrdp/current/index.html at mode -rw-r--r--. The live sweep enumerated 72 unique Markdown routes from the final audits/qwizz/ vault and all 72 returned HTTP 200; all ten named needle routes passed; the five table-cell pages each returned HTTP 200 with a literal [[ count of 0; and zero unresolved wikilink syntax was served outside code, pre, script and style — the changelog and the corpus-repair record still carry deliberate literal [[ examples inside code, which is exactly why the assertion is scoped that way. logs/debug.log stayed at 7042962 bytes across the publication. No third production build ran or is claimed: these post-swap receipt edits — this entry, the now public-wiki row, the masterplan traceability bullet and the dated repair record’s final receipt — are source-only and were never republished, while every behaviour and route they record was observed live on that final current dist.

Compact pickup:

./scripts/qwgit.sh status -sb                 # expect: ## main...origin/main
./scripts/quizwizz-probe.sh --wave all        # expect: 1..93; assertions=93 failures=0
cd /home/loca/dev/wikis
umask 022 && ./build.sh wrdp --check-only     # documentation gate only; never a production publish

Status and vocabulary now meet in the 126-row open-work ledger, the program masterplan, the probe harness and shared language. Everything remains releaseEligible: false.

2026-08-31 - Fix-loop era opens: distilled skills, seeded tickets, first gated fix, wiki live

Quickstart - what changed and where to pick up:

  • two bench-local skills now govern QuizWizz work: qwizz-shared-language (vocabulary, decision records, handoffs) and qwizz-fix-loop (five gated phases: diagnose, specify, implement, verify, review+handoff). Distilled from the MIT-licensed mattpocock/skills set rather than installed verbatim; the why lives in the distillation decision.
  • canonical vocabulary has a page: the shared language seeds eight load-bearing terms (probe wave, stage-and-install, releaseEligible: false, plugin-vs-schema version, browser-authoritative, matched A/B pair, exposure settings, craft). Use its terms; avoid its listed synonyms.
  • the issue tracker is live: issues 1-8 opened in loca/quizwizz on git.omp.loca.zone from the open ledger rows (sources 3.2.1, 3.2.3, FL-001..003, 3.2.7, TOUR-01/02). A dedicated write:issue token sits at /home/loca/gitea/qw-issue-token.txt; the push token cannot touch issues. Remainder queue starts at 3.2.5.
  • first fix went through all five gates: issue #6 closed by commit cf07530 (80-insertion CSS-only, choice-card base rules plus selected/hover/focus/forced-colors states). Wave 6 1..14, standing 1..76, browser smoke 30/30, matched normal and forced-colors mutation pairs, empty debug window. Record: the choice-card prepend fix; ledger row 3.2.7 closed in open work.
  • wiki rebuilt and live-verified: 77 pages, seven touched routes asserted 200 with zero literal wikilinks; the previously unreachable corpus x-ray and question SSOT is now navigable from the audits index.

Command cheat sheet for the next fix:

TOKEN=$(cat /home/loca/gitea/qw-issue-token.txt)                     # issue API auth
curl -s -H "Authorization: token $TOKEN" \
  http://127.0.0.1:51400/api/v1/repos/loca/quizwizz/issues           # pick an open issue
./scripts/quizwizz-probe.sh --wave <n>                               # narrowest red first
sudo -n install -o www-data -g www-data -m 0644 /tmp/qwfix/<f> wp/wp-content/plugins/quizwizz/<f>
sudo docker compose exec wordpress php -l wp-content/plugins/quizwizz/<f>.php
./scripts/quizwizz-probe.sh --wave all                               # gate: 1..93, 0 failures
./scripts/qwgit.sh add <path> && ./scripts/qwgit.sh commit -m "<cause and behavior>" && ./scripts/qwgit.sh push

Everything remains releaseEligible: false; the release owner applies source changes through the locked pipeline.

2026-08-27 - Zero-question draft cleanup, and the figure that was wrong

  • the last open bench-data item from the four clusters is closed: all 15 zero-question qw_quiz draft rows were deleted with wp post delete --force, after a full bench backup at /home/loca/backups/wrdp/20260827T034540Z.
  • the published figure was wrong and is corrected here. The open finding read ~109 zero-question Automatischer Entwurf draft quizzes. Re-measured by grouping qw_quiz on post_status and title against qw_question_count, the bench held 109 drafts in TOTAL, of which exactly 15 carried zero questions, and only 5 of those were titled Automatischer Entwurf - the rest being 4 English Auto Draft, 5 Automatisch gespeicherter Entwurf and 1 named Autocool. The 109 described the whole draft population, never the zero-question subset. The Cluster 2 record had already flagged the two counts as irreconcilable and named the exact query that would settle it; running that query settled it in the census’s favour.
  • deletion was safe rather than assumed safe: before deleting, the 15 ids were checked against wp_qwizz_attempts (0 rows), wp_term_relationships (0), wp_comments (0), post_parent children (0) and wp_postmeta (34 rows, which a force delete removes).
  • verified after: 94 drafts remain and every one holds questions, zero_q is 0 for every post_status, wp_qwizz_attempts still 22, zero orphaned wp_postmeta rows, wp_qwizz_question_index unchanged at 9,069, and AdminStatistics::payload() rebuilt itself to 107 quizzes (13 published, 94 draft) at generated_at age 0s, proving the delete hooks invalidated the mirror.
  • standing gate still 1..76, assertions=76 failures=0. Wave 10 is the interesting case: it discovers its control by taking the newest draft quiz, so the cleanup moved its control from 10989 to a draft that HOLDS questions - and the wave still passes, which confirms the assertion tests unreadability (draft status) rather than emptiness.
  • consequence for the record: MAX(ID) for qw_quiz moved 10989 to 10779. Bench-state figures on pages dated before this cleanup cite the older maximum and remain correct for their dates.

2026-08-27 - Canonical handoff of four bench clusters

  • Clusters 1, 2, 4 and 5 packaged for the release owner as one ordered series: 18 distinct files, four patches, eight digest manifests and 2026-08-27-apply-clusters.sh, a transactional applier that snapshots every already-present file any cluster touches and records every path the series will create, then on any failure restores each snapshot, deletes each run-created file and exits non-zero. Cluster 3 was an audit and changed nothing, which is why the series skips from 2 to 4. Record: the canonical handoff.
  • ordering is enforced by digest rather than by prose: four files are touched by more than one cluster and they produce six ordering links, because QuizEmbed.php (1→2, 2→4) and QuizQueryViewer.php (1→2, 2→5) each appear twice, alongside qwizz-tokens.css (1→5) and DashboardPresenter.php (2→4); each later preimage equals the nearest earlier postimage, so an out-of-order run fails a preimage check instead of producing a wrong tree.
  • proof was executed, not claimed: the live tree was copied, all four patches reverse-applied newest first, the one new file deleted, --check-only matched cluster 1’s five preimages, the full run applied all four clusters with every postimage matching, and all 18 files compared against the live bench at 18/18 byte-identical, zero mismatches.
  • three defects the packaging exposed and fixed: the Cluster 4 patch had been generated against an empty placeholder for the new assets/css/qwizz-empty.css instead of an absent path, so it would have failed on any canonical checkout — regenerated at sha256 0b60aa9f…, superseding 65605c06…, with non-blank line counts unchanged at +210/−72; two set -u bash bugs in the applier itself, the second of which aborted mid-cluster-1 and thereby proved the rollback by restoring every file it had snapshotted; and an overstated rollback guarantee, since the applier’s restore loop only copied and never deleted, so a failure after Cluster 4 created qwizz-empty.css would have left that file behind — the script now records absent paths at snapshot time and deletes run-created files on rollback, proven against an induced mid-series failure.
  • --check-only verifies cluster 1 only, stated as a limitation in the script: clusters 2, 4 and 5 have preimages that are the preceding cluster’s postimages. The handoff builds, lints, tests, versions and signs nothing; everything stays releaseEligible: false.

2026-08-27 - Cluster 5: not-found contract and empty-card token scope

  • the play route’s soft-404 is closed, and it was worse than the Cluster 1 finding said: an unreadable existing quiz served 121,285 bytes of home page under a 404, a nonexistent quiz id answered HTTP 200 with 121,286 bytes and the id of a post that is not a quiz answered HTTP 200 with 121,284 bytes. All three now return a real 404 at 55,655 bytes — 65,630 bytes and 54% off every not-found request. QuizQueryViewer.php routes them through one emit_404() (:64-82, called at :21 and :30) that clears the stale loop out of $wp_query, sets 404, includes the theme’s own template and exits. Record: the not-found and token-scope repair.
  • the readable quiz and the readable-but-empty quiz are unchanged: 200 with the player, and 200 with the unavailable card, which is the Cluster 2 contract.
  • the shared unavailable card finally paints on the standalone route: .qwizz-library__empty became its own token root in assets/css/qwizz-tokens.css at :153 (base), :238 (@supports color-mix) and :376 (@media forced-colors: active). All three layers were required because a custom property declared on an element outranks one inherited from an ancestor, so a base-only addition would have flipped the already-correct library card onto flat fallbacks. Every shared property measured byte-identical on both surfaces afterwards, which is the regression proof.
  • decided on measurement and closed: the 37ms dashboard subject/language aggregate stays. No index is missing (EXPLAIN already drives from the Cluster 4 is_valid_lang key with Using index), STRAIGHT_JOIN buys 4.7ms but permanently pins a join order whose winning drive side depends on this bench’s 9,315-to-9,069 row ratio, and a rollup table would add a sixteenth table plus a sync, drift, teardown and migration surface. Verified against the query log rather than the clock: the matrix query is reached on exactly one of payload()’s three exits, so the remaining synchronous interactive path is the first admin view after a content mutation at 72.9ms / 8 queries.
  • wave 10 adds 4 assertions, TAP 73-76; the standing gate moved 1..721..76, assertions=76 failures=0. Mutation-proved, and the reverted draft reproduced the Cluster 1 measurement of 121,285 bytes exactly. Patch 2026-08-27-cluster5-source.patch, sha256 34e2829f…, +61/−8 over 2 files. Bench state unchanged: wp_qwizz_attempts 22, MAX(ID) qw_quiz 10989 and qw_question 10993.

2026-08-27 - Cluster 4: performance remediation

  • four code changes plus two indexes implemented the Cluster 3 audit, all measured as quiescent medians of three: SubjectTaxonomy::admin_tree() 56.2ms/48q → 5.6ms/2q, settings page assembly 218.3ms/55q → 112.4ms/3q, QuizController::attempt_payload() 44.5ms/33q → 18.6ms/5q, cold AdminStatistics::payload() on TTL lapse 134.1ms/20q → 2.23ms/2q, warm 0.4ms → 0.23ms, and catalog CSS on a player surface 6,077 bytes → 917. Record: the performance remediation.
  • two millisecond targets were missed and the reason is a flaw in the audit’s projection, not in the implementation: capacity plus coverage landed at 42.8ms/2q against ≤35ms/2q, and whole build() at 78.2ms/10q against ≤65ms, because one irreducible aggregate over a 9,315-row join table has a ~37ms floor post-index and the targets treated two isolated builder medians as independently reducible. What the change did buy: coverage 20.5ms/1q → 0.4ms/0q, net −17.2ms and −2 queries on the pair.
  • stale-while-refresh cannot live in the statistics transient, because invalidate() deletes it on 16 mutation hooks; the mirror is a separate non-autoloaded 48,425-byte option that invalidate() also deletes. Proven live: after invalidate() the next payload() rebuilt synchronously in 94.3ms / 8q with generated_at age 0s.
  • schema 1.6.71.6.8 through the plugin’s own Installer::maybe_upgrade(), never a hand-written ALTER TABLE: is_valid_lang (is_valid, lang) and created_by_created_backup (created_by, created_at, backup_id) both landed, type ALL / key NULL / Using filesort are gone from the backups list query, and the index-only delta on whole build() is 92.3 → 78.2ms.
  • wave 9 adds 17 assertions, TAP 56-72; the standing gate moved 1..551..72, assertions=72 failures=0. Wave 8’s assertion 54 was re-pinned from catalog-css=1 to catalog-css=0 empty-css=1 and the full gate failed exactly there once before the reconciliation. Each subsystem was reverted in turn and the reverted figures reproduced the Cluster 3 baseline at 48, 12 and 33 queries; three assertions cannot be made to fail by reverting a file and are published as coverage gaps, the same class as the wave 8 CTA belt. The three output digests matched at three separate points.
  • corrections to the record: DashboardPresenter.php:320’s justification bounded to five rows on indexed meta keys was false and now states the measured truth, that LIMIT 5 bounds returned rows while EXPLAIN starts at all 122 qw_question_count meta rows with Using temporary; Using filesort; assets/css/qwizz-empty.css is 917 bytes, not the projected 867, because the mandated comment line adds 50; the settings category section renders no pool numbers beside its checkboxes, only 24 integers in the localized payload.
  • new finding, recorded open rather than folded into performance work and closed the same day by Cluster 5: the standalone unavailable card had no border, background or icon tile, and a matched A/B against pristine bytes proved it never had. Patch 2026-08-27-cluster4-source.patch, sha256 0b60aa9f… after the handoff regeneration, +210/−72 over 14 files. wp_qwizz_attempts still 22.

2026-08-26 - Cluster 3: performance audit, nothing changed

  • the audit was delivered as a table and has no dated page of its own; it changed no file, which is why the canonical series skips from Cluster 2 to Cluster 4. Its baselines are published as the before column of the Cluster 4 recordadmin_tree() 56.2ms/48q, attempt_payload() 44.5ms/33q, cold payload() 134.1ms/20q, settings page assembly 218.3ms/55q, 6,077 bytes of catalog CSS on every player surface.
  • the wave 9 mutation reverts reproduced those baselines exactly at 48, 12 and 33 queries, which independently confirms the audit measured the code Cluster 4 then changed.
  • one audit claim did not survive: its spot-check reporting that two figures on the settings memoization page no longer reproduced was a pair of contended single runs, superseded by quiescent 2026-08-27 medians of three. Its finding against the recent_quizzes() phpcs:ignore justification did survive and was corrected in Cluster 4.

2026-08-26 - Cluster 2: playable-quiz contract

  • the wp-admin Dashboard no longer offers Play on a quiz with no questions: a qw_question_count > 0 clause was ANDed beside the preserved ephemeral group, and the census makes it safe rather than lossy — every qw_quiz row carries the meta key, so the clause removes exactly the 15 zero-question rows while the 94 drafts that hold questions stay listable. Browser, cache disabled: five Play links to quizzes 77, 10779, 10728, 10627 and 10526 with zero occurrences of Automatischer Entwurf, where before the fix all five pointed at zero-question drafts. Record: the playable quiz repair.
  • the play route substitutes QuizEmbed::unavailable() when the render is empty. /?qwizz_play=10989 had served HTTP 200 with a correct title and a white page holding nothing but <main class="qwizz-single-quiz" id="qwizz-content"></main>; it now serves the shared Quiz unavailable card inside that wrapper, measured display: grid, padding: 24px, border-radius: 14px, text-align: center. That the card’s border and icon tile were still absent was found later, by Cluster 4, and closed by Cluster 5.
  • the $rendered precompute position is load-bearing rather than cosmetic: it runs LibraryShortcode::enqueue_catalog() before wp_head(), so the card lands styled; the reverting mutation proved it by reporting catalog-css=0.
  • wave 8 adds 4 assertions, TAP 52-55; the standing gate moved 1..511..55, assertions=55 failures=0. Mutation-proved against live code: reverting DashboardPresenter.php gave rows=5 playable=0 dead-play=5, reverting QuizQueryViewer.php gave card=0 unavailable=0 wrapped=0 catalog-css=0.
  • two findings recorded rather than smoothed: assertion 52 was itself wrong while the fix was right — it demanded with-play=rows, passed under --wave 8 alone and failed under --wave all at with-play=4 because an earlier wave’s access-gated fixture correctly gets no CTA — and the $count > 0 CTA belt is not independently pinned, since with the query clause in place that branch is unreachable.
  • patch 2026-08-26-cluster2-source.patch, 5257 bytes, sha256 3d6cf254…, +27/−11 over 3 files; its preimage digests for the two shared files equal the Cluster 1 postimage digests, so the apply order is a property of the artifacts.

2026-08-26 - Cluster 1: play surface repair

  • the play route opens question 1 with no second gesture, across all three Play entry points exercised as real guest gestures: data-autostart """1", intro Start quiznull. Record: the play surface repair.
  • a non-site palette now paints the whole standalone surface: body background rgb(255,255,255)rgb(23,24,29) with body.dataset.qwizzTheme === 'dark', .qwizz-player__card background → rgba(0,0,0,0) and radius 18px0px, and a full-DOM sweep for white-painting elements between card and viewport edge returned [] on both surfaces at both viewports.
  • the route is a correct singular document: <title> count 0 → 1 reading Geografie-Weltreise – QuizWizz, and the body class moved off home … page-id-2 onto single single-qw_quiz postid-99.
  • 5 bench-local files. Guest verification ran in a separate incognito context at 1600×1000 and 375×812: no admin bar, no horizontal overflow, an empty REST nonce confirming the true guest path, and elementFromPoint(2, viewportHeight-3) resolving to MAIN.qwizz-single-quiz. Access control re-checked because the craft redirect carries a token: private craft quiz 11081 anonymous and cookieless returns HTTP 404.
  • wave 7 adds 5 assertions, TAP 47-51; the standing gate moved 1..461..51, assertions=51 failures=0. Mutation-proved twice: textually mutated copies each failed exactly their own assertion, and installing the pristine pre-fix bytes gave --wave 7 assertions=5 failures=4 with assertion 48 correctly staying ok, because the passive default was never part of the fix. logs/debug.log 38536 → 38544, all 8 lines core Automatic updates cron blocks.
  • patch 2026-08-26-cluster1-source.patch, 7302 bytes, sha256 644de6e5…, +50/−8; its postimage sidecar is superseded for the two files Cluster 2 touched again, so the chain is what verifies, not the sidecar alone.
  • NOT MEASURED: no pre-fix screenshot exists. The before state is textual and computed-style evidence plus the preimage digest record, and nothing claims a pixel comparison.

2026-08-25 - Settings memoization performance fix

  • SettingsStore::get() ran a full schema deep-merge plus sanitize on every call with no memoization, at 6.51ms per call, so every translated string paid for it. Memoized per request per blog across three files and measured as a matched A/B in one sitting against sha256-verified pristine bytes: __( 'Quiz', 'quizwizz' ) ×1000 13,373.63ms → 2.67ms, get() ×1000 6,513.27ms → 0.16ms, init 1919.9ms → 51.0ms, total wp-load 3811.2ms → 359.9ms, and TTFB best-of-3 / 7.645s → 0.362s, craft 7.625s → 0.355s, library fixture 4.652s → 0.202s. Record: the settings memoization fix.
  • the trap is worth keeping: the first attempt invalidated on added_option_qw_exposure_settings and its siblings, names WordPress core never fires, so after an update the stored iface_lang was de while get() still returned en — a silently stale cache that passed lint, activation and all 46 probe assertions. Corrected to the generic added_option/updated_option/deleted_option actions with an option-name guard plus switch_blog.
  • gate after the A/B cycle: 1..46, assertions=46 failures=0, with no harness line added to logs/debug.log. releaseEligible: false, so the shipped plugin still carries the cost.
  • re-verified 2026-08-27 after a contended Cluster 3 spot-check questioned two of the figures: all three reproduce as quiescent medians of three at 2.612114ms, 0.178099ms and 367.375ms/4q, and the spot-check is what is superseded.

2026-08-25 - UI corpus recaptured after the TNDM remediation

  • 294 shots on disk over 58 routes against a 346-entry shotlist, with 52 blocked entries each carrying a file:line-grade cause; expected_total == on_disk + blocked holds at 0 missing and 0 orphans, corpus size 22.0 MB. It supersedes the 2026-08-20 gallery for every route it covers, because that gallery photographed a UI that no longer exists. Record: the 2026-08-25 UI corpus.
  • the gate that paid for itself: a sha256 sweep over raw bytes found 37 duplicate groups on the first pass, every one a file claiming a state it did not hold, because the data-driven driver knew one URL per route and captured extra-state shots at the route’s base URL. Each such shot now pins its own URL; 18 groups remain, each documented as legitimately identical.
  • seven independent read-only reviewers removed 12 shots and renamed 3, including four g16 page shots that photographed a WordPress 404 captured at 07:02 against a fixture only repaired at 07:05, an inverted sound-toggle pair, and a mislabelled language-pills crop deleted rather than published.
  • the recapture confirmed the remediation from pixels plus source: the fine-tune bar on one row with Undo/Redo at 88×46 and 86×46, a05-d-p07-no-rail as a 1100×3374 crop of a rail-free quiz editor, the mobile statistics rail wrapped 2+2+1 inside a 368px box, all six shortcodes advertised, the 2×2 desktop answer grid with one column at 390px, one title and one sign-in card.
  • 25 new findings raised and none fixed, from the question list rendering 1497px wide inside a 1280px viewport with the source badge overprinting the Updated cell on 19 of 20 rows, to /?qwizz_play=999999 serving the ordinary front page instead of any denial — the finding Cluster 5 later closed.
  • residue: 0 fixture ids and 0 fixture users remaining, admin#1 the only administrator, qw_exposure_settings md5 byte-identical to the pre-tour baseline after four mutation waves, all 218 settings-backup rows deleted; 56 wp_qwizz_attempts rows kept deliberately and disclosed.

2026-08-25 - TNDM tandem UI review harvested and fixed

  • 36 verbatim operator findings from tandem session 46937fb4893da860: 33 fixed on the bench, 1 verified-correct with no change needed, 1 content-data, 1 done on bench and recorded in creds.md, 0 blocked and 0 deferred to the release pipeline. 33 plugin files across two passes, none under vendor/, build/ or languages/. Record: the TNDM UI review.
  • the dominant root cause was one token collapse: Twenty Twenty-Five defines no --wp--preset--color--primary and no --wp--style--color--link, so --qw-v and --qw-ink resolve to currentColor, and any element using them as a background while setting its own colour renders invisible. Filled states moved to the --qw-action-bg/--qw-action-ink pair in the leaf sheets, never in qwizz-tokens.css; the builder toast now measures rgb(255,255,255) on rgb(17,17,17).
  • the other clusters: two builder <select>s and eight full-width switch rows became Difficulty-style tile rows with every submitted field name preserved and zero selects left; nested player chrome flattened, the width caps and the duplicated title removed; a click-to-check path added where none existed, the only trigger having been the form submit event; admin controls with no base CSS given real base blocks, measured display:inline with 2 overlapping client rects before and display:grid with 1 rect after; PDF worksheet answers laid out 2 per row, verified in the generated PDF opened in a viewer.
  • defaults applied by operator ruling: player.auto_advance_ms 2500 → 0 and presentation.layout_cols 2 → 1, both re-read from qw_exposure_settings; quiz 77 retitled General Knowledge Compact with its slug intact.
  • gates: php -l clean on all 11 changed PHP files, node --check clean on all 4 changed JS files, ./scripts/quizwizz-probe.sh --wave all 1..46, assertions=46 failures=0, identical to the pre-fix baseline, and logs/debug.log 38522 lines before and after. 21 verification screenshots pinned by sha256 in evidence/2026-08-25-tndm-verify/digests.json.
  • disclosed: to browser-verify the fine-tune print studio at all, matrix.editor.def had to be flipped to true for the duration of the check and was restored and re-read afterwards. The step is implemented and now good, but unreachable as configured — an open ruling, not a fix.

2026-08-20 - UI and UX feedback tour captured

  • 315 shots on disk against a 320-entry shotlist over 65 routes and four personas, verdicts 250 clean and 65 findings with 0 unresolved retakes and 0 orphans; the 5 blocked shots are kept in the shotlist with a cause each rather than silently dropped. Superseded for pixels on 2026-08-25 and retained for the feedback dialogue it records. Record: the 2026-08-20 feedback tour.
  • two owner-facing feature clusters proved dead at runtime during capture: wp_nonce_field() is called with $echo = false inside a bare <?php ?> tag, so the nonce markup is computed and thrown away. Observed live, snapshot Delete lands on WordPress’ expired-link screen and a scripted question-pack POST returns HTTP 403, while the correct pattern is used in the same file roughly 863 lines above.
  • a third, cosmetic-but-total defect: the builder toast is announced via role="status" but never visible, its background and colour both computing to color(srgb 0.972 0.972 0.972) because --qw-ink resolves to currentColor and --qw-card to a color-mix() against it.
  • no plugin source was modified: the tour’s bench patch surface is evidence and documentation only. The 36 notes it harvested were triaged and fixed on 2026-08-25.

2026-08-19 - Homerun ledger close-out

  • German catalog (task 2.1.1) closed at source parity using WP-CLI i18n tooling because GNU gettext was absent on both host and container: POT=PO 1650 total entries / 1648 real msgids by the worker receipt convention, missing_from_catalog=0, obsolete_in_catalog=0, fuzzy 0, obsolete marks 0, empty msgstr 0, placeholder mismatches 0 over 1650 entries; 10 mistranslations corrected; MO plus all eleven handle-named JSON catalogs rebuilt and installed atomically as www-data 0644; forced-DE rendered Next question -> Nächste Frage while iface_lang remained en before and after.
  • Bet B001 re-proof closed: quiz 413 (https://wrdp.loca.zone/?qw_quiz=world-quiz-english) played end-to-end as a fresh cookie-less guest in spawned Chromium; finished result 13 / 58 (22%), 58 .qwizz-player__review-item nodes (13 correct / 45 wrong), 0 console errors, 115 clicks, screenshot 03 EVIDENCE/2026-08-19-quiz413-browser-playthrough.png; receipts appended to play and print answers.
  • UX-ANS-01 measured but remains open: wp eval-file /tmp/qw-forced-matrix.php showed key.st=forced plus per-quiz qw_include_answers='0' gives sheet_allowed=false and REST payload presentation.include_answers=false, but PresentationDocument::pdf_args() still returns include_answers=true; source formula locations recorded at Rest/QuizController.php:174-177,226,243, ExposureSettings.php:350-353,581-582, Pdf/PdfGenerator.php:225.
  • Answers split UI verified live with no further code change in this ledger pass: quiz edit screen 413 renders fieldset.qwizz-answers-controls with checked/disabled #qw-answer-review titled Site policy forces the answer key, independent unchecked/enabled #qw-answer-sheet, and hidden qw_answer_review_present=1; screenshots 03 EVIDENCE/2026-08-19-answers-controls-metabox.png and 03 EVIDENCE/2026-08-19-settings-segments.png.
  • Segmented-control complaint retracted in place: /wp-admin/admin.php?page=qw-settings (real slug; quizwizz-settings returns 403 via AdminMenu.php:47-48) renders all 12 .qwizz-segment controls styled; container computed #fff, 0.625px solid rgb(195,196,199), radius 9px; pressed aria-pressed=true computes rgb(246,247,247) / rgb(33,69,230) versus unpressed transparent / rgb(100,105,112).
  • Question-corpus audit refreshed: 679 published questions / 1 auto-draft / 0 draft, index 679, drift 0, 908 question-subject rows, language split 508 en / 57 de / 57 es / 57 fr, 456 subject terms with 18 zero-pool, difficulty 276 easy / 240 normal / 163 hard / 0 no-term, 0 validator violations (40 empty explanations), 1 duplicate group (357 == 1915), sufficiency 2 playable specific default-English progressive subjects plus synthetic any, 197 non-empty-but-insufficient and 257 zero-capacity pools, local corpus 5,701 distinct stems, 360 bench overlaps, grand union 6,019.
  • Masterplan diet and lint gate verified: masterplan.md is 84 lines, narrative record 257 lines, ~/dev/wikis/build.sh:55-58 prints Running wiki-lint for wrdp... and exits 1 on /tmp/vlint-bad; 11 aliased table wikilinks converted to Markdown links.
  • Probe wave after catalog install passed: 1..46, assertions=46 failures=0.

2026-08-19 - Wiki SSOT audit remediation

  • retracted the German full-parity claim at all eight sites where it was made (masterplan ×4, 2026-07-31-w8-ssot-capability-pass ×2, can-do ×2) with the measured method: a POT regenerated from installed source via wp i18n make-pot is missing 153 msgids from the shipped catalog and 76 are obsolete (comm -23/comm -13; PO holds 1568 msgids); the fresh run supersedes the 152/75 counts from 2026-08-18

  • corrected now.md: 59 vault pages (was 58), debug log 38,433 lines (was 38,429), fresh drift counts, and a new row stating wiki validation is not gated because no wiki-ia.json exists

  • added a Programme codenames glossary and a five-token status vocabulary (done · verified · open · blocked(<what>) · retracted) to orientation; normalised every status/state ledger cell on tasklist, masterplan, backlog, frontier, can-do and 2026-08-17-launch-readiness to it, preserving explanatory prose as token — sentence; the ritual phrase bench-verified with release-input remainder survives only as quoted history

  • introduced an archive layer without moving files: archive: true frontmatter on 26 historical pages and a restructured audits/qwizz/index with exactly Current and Archive sections; the three 2026-08-17-* contract pages stay current

  • added scripts/wiki-lint.py (wikilink resolution, frontmatter, single H1, archive flag, status vocabulary, retired-phrase rules; exit 1 on violation) and drove it to zero

  • unpinned the wiki press: build.sh now resolves python3.11 || python3 at all eight former literal sites, verified with /tmp/pyshim renamed away for both wrdp and stmx; decided wrdp deliberately ships no wiki-ia.json (recorded in operations), closing tasks 1.3.1, 1.3.2 and 1.4.5

  • probe harness re-run before edits: 1..46, assertions=46 failures=0

  • masterplan diet (task 1.2.3): audits/qwizz/masterplan.md 307 → 84 lines; all narrative relocated verbatim to the new archived narrative record (dated sections, 2026-07-31 plan prose, W7 evidence, the 2026-07-30 delivery list with both retraction blockquotes, runtime/release-input tables, architecture/operations/privacy notes, references, 60 historical ledger rows); the slim page keeps header/authority, ordered waves, verification contract, retained-defects frontier, status vocabulary and the nine blocked(release inputs) rows

  • all five inbound masterplan# anchors repointed to the narrative page (2026-07-30-canonical-port-packet ×2, 2026-07-30-release-readiness, 2026-08-16-w10-canonical-handoff, backlog); grep -rno "masterplan#" now returns nothing

  • lint gate (task 1.3.3): ~/dev/wikis/build.sh:55-58 runs wiki-lint.py over q5vault for wrdp after SSOT validation and before Quartz; sabotage page with an unresolved wikilink made build.sh wrdp --check-only exit 1 at the gate, and the clean run emitted 390 files from 60 inputs

  • quiz 413 played end-to-end in a browser as an anonymous guest (58/58 answered): result 13 / 58 (22%), .qwizz-player__review-item count 58, 0 console errors, screenshot 2026-08-19-quiz-413-playthrough-review.webp; closure recorded on play and print answers

  • German catalog regenerated to source parity: fresh POT (1644 msgids) merged into quizwizz-de_DE.po (1567 → 1644 msgids), 153 new strings translated in informal Du with mechanically verified placeholder parity (1666 pairs, 0 mismatches), 76 obsolete entries pruned, MO rebuilt (entries=1644) and all eleven handle-named script JSON catalogs regenerated and cross-checked against wp i18n make-json; installed atomically as www-data 0644. Drift after install missing_from_catalog=0 obsolete_in_catalog=0; forced-DE prints Nächste Frage. GNU gettext is absent on the host and in wordpress:cli, so WP-CLI’s i18n update-po / make-mo / make-json did the merge, prune and compile.

  • catalog topped up after the answers-split quiz-edit controls installed: POT 1644 → 1650 msgids, six new strings translated in informal Du, parity re-checked (1672 pairs, 0 mismatches), reinstalled www-data 0644; drift stays missing_from_catalog=0 obsolete_in_catalog=0 and forced-DE renders Lösungsblatt im PDF.

  • answers-split UI: native quiz metabox and builder now expose independent Answer review for players / Answer sheet in PDF controls writing qw_experience.include_answers and qw_include_answers; Forced site policy disables the player-review control in place. Scratch-quiz eval: include_answers=true, answer_sheet=false → experience 1 / sheet '0'. Browser proof on draft 1657 (round-trip) and quiz 413 replay (58 review items, 0 console errors). Probe after install 1..46 / 46 / 0. Assumed instant\|end\|never reveal enum retracted.

  • question-corpus audit: live bench 679 published / index 679 / 0 QuestionValidator violations / 1 exact duplicate (357+1915 Mona Lisa) / 40 empty explanations; local union 1,425 fingerprints, 324 shared with the bench; 0 subjects meet en≥10 + 3/3/3, 3 meet en≥10 + 1/1/1. Page: 2026-08-19 question-corpus audit.

  • local TTS: speak_as queued then silent because pi.on("turn_start") called stopAll() which SIGKILLed afplay and dropped the queue; voice.ts now pins speak_as clips so they survive the next turn. Direct xAI synth (eve, 127 KB) already played via afplay.

2026-08-18 - Subject cards gate on sufficiency instead of existence

  • added SubjectTaxonomy::can_satisfy(): it resolves a subject the way a real query would, clones the request, and asks the existing QuestionSelector::capacity(); no new capacity mathematics were written
  • SubjectTaxonomy::builder_cards() takes an optional request; the three term-count gates and the Surprise me card now also require sufficiency, and a null request leaves operator callers untouched
  • includes/Frontend/Shortcodes/CraftShortcode.php resolves language, difficulty, question format and count before building cards, then passes that request; an unavailable dynamic mode degrades to the previous behaviour instead of erroring
  • measured effect on the bench: guest cards 11 -> 3 (any, general-knowledge, geography); the rendered shortcode no longer contains animals, which holds 16 published questions but yields a progressive capacity of 2
  • admin_tree() unchanged: operators still see every subject with its state, including zero-pool subjects
  • new Wave 6 PHP assertion 14 provisions itself from the smallest non-empty pool, so it survives content drift
  • verification: php -l clean in-container; ./scripts/quizwizz-probe.sh --wave all = 1..46, assertions=46 failures=0, Wave 6 PHP assertions=17 failures=0; debug log unchanged at 38,433 lines
  • published subject sufficiency census; no version bump, no fixture retune

2026-08-18 - Wiki authentication removed at owner request

  • removed HTTP basic authentication from the wiki host and reloaded the proxy; anonymous cache-busted requests to root, now, tasklist and the play-and-print decision page each return 200
  • the exposure closed on 2026-08-18 is open again: setup publishes the host path, loopback app port, container network name and destructive reset command; operations publishes the host path and loopback port; plugin-testing is clean
  • the owner then accepted that exposure: the audience is two people, so the operator detail on setup and operations is not treated as a leak and basic auth is not returning; tasks 1.4.2 and 1.4.3 are historical and 1.4.6 is closed as accepted
  • recorded a someday idea as task 1.4.7: use the existing auth.loca.zone portal (Authelia) as one login for both the WordPress administrator session and the wiki, instead of a per-site password; unscheduled and unmeasured
  • the ACME challenge location keeps serving unauthenticated as before; no vault content changed in this step

2026-08-18 - Player reveal decoupled from the print key

  • stopped reading qw_include_answers when deciding player reveal (includes/QuizService.php, includes/Rest/QuizController.php); print still owns that meta
  • quiz 413 (World Quiz — English) finish now returns review length 58 at 13/58; quiz 1284 PDF HTML still contains the answer-key block
  • Wave 6 resume assertion now requires the progress keys without forbidding feedback fields, because catalog quizzes can teach again
  • verification: php -l clean in-container; ./scripts/quizwizz-probe.sh --wave all = 1..46, assertions=46 failures=0; debug log unchanged at 38,429 lines
  • no fixture retune, no craft change, no theme fork, no version bump

2026-08-18 - Import blocker fix, English defaults, corpus import, forward strategies

  • recorded the owner decision on player reveal vs PDF answer sheet: split the mechanism, keep one default Answers switch, echo the owner wording on play and print answers; measured that 8 of 13 published quizzes muted player review via qw_include_answers
  • fixed the question-pack import blocker at its root: includes/QuestionService.php persist() now resolves each requested subject as slug, then numeric term id, then exact name, and stores the term canonical slug; a pack naming chess no longer dies against the stored slug games-chess with the generic qw_question_store error
  • acceptance matrix on the bench: canonical slug, term name, bare slug and numeric id all store games-chess in both post terms and the question-subjects index; an unknown subject now fails early with a named error instead of a rollback
  • verification: php -l clean in-container, ./scripts/quizwizz-probe.sh --wave all = 1..46, assertions=46 failures=0, logs/debug.log steady at 38,425 lines; rollback copy retained at /tmp/qwfix/QuestionService.php.bak
  • imported five English question packs built from the curated gold corpus: published questions 269 to 679, question index 679, 508 rows lang=en, 456 qw_subject terms, draft quizzes 1556, 1657, 1758, 1859 and 1960
  • set bench defaults to English: qw_exposure_settings.iface_lang = en and langs = {en:true, de:false, fr:false, es:false}, verified after a hard reload
  • measured catalog drift against installed source: shipped quizwizz.pot and quizwizz-de_DE.po both hold 1568 msgids while a POT regenerated from source holds 1645, so 152 source strings are missing from the catalog and 75 msgids are obsolete; the earlier full-parity claim compared PO against POT, never POT against source
  • published two forward-strategy pages: admin information architecture strategy and question corpus strategy
  • corrected earlier claims that had been derived from the archived zip rather than the deployed build: the archive does not match the bench (live qwizz-admin-settings.js is 66,288 bytes against 47,344), a default PDF theme does exist (theme_default = cyber), all 140 settings controls carry accessible names, and the all-sections-visible settings page is intentional scroll-spy design
  • bench note: /home/loca/dev/wikis/build.sh hardcodes python3.11, which is absent on this host (now python3.13); this publication ran with a temporary PATH shim at /tmp/pyshim/python3.11

2026-08-17 — Option F evidence and launch no-go documented

  • archived Option F verification in evidence/2026-08-17-option-f/verify.json with operational health, restore-drill, browser, shell-probe, and wiki-check evidence while keeping the host in bench-only mode
  • added the Option F status pages for operators: launch readiness, owner-decision intake, current source preservation, and probe assertions
  • preserved the NO-GO boundary in records: releaseEligible: false, PW-01 and legal/operator/release inputs unresolved, and no plugin version bump, provenance, signing, or shipping action claimed
  • repaired archive references: replaced 32 dead session-local roadmap citations in the 2026-07-31 W8 record with q5vault/audits/qwizz/can-do.md, converted three out-of-tree clickable evidence links to plain paths, corrected the q5vault/operations.md alerting, off-host-backup, and image line citations in the current readiness and intake pages, and repaired the nesting of the Service State Health check
  • reconciled current truth: [quizwizz_my_library] is recorded as exposing Unpublish and Delete only to capability-holding owners with PW-01 still blocked-owner, and the superseded 2026-08-16 readiness and current-source packets are now marked historical and linked from the audit index

2026-08-16 — Visual and IA remediation recorded and wiki published

  • recorded the 2026-08-14 fourteen-slice visual and IA audit: 151 findings (2 blocker, 48 high, 83 medium, 18 low), 78 evidenced strengths, and an 18-finding adversarial review that corrected or narrowed five findings
  • recorded the eight bench repairs as W10-01 through W10-08: Builder initialization, destructive backup styling, 320 px quiz reflow, the five-row admin rail, gesture-gated attempts with dedicated-single autostart, visible and accessible player controls, direct result-review placement, and plugin-owned 24 px minimum targets
  • retained the 178-file audit corpus and its manifest at evidence/2026-08-15-visual-ia/, outside the published content root because it contains authenticated DOM dumps
  • re-verification in evidence/2026-08-15-visual-ia/verify-2026-08-16.json passed: 1..30, 30 assertions, zero failures, no console errors, and an unchanged final debug-log baseline of 38,409 lines; expiry cleanup reduced attempt rows from 130 to 12 with zero expired rows remaining
  • corrected three stale SSOT claims: the five-item rail became true only on 2026-08-15 after reversing the deliberate 2026-07-30 two-row submenu decision, and the answer review is now a direct result child rather than content inside More actions
  • advanced the living program masterplan’s authority date to 2026-08-16 while retaining the bench-only releaseEligible: false boundary
  • publication/documentation made no additional plugin source changes; separately, the verified W10-08 bench-local repair changed installed CSS in assets/css/qwizz-admin-dashboard.css and assets/css/qwizz-admin-settings-core.css. No build/ edit, version bump, release, or provenance work was performed.
  • vault evidence: --check-only 43 Markdown inputs → 312 emitted artifacts; first recorded published dist dist-1786861738.695567118-3945163; rollback target dist-1785651677.699209047-3759274; live sitemap 43 URLs; live page checks passed (remediation page returned 200 with W10-01 and W10-08, the masterplan date rendered Aug 16 2026, and no wikilink rendering trap appeared). Later builds publish this record and are deliberately not self-recorded in the vault; their labeled targets live in evidence/2026-08-15-visual-ia/publish-2026-08-16.txt.

2026-08-16 — Post-W10 execution, current-source preservation, and probe hardening

  • Wave 5 passed portability 12/12 and user surfaces 7/7; the later Wave 6 gate passed 14/14 shell assertions and 16/16 embedded PHP contracts, bringing --wave all to 1..46, 46 assertions, zero failures. The full run added no line to the already-current 38,412-line debug baseline.
  • Wave 6 covers password page/embed denial, generic draft denial, attempt resume and retry semantics, site sound/final-cue ceilings, category projections, list-table subject retrieval, the durable Library fixture, and paired status-token/copy source requirements. A deliberate nonexistent-Library-page mutation produced four failures and a nonzero exit; restoration returned green, with unchanged Settings SHA-256, 13 published quizzes, and zero probe posts, terms, or attempts.
  • recorded the Settings trust, authoring/retrieval, and access/continuity work in q5vault/audits/qwizz/2026-08-16-post-w10-execution.md, with browser evidence under evidence/2026-08-16-settings/, evidence/2026-08-16-authoring-retrieval/, evidence/2026-08-16-access-continuity/, and evidence/2026-08-16-library-fixture/
  • retained the durable Library fixture on the bench: quizzes 1284–1288 and page 1289; teardown is recorded in evidence/2026-08-16-library-fixture/ids.json
  • preserved the current installed source as a 218-path inventory excluding only the three protected roots in evidence/2026-08-16-current-source/
  • boundary unchanged: bench-local, releaseEligible: false; no build, version bump, provenance, signing, or release act

2026-07-30 — Evidence-only re-audit, then feature completion

  • ran an evidence-only re-audit of the whole requested feature list across eleven parallel slices, trusting only current source plus live runtime/DOM; recorded it as a dated section in the preserved backlog history
  • reset the drifted bench qw_exposure_settings to sanitized source defaults, deleted a leftover verification account, and closed the public-CSS leak the audit proved (#wpcontent and Settings selectors were being served to every visitor)
  • schema 1.6.5 after explicit owner approval: wp_qwizz_attempts.user_id plus index; durable qwizz_user_stats per-user aggregate survives attempt expiry, with replay idempotency and core privacy export/erase coverage
  • delivered the requested product work: independent question numbering and answer markers, suppressible editor helper, defaults-off print profile, sound/final-cue/score-animation options with a per-second final-ten countdown and animated score, autosave-only settings with truthful state and reload-free language switching, clearable default theme, side-by-side source choices, sticky Print/Play with a wizard-hat glyph, compact hover/focus/click answer-review affordance, print-score and print-unsolved actions, real dashboard metrics, trimmed submenu, content-ideas card, [quizwizz_my_library] and [quizwizz_my_stats], five Site Editor patterns, wizard-hat brand default, and mtime-based asset cache busting
  • hardened the new telemetry after review: removed the forgeable client print endpoint, bound share recording to a valid attempt token with rate limiting and idempotency, and counted printable-sheet downloads server-side in PdfArtifact::stream() for delivered non-inline sends only
  • localization: regenerated POT, authored 1,477+ German entries with zero fuzzy/empty, compiled de_DE MO plus nine per-handle JSON catalogs, and corrected mistranslations (AktienFreigaben, DruckeAusdrucke); these catalogs are bench artifacts the release owner must still regenerate and review through the locked pipeline
  • evidence: --wave all = 30/30 with an unchanged debug.log (224 lines) across the pass, cache-disabled browser verification of every changed UI path, and byte-identical restoration of every temporarily mutated option or post meta
  • reconciled current-truth pages: printable-sheet metrics count each successful non-inline attachment download (share alone remains rate-limited and attempt-token/7-day idempotent), cache-versioning claims are source-scoped, and German catalog remediation is qualified pending release-owner regeneration/review.
  • repaired the vault itself in four parallel slices so it can act as an SSOT: gave each landing exactly one role (bench operations, family index, and the single QuizWizz-corpus enumeration) instead of three overlapping link stacks, dated a status banner onto every historical page, marked the archival handoff pages as prohibited patch sources, escaped the table-cell wikilinks that had been rendering as literal [[audits/... text, de-slashed the one truncating alias, corrected the qw-get-started/qw-import and stylesheet contradictions in the design subtree against live source, refreshed the probe page to the 2026-07-30 result, and dropped the stale vault page count
  • corrected one of my own audit findings rather than acting on it: the “39 supposedly broken design/... targets” I reported were a false positive from my own resolver assumption. Quartz resolves them correctly (live HTML shows data-slug="audits/qwizz/design/studio-builder" with no broken marker), so the established subtree convention was left untouched
  • vault evidence: build.sh wrdp --check-only exits 0 (29 files → 276 emitted) and a captured render of the check build shows zero literal [[ leakage and zero broken internal targets across all 62 emitted pages. One regression introduced during the pass, an unquoted YAML description: containing a colon that aborted the build, was found by that build and fixed
  • not done, deliberately: no wiki publish or prune (owner deferred it), no compiled build/ edit, no version bump, no release or provenance work

2026-07-29 — WordPress-native token phase and final contrast repair

  • completed the WordPress-native token phase: admin-owned pages now carry qwizz-admin, active wp-admin scheme colours flow through --wp-admin-theme-color to --qw-brand / --qw-focus, and public site mode inherits site type/colour/accent without player data-theme while its PDF palette prints light
  • migrated live CSS sheets are literal-free except canonical assets/css/qwizz-tokens.css; dormant qwizz-admin-starter.css remains intentionally deferred. The orphaned settings visual sheet was retained, renamed assets/css/qwizz-admin-settings-visual.unused.css, with zero references; it was not deleted
  • stored exposure settings now enable site, light, dark, retro, and cyber, default to site, and set themes.site={on:true,def:true}. Existing published quizzes retain any stored qw_experience.pdf_theme; no per-quiz presentation values were migrated
  • repaired arbitrary inherited-accent actions to use --qw-action-bg / --qw-action-ink; Twenty Twenty-Five #FFEE58 measured 18.88:1 action contrast with opaque derived cards. Explicit palettes keep their action pair, and CDP forced-colors emulation confirms explicit players resolve CanvasText/Canvas/LinkText
  • cache-disabled browser sweeps found settings, subjects, question editor, and portability roots visible with zero document horizontal overflow at 1600, 782, and 390 px; at 390 px the one-column settings grid and anchored 150 px help bubbles remove overflow
  • after every final CSS/option repair, ./scripts/quizwizz-probe.sh --wave all returned assertions=30 failures=0; the final debug-log slice contains only automatic-update lines through 18:46 UTC and no new plugin error
  • catalog generation remains release-owner work; no fr_FR/es_ES catalog generation was performed on the bench

2026-07-29 — Truth-page consolidation and SSOT correction

  • audits/qwizz/masterplan.md rewritten as the explicit SSOT for current QuizWizz status on WRDP, with releaseEligible: false stated plainly
  • landing pages updated so they no longer overclaim universal visual/admin repair and now point to the masterplan, probe harness, visual audit, and triage ledger consistently
  • backlog converted from a residue note into an itemized frontier with done/partial/open states, marking only source-proven completions complete
  • probe record tightened around its real authority boundary and explicit non-claims
  • existing documentation now distinguishes bench-verified runtime work, retained compiled-block defects, Site Health / Privacy evidence gaps, and release-owner-only provenance/build blockers
  • no production publish or deploy performed as part of this curation
  • completed the live builder/fine-tune cutover: removed visitor density, Start over, review/version, and Exact PDF UI; retained step-level Change plus visible undo/redo; verified a real edited question reached the protected print-artifact request
  • unified dynamic/prepared criteria, count, capacity, and selection policy; enforced attempt expiry at write-time compare-and-swap; bounded guest cleanup to 100 rows with guarded continuation
  • reran the full live probe harness after final review fixes: 30/30 shell assertions, 34/34 Wave 2, 12/12 Wave 3, and 12/12 Wave 4; no new debug-log entries
  • closed the independent review P1s: consumed fine-tune artifact fields now clear before later outputs, and shared criteria reject more than 20 categories
  • replaced the interface-language duplication with one catalog-driven authority behind the storage sanitizer, REST enum, and both settings UIs; a language is offered only while its complete catalog set is readable, so this bench truthfully exposes auto/en/de and degrades a stored-but-unrenderable choice to auto
  • deliberately did not generate fr_FR/es_ES catalogs on the bench: authoring/compiling them would reconstruct the absent locked i18n toolchain and ship unreviewable binaries, so the dormant fr/es plumbing is recorded as a release-pipeline remainder

2026-07-28 — Option F remediation implemented and bench-verified

  • implemented and bench-verified Waves 1–4: banner safety/cache behavior; service authorization and backup ownership; template, localization, responsive/accessibility, and result-state UX; strict SVG validation; and scoped cleanup
  • final executable evidence: 30/30 shell assertions plus 34/34 Wave 2, 12/12 Wave 3, and 12/12 Wave 4 embedded assertions; see the probe record and program masterplan
  • browser evidence covers template precedence, 320/390/740 responsive states, RTL, reduced motion, locale overrides, a logged-out ten-question playthrough, inert subject icons, and shortcode-copy status; forced-colors treatment was source-reviewed because Chromium media emulation was unavailable, and OS clipboard invocation counts were not directly observable
  • all changed PHP and JavaScript passed syntax checks; the plugin deactivated/reactivated cleanly; the live quiz returned HTTP 200; temporary verification user and fixtures were removed
  • focused review confirmed the caught banner-cache regression was fixed and found no remaining P0/P1 across Waves 1–4
  • development bench only: Wave 5 release-owner integration, CI, provenance, and signed release artifacts remain open

2026-07-28 — Wiki curation, canonical masterplan, RSS cleanup

  • homepage rebuilt around reader intent: bench identity, QuizWizz current-state callout, operations, evidence/history, handoff artifacts, changelog
  • vault pages carry explicit title + description frontmatter; architecture map re-titled and its source map corrected to the real case-sensitive layout
  • audits/qwizz/masterplan.md replaced in place with the then-current canonical remediation masterplan; design masterplan rewritten as the historical 2026-07-24 Design Remediation Record
  • 2026-07-27 full audit annotated with a dated reconciliation: F-3 narrowed, F-4 retracted, F-6/F-7a/F-7b verified no-change, U-6 fixture, U-7/U-8 verified strengths
  • RSS feed fixed via includeEmptyFiles: false (empty virtual tag pages no longer flood the newest entries); explorer defaults pinned with 🧭 Explorer label
  • accidental #211d31 tag literal code-formatted; no plugin code changed in this curation
  • no still-open plugin finding was implied fixed by that curation alone

2026-07-27 — Full re-audit, architecture map, live fixture quiz

  • full 6-slice re-audit of QuizWizz v1.10.0 (~23k LOC PHP + ~4.4k LOC JS) with live REST authorization matrix, in-browser admin/Studio probes, and full guest playthrough
  • every 2026-07-24 fix re-verified live with no regressions; new findings recorded in 2026-07-27 Full Plugin Audit (headline: unauthenticated fatal on the public banner endpoint)
  • architecture map added as reference
  • quiz 110 deliberately published and left published as the live verification fixture (previously draft)

2026-07-24 — Audit round, code/design remediation, handoff artifacts

  • backend roast + frontend/UX audit of QuizWizz v1.10.0 live on the bench
  • four code fixes authored, applied, and live-verified on the bench: FE-1 (primary-button fill), FE-8 (player loading spinner), BE-3 (dead RateLimiter::allow()), BE-7 (dead QUIZWIZZ_VER alias); FE-2/FE-3/FE-4/FE-7 retracted after deeper inspection
  • six-surface design audit executed; bench-verified design remediation: brand token unification, product-wide density toggle, Studio/metric hierarchy, Settings “Appearance” workspace, enriched player empty state
  • handoff artifacts published: merge-ready patch spec and design patch spec — development artifacts for the release owner’s locked signed pipeline

2026-07-23 — Initial provisioning

  • provisioned isolated WordPress plugin-test bench at /home/loca/dev/wrdp
  • stack: wordpress:latest (WP 7.0) + mariadb:11.4 via Docker Compose, dedicated wrdp_net bridge
  • app bound loopback 127.0.0.1:51080; db has no host port
  • non-interactive install via wordpress:cli (wp core install)
  • published at https://wrdp.loca.zone (nginx reverse proxy + Let’s Encrypt TLS)
  • companion wiki published at https://wiki.wrdp.loca.zone (Quartz static build, vault dev/wrdp/q5vault)
  • WordPress configured to trust X-Forwarded-Proto; WP_HOME/WP_SITEURL = https