πŸ“š 2026-08-19 question-corpus audit

Superseded β€” 2026-08-19

The 679-question / 456-subject bench state measured here at 06:45 UTC is superseded by the 2026-08-19 corpus import and the 2026-08-19 legacy WXR import, which closed the same day at 9,069 questions and 483 subject terms. Preserved as observed.

One sentence

The live bench still holds 679 published questions with a matching 679-row index and 0 QuestionValidator violations; the repaired local-corpus pass finds 5,701 distinct local stems and 360 overlaps with the bench; one exact published duplicate and the English progressive subject pool remain the live defects.

Status vocabulary on this page: done Β· verified Β· open Β· blocked(<what>) Β· retracted.

What this page already proved before the 06:45 UTC bench pass

The existing page already proved the core corpus shape: 679 published questions, 679 index rows, 0 content-vs-index drift, 456 subject terms, 908 question-subject rows, language rows en=508 / de=57 / es=57 / fr=57, 0 validator violations over published questions, one exact normalised Mona Lisa duplicate, local union 1,425 fingerprints, and 324 bench/local overlaps. The 06:45 UTC pass below re-measured the bench half with a single mounted wp eval-file audit script and supersedes stale sufficiency text: the deployed gate now exposes only 2 specific subjects for default English progressive criteria (general-knowledge, geography) plus the synthetic any card, not 3 specific subjects. The local-corpus handoff then superseded the earlier local union/overlap numbers after fixing XLSX shared-string parsing and adding more corpus paths.

Bench command transcript

All bench measurements in the State, Taxonomy, Conformance, Duplicates, and Sufficiency sections came from this mounted read-only PHP audit command:

ssh loca@178.18.250.170 'cd ~/dev/wrdp && sudo -n docker compose --profile cli run --rm -v /tmp/qw_corpus_audit.php:/tmp/qw_corpus_audit.php wpcli wp eval-file /tmp/qw_corpus_audit.php'

Script source path on the bench: /tmp/qw_corpus_audit.php. The script reads wp_posts, wp_qwizz_question_index, wp_qwizz_question_subjects, term assignments, and question meta only; it does not update options, post meta, posts, or plugin files.

Headline cross-check command:

ssh loca@178.18.250.170 'cd ~/dev/wrdp && sudo -n docker compose --profile cli run --rm wpcli wp post list --post_type=qw_question --post_status=publish --format=count' β†’ 679.

Code contracts cited by this page:

ContractSource
Validator payload for indexed questions is built from qw_type, post content/title, qw_choices, qw_correct_idx, qw_explanation, qw_lang, and exactly one qw_difficulty term.wp/wp-content/plugins/quizwizz/includes/QuestionIndex.php:223-233
QuestionValidator accepts only multiple/boolean, non-empty stem ≀2000 chars, 2-8 non-empty string choices, boolean exactly 2 choices, each choice ≀1000 chars, distinct normalised choices, in-range integer correct_idx, explanation ≀4000 chars, valid language slug, and difficulty `easynormal
Progressive capacity is 2 * min(easy, harder) + (easy > harder ? 1 : 0), where harder = normal + hard; a progressive selection of count 10 needs easy >= 5 and normal+hard >= 5.wp/wp-content/plugins/quizwizz/includes/QuestionSelector.php:160-177, wp/wp-content/plugins/quizwizz/includes/QuestionSelector.php:181-196
Builder cards are only advertised when enabled, pool β‰₯1, and SubjectTaxonomy::can_satisfy(...) returns true.wp/wp-content/plugins/quizwizz/includes/SubjectTaxonomy.php:395-428, wp/wp-content/plugins/quizwizz/includes/SubjectTaxonomy.php:436-502

State

Re-measured 2026-08-19 at 06:45 UTC. Headline publish count equals the wp post list cross-check above: 679.

MetricValueCommand / key
Published qw_question679count.qw_question.publish=679 from the mounted wp eval-file; cross-check wp post list --post_type=qw_question --post_status=publish --format=count β†’ 679
Auto-draft qw_question1 (ID 1351, empty title)count.qw_question.auto-draft=1; local-corpus bench census dumped all qw_question posts and identified ID 1351
Draft / pending / private / trash questions0 / 0 / 0 / 0no grouped count.qw_question.* rows for those statuses in the mounted output
Published qw_quiz13count.qw_quiz.publish=13
Draft qw_quiz10count.qw_quiz.draft=10
Draft quiz IDs598, 613, 694, 710, 938, 1556, 1657, 1758, 1859, 1960quiz.draft_ids=598,613,694,710,938,1556,1657,1758,1859,1960
Index rows679index.rows=679 (SELECT COUNT(*) FROM wp_qwizz_question_index)
Valid index rows679index.valid_rows=679
wp_qwizz_question_subjects rows908subjects.rows=908
Published questions missing from index0drift.published_not_indexed=0
Index rows without published question0drift.indexed_not_published=0
Subject rows without indexed question0drift.subject_rows_orphan_question=0
Content-vs-index drift0drift.published_not_indexed=0 and drift.indexed_not_published=0

The five imported drafts named on now (1556, 1657, 1758, 1859, 1960) are still draft. Five older draft quizzes also remain: 598, 613, 694, 710, 938. The previous page note about a deleted workstream-E scratch quiz is historical evidence; the current grouped query reports no such draft ID.

Language

Rows by lang from SELECT lang, COUNT(*) FROM wp_qwizz_question_index GROUP BY lang in /tmp/qw_corpus_audit.php:

langrows
en508
es57
fr57
de57

Retracted

now.md previously said content languages were en only. That is retracted. The index still holds 171 non-English rows (57 Γ— de/es/fr). Interface language is a separate setting and is not the content-language count.

Taxonomy

Difficulty

Index difficulty rows and taxonomy term assignments both agree in the 06:45 UTC pass:

difficultyindex rowsqw_difficulty term rows
easy276276
normal240240
hard163163
no qw_difficulty term on published questions00
multiple qw_difficulty terms on one published question00

Command keys: index.difficulty.easy=276, index.difficulty.normal=240, index.difficulty.hard=163, term.difficulty.easy=276, term.difficulty.normal=240, term.difficulty.hard=163, term.difficulty.none_count=0, term.difficulty.multi_count=0.

Difficulty is a qw_difficulty term for validator/index purposes (QuestionIndex.php:207-233), not qw_difficulty post meta. A validator payload that reads the empty meta key would report a false qw_invalid_difficulty on every row.

Subjects

qw_subject terms: 456 (subject.terms=456). Published-question pool size per qw_subject term, counting distinct indexed published questions via wp_qwizz_question_subjects:

poolsubjectsCommand key
20+3subject.hist.20+=3
10-1916subject.hist.10-19=16
5-911subject.hist.5-9=11
1-4408subject.hist.1-4=408
018subject.hist.0=18

Top 20 by published count (subject.top20=...): geography 26, history 26, general-knowledge 22, science 16, language 13, society 13, animals 12, art 12, film-tv 12, food-drink 12, games 12, literature 12, math 12, entertainment-music 12, mythology 12, politics 12, sports 12, tech 12, science-nature 10, science-physics 9.

Zero-pool subjects: 18 (subject.zero_pool_count=18). First 15 by term order (subject.zero_pool_first15=...): animals-nature, entertainment-japanese-anime-manga, entertainment-board-games, entertainment-books, entertainment-cartoon-animations, celebrities, entertainment-comics, science-computers, entertainment, entertainment-film, games-technology, literature-arts, science-mathematics, people-society, qw-svg-probe-4lhqftjo.

Conformance

Conformance was re-run over all published and draft qw_question posts. The scan set is conformance.scanned=679, with conformance.published=679 and conformance.draft=0; the one qw_question auto-draft is intentionally outside the requested published+draft set.

Implementation notes: the audit script mirrored the indexed payload contract from QuestionIndex.php:223-233 and also called QuizWizz\QuestionValidator::validate_array(...) for each scanned question. The exact rule source is QuestionValidator.php:35-120.

ruleviolationssample idsCommand key
type not in `multipleboolean`0β€”
stem empty or > 20000β€”absent rule.stem_empty_or_over_2000; conformance.rule_violations=0
choices not a 2-8 list / empty / non-string0β€”absent rule.choices_not_list, rule.choice_not_string, rule.choices_outside_2_8_or_empty; conformance.rule_violations=0
boolean not exactly 2 choices0β€”absent rule.boolean_not_exactly_2; conformance.rule_violations=0
any choice > 1000 chars0β€”absent rule.choice_over_1000; conformance.rule_violations=0
choices not distinct after validator normalisation0β€”absent rule.choices_not_distinct; conformance.rule_violations=0
correct_idx missing or out of range0β€”absent rule.correct_idx_missing_or_out_of_range; conformance.rule_violations=0
explanation > 4000 chars0β€”absent rule.explanation_over_4000; conformance.rule_violations=0
invalid lang slug0β€”absent rule.lang_invalid; conformance.rule_violations=0
no / multiple difficulty terms0β€”absent rule.no_difficulty_term, rule.multiple_difficulty_terms; conformance.rule_violations=0

0 violations. The direct validator call also returned 0 failures (conformance.validator_failures=0, conformance.validator_failure_detail=). Missing qw_choices/qw_type meta: 0 (conformance.missing_meta=0).

Choice-count histogram over the 679 scanned questions:

choicesquestionsCommand key
291choice_hist.2=91
4585choice_hist.4=585
52choice_hist.5=2
81choice_hist.8=1

Empty explanation is allowed by the validator; the rule is only a 4000-character cap. Current empty-explanation count: 40 (conformance.empty_explanation=40).

Duplicates

Normalisation for duplicate detection: use the question stem from post content when non-empty, otherwise post title; strip tags; lowercase; replace punctuation/non-alphanumeric runs with one space; collapse whitespace; trim. The local-corpus handoff separately proved question text lives in post_title and post_content duplicates it for ID 67; meta keys are qw_type, qw_choices, qw_correct_idx, qw_explanation, qw_lang, qw_source, and qw_opentdb_id, none of which holds the stem.

kindgroupsposts10 largest groups / evidenceCommand key
Exact normalised stem among published questions122x [357/publish 1915/publish] "who painted the mona lisa"dup.groups_publish_only=1; dup.group1=2x [357/publish 1915/publish] "who painted the mona lisa"
Exact normalised stem across published + draft questions12same group; there are no draft qw_question postsdup.groups_total=1, conformance.draft=0
Published-vs-draft collisions00nonedup.groups_publish_vs_draft=0
Unique bench fingerprints in published + draft scan678β€”679 scanned posts minus the one 2-post groupdup.unique_fingerprints=678

The local-corpus bench census agrees: duplicate group ID 357 Who painted the 'Mona Lisa'? equals ID 1915 Who painted the Mona Lisa? after quote stripping; publish distinct count is 678.

Historical near-duplicate evidence retained

The earlier page also listed a near-duplicate pair, 1574 Which compound is chiefly responsible for the heat of chili peppers? and 1591 Which compound is chiefly responsible for the pungent heat of hot chili.... That was a heuristic first-40-normalised-character check, not part of the exact-normalised duplicate requirement re-measured in this pass, so it remains historical evidence and is not counted in the exact collision table above.

Sufficiency against the default English progressive request

Default criteria measured through the deployed code path: GenerationCriteria::from_array(array('lang'=>'en','difficulty'=>'prog','count'=>10), ExposureSettings::get()) produced suff.criteria=source=dynamic lang=en difficulty=prog type=mixed count=10; default language is en (suff.default_lang=en) and default count is 10 (suff.count_default=10).

The code’s own progressive rule is not 3/3/3. QuestionSelector::capacity() computes progressive capacity as 2 * min(easy, harder) + (easy > harder ? 1 : 0), where harder is normal + hard (QuestionSelector.php:160-177). QuestionSelector::select() then requires easy >= ceil(count / 2) and harder >= floor(count / 2) (QuestionSelector.php:181-196). For a 10-question progressive English quiz, the real requirement is therefore 5 easy English questions and 5 normal-or-hard English questions under the selected subject.

Builder advertisement also uses that same rule: SubjectTaxonomy::can_satisfy() clones the criteria, sets the subject categories, calls QuestionSelector::capacity($probe), and requires capacity >= count (SubjectTaxonomy.php:395-428); builder_cards() skips cards unless pool >= 1 and can_satisfy(...) is true (SubjectTaxonomy.php:436-502).

MetricValueCommand key
Subject terms considered456suff.subjects_advertised=456
Specific subject terms satisfying default English progressive 102suff.subjects_can_satisfy=2
Satisfying specific subjectsgeneral-knowledge, geographysuff.can_satisfy_slugs=general-knowledge, geography
Non-empty but insufficient subject pools197suff.nonempty_but_insufficient=197
Zero-capacity subject pools for the progressive criteria257suff.zero_capacity=257
Synthetic any card satisfies the same criteriayessuff.any_can_satisfy=yes
Synthetic any progressive capacity438suff.any_capacity=438

Top progressive capacities under the code rule (suff.top12_prog_capacity=...): geography 14, general-knowledge 13, science-nature 7, history 6, language 4, society 4, science 3, animals 3, geography-maps 3, geography-world-capitals 3, food-drink 2, film-tv 2.

Superseded 2026-08-19 06:45 UTC

The earlier text on this page used two hand-derived thresholds (3/3/3 and 1/1/1) and said history also qualified under the relaxed bar. That is now superseded. The deployed code’s rule is easy-vs-harder progressive capacity; under that rule history’s capacity is only 6, so the real specific-subject count is 2, not 3. Including the synthetic any card, the builder can advertise 3 cards: any, general-knowledge, and geography.

Local corpus inventory

Method from local-corpus handoff: stdlib XLSX reader /tmp/corpus-work/xlsx.py using zipfile + ElementTree, with sharedStrings indexed and t="s" resolved as an index; fingerprint is sha1(lower β†’ strip punctuation β†’ collapse whitespace β†’ strip); fingerprints live in /tmp/corpus-fingerprints/*.txt. Bench dump command used by that handoff: scp /tmp/corpus-work/dump.php loca@…:/tmp/dump.php then ssh loca@178.18.250.170 'cd ~/dev/wrdp && sudo -n docker compose --profile cli run --rm -v /tmp/dump.php:/tmp/dump.php wpcli wp eval-file /tmp/dump.php'; it emitted 680 qw_question rows.

datasetsheet/nodequestion columnrecordsnon-emptyunique norm∩ bench pub% of set
04 QUESTIONS/Qwizz_Gold_Question_Corpus_240.xlsxQuestion BankQuestion2402402406527.1%
04 QUESTIONS/Qwizz_Gold_Question_Corpus_360.xlsxQuestion BankQuestion3603603607019.4%
04 QUESTIONS/Qwizz_Gold_Question_Corpus_504.xlsxQuestion BankQuestion5045045047013.9%
04 QUESTIONS/Qwizz_Gold_Question_Corpus_1008.xlsxQuestion BankQuestion10081008100810110.0%
04 QUESTIONS/Qwizz_10k_Content_Runway.xlsxQuestion Bank (+ Production Queue: 8992 placeholder rows, empty Question)Question100001008100810110.0%
04 QUESTIONS/Qwizz_10k_Content_Runway_dfq.xlsxbyte-identical to aboveQuestion100001008100810110.0%
04 QUESTIONS/Qwizz_Wave_01_Editorial_Candidates_168 (1).xlsxQuestion BankQuestion1681681651911.5%
04 QUESTIONS/Qwizz_Wave_01_Editorial_Candidates_168.xlsxbyte-identical to aboveQuestion1681681651911.5%
04 QUESTIONS/Qs.jsonquestions[]stem32323226.2%
02 DOCS/questions.jsonquestions[]question22922922920589.5%
04 QUESTIONS/World Quiz Datase files 4 qwizz/questions.jsonidentical copyquestion22922922920589.5%
04 QUESTIONS/quiz-lib_claude-jam_files/questions.jsonidentical copyquestion22922922920589.5%
04 QUESTIONS/loca-dev-trivia-atlas/data/physical-sciences/easy.jsonljsonlq26262400.0%
04 QUESTIONS/loca-dev-trivia-atlas/meta/rejections.jsonljsonlpacket.q33262600.0%
04 QUESTIONS/world_quiz_reference_demo_v1/data/items.jsonljsonlprompt.stem33333313.0%
01 APP/quizwizz-1.3.1-external-audit/…/assets/data/opentdb-local.jsonjson arrayquestion_en419641964192370.9%

Superseded local inventory

The earlier local section on this page reported a 1,425-fingerprint local union and 324 bench overlaps. The local-corpus handoff supersedes that after fixing the XLSX shared-string reader and including additional corpus files: total distinct local is 5,701, local ∩ bench is 360, and grand distinct union is 6,019.

Overlap with the bench

setunique fingerprintsMethod / proof
Bench published posts679local-corpus bench dump and this page’s wp post list cross-check agree
Bench published distinct678one exact duplicate group, ID 357 vs ID 1915
Total distinct local5,701local-corpus fingerprint union using sha1(lower β†’ strip punctuation β†’ collapse whitespace β†’ strip)
Local ∩ bench360local-corpus cross-match against the 678 distinct bench published stems
Bench questions in no local dataset318678 distinct bench stems minus 360 shared
Grand distinct union6,0195,701 local + 678 bench - 360 shared

Notable structure from the local-corpus handoff:

  • Gold 360 βŠ‚ 504 βŠ‚ 1008, and Gold 1008 is identical to the 10k Runway Question Bank.
  • Gold 240 carries into Gold 360 at 239/240; exactly one 240-era question was replaced or reworded.
  • Byte-identical file pairs/triples: 10k_Content_Runway.xlsx equals _dfq.xlsx; both Wave 01 files are identical; the three questions.json copies are identical.
  • Sixteen discovered dataset files collapse to thirteen real corpora after byte-identical duplicates.
  • Wave 01 shares only one item with the Gold line and has three internal duplicates.
  • Gold is almost disjoint from imported material: Gold ∩ OpenTDB pack = 2; Gold ∩ 229-pack = 1.
  • The trivia-atlas material has not been imported: 0 bench overlap for easy.jsonl; easy.jsonl has 24 unique stems and rejections.jsonl has 26, with 2 shared.
  • Qs.json needed in-memory repair only: line 287 contains one illegal JSON escape, a bare \l in \lim; source was untouched.
  • No workbook carries a language column; Qs.json declares meta.languages = [en,es,fr,de,zh-Hans,pt-BR] but every stem is English.

Deltas this programme

Every bench number below was re-measured on 2026-08-19 at 06:45 UTC where possible; source-history items that cannot be re-derived from current database state are marked [cited] with the page that records them.

changethennowproof
Import blocker (chess vs games-chess)packs died on slug mismatch[cited] slug resolution fixed and recorded completecompleted task log 2026-08-18 completed row
Corpus import269 published [cited]679 published, index 679, drift 0mounted audit keys count.qw_question.publish=679, index.rows=679, drift.published_not_indexed=0, drift.indexed_not_published=0; headline cross-check wp post list --post_type=qw_question --post_status=publish --format=count β†’ 679
Five English packsβ€”drafts 1556 / 1657 / 1758 / 1859 / 1960 still draft; five older drafts also remainquiz.draft_ids=598,613,694,710,938,1556,1657,1758,1859,1960
Sufficiency gate / Wave 6 #12guest cards 11 [cited]code-derived default English progressive: 2 specific subjects (general-knowledge, geography) plus synthetic any; 197 non-empty subject pools still insufficientsufficiency census; mounted audit keys suff.subjects_can_satisfy=2, suff.can_satisfy_slugs=general-knowledge, geography, suff.any_can_satisfy=yes, suff.nonempty_but_insufficient=197
B001 player review restorein-process review length 58 [cited]browser-verified anonymous quiz 413 result 13 / 58 (22%), 58 .qwizz-player__review-item, 0 console errors [cited]play and print answers; screenshot 03 EVIDENCE/2026-08-19-quiz-413-playthrough-review.webp
Assumed reveal enum `instantendnever`written as the player contract
Answers operator UIone hidden/preserved bittwo visible controls on the quiz metabox and the builder; sheet bit persists independently; player-review disabled under Forced site policy [cited]metabox/browser proof from answers-switch workstream
German catalog153 missing / 76 obsolete1650 = 1650, missing 0 / obsolete 0 [cited]task 2.1.1
Probe harness1..46 / 46 / 0no probe run by this bench-corpus pass; latest known post-install probe remains [cited]coordinator-owned probe receipts, not this page’s bench audit command
Debug log38,433not re-measured by this passprevious page evidence retained; no current claim

Open recommendations

Each open, one line, no schedule.

idstatusrecommendation
QC-01openMerge published pair 357 / 1915 (Mona Lisa) β€” same English easy item, punctuation-only difference.
QC-02openDecide whether chili pair 1574 / 1591 is a rewrite to keep or a near-duplicate to drop; it is not part of the exact-normalised collision count.
QC-03openFill or explicitly mark the 40 published questions with an empty explanation.
QC-04openEnglish progressive pool is the bottleneck, not raw count: only general-knowledge and geography satisfy the real code rule for a specific subject; any satisfies through the aggregate pool.
QC-05openGold 1008 and the 10k runway sheet are the same 1008 non-empty rows β€” do not count them twice in the fusion ledger.
QC-06openTreat doctrine files separately from inventory; the repaired local pass did not count qwizz-irresist.yaml as a question corpus.
QC-07openDrop byte-identical duplicate corpus files from the working tree so future globs do not double-count them.
QC-08openqw-svg-probe-4lhqftjo is a leftover probe subject with a zero pool β€” delete or quarantine.
QC-09openOwner decision UX-ANS-01 (may Forced honour per-quiz sheet off?) is still open; today’s REST already honours per-quiz '0' for the sheet flag.