archive repo

emptying out this repo and adding a README
with info about superseded repo.

Bug: T274680
Change-Id: I8aaecacc44ca2e46bce1fe1b599e2e3a4d36ea3a
diff --git a/Gruntfile.js b/Gruntfile.js
deleted file mode 100644
index c32d669..0000000
--- a/Gruntfile.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/* eslint-env node */
-module.exports = function ( grunt ) {
-	var conf = grunt.file.readJSON( 'extension.json' );
-
-	grunt.loadNpmTasks( 'grunt-jsonlint' );
-	grunt.loadNpmTasks( 'grunt-banana-checker' );
-
-	grunt.initConfig( {
-		banana: conf.MessagesDirs,
-		jsonlint: {
-			all: [
-				'**/*.json',
-				'!node_modules/**',
-				'!vendor/**'
-			]
-		}
-	} );
-
-	grunt.registerTask( 'test', [ 'jsonlint', 'banana' ] );
-	grunt.registerTask( 'default', 'test' );
-};
diff --git a/Jade.namespaces.php b/Jade.namespaces.php
deleted file mode 100644
index f9b982b..0000000
--- a/Jade.namespaces.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-/**
- * Translations of the namespaces introduced by Jade.
- *
- * @file
- */
-
-require_once __DIR__ . '/defines.php';
-
-$namespaceNames = [];
-$namespaceAliases = [];
-
-/** English */
-$namespaceNames['en'] = [
-	NS_JUDGMENT => 'Judgment',
-	NS_JUDGMENT_TALK => 'Judgment_talk',
-];
-
-// "judgment" and "judgement" are alternative spellings, so allow either.
-$namespaceAliases['en'] = [
-	'Judgement' => NS_JUDGMENT,
-	'Judgement_talk' => NS_JUDGMENT_TALK,
-];
-
-/** Spanish */
-$namespaceNames['es'] = [
-	NS_JUDGMENT => 'Jade',
-	NS_JUDGMENT_TALK => 'Jade_discusión',
-];
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1dbdcce
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# JADE
+
+This repo is archived and has been superseded by 
+https://gerrit.wikimedia.org/g/mediawiki/extensions/Jade
+
+For more info see: https://phabricator.wikimedia.org/T274680
diff --git a/composer.json b/composer.json
deleted file mode 100644
index caf7f44..0000000
--- a/composer.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
-	"name": "mediawiki/jade",
-	"type": "mediawiki-extension",
-	"description": "Judgment and Dialog Engine",
-	"keywords": [
-		"mediawiki",
-		"wiki"
-	],
-	"homepage": "https://www.mediawiki.org/wiki/JADE",
-	"authors": [],
-	"license": "GPL-3.0-or-later",
-	"support": {
-		"irc": "irc://irc.freenode.net/wikimedia-ai"
-	},
-	"require": {
-		"justinrainbow/json-schema": "~5.2"
-	},
-	"require-dev": {
-		"jakub-onderka/php-parallel-lint": "1.0.0",
-		"mediawiki/mediawiki-codesniffer": "24.0.0",
-		"jakub-onderka/php-console-highlighter": "0.3.2",
-		"mediawiki/minus-x": "0.3.1"
-	},
-	"scripts": {
-		"fix": [
-			"phpcbf",
-			"minus-x fix ."
-		],
-		"test": [
-			"parallel-lint . --exclude vendor --exclude node_modules",
-			"phpcs -s -p",
-			"minus-x check ."
-		]
-	},
-	"extra": {
-		"phan-taint-check-plugin": "1.5.0"
-	}
-}
diff --git a/defines.php b/defines.php
deleted file mode 100644
index 997a704..0000000
--- a/defines.php
+++ /dev/null
@@ -1,7 +0,0 @@
-<?php
-
-// Constants
-if ( !defined( 'NS_JUDGMENT' ) ) {
-	define( 'NS_JUDGMENT', 810 );
-	define( 'NS_JUDGMENT_TALK', 811 );
-}
diff --git a/extension.json b/extension.json
deleted file mode 100644
index 9dc0263..0000000
--- a/extension.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
-	"name": "Jade",
-	"descriptionmsg": "jade-desc",
-	"version": "0.0.1",
-	"license-name": "GPL-3.0-or-later",
-	"type": "other",
-	"author": [
-		"Adam Roses Wight"
-	],
-	"url": "https://www.mediawiki.org/wiki/Extension:JADE",
-	"requires": {
-		"MediaWiki": ">= 1.31.0"
-	},
-	"namespaces": [
-		{
-			"id": 810,
-			"constant": "NS_JUDGMENT",
-			"name": "Judgment",
-			"defaultcontentmodel": "JadeJudgment"
-		},
-		{
-			"id": 811,
-			"constant": "NS_JUDGMENT_TALK",
-			"name": "Judgment_talk"
-		}
-	],
-	"APIListModules": {
-		"getjudgments": "Jade\\ApiGetJudgments"
-	},
-	"AutoloadNamespaces": {
-		"Jade\\": "includes/",
-		"Jade\\Maintenance\\": "maintenance/",
-		"Jade\\Tests\\": "tests/phpunit/"
-	},
-	"ContentHandlers": {
-		"JadeJudgment": "Jade\\Content\\JudgmentContentHandler"
-	},
-	"Hooks": {
-		"ArticleDeleteComplete": "Jade\\Hooks\\LinkTableHooks::onArticleDeleteComplete",
-		"ArticleUndelete": "Jade\\Hooks\\LinkTableHooks::onArticleUndelete",
-		"LoadExtensionSchemaUpdates": "Jade\\Hooks\\DatabaseSchemaHooks::onLoadExtensionSchemaUpdates",
-		"MovePageIsValidMove": "Jade\\Hooks\\MoveHooks::onMovePageIsValidMove",
-		"PageContentInsertComplete": "Jade\\Hooks\\LinkTableHooks::onPageContentInsertComplete",
-		"PageContentSaveComplete": "Jade\\Hooks\\LinkSummaryHooks::onPageContentSaveComplete"
-	},
-	"MessagesDirs": {
-		"Jade": [
-			"i18n",
-			"i18n/api"
-		]
-	},
-	"ServiceWiringFiles": [
-		"includes/ServiceWiring.php"
-	],
-	"config": {
-		"JadeAllowedScoringSchemas": {
-			"value": {
-				"diff": [
-					"damaging",
-					"goodfaith"
-				],
-				"revision": [
-					"contentquality"
-				]
-			}
-		},
-		"JadeEntityTypeNames": {
-			"value": {
-				"diff": "Diff",
-				"revision": "Revision"
-			}
-		},
-		"JadeContentQualityLevels": {
-			"value": 6
-		}
-	},
-	"ExtensionMessagesFiles": {
-		"JadeNamespaces": "Jade.namespaces.php"
-	},
-	"manifest_version": 2
-}
diff --git a/i18n/api/ar.json b/i18n/api/ar.json
deleted file mode 100644
index 298aa45..0000000
--- a/i18n/api/ar.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"ديفيد"
-		]
-	},
-	"apihelp-createjudgment-summary": "إنشاء حكم جديد",
-	"apihelp-createjudgment-param-entitytype": "يمكن أن يكون نوع كيان الويكي المستهدف هو \"فرق\" أو \"مراجعة\" أو \"صفحة\".",
-	"apihelp-createjudgment-param-entityid": "معرف المراجعة لأهداف الفرق والمراجعة، معرف الصفحة لنوع هدف التاريخ.",
-	"apihelp-createjudgment-param-schema": "مخطط التهديف الذي يستخدمه هذا الحكم، إما \"ضار\" أو \"حسن النية\" أو \"wp10\" أو \"مسودة موضوعية\".",
-	"apihelp-createjudgment-param-data": "بيانات التهديف الخام، يتم تفسير data=\"true\" و\"false\" على أنها بوليان.",
-	"apihelp-createjudgment-param-notes": "نص اختياري يشرح الحكم.",
-	"apihelp-createjudgment-param-summary": "ملخص التعديل الاختياري.",
-	"apihelp-createjudgment-param-tags": "وسوم تغيير اختيارية لتطبيقها على الحكم.",
-	"apihelp+jade-createjudgment-example": "أنشئ حكما يقول أن الفرق #3 ضار.",
-	"apihelp-query+getjudgments-param-entitytype": "يمكن أن يكون نوع كيان الويكي المستهدف هو \"فرق\" أو \"مراجعة\" أو \"صفحة\".",
-	"apihelp-query+getjudgments-param-entityid": "معرف المراجعة لأهداف الفرق والمراجعة، معرف الصفحة لنوع هدف التاريخ.",
-	"apihelp-query+getjudgments-summary": "احصل على أية أحكام متاحة لكيان ويكي.",
-	"apihelp-query+jade-getjudgments-list-example": "صفحة قائمة حكم الفرق #3.",
-	"apihelp-query+jade-getjudgments-generator-example": "الحصول على محتوى الحكم للفرق #3."
-}
diff --git a/i18n/api/ast.json b/i18n/api/ast.json
deleted file mode 100644
index cf1f2b8..0000000
--- a/i18n/api/ast.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Xuacu"
-		]
-	},
-	"apihelp-createjudgment-summary": "Crear un xuiciu nuevu",
-	"apihelp-createjudgment-param-entitytype": "Tipu d'entidá wiki de destín, puede ser una \"diff\", \"revision\", o \"páxina\".",
-	"apihelp-createjudgment-param-notes": "Testu opcional pa esplicar el xuiciu.",
-	"apihelp-createjudgment-param-summary": "Resume d'edición opcional."
-}
diff --git a/i18n/api/de.json b/i18n/api/de.json
deleted file mode 100644
index af7f40f..0000000
--- a/i18n/api/de.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Metalhead64"
-		]
-	},
-	"apihelp-createjudgment-summary": "Erstellt eine neue Beurteilung.",
-	"apihelp-createjudgment-param-entitytype": "Elementtyp des Zielwikis. Kann „diff“, „revision“ oder „page“ sein.",
-	"apihelp-createjudgment-param-entityid": "Versionskennung für den Unterschied und Versionsziele, Seitenkennung für den Datumszieltyp.",
-	"apihelp-createjudgment-param-schema": "Das von dieser Beurteilung verwendete Bewertungsschema, entweder „damaging“, „goodfaith“, „wp10“ oder „drafttopic“.",
-	"apihelp-createjudgment-param-data": "Rohe Bewertungsdaten. data=\"true\" und \"false\" werden als boolesch interpretiert.",
-	"apihelp-createjudgment-param-notes": "Optionaler Text, der die Beurteilung erklärt.",
-	"apihelp-createjudgment-param-summary": "Optionale Bearbeitungszusammenfassung.",
-	"apihelp-createjudgment-param-tags": "Optionale auf die Beurteilung anzuwendende Änderungsmarkierungen.",
-	"apihelp+jade-createjudgment-example": "Erstellt eine Beurteilung, die aussagt, dass der Unterschied 3 schädlich ist.",
-	"apihelp-query+getjudgments-param-entitytype": "Elementtyp des Zielwikis. Kann „diff“, „revision“ oder „page“ sein.",
-	"apihelp-query+getjudgments-param-entityid": "Versionskennung für den Unterschied und Versionsziele, Seitenkennung für den Datumszieltyp.",
-	"apihelp-query+getjudgments-summary": "Ruft beliebige verfügbare Beurteilungen für ein Wikielement ab.",
-	"apihelp-query+jade-getjudgments-list-example": "Listet die Beurteilungsseite für den Unterschied 3 auf.",
-	"apihelp-query+jade-getjudgments-generator-example": "Ruft den Beurteilungsinhalt für den Unterschied 3 ab."
-}
diff --git a/i18n/api/el.json b/i18n/api/el.json
deleted file mode 100644
index 826098e..0000000
--- a/i18n/api/el.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Nikosgranturismogt"
-		]
-	},
-	"apihelp-createjudgment-summary": "Δημιουργία νέας κρίσης",
-	"apihelp-createjudgment-param-entityid": "Αναγνωριστικό αναθεώρησης για στόχους διαφοράς και αναθεώρησης, αναγνωριστικό σελίδας για τύπο στόχου ημερομηνίας.",
-	"apihelp-createjudgment-param-notes": "Προαιρετικό κείμενο που εξηγεί την απόφαση.",
-	"apihelp-createjudgment-param-summary": "Προαιρετική σύνοψη επεξεργασίας.",
-	"apihelp-createjudgment-param-tags": "Προαιρετικές ετικέτες αλλαγές για την εφαρμογή της σκέψης."
-}
diff --git a/i18n/api/en.json b/i18n/api/en.json
deleted file mode 100644
index 08efeee..0000000
--- a/i18n/api/en.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Adamw"
-		]
-	},
-	"apihelp-createjudgment-summary": "Create a new judgment",
-	"apihelp-createjudgment-param-entitytype": "Target wiki entity type, can be a \"diff\", \"revision\", or \"page\".",
-	"apihelp-createjudgment-param-entityid": "Revision ID for diff and revision targets, page ID for date target type.",
-	"apihelp-createjudgment-param-schema": "Scoring schema used by this judgment, either \"damaging\", \"goodfaith\", \"wp10\", or \"drafttopic\".",
-	"apihelp-createjudgment-param-data": "Raw scoring data.  data=\"true\" and \"false\" are interpreted as booleans.",
-	"apihelp-createjudgment-param-notes": "Optional text explaining the judgment.",
-	"apihelp-createjudgment-param-summary": "Optional edit summary.",
-	"apihelp-createjudgment-param-tags": "Optional change tags to apply to the judgment.",
-	"apihelp+jade-createjudgment-example": "Create a judgment saying that diff #3 is damaging.",
-	"apihelp-query+getjudgments-param-entitytype": "Target wiki entity type, can be a \"diff\", \"revision\", or \"page\".",
-	"apihelp-query+getjudgments-param-entityid": "Revision ID for diff and revision targets, page ID for date target type.",
-	"apihelp-query+getjudgments-summary": "Get any available judgments for a wiki entity.",
-	"apihelp-query+jade-getjudgments-list-example": "List judgment page for diff #3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Get judgment content for diff #3."
-}
diff --git a/i18n/api/es.json b/i18n/api/es.json
deleted file mode 100644
index cdaf287..0000000
--- a/i18n/api/es.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Yllelder"
-		]
-	},
-	"apihelp-createjudgment-param-summary": "Resumen de edición opcional."
-}
diff --git a/i18n/api/fr.json b/i18n/api/fr.json
deleted file mode 100644
index 47f6ee1..0000000
--- a/i18n/api/fr.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Gomoko",
-			"Wladek92"
-		]
-	},
-	"apihelp-createjudgment-summary": "Créer un nouveau jugement",
-	"apihelp-createjudgment-param-entitytype": "Type d’entité du wiki cible, peut être « diff », « revision » ou « page ».",
-	"apihelp-createjudgment-param-entityid": "ID de révision pour les cibles diff et revision, ID de page pour le type de cible date.",
-	"apihelp-createjudgment-param-schema": "Schéma de notation utilisé par ce jugement, soit « damaging », « goodfaith », « wp10 » ou « drafttopic ».",
-	"apihelp-createjudgment-param-data": "Données de notation brutes. data=\"true\" et \"false\" sont interprétés comme des booléens.",
-	"apihelp-createjudgment-param-notes": "Texte facultatif expliquant le jugement.",
-	"apihelp-createjudgment-param-summary": "Résumé facultatif de la modification.",
-	"apihelp-createjudgment-param-tags": "Balises facultatives de la modification à appliquer au jugement.",
-	"apihelp+jade-createjudgment-example": "Créer un jugement disant que diff #3 est endommagé.",
-	"apihelp-query+getjudgments-param-entitytype": "Type d’entité du wiki cible, peut être « diff », « revision » ou « page ».",
-	"apihelp-query+getjudgments-param-entityid": "ID de révision pour les cibles diff et revision, ID de page pour le type de cible date.",
-	"apihelp-query+getjudgments-summary": "Obtenir des jugements disponibles pour une entité wiki.",
-	"apihelp-query+jade-getjudgments-list-example": "Lister la page de jugement pour le diff #3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Obtenir le contenu du jugement pour diff #3."
-}
diff --git a/i18n/api/he.json b/i18n/api/he.json
deleted file mode 100644
index 4494712..0000000
--- a/i18n/api/he.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Amire80",
-			"Guycn2"
-		]
-	},
-	"apihelp-createjudgment-summary": "יצירת שיפוט חדש",
-	"apihelp-createjudgment-param-entitytype": "סוג ישות הוויקי של היעד, יכול להיות \"diff\"‏, \"revision\" או \"page\".",
-	"apihelp-createjudgment-param-entityid": "מזהה גרסה עבור יעדי השוואה וגרסה, מזהה דף עבור סוג היעד.",
-	"apihelp-createjudgment-param-schema": "סכמת דירוג שמשמשת בשפיטה הזאת, אחד מ־\"damaging\"‏, \"goodfaith\"‏, \"wp10\", או \"drafttopic\".",
-	"apihelp-createjudgment-param-data": "נתוני דירוג גולמיים. data=\"true\"‎ ו־\"false\" מתפרשים בתור ערכים בוליאניים.",
-	"apihelp-createjudgment-param-notes": "טקסט, שלא חובה לרשום, שמסביר את השיפוט.",
-	"apihelp-createjudgment-param-summary": "תקציר עריכה, לא חובה.",
-	"apihelp-createjudgment-param-tags": "תגי שינוי, לא חובה, שיחולו על השיפוט.",
-	"apihelp+jade-createjudgment-example": "יצירת שיפוט באמצעות אמירה שהשוואה #3 היא מזיקה (damaging).",
-	"apihelp-query+getjudgments-param-entitytype": "סוג הישות בוויקי היעד, יכול להיות \"diff\"‏, \"revision\", או \"page\".",
-	"apihelp-query+getjudgments-param-entityid": "מזהה גרסה עבור יעדי השוואה וגרסה, מזהה דף עבור סוג יעד תאריך.",
-	"apihelp-query+getjudgments-summary": "קבלת כל השיפורים עבור ישות ויקי.",
-	"apihelp-query+jade-getjudgments-list-example": "דף רשימת שיפוט עבור ההשוואה #3.",
-	"apihelp-query+jade-getjudgments-generator-example": "קבלת נתוני שיפוט עבור ההשוואה #3."
-}
diff --git a/i18n/api/ko.json b/i18n/api/ko.json
deleted file mode 100644
index a6972b8..0000000
--- a/i18n/api/ko.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ykhwong"
-		]
-	},
-	"apihelp-createjudgment-param-entitytype": "대상 위키 엔티티 타입으로, \"diff\", \"revision\" 또는 \"page\"가 올 수 있습니다.",
-	"apihelp-createjudgment-param-summary": "선택적 편집 요약입니다.",
-	"apihelp-query+getjudgments-param-entitytype": "대상 위키 엔티티 타입으로, \"diff\", \"revision\" 또는 \"page\"가 올 수 있습니다."
-}
diff --git a/i18n/api/mk.json b/i18n/api/mk.json
deleted file mode 100644
index f3f62f6..0000000
--- a/i18n/api/mk.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Bjankuloski06"
-		]
-	},
-	"apihelp-createjudgment-summary": "Создај нов суд",
-	"apihelp-createjudgment-param-entitytype": "Целна вид викиединица, може да биде „diff“, „revision“ или „page“.",
-	"apihelp-createjudgment-param-entityid": "Назнака на преработката за разликата и целта на преработката, назнака на страницата за видот на датумска цел",
-	"apihelp-createjudgment-param-schema": "Шемата на оценување која се користи во ова просудување; може да биде „damaging“, „goodfaith“, „wp10“ или „drafttopic“.",
-	"apihelp-createjudgment-param-data": "Сирови податоци од оценувањето. data=\"true\" и \"false\" се толкуват како Булови.",
-	"apihelp-createjudgment-param-notes": "Незадолжителен текст во кој се објаснува просудувањето.",
-	"apihelp-createjudgment-param-summary": "Незадолжителен опис на уредувањето.",
-	"apihelp-createjudgment-param-tags": "Незадолжителни ознаки за промената за примена врз просудувањето.",
-	"apihelp+jade-createjudgment-example": "Создај просудување кое вели дека разликата 3 е штетна.",
-	"apihelp-query+getjudgments-param-entitytype": "Целна вид викиединица, може да биде „diff“, „revision“ или „page“.",
-	"apihelp-query+getjudgments-param-entityid": "Назнака на преработката за разликата и целта на преработката, назнака на страницата за типот на датумска цел",
-	"apihelp-query+getjudgments-summary": "Дај ги достапните просудувања за извесна викиединица.",
-	"apihelp-query+jade-getjudgments-list-example": "Наведува страница на просудувањето за разликата 3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Наведува содржина на просудувањето за разликата 3."
-}
diff --git a/i18n/api/mni.json b/i18n/api/mni.json
deleted file mode 100644
index bcfc121..0000000
--- a/i18n/api/mni.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Awangba Mangang"
-		]
-	},
-	"apihelp-createjudgment-summary": "ꯑꯅꯧꯕ ꯋꯥꯌꯦꯜ ꯱ ꯁꯥꯔꯣ"
-}
diff --git a/i18n/api/pt-br.json b/i18n/api/pt-br.json
deleted file mode 100644
index a3383de..0000000
--- a/i18n/api/pt-br.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Eduardo Addad de Oliveira"
-		]
-	},
-	"apihelp-createjudgment-summary": "Criar uma avaliação nova",
-	"apihelp-createjudgment-param-entitytype": "Tipo da entidade alvo na wiki: pode ser lista de \"diferenças\", \"revisão\" ou \"página\".",
-	"apihelp-createjudgment-param-entityid": "Identificador de revisão para destinos de diferenças e revisão, identificador de página para o tipo de data de destino.",
-	"apihelp-createjudgment-param-schema": "Esquema de classificação usado por esta avaliação: \"prejudicial\", \"bem intencionada\", \"wp10\" ou \"rascunho\"",
-	"apihelp-createjudgment-param-data": "Dados de avaliação em bruto. Os valores \"true\" e \"false\" são interpretados como boolianos.",
-	"apihelp-createjudgment-param-notes": "Texto opcional de explicação da avaliação.",
-	"apihelp-createjudgment-param-summary": "Resumo de edição opcional.",
-	"apihelp-createjudgment-param-tags": "Etiquetas de edição opcionais a aplicar à avaliação.",
-	"apihelp+jade-createjudgment-example": "Criar uma avaliação que diz que a lista de diferenças n.º 3 é prejudicial.",
-	"apihelp-query+getjudgments-param-entitytype": "Tipo da entidade alvo na wiki: pode ser lista de \"diferenças\", \"revisão\" ou \"página\".",
-	"apihelp-query+getjudgments-param-entityid": "Identificador de revisão para destinos de diferenças e revisão, identificador de página para o tipo de data de destino.",
-	"apihelp-query+getjudgments-summary": "Obter todas as avaliações disponíveis para uma entidade da wiki.",
-	"apihelp-query+jade-getjudgments-list-example": "Listar a página de avaliação da lista de diferenças n.º 3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Obter o conteúdo das avaliações da lista de diferenças n.º 3."
-}
diff --git a/i18n/api/pt.json b/i18n/api/pt.json
deleted file mode 100644
index adb33a3..0000000
--- a/i18n/api/pt.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Hamilton Abreu",
-			"He7d3r"
-		]
-	},
-	"apihelp-createjudgment-summary": "Criar uma avaliação nova",
-	"apihelp-createjudgment-param-entitytype": "Tipo da entidade alvo na wiki: pode ser lista de \"diferenças\", \"revisão\" ou \"página\".",
-	"apihelp-createjudgment-param-entityid": "Identificador de revisão para alvos de tipo \"diferenças\" e \"revisão\", ou identificador de página para alvos de tipo \"data\".",
-	"apihelp-createjudgment-param-schema": "Esquema de classificação usado por esta avaliação: \"damaging\", \"goodfaith\", \"wp10\" ou \"drafttopic\"",
-	"apihelp-createjudgment-param-data": "Dados de avaliação em bruto. Os valores \"true\" e \"false\" são interpretados como boolianos.",
-	"apihelp-createjudgment-param-notes": "Texto opcional de explicação da avaliação.",
-	"apihelp-createjudgment-param-summary": "Resumo de edição opcional.",
-	"apihelp-createjudgment-param-tags": "Etiquetas de edição opcionais a aplicar à avaliação.",
-	"apihelp+jade-createjudgment-example": "Criar uma avaliação que diz que a lista de diferenças n.º 3 é prejudicial.",
-	"apihelp-query+getjudgments-param-entitytype": "Tipo da entidade alvo na wiki: pode ser lista de \"diferenças\", \"revisão\" ou \"página\".",
-	"apihelp-query+getjudgments-param-entityid": "Identificador de revisão para alvos de tipo \"diferenças\" e \"revisão\", ou identificador de página para alvos de tipo \"data\".",
-	"apihelp-query+getjudgments-summary": "Obter todas as avaliações disponíveis para uma entidade da wiki.",
-	"apihelp-query+jade-getjudgments-list-example": "Listar a página de avaliação da lista de diferenças n.º 3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Obter o conteúdo das avaliações da lista de diferenças n.º 3."
-}
diff --git a/i18n/api/qqq.json b/i18n/api/qqq.json
deleted file mode 100644
index 715f8bb..0000000
--- a/i18n/api/qqq.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Adamw",
-			"Robby",
-			"Umherirrender",
-			"Raymond"
-		]
-	},
-	"apihelp-createjudgment-summary": "{{doc-apihelp-summary|createjudgment}}",
-	"apihelp-createjudgment-param-entitytype": "{{doc-apihelp-param|createjudgment|entitytype}}",
-	"apihelp-createjudgment-param-entityid": "{{doc-apihelp-param|createjudgment|entityid}}",
-	"apihelp-createjudgment-param-schema": "{{doc-apihelp-param|createjudgment|schema}}",
-	"apihelp-createjudgment-param-data": "{{doc-apihelp-param|createjudgment|data}}",
-	"apihelp-createjudgment-param-notes": "{{doc-apihelp-param|createjudgment|notes}}",
-	"apihelp-createjudgment-param-summary": "{{doc-apihelp-param|createjudgment|summary}}",
-	"apihelp-createjudgment-param-tags": "{{doc-apihelp-param|createjudgment|tags}}",
-	"apihelp+jade-createjudgment-example": "Description of simple createjudgment API example",
-	"apihelp-query+getjudgments-param-entitytype": "{{doc-apihelp-param|query+getjudgments|entitytype}}",
-	"apihelp-query+getjudgments-param-entityid": "{{doc-apihelp-param|query+getjudgments|entityid}}",
-	"apihelp-query+getjudgments-summary": "{{doc-apihelp-summary|query+getjudgments}}",
-	"apihelp-query+jade-getjudgments-list-example": "Description of getjudgments list API example\n{{doc-apihelp-example|query+getjudgments}}",
-	"apihelp-query+jade-getjudgments-generator-example": "Description of getjudgments generator API example\n{{doc-apihelp-example|query+getjudgments}}"
-}
diff --git a/i18n/api/roa-tara.json b/i18n/api/roa-tara.json
deleted file mode 100644
index b8d720d..0000000
--- a/i18n/api/roa-tara.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Joetaras"
-		]
-	},
-	"apihelp-createjudgment-summary": "Ccrèje 'nu giudizie nuève"
-}
diff --git a/i18n/api/ru.json b/i18n/api/ru.json
deleted file mode 100644
index 0a27184..0000000
--- a/i18n/api/ru.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Vlad5250"
-		]
-	},
-	"apihelp-createjudgment-param-summary": "необязательное описание правки"
-}
diff --git a/i18n/api/sat.json b/i18n/api/sat.json
deleted file mode 100644
index 89a4005..0000000
--- a/i18n/api/sat.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"R Ashwani Banjan Murmu"
-		]
-	},
-	"apihelp-query+jade-getjudgments-generator-example": "ᱡᱩᱫᱟᱹ #᱓ ᱞᱟᱹᱜᱤᱫ ᱵᱤᱪᱟᱹᱨ ᱥᱟᱛᱟᱢ ᱧᱟᱢ ᱢᱮ"
-}
diff --git a/i18n/api/sr-ec.json b/i18n/api/sr-ec.json
deleted file mode 100644
index 673b2f5..0000000
--- a/i18n/api/sr-ec.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"BadDog"
-		]
-	},
-	"apihelp-createjudgment-param-summary": "Опционални резиме измене."
-}
diff --git a/i18n/api/uk.json b/i18n/api/uk.json
deleted file mode 100644
index aa183c3..0000000
--- a/i18n/api/uk.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Piramidion"
-		]
-	},
-	"apihelp-createjudgment-summary": "Створити нову оцінку",
-	"apihelp-createjudgment-param-entitytype": "Тип сутності цільової вікі, може бути «diff», «revision», або «page».",
-	"apihelp-createjudgment-param-entityid": "Ідентифікатор версії для цільових типів «diff» та «revision», ідентифікатор сторінки для цільового типу «date».",
-	"apihelp-createjudgment-param-schema": "Схема оцінювання, використана цією оцінкою: або «damaging«, «goodfaith», «wp10», або «drafttopic».",
-	"apihelp-createjudgment-param-data": "Сирі дані оцінювання. data=\"true\" і \"false\" розцінюються як логічні значення.",
-	"apihelp-createjudgment-param-notes": "Необов'язковий текст, що пояснює оцінку.",
-	"apihelp-createjudgment-param-summary": "Необов'язковий опис редагування.",
-	"apihelp-createjudgment-param-tags": "Необов'язкові мітки редагування для застосування до оцінки.",
-	"apihelp+jade-createjudgment-example": "Створити оцінку, яка стверджує, що версія #3 є шкідливою.",
-	"apihelp-query+getjudgments-param-entitytype": "Тип сутності цільової вікі, може бути «diff», «revision», або «page».",
-	"apihelp-query+getjudgments-param-entityid": "Ідентифікатор версії для цільових типів «diff» та «revision», ідентифікатор сторінки для цільового типу «date».",
-	"apihelp-query+getjudgments-summary": "Отримати будь-які доступні оцінки для сутності вікі.",
-	"apihelp-query+jade-getjudgments-list-example": "Вивести список сторінки оцінок для версії #3.",
-	"apihelp-query+jade-getjudgments-generator-example": "Отримати вміст оцінки для версії #3."
-}
diff --git a/i18n/api/zh-hans.json b/i18n/api/zh-hans.json
deleted file mode 100644
index 685aea2..0000000
--- a/i18n/api/zh-hans.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"A Chinese Wikipedian",
-			"夢蝶葬花"
-		]
-	},
-	"apihelp-createjudgment-summary": "创建新活动",
-	"apihelp-createjudgment-param-summary": "可选的编辑摘要。",
-	"apihelp-createjudgment-param-tags": "可选的更改标记以应用于判断。"
-}
diff --git a/i18n/api/zh-hant.json b/i18n/api/zh-hant.json
deleted file mode 100644
index 21a93b1..0000000
--- a/i18n/api/zh-hant.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Kly"
-		]
-	},
-	"apihelp-createjudgment-summary": "建立新判斷",
-	"apihelp-createjudgment-param-entitytype": "目標 wiki 項目類型,可以是「變動(diff)」、「修訂(revision)」、或「頁面(page)」。",
-	"apihelp-createjudgment-param-entityid": "修訂 ID 用於變動與修訂目標,頁面 ID 用於日期目標類型。",
-	"apihelp-createjudgment-param-schema": "由此判斷使用的記分架構,可以是「damaging」、「goodfaith」、「wp10」、或是「drafttopic」。",
-	"apihelp-createjudgment-param-data": "原始記分資料。資料以「true」與「false」來解讀為布林值。",
-	"apihelp-createjudgment-param-notes": "解釋判斷的可選文字。",
-	"apihelp-createjudgment-param-summary": "可選編輯摘要。",
-	"apihelp-createjudgment-param-tags": "套用到判斷的可選更改標籤。",
-	"apihelp+jade-createjudgment-example": "建立反應出變動 #3 為帶有毀謗的判斷。",
-	"apihelp-query+getjudgments-param-entitytype": "目標 wiki 項目類型,可以是「變動(diff)」、「修訂(revision)」、或「頁面(page)」。",
-	"apihelp-query+getjudgments-param-entityid": "修訂 ID 用於變動與修訂目標,頁面 ID 用於日期目標類型。",
-	"apihelp-query+getjudgments-summary": "取得 wiki 項目的任何可用判斷。",
-	"apihelp-query+jade-getjudgments-list-example": "列出變動 #3 的判斷頁面。",
-	"apihelp-query+jade-getjudgments-generator-example": "取得變動 #3 的判斷內容。"
-}
diff --git a/i18n/ar.json b/i18n/ar.json
deleted file mode 100644
index 5897171..0000000
--- a/i18n/ar.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"ديفيد",
-			"محمد أحمد عبد الفتاح",
-			"Meno25"
-		]
-	},
-	"jade-desc": "Judgment ومحرك الحوار",
-	"jade-damaging-scale-true-label": "مدمر",
-	"jade-damaging-scale-false-label": "غير مدمر",
-	"jade-goodfaith-scale-true-label": "نية حسنة",
-	"jade-goodfaith-scale-false-label": "نية سيئة",
-	"jade-contentquality-scale-1-label": "مقالة من الرتبة بذرة",
-	"jade-contentquality-scale-2-label": "مقال بدرجة بداية",
-	"jade-contentquality-scale-3-label": "مقال بدرجة ج",
-	"jade-contentquality-scale-4-label": "مقال بدرجة ب",
-	"jade-contentquality-scale-5-label": "مقالة جيدة",
-	"jade-contentquality-scale-6-label": "مقالة مختارة",
-	"jade-contentquality-generic": "جودة المحتوى \"$1\"",
-	"jade-new-judgment": "حكم جديد",
-	"jade-add-judgment": "إضافة الحكم",
-	"jade-notes-placeholder": "ملاحظات حول الحكم",
-	"jade-delete": "حذف",
-	"jade-bad-title-format": "تنسيق تاريخ غير صالح.",
-	"jade-bad-title-namespace": "نطاق غير صالح للحصول على عنوان حكم.",
-	"jade-non-canonical-title": "يجب أن يكون للعنوان الشكل الأساسي ''$1''.",
-	"jade-bad-entity-type": "نوع كيان غير صالح ''$1''",
-	"jade-bad-entity-id-format": "تنسيق معرف كيان غير صالح ''$1''",
-	"jade-bad-revision-id": "لا يمكن العثور على مراجعة بالمعرف: ''$1''",
-	"jade-bad-content-generic": "أخطاء في بناء الجملة في محتوى JSON.",
-	"jade-bad-content": "لا يتوافق الحكم مع المخطط: $1",
-	"jade-too-many-preferred": "أحكام متعددة مفضلة، ولكن يمكن أن يكون هناك واحد فقط.",
-	"jade-none-preferred": "لا توجد أحكام مفضلة، ولكن يجب أن يكون هناك اختيار واحد.",
-	"jade-illegal-schema": "المخطط ''$1'' غير مسموح به لهذا النوع من الكيان.",
-	"jade-user-local-id-invalid": "المعرف المحلي للمستخدم ''$1'' غير موجود.",
-	"jade-user-central-id-invalid": "المعرف المركزي للمستخدم ''$1'' غير موجود.",
-	"jade-user-id-mismatch": "المعرف المحلي للمستخدم ''$1'' والمعرف المركزي ''$2'' يعرفان مستخدمين مختلفين.",
-	"jade-user-ip-invalid": "عنوان الأيبي ''$1'' غير صحيح.",
-	"jade-created-timestamp-invalid": "الطابع الزمني المنشأ بواسطة الدعم غير صحيح: ''$1''",
-	"jade-bad-contentquality-value": "يجب أن يكون المؤشر السيئ ''$1'' في مخطط جودة المحتوى، مستوى جودة يتراوح بين 1 و$2.",
-	"jade-cannot-create-page": "لا يمكنك إنشاء هذه الصفحة.",
-	"jade-cannot-edit-page": "لا يمكنك تحرير هذه الصفحة.",
-	"jade-invalid-move-any": "نقل صفحات الحكم غير مسموح به.",
-	"jade-db-error": "خطأ في قاعدة البيانات: $1",
-	"jade-content-model-error": "نموذج محتوى غير صحيح للحكم.",
-	"jade-endorsement": "المصادقة",
-	"jade-endorsements": "موافقات",
-	"jade-user": "المستخدم"
-}
diff --git a/i18n/ast.json b/i18n/ast.json
deleted file mode 100644
index 69a1172..0000000
--- a/i18n/ast.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Xuacu"
-		]
-	},
-	"jade-desc": "Motor de xuiciu y diálogu",
-	"jade-damaging-scale-true-label": "Dañible",
-	"jade-damaging-scale-false-label": "Non dañible",
-	"jade-goodfaith-scale-true-label": "Bona fe",
-	"jade-goodfaith-scale-false-label": "Mala fe",
-	"jade-new-judgment": "Nueva valoración",
-	"jade-add-judgment": "Añadir valoración",
-	"jade-notes-placeholder": "Notes sobro la valoración",
-	"jade-delete": "Desaniciar"
-}
diff --git a/i18n/be-tarask.json b/i18n/be-tarask.json
deleted file mode 100644
index 7435a79..0000000
--- a/i18n/be-tarask.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Red Winged Duck"
-		]
-	},
-	"jade-desc": "Рухавік ацэнак і дыялёгаў"
-}
diff --git a/i18n/bn.json b/i18n/bn.json
deleted file mode 100644
index 22886fc..0000000
--- a/i18n/bn.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"আফতাবুজ্জামান"
-		]
-	},
-	"jade-delete": "অপসারণ"
-}
diff --git a/i18n/ce.json b/i18n/ce.json
deleted file mode 100644
index b1173fa..0000000
--- a/i18n/ce.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Умар"
-		]
-	},
-	"jade-delete": "ДӀаяккха"
-}
diff --git a/i18n/cs.json b/i18n/cs.json
deleted file mode 100644
index 7191ef4..0000000
--- a/i18n/cs.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ilimanaq29"
-		]
-	},
-	"jade-desc": "Nástroj rozsudku a dialogu"
-}
diff --git a/i18n/da.json b/i18n/da.json
deleted file mode 100644
index 677c933..0000000
--- a/i18n/da.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Saederup92"
-		]
-	},
-	"jade-damaging-scale-true-label": "Skadelig",
-	"jade-damaging-scale-false-label": "Ikke skadelig",
-	"jade-goodfaith-scale-true-label": "God hensigt",
-	"jade-goodfaith-scale-false-label": "Ond hensigt",
-	"jade-contentquality-scale-3-label": "C-klasse artikel",
-	"jade-contentquality-scale-4-label": "B-klasse artikel",
-	"jade-contentquality-scale-5-label": "God artikel",
-	"jade-contentquality-scale-6-label": "Fremhævet artikel",
-	"jade-contentquality-generic": "Indholds kvalitet \"$1\"",
-	"jade-delete": "Slet",
-	"jade-user-ip-invalid": "IP-adressen ''$1'' er ugyldig.",
-	"jade-cannot-edit-page": "Du kan ikke redigere denne side.",
-	"jade-db-error": "Databasefejl: $1",
-	"jade-user": "Bruger"
-}
diff --git a/i18n/de.json b/i18n/de.json
deleted file mode 100644
index b1adeba..0000000
--- a/i18n/de.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Metalhead64"
-		]
-	},
-	"jade-desc": "Beurteilungs- und Dialogengine",
-	"jade-damaging-scale-true-label": "Schädlich",
-	"jade-damaging-scale-false-label": "Nicht schädlich",
-	"jade-goodfaith-scale-true-label": "Gute Absicht",
-	"jade-goodfaith-scale-false-label": "Schlechte Absicht",
-	"jade-contentquality-scale-1-label": "Stubklassen-Artikel",
-	"jade-contentquality-scale-2-label": "Startklassenartikel",
-	"jade-contentquality-scale-3-label": "C-Klassen-Artikel",
-	"jade-contentquality-scale-4-label": "B-Klassen-Artikel",
-	"jade-contentquality-scale-5-label": "Guter Artikel",
-	"jade-contentquality-scale-6-label": "Vorgestellter Artikel",
-	"jade-contentquality-generic": "Inhaltsqualität „$1“",
-	"jade-new-judgment": "Neue Beurteilung",
-	"jade-add-judgment": "Beurteilung hinzufügen",
-	"jade-notes-placeholder": "Anmerkungen zur Beurteilung",
-	"jade-delete": "Löschen",
-	"jade-bad-title-format": "Ungültiges Titelformat",
-	"jade-bad-title-namespace": "Ungültiger Namensraum für einen Beurteilungstitel.",
-	"jade-non-canonical-title": "Der Titel sollte die kanonische Form ''$1'' haben.",
-	"jade-bad-entity-type": "Ungültiger Objekttyp ''$1''",
-	"jade-bad-entity-id-format": "Ungültiges Objektkennung-Format ''$1''",
-	"jade-bad-revision-id": "Die Version nach Kennung konnte nicht gefunden werden: ''$1''",
-	"jade-bad-content-generic": "Syntaxfehler im JSON-Inhalt.",
-	"jade-bad-content": "Die Beurteilung ist nicht mit dem Schema konform: $1",
-	"jade-too-many-preferred": "Es werden mehrere Beurteilungen bevorzugt, es kann jedoch nur eine geben.",
-	"jade-none-preferred": "Es werden keine Beurteilungen bevorzugt, es muss jedoch eine ausgewählt werden.",
-	"jade-illegal-schema": "Das Schema ''$1'' ist für diesen Objekttyp nicht erlaubt.",
-	"jade-user-local-id-invalid": "Der Benutzer mit der lokalen Kennung ''$1'' ist nicht vorhanden.",
-	"jade-user-central-id-invalid": "Der Benutzer mit der zentralen Kennung ''$1'' ist nicht vorhanden.",
-	"jade-user-id-mismatch": "Der Benutzer mit der lokalen Kennung ''$1'' und der zentralen Kennung ''$2'' identifizieren unterschiedliche Benutzer.",
-	"jade-user-ip-invalid": "Die IP-Adresse ''$1'' ist ungültig.",
-	"jade-created-timestamp-invalid": "Der Zeitstempel der Erstellung der Bestätigung ist ungültig: ''$1''",
-	"jade-bad-contentquality-value": "Ungültiger Index ''$1'' im Inhaltsqualitätsschema, muss ein Qualitätsniveau zwischen 1 und $2 sein.",
-	"jade-cannot-create-page": "Du kannst diese Seite nicht erstellen.",
-	"jade-cannot-edit-page": "Du kannst diese Seite nicht bearbeiten.",
-	"jade-invalid-move-any": "Das Verschieben von Beurteilungsseiten ist nicht erlaubt.",
-	"jade-db-error": "Datenbankfehler: $1",
-	"jade-content-model-error": "Falsches Inhaltsmodell für die Beurteilung.",
-	"jade-endorsement": "Bestätigung",
-	"jade-endorsements": "Bestätigungen",
-	"jade-user": "Benutzer"
-}
diff --git a/i18n/diq.json b/i18n/diq.json
deleted file mode 100644
index 5eda222..0000000
--- a/i18n/diq.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Mirzali"
-		]
-	},
-	"jade-db-error": "Xetaya ardoği:$1",
-	"jade-endorsement": "Tesdiq",
-	"jade-endorsements": "Tesdiqi",
-	"jade-user": "Karber"
-}
diff --git a/i18n/el.json b/i18n/el.json
deleted file mode 100644
index e4501f6..0000000
--- a/i18n/el.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Nikosgranturismogt"
-		]
-	},
-	"jade-damaging-scale-true-label": "Επιζήμια",
-	"jade-damaging-scale-false-label": "Μη ζημιοφόρο",
-	"jade-goodfaith-scale-true-label": "Καλής πίστης",
-	"jade-goodfaith-scale-false-label": "Κακής πίστης",
-	"jade-contentquality-scale-1-label": "Λήμματα τάξης προς επέκταση",
-	"jade-contentquality-scale-2-label": "Λήμματα τάξης Έναρξη",
-	"jade-contentquality-scale-3-label": "Λήμμα Τάξης Γ",
-	"jade-contentquality-scale-4-label": "Λήμματα τάξης Β",
-	"jade-contentquality-scale-5-label": "Καλό λήμμα",
-	"jade-contentquality-scale-6-label": "Προβεβλημένο λήμμα",
-	"jade-new-judgment": "Νέα κρίση",
-	"jade-add-judgment": "Προσθήκη κρίσης",
-	"jade-delete": "Διαγραφή"
-}
diff --git a/i18n/en-gb.json b/i18n/en-gb.json
deleted file mode 100644
index 9ad2154..0000000
--- a/i18n/en-gb.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Pasianssi",
-			"Sau226"
-		]
-	},
-	"jade-delete": "Delete"
-}
diff --git a/i18n/en.json b/i18n/en.json
deleted file mode 100644
index d21542a..0000000
--- a/i18n/en.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Adamw"
-		]
-	},
-	"jade-desc": "Judgment and dialog engine",
-	"jade-damaging-scale-true-label": "Damaging",
-	"jade-damaging-scale-false-label": "Not damaging",
-	"jade-goodfaith-scale-true-label": "Good faith",
-	"jade-goodfaith-scale-false-label": "Bad faith",
-	"jade-contentquality-scale-1-label": "Stub-class article",
-	"jade-contentquality-scale-2-label": "Start-class article",
-	"jade-contentquality-scale-3-label": "C-class article",
-	"jade-contentquality-scale-4-label": "B-class article",
-	"jade-contentquality-scale-5-label": "Good article",
-	"jade-contentquality-scale-6-label": "Featured article",
-	"jade-contentquality-generic": "Content quality \"$1\"",
-	"jade-new-judgment": "New judgment",
-	"jade-add-judgment": "Add judgment",
-	"jade-notes-placeholder": "Notes about the judgment",
-	"jade-delete": "Delete",
-	"jade-bad-title-format": "Invalid title format",
-	"jade-bad-title-namespace": "Invalid namespace for a judgment title.",
-	"jade-non-canonical-title": "Title should have canonical form ''$1''.",
-	"jade-bad-entity-type": "Invalid entity type ''$1''",
-	"jade-bad-entity-id-format": "Invalid entity ID format ''$1''",
-	"jade-bad-revision-id": "Cannot find revision by ID: ''$1''",
-	"jade-bad-content-generic": "Syntax errors in JSON content.",
-	"jade-bad-content": "Judgment doesn't conform to schema: $1",
-	"jade-too-many-preferred": "Multiple judgments preferred, but there can be only one.",
-	"jade-none-preferred": "No judgments are preferred, but there must be a chosen one.",
-	"jade-illegal-schema": "Schema ''$1'' not allowed for this entity type.",
-	"jade-user-local-id-invalid": "User local ID ''$1'' doesn't exist.",
-	"jade-user-central-id-invalid": "User central ID ''$1'' doesn't exist.",
-	"jade-user-id-mismatch": "User local ID ''$1'' and central ID ''$2'' identify different users.",
-	"jade-user-ip-invalid": "IP address ''$1'' is invalid.",
-	"jade-created-timestamp-invalid": "Endorsement created timestamp is invalid: ''$1''",
-	"jade-bad-contentquality-value": "Bad index ''$1'' into the content quality schema, must be a quality level between 1 and $2.",
-	"jade-cannot-create-page": "You cannot create this page.",
-	"jade-cannot-edit-page": "You cannot edit this page.",
-	"jade-invalid-move-any": "Moving judgment pages is not allowed.",
-	"jade-db-error": "Database error: $1",
-	"jade-content-model-error": "Wrong content model for judgment.",
-	"jade-endorsement": "Endorsement",
-	"jade-endorsements": "Endorsements",
-	"jade-user": "User"
-}
diff --git a/i18n/es.json b/i18n/es.json
deleted file mode 100644
index fd5892d..0000000
--- a/i18n/es.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Fitoschido",
-			"MarcoAurelio",
-			"Yllelder"
-		]
-	},
-	"jade-desc": "Motor de valoración y diálogo",
-	"jade-damaging-scale-true-label": "Dañina",
-	"jade-damaging-scale-false-label": "Productiva",
-	"jade-goodfaith-scale-true-label": "Buena fe",
-	"jade-goodfaith-scale-false-label": "Mala fe",
-	"jade-contentquality-scale-6-label": "Artículo destacado",
-	"jade-new-judgment": "Nueva valoración",
-	"jade-add-judgment": "Añadir valoración",
-	"jade-notes-placeholder": "Notas acerca de la valoración",
-	"jade-delete": "Borrar",
-	"jade-bad-content-generic": "Error de sintaxis en el contenido JSON.",
-	"jade-user-ip-invalid": "La dirección IP \"$1\" no es válida.",
-	"jade-cannot-create-page": "No puedes crear esta página.",
-	"jade-cannot-edit-page": "No puedes editar esta página.",
-	"jade-db-error": "Error de la base de datos: $1",
-	"jade-user": "Usuario"
-}
diff --git a/i18n/fa.json b/i18n/fa.json
deleted file mode 100644
index b6865fb..0000000
--- a/i18n/fa.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ladsgroup",
-			"درفش کاویانی",
-			"Amirsara"
-		]
-	},
-	"jade-damaging-scale-true-label": "آسیب‌زننده",
-	"jade-damaging-scale-false-label": "آسیب‌زننده نیست",
-	"jade-goodfaith-scale-true-label": "حسن‌نیت",
-	"jade-goodfaith-scale-false-label": "سونیت",
-	"jade-contentquality-scale-1-label": "مقالهٔ سطح خُرد",
-	"jade-contentquality-scale-3-label": "مقالهٔ سطح پ",
-	"jade-contentquality-scale-4-label": "مقالهٔ سطح ب",
-	"jade-contentquality-scale-5-label": "مقالهٔ خوب",
-	"jade-contentquality-scale-6-label": "مقالهٔ برگزیده",
-	"jade-contentquality-generic": "کیفیت محتوا «$1»",
-	"jade-delete": "حذف",
-	"jade-user": "کاربر"
-}
diff --git a/i18n/fi.json b/i18n/fi.json
deleted file mode 100644
index 613dd61..0000000
--- a/i18n/fi.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Nike"
-		]
-	},
-	"jade-damaging-scale-true-label": "Haitallinen",
-	"jade-damaging-scale-false-label": "Ei haitallinen",
-	"jade-goodfaith-scale-true-label": "Hyväntahtoinen",
-	"jade-goodfaith-scale-false-label": "Pahantahtoinen",
-	"jade-delete": "Poista"
-}
diff --git a/i18n/fr.json b/i18n/fr.json
deleted file mode 100644
index da3c9d5..0000000
--- a/i18n/fr.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Gomoko",
-			"Wladek92",
-			"Zarisi",
-			"Tartare"
-		]
-	},
-	"jade-desc": "Moteur de verdict et de dialogue",
-	"jade-damaging-scale-true-label": "Nuisible",
-	"jade-damaging-scale-false-label": "Non nuisible",
-	"jade-goodfaith-scale-true-label": "Bonne foi",
-	"jade-goodfaith-scale-false-label": "Mauvaise foi",
-	"jade-contentquality-scale-1-label": "Article de classe ébauche",
-	"jade-contentquality-scale-2-label": "Article de classe démarrage",
-	"jade-contentquality-scale-3-label": "Article de classe C",
-	"jade-contentquality-scale-4-label": "Article de classe B",
-	"jade-contentquality-scale-5-label": "Bon article",
-	"jade-contentquality-scale-6-label": "Article en vedette",
-	"jade-contentquality-generic": "Qualité du contenu « $1 »",
-	"jade-new-judgment": "Nouveau jugement",
-	"jade-add-judgment": "Ajouter un jugement",
-	"jade-notes-placeholder": "Notes sur le jugement",
-	"jade-delete": "Supprimer",
-	"jade-bad-title-format": "Format de titre invalide",
-	"jade-bad-title-namespace": "Espace de noms non valide pour un titre d'appréciation.",
-	"jade-non-canonical-title": "Le titre doit avoir la forme canonique ''$1''.",
-	"jade-bad-entity-type": "Type invalide d'entité « $1 »",
-	"jade-bad-entity-id-format": "Format non valide de l'entité d'ID « $1 »",
-	"jade-bad-revision-id": "Version non trouvée avec l'ID: « $1 »",
-	"jade-bad-content-generic": "Erreurs de syntaxe dans le contenu JSON.",
-	"jade-bad-content": "L'appréciation n'est pas conforme au schéma: $1",
-	"jade-too-many-preferred": "Préférence aux appréciations multiples, mais une seule est autorisée.",
-	"jade-none-preferred": "Pas de préférence d'avis, mais il en faut un.",
-	"jade-illegal-schema": "Schéma « $1 » non autorisé pour ce type d'entité.",
-	"jade-user-local-id-invalid": "L’ID d’utilisateur local « $1 » n’existe pas.",
-	"jade-user-central-id-invalid": "L’ID d’utilisateur central « $1 » n’existe pas.",
-	"jade-user-id-mismatch": "L’ID de l’utilisateur local « $1 » et l’ID central « $2 » identifient des utilisateurs différents.",
-	"jade-user-ip-invalid": "L’adresse IP « $1 » n’est pas valide.",
-	"jade-created-timestamp-invalid": "L'horodatage créé par l'endossement est invalide: « $1 »",
-	"jade-bad-contentquality-value": "Mauvais indice « $1 » pour le schéma de qualité du contenu; le niveau de qualité doit être compris entre 1 et $2 .",
-	"jade-cannot-create-page": "Vous ne pouvez pas créer cette page.",
-	"jade-cannot-edit-page": "Vous ne pouvez pas modifier cette page.",
-	"jade-invalid-move-any": "Le renommage des pages d'appréciation n'est pas autorisé.",
-	"jade-db-error": "Erreur de base de données : $1",
-	"jade-content-model-error": "Mauvais modèle de contenu pour les appréciations.",
-	"jade-endorsement": "Approbation",
-	"jade-endorsements": "Approbation",
-	"jade-user": "Utilisateur"
-}
diff --git a/i18n/gl.json b/i18n/gl.json
deleted file mode 100644
index 72fe4ab..0000000
--- a/i18n/gl.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Banjo"
-		]
-	},
-	"jade-goodfaith-scale-true-label": "Boa fe",
-	"jade-goodfaith-scale-false-label": "Mala fe",
-	"jade-delete": "Borrar"
-}
diff --git a/i18n/he.json b/i18n/he.json
deleted file mode 100644
index f1307b1..0000000
--- a/i18n/he.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Amire80",
-			"Guycn2",
-			"Strayblues"
-		]
-	},
-	"jade-desc": "מנוע שיפוט ושיחה (JADE)",
-	"jade-damaging-scale-true-label": "מזיקה",
-	"jade-damaging-scale-false-label": "לא מזיקה",
-	"jade-goodfaith-scale-true-label": "כוונה טובה",
-	"jade-goodfaith-scale-false-label": "כוונה רעה",
-	"jade-contentquality-scale-1-label": "ערך ברמת קצרמר",
-	"jade-contentquality-scale-2-label": "ערך ברמה התחלתית",
-	"jade-contentquality-scale-3-label": "ערך ברמה ג",
-	"jade-contentquality-scale-4-label": "ערך ברמה ב",
-	"jade-contentquality-scale-5-label": "ערך טוב",
-	"jade-contentquality-scale-6-label": "ערך מומלץ",
-	"jade-contentquality-generic": "איכות תוכן \"$1\"",
-	"jade-new-judgment": "שיפוט חדש",
-	"jade-add-judgment": "הוספת שיפוט",
-	"jade-notes-placeholder": "הערות על השיפוט",
-	"jade-delete": "מחיקה",
-	"jade-bad-title-format": "תסדיר כותרת בלתי־תקין",
-	"jade-bad-title-namespace": "מרחב שם בלתי־תקין אבל כותרת של שיפוט.",
-	"jade-bad-entity-type": "סוג ישות בלתי־תקין \"$1\"",
-	"jade-bad-entity-id-format": "תסדיר מזהה ישות בלתי־תקין \"$1\"",
-	"jade-bad-revision-id": "לא ניתן למצוא את הגרסה לפי מזהה: \"$1\"",
-	"jade-bad-content-generic": "שגיאות תחביר בתוכן JSON.",
-	"jade-bad-content": "השיפוט אינו מתאים לסכמה: $1",
-	"jade-too-many-preferred": "שיפוטים מועדפים רבים, אבל יכול להיות רק אחד.",
-	"jade-none-preferred": "אין שיפוט מועדף, אבל חובה לבחור אחד.",
-	"jade-illegal-schema": "סכמה \"$1\" אינה מותרת אבל סוג הישות הזה.",
-	"jade-user-local-id-invalid": "מזהה משתמש מקומי \"$1\" אינו קיים.",
-	"jade-user-central-id-invalid": "מזהה משתמש מרכזי \"$1\" אינו קיים.",
-	"jade-user-id-mismatch": "מזהה משתמש מקומי \"$1\" ומזהה מרכזי \"$2\" מזהים משתמשים שונים.",
-	"jade-user-ip-invalid": "כתובת ה־IP‏ \"$1\" אינה תקינה.",
-	"jade-bad-contentquality-value": "ערך גרוע \"$1\" עבור סכמת contentquality, הערכים האפשריים הם: $2",
-	"jade-cannot-create-page": "לא ניתן ליצור את הדף הזה.",
-	"jade-cannot-edit-page": "אין באפשרותך לערוך את הדף הזה.",
-	"jade-invalid-move-any": "העברת דפי שיפוט אינה מותרת."
-}
diff --git a/i18n/hi.json b/i18n/hi.json
deleted file mode 100644
index 5a93cad..0000000
--- a/i18n/hi.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Prong$31"
-		]
-	},
-	"jade-endorsement": "समर्थन",
-	"jade-endorsements": "समर्थन",
-	"jade-user": "सदस्य"
-}
diff --git a/i18n/hy.json b/i18n/hy.json
deleted file mode 100644
index f6796d8..0000000
--- a/i18n/hy.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Kareyac"
-		]
-	},
-	"jade-contentquality-scale-5-label": "Լավ հոդված"
-}
diff --git a/i18n/ia.json b/i18n/ia.json
deleted file mode 100644
index c698199..0000000
--- a/i18n/ia.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"McDutchie"
-		]
-	},
-	"jade-bad-revision-id": "Version con ID \"$1\" non trovate"
-}
diff --git a/i18n/it.json b/i18n/it.json
deleted file mode 100644
index 448703c..0000000
--- a/i18n/it.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Beta16"
-		]
-	},
-	"jade-damaging-scale-false-label": "Non dannosa",
-	"jade-goodfaith-scale-true-label": "Buona fede",
-	"jade-goodfaith-scale-false-label": "Mala fede",
-	"jade-contentquality-scale-5-label": "Voce di qualità",
-	"jade-contentquality-scale-6-label": "Voce in vetrina",
-	"jade-delete": "Cancella",
-	"jade-bad-title-format": "Formato titolo non valido",
-	"jade-bad-entity-type": "Tipo di entità non valido ''$1''",
-	"jade-bad-content-generic": "Errori di sintassi nel contenuto JSON.",
-	"jade-user-local-id-invalid": "L'utente locale con ID ''$1'' non esiste.",
-	"jade-user-central-id-invalid": "L'utente centrale con ID ''$1'' non esiste.",
-	"jade-user-ip-invalid": "L'indirizzo IP ''$1'' non è valido.",
-	"jade-cannot-create-page": "Non puoi creare questa pagina.",
-	"jade-cannot-edit-page": "Non puoi modificare questa pagina.",
-	"jade-db-error": "Errore database: $1",
-	"jade-user": "Utente"
-}
diff --git a/i18n/ja.json b/i18n/ja.json
deleted file mode 100644
index d28f9af..0000000
--- a/i18n/ja.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Omotecho"
-		]
-	},
-	"jade-desc": "判断と会話のエンジン"
-}
diff --git a/i18n/kjp.json b/i18n/kjp.json
deleted file mode 100644
index e5cd3ec..0000000
--- a/i18n/kjp.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Rul1902"
-		]
-	},
-	"jade-contentquality-scale-5-label": "လိက်သာထိင်ႋမုက်"
-}
diff --git a/i18n/km.json b/i18n/km.json
deleted file mode 100644
index a21904a..0000000
--- a/i18n/km.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"គីមស៊្រុន"
-		]
-	},
-	"jade-contentquality-scale-5-label": "អត្ថបទល្អ",
-	"jade-contentquality-scale-6-label": "អត្ថបទឆ្នើម"
-}
diff --git a/i18n/ko.json b/i18n/ko.json
deleted file mode 100644
index e863e5a..0000000
--- a/i18n/ko.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ykhwong",
-			"Znkim"
-		]
-	},
-	"jade-damaging-scale-true-label": "해를 끼칩니다",
-	"jade-damaging-scale-false-label": "해를 끼치지 않습니다",
-	"jade-goodfaith-scale-true-label": "선의",
-	"jade-goodfaith-scale-false-label": "악의",
-	"jade-contentquality-scale-1-label": "토막글 등급 문서",
-	"jade-contentquality-scale-2-label": "시작 등급 문서",
-	"jade-contentquality-scale-3-label": "C등급 문서",
-	"jade-contentquality-scale-4-label": "B등급 문서",
-	"jade-contentquality-scale-5-label": "좋은 글",
-	"jade-contentquality-scale-6-label": "알찬 글",
-	"jade-contentquality-generic": "내용 품질 \"$1\"",
-	"jade-delete": "삭제",
-	"jade-bad-title-format": "유효하지 않은 제목 형식",
-	"jade-bad-revision-id": "ID로 판을 찾을 수 없습니다: \"$1\"",
-	"jade-bad-content-generic": "JSON 내용에 문법 오류가 있습니다.",
-	"jade-user-local-id-invalid": "\"$1\" 사용자 로컬 ID가 존재하지 않습니다.",
-	"jade-user-central-id-invalid": "\"$1\" 사용자 통합 ID가 존재하지 않습니다.",
-	"jade-user-id-mismatch": "\"$1\" 사용자 로컬 ID와 \"$2\" 통합 ID가 서로 다른 사용자로 식별됩니다.",
-	"jade-user-ip-invalid": "\"$1\" IP 주소가 유효하지 않습니다.",
-	"jade-cannot-create-page": "이 문서를 만들 수 없습니다.",
-	"jade-cannot-edit-page": "이 문서를 편집할 수 없습니다.",
-	"jade-db-error": "데이터베이스 오류: $1",
-	"jade-user": "사용자"
-}
diff --git a/i18n/ksw.json b/i18n/ksw.json
deleted file mode 100644
index b53f1d3..0000000
--- a/i18n/ksw.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"SawJaemin"
-		]
-	},
-	"jade-user": "ပှၤသူတၢ်ဖိ"
-}
diff --git a/i18n/lb.json b/i18n/lb.json
deleted file mode 100644
index c73e9b3..0000000
--- a/i18n/lb.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Robby"
-		]
-	},
-	"jade-damaging-scale-true-label": "Schiedlech",
-	"jade-damaging-scale-false-label": "Net schiedlech",
-	"jade-goodfaith-scale-true-label": "Gutt Absicht",
-	"jade-goodfaith-scale-false-label": "Schlecht Absicht",
-	"jade-contentquality-scale-3-label": "C-Klass-Artikel",
-	"jade-contentquality-scale-4-label": "B-Klass-Artikel",
-	"jade-contentquality-scale-5-label": "Gudden Artikel",
-	"jade-delete": "Läschen",
-	"jade-user-ip-invalid": "D'IP-Adress \"$1\" ass net valabel.",
-	"jade-cannot-edit-page": "Dir kënnt dës Säit net änneren.",
-	"jade-db-error": "Datebank Feeler: $1",
-	"jade-user": "Benotzer"
-}
diff --git a/i18n/lg.json b/i18n/lg.json
deleted file mode 100644
index ef6024e..0000000
--- a/i18n/lg.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Selwanga"
-		]
-	},
-	"jade-cannot-create-page": "Tosobola kuteekawo muko guno",
-	"jade-cannot-edit-page": "Tosobola kusunsula muko guno"
-}
diff --git a/i18n/li.json b/i18n/li.json
deleted file mode 100644
index 9df4483..0000000
--- a/i18n/li.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ooswesthoesbes"
-		]
-	},
-	"jade-desc": "Oeardeil- en dialoogmesjien"
-}
diff --git a/i18n/lt.json b/i18n/lt.json
deleted file mode 100644
index 3420a72..0000000
--- a/i18n/lt.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Eitvys200",
-			"Manvydasz"
-		]
-	},
-	"jade-contentquality-scale-2-label": "Pradinės klasės straipsnis",
-	"jade-contentquality-scale-3-label": "C klasės straipsnis",
-	"jade-contentquality-scale-4-label": "B klasės straipsnis",
-	"jade-contentquality-scale-5-label": "Vertingas straipsnis"
-}
diff --git a/i18n/lv.json b/i18n/lv.json
deleted file mode 100644
index 85fe7d3..0000000
--- a/i18n/lv.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Papuass"
-		]
-	},
-	"jade-contentquality-scale-5-label": "Labs raksts",
-	"jade-contentquality-scale-6-label": "Vērtīgs raksts"
-}
diff --git a/i18n/mk.json b/i18n/mk.json
deleted file mode 100644
index eae9eb8..0000000
--- a/i18n/mk.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Bjankuloski06"
-		]
-	},
-	"jade-desc": "Погон за просудување и дијалог",
-	"jade-damaging-scale-true-label": "Штетно",
-	"jade-damaging-scale-false-label": "Нештетно",
-	"jade-goodfaith-scale-true-label": "Добронамерно",
-	"jade-goodfaith-scale-false-label": "Недобронамерно",
-	"jade-contentquality-scale-1-label": "Класа „Никулец“",
-	"jade-contentquality-scale-2-label": "Класа „Почетна“",
-	"jade-contentquality-scale-3-label": "Класа III",
-	"jade-contentquality-scale-4-label": "Класа II",
-	"jade-contentquality-scale-5-label": "Добра статија",
-	"jade-contentquality-scale-6-label": "Избрана статија",
-	"jade-contentquality-generic": "Квалитет „$1“",
-	"jade-new-judgment": "Нов суд",
-	"jade-add-judgment": "Додај суд",
-	"jade-notes-placeholder": "Напомени за судот",
-	"jade-delete": "Избриши",
-	"jade-bad-title-format": "Неважечки формат на насловот",
-	"jade-bad-title-namespace": "Неважечки именски простор за насловот на просудувањето.",
-	"jade-non-canonical-title": "Насловот треба да биде во канонскиот облик ''$1''.",
-	"jade-bad-entity-type": "Неважечки вид на единица ''$1''",
-	"jade-bad-entity-id-format": "Неважечки формат ''$1'' на ознака за единицата",
-	"jade-bad-revision-id": "Не можам да најдам преработка со назнаката ''$1''",
-	"jade-bad-content-generic": "Синтаксни грешки во JSON-содржини.",
-	"jade-bad-content": "Просудувањето не одговара на шемата: $1",
-	"jade-too-many-preferred": "Се препочитаат повеќе просудувања, но може има само едно.",
-	"jade-none-preferred": "Не се препочитаат просудувања, но мора да се избере едно.",
-	"jade-illegal-schema": "Шемата ''$1'' не е дозволена за овој вид единица.",
-	"jade-user-local-id-invalid": "Нема корисник со месна назнака ''$1''.",
-	"jade-user-central-id-invalid": "Нема корисник со централна назнака ''$1''.",
-	"jade-user-id-mismatch": "Месната назнака ''$1'' и централната назнака ''$2'' се однесуваат на различни корисници.",
-	"jade-user-ip-invalid": "IP-адресата ''$1'' е неважечка.",
-	"jade-created-timestamp-invalid": "Времето и датумот на одобрувањето се неважечки: ''$1''",
-	"jade-bad-contentquality-value": "Неисправен индекс ''$1'' во шемата за квалитет на содржини. Мора да биде степен на квалитет помеѓу 1 и $2.",
-	"jade-cannot-create-page": "Не можете да ја создадете страницава.",
-	"jade-cannot-edit-page": "Не можете да ја уредувате страницава.",
-	"jade-invalid-move-any": "Преместувањето на просудни страници не е допуштено.",
-	"jade-db-error": "Грешка во базата: $1",
-	"jade-content-model-error": "Погрешен содржински модел за просудување.",
-	"jade-endorsement": "Потврдување",
-	"jade-endorsements": "Потврдувања",
-	"jade-user": "Корисник"
-}
diff --git a/i18n/ml.json b/i18n/ml.json
deleted file mode 100644
index f4c058a..0000000
--- a/i18n/ml.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Santhosh.thottingal"
-		]
-	},
-	"jade-user": "ഉപയോക്താവ്"
-}
diff --git a/i18n/mni.json b/i18n/mni.json
deleted file mode 100644
index bcfc121..0000000
--- a/i18n/mni.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Awangba Mangang"
-		]
-	},
-	"apihelp-createjudgment-summary": "ꯑꯅꯧꯕ ꯋꯥꯌꯦꯜ ꯱ ꯁꯥꯔꯣ"
-}
diff --git a/i18n/mr.json b/i18n/mr.json
deleted file mode 100644
index 8c63e2f..0000000
--- a/i18n/mr.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Susheelkasab"
-		]
-	},
-	"jade-desc": "न्यायिक आणि संभाषण इंजिन"
-}
diff --git a/i18n/ne.json b/i18n/ne.json
deleted file mode 100644
index 2f3866e..0000000
--- a/i18n/ne.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"पर्वत सुबेदी"
-		]
-	},
-	"jade-endorsement": "समर्थन",
-	"jade-user": "प्रयोगकर्ता"
-}
diff --git a/i18n/nl.json b/i18n/nl.json
deleted file mode 100644
index f4c931e..0000000
--- a/i18n/nl.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Robin van der Linde",
-			"Mainframe98",
-			"Elroy"
-		]
-	},
-	"jade-contentquality-scale-5-label": "Goed artikel",
-	"jade-delete": "Verwijderen",
-	"jade-user": "Gebruiker"
-}
diff --git a/i18n/pl.json b/i18n/pl.json
deleted file mode 100644
index 4a7a1c7..0000000
--- a/i18n/pl.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Chrumps"
-		]
-	},
-	"jade-contentquality-scale-6-label": "Wyróżniony artykuł",
-	"jade-delete": "Usuń",
-	"jade-bad-title-format": "Nieprawidłowy format tytułu",
-	"jade-bad-content-generic": "Błędy składni w treści JSON.",
-	"jade-user-ip-invalid": "Adres IP „$1” jest nieprawidłowy.",
-	"jade-cannot-create-page": "Nie możesz utworzyć tej strony.",
-	"jade-cannot-edit-page": "Nie możesz edytować tej strony."
-}
diff --git a/i18n/pt-br.json b/i18n/pt-br.json
deleted file mode 100644
index 74b6bca..0000000
--- a/i18n/pt-br.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Eduardo Addad de Oliveira",
-			"Felipe L. Ewald"
-		]
-	},
-	"jade-desc": "Motor de avaliação e diálogo JADE",
-	"jade-damaging-scale-true-label": "Prejudicial",
-	"jade-damaging-scale-false-label": "Não prejudicial",
-	"jade-goodfaith-scale-true-label": "Boa-fé",
-	"jade-goodfaith-scale-false-label": "Má-fé",
-	"jade-contentquality-scale-1-label": "Artigo de classe de esboço",
-	"jade-contentquality-scale-2-label": "Artigo de primeira classe",
-	"jade-contentquality-scale-3-label": "Artigo de classe C",
-	"jade-contentquality-scale-4-label": "Artigo de classe B",
-	"jade-contentquality-scale-5-label": "Artigos bom",
-	"jade-contentquality-scale-6-label": "Artigo destacado",
-	"jade-contentquality-generic": "Qualidade do conteúdo \"$1\"",
-	"jade-new-judgment": "Nova avaliação",
-	"jade-add-judgment": "Adicionar avaliação",
-	"jade-notes-placeholder": "Notas sobre a avaliação",
-	"jade-delete": "Deletar",
-	"jade-bad-title-format": "Formato de título inválido",
-	"jade-bad-title-namespace": "Espaço de nomes inválido para um título de julgamento.",
-	"jade-non-canonical-title": "Título deve ter forma canônica ''$1''.",
-	"jade-bad-entity-type": "Tipo de entidade inválido ''$1''",
-	"jade-bad-entity-id-format": "Formato de ID de entidade inválido ''$1''",
-	"jade-bad-revision-id": "Não é possível encontrar revisão por ID: ''$1''",
-	"jade-bad-content-generic": "Erros de sintaxe no conteúdo JSON.",
-	"jade-bad-content": "O julgamento não está em conformidade com o esquema: $1",
-	"jade-too-many-preferred": "Julgamentos múltiplos preferidos, mas só pode haver um.",
-	"jade-none-preferred": "Nenhum julgamento é preferido, mas deve haver um escolhido.",
-	"jade-illegal-schema": "Esquema ''$1'' não permitido para este tipo de entidade.",
-	"jade-user-local-id-invalid": "O ID local do usuário ''$1'' não existe.",
-	"jade-user-central-id-invalid": "A ID central do usuário ''$1'' não existe.",
-	"jade-user-id-mismatch": "O ID local do usuário ''$1'' e o ID ''$2'' central identificam diferentes usuários.",
-	"jade-user-ip-invalid": "O endereço IP ''$1''  é inválido.",
-	"jade-created-timestamp-invalid": "O timestamp criado para aprovação é inválido: ''$1''",
-	"jade-bad-contentquality-value": "Índice ''$1'' inválido para o esquema de qualidade de conteúdo; tem de ser um nível de qualidade entre 1 e $2.",
-	"jade-cannot-create-page": "Você não pode criar esta página.",
-	"jade-cannot-edit-page": "Você não pode editar esta página.",
-	"jade-invalid-move-any": "Mover páginas de julgamento não é permitido.",
-	"jade-db-error": "Erro no banco de dados: $1",
-	"jade-content-model-error": "Modelo de conteúdo errado para julgamento.",
-	"jade-endorsement": "Endosso",
-	"jade-endorsements": "Endossos",
-	"jade-user": "Usuário"
-}
diff --git a/i18n/pt.json b/i18n/pt.json
deleted file mode 100644
index 11044c9..0000000
--- a/i18n/pt.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Hamilton Abreu",
-			"Vitorvicentevalente",
-			"He7d3r"
-		]
-	},
-	"jade-desc": "Motor de avaliação e diálogo JADE",
-	"jade-damaging-scale-true-label": "Prejudicial",
-	"jade-damaging-scale-false-label": "Não prejudicial",
-	"jade-goodfaith-scale-true-label": "Bem intencionada",
-	"jade-goodfaith-scale-false-label": "Mal intencionada",
-	"jade-contentquality-scale-1-label": "Artigo da classe Provisório",
-	"jade-contentquality-scale-2-label": "Artigo da classe Iniciado",
-	"jade-contentquality-scale-3-label": "Artigo da classe C",
-	"jade-contentquality-scale-4-label": "Artigo da classe B",
-	"jade-contentquality-scale-5-label": "Artigo bom",
-	"jade-contentquality-scale-6-label": "Artigo destacado",
-	"jade-contentquality-generic": "Qualidade do conteúdo \"$1\"",
-	"jade-new-judgment": "Nova avaliação",
-	"jade-add-judgment": "Adicionar avaliação",
-	"jade-notes-placeholder": "Notas acerca da avaliação",
-	"jade-delete": "Eliminar",
-	"jade-bad-title-format": "Formato de título inválido",
-	"jade-bad-title-namespace": "Espaço nominal/domínio inválido para o título de uma avaliação.",
-	"jade-non-canonical-title": "O título deve ter forma a canónica ''$1''.",
-	"jade-bad-entity-type": "Tipo de entidade inválido ''$1''",
-	"jade-bad-entity-id-format": "Formato de identificador de entidade inválido ''$1''",
-	"jade-bad-revision-id": "Não foi possível encontrar uma revisão pelo identificador: ''$1''",
-	"jade-bad-content-generic": "Erros sintáticos no conteúdo JSON.",
-	"jade-bad-content": "A avaliação não está em conformidade com o esquema: $1",
-	"jade-too-many-preferred": "Mais do que uma avaliação foi marcada como preferida, mas só pode haver uma.",
-	"jade-none-preferred": "Nenhuma avaliação foi marcada como preferida, mas tem de haver uma.",
-	"jade-illegal-schema": "O esquema ''$1'' não é permitido para este tipo de entidade.",
-	"jade-user-local-id-invalid": "O identificador local ''$1'' do utilizador não existe.",
-	"jade-user-central-id-invalid": "O identificador central ''$1'' do utilizador não existe.",
-	"jade-user-id-mismatch": "O identificador local ''$1'' e o identificador central ''$2'' do utilizador identificam utilizadores diferentes.",
-	"jade-user-ip-invalid": "O endereço IP ''$1''  é inválido.",
-	"jade-created-timestamp-invalid": "A data e hora criada pela aprovação é inválida: ''$1''",
-	"jade-bad-contentquality-value": "Índice ''$1'' inválido para o esquema de qualidade de conteúdo; tem de ser um nível de qualidade entre 1 e $2.",
-	"jade-cannot-create-page": "Não pode criar esta página.",
-	"jade-cannot-edit-page": "Não pode editar esta página.",
-	"jade-invalid-move-any": "Não é permitido mover páginas de avaliações.",
-	"jade-db-error": "Erro da base de dados: $1",
-	"jade-content-model-error": "Modelo de conteúdo incorreto para a avaliação.",
-	"jade-endorsement": "Aprovação",
-	"jade-endorsements": "Aprovações",
-	"jade-user": "Utilizador"
-}
diff --git a/i18n/qqq.json b/i18n/qqq.json
deleted file mode 100644
index cf989d3..0000000
--- a/i18n/qqq.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Adamw",
-			"Robby",
-			"Umherirrender",
-			"Raymond"
-		]
-	},
-	"jade-desc": "{{desc|name=JADE|url=https://www.mediawiki.org/wiki/Extension:JADE}}",
-	"jade-damaging-scale-true-label": "Label for a damaging edit",
-	"jade-damaging-scale-false-label": "Label for an edit which is not damaging",
-	"jade-goodfaith-scale-true-label": "Label for a good faith edit",
-	"jade-goodfaith-scale-false-label": "Label for a bad faith edit",
-	"jade-contentquality-scale-1-label": "Label for this wiki's lowest quality rating.",
-	"jade-contentquality-scale-2-label": "Label for this wiki's second-from-lowest quality rating.",
-	"jade-contentquality-scale-3-label": "Label for this wiki's third-from-lowest quality rating.",
-	"jade-contentquality-scale-4-label": "Label for this wiki's fourth-from-lowest quality rating.",
-	"jade-contentquality-scale-5-label": "Label for this wiki's fifth-from-lowest quality rating.",
-	"jade-contentquality-scale-6-label": "Label for this wiki's sixth-from-lowest quality rating. On English Wikipedia the sixth level would be its highest quality \"Featured article\" but your wiki's scale may have more or fewer levels. Customized labels can be applied on the local wiki, sorry if this breaks TWN integration.",
-	"jade-contentquality-generic": "Label for a content quality judgment. This is a fallback which only appears when translations are missing. Parameters:\n* $1 - content quality code or level number.",
-	"jade-new-judgment": "Label for the new judgment form",
-	"jade-add-judgment": "Label for the judgment submit button",
-	"jade-notes-placeholder": "Placeholder for the judgment notes field",
-	"jade-delete": "Label for the judgment delete button\n{{Identical|Delete}}",
-	"jade-bad-title-format": "Error message for an illegal judgment page title.",
-	"jade-bad-title-namespace": "Error message when trying to use judgment titles outside of the Judgment namespace.",
-	"jade-non-canonical-title": "Error message when a title has a non-canonical form. Parameters:\n* $1 - expected title for this target",
-	"jade-bad-entity-type": "Error message for an illegal entity type in page title. Parameters:\n* $1 - requested entity type",
-	"jade-bad-entity-id-format": "Error message for a nonnumeric entity ID. Parameters:\n* $1 - requested entity ID",
-	"jade-bad-revision-id": "Error message when a revision judgment target cannot be found. Parameters:\n* $1 - Revision ID",
-	"jade-bad-content-generic": "Error message when basic JSON syntax is invalid.",
-	"jade-bad-content": "Error message when JSON doesn't conform to judgment jsonschema. Parameters:\n* $1 - raw validation exception (English)",
-	"jade-too-many-preferred": "Error message when more than one judgment is marked \"preferred\" on a page.",
-	"jade-none-preferred": "Error message when more than one judgment exists, but none are marked \"preferred\" on a page.",
-	"jade-illegal-schema": "Error message when attempting to use a schema that isn't configured for this entity type.  See $wgJadeAllowedScoringSchemas for your wiki. Parameters:\n* $1 - schema name",
-	"jade-user-local-id-invalid": "Error message when an endorsement local user doesn't exist. Parameters:\n* $1 - attempted user ID",
-	"jade-user-central-id-invalid": "Error message when an endorsement central user doesn't exist. Parameters:\n* $1 - attempted user ID",
-	"jade-user-id-mismatch": "Error message when endorsement user IDs don't match. Parameters:\n* $1 - attempted local ID\n* $2 - attempted central ID",
-	"jade-user-ip-invalid": "Error message when a user IP has an invalid format. Parameters:\n* $1 - attempted IP address",
-	"jade-created-timestamp-invalid": "Error message for an invalid ISO 8601 timestamp. Parameters:\n* $1 - Invalid timestamp",
-	"jade-bad-contentquality-value": "Error message when attempting to use a contentquality outside the range of $wgJadeArticleQualityLevels. Parameters:\n* $1 - attempted value\n* $2 - Number of quality levels on this wiki.",
-	"jade-cannot-create-page": "Error message when the user isn't allowed to create a judgment page.",
-	"jade-cannot-edit-page": "Error message when the user isn't allowed to edit a judgment page.",
-	"jade-invalid-move-any": "Error message when moving judgment pages, when no moves are allowed.",
-	"jade-db-error": "Error message for database errors. Parameters:\n $1 - Exception message.",
-	"jade-content-model-error": "Error message when a document in the Judgment namespace has the wrong content model.",
-	"jade-endorsement": "Label for an endorsement comment.",
-	"jade-endorsements": "Label for a group of endorsements.",
-	"jade-user": "Label for a user nick or IP.\n{{Identical|User}}"
-}
diff --git a/i18n/roa-tara.json b/i18n/roa-tara.json
deleted file mode 100644
index c019d66..0000000
--- a/i18n/roa-tara.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Joetaras"
-		]
-	},
-	"jade-desc": "Motore de giudizie e dialoghe",
-	"jade-user-ip-invalid": "Indirizze IP \"$1\" non g'è valide.",
-	"jade-user": "Utende"
-}
diff --git a/i18n/ru.json b/i18n/ru.json
deleted file mode 100644
index ba8bdc3..0000000
--- a/i18n/ru.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Vlad5250",
-			"Link2xt"
-		]
-	},
-	"jade-damaging-scale-true-label": "Вредоносная",
-	"jade-damaging-scale-false-label": "Безвредная",
-	"jade-goodfaith-scale-true-label": "Добронамеренная",
-	"jade-goodfaith-scale-false-label": "Злонамеренная",
-	"jade-contentquality-scale-1-label": "Класс «Заготовка»",
-	"jade-contentquality-scale-3-label": "Статья класса C",
-	"jade-contentquality-scale-4-label": "Статья класса B",
-	"jade-contentquality-scale-5-label": "Хорошая статья",
-	"jade-contentquality-scale-6-label": "Избранная статья",
-	"jade-contentquality-generic": "Качество «$1»",
-	"jade-delete": "Удалить",
-	"jade-user-local-id-invalid": "Не существует участника с локальным ID ''$1''.",
-	"jade-user-central-id-invalid": "Не существует участника с центральным ID ''$1''.",
-	"jade-user-id-mismatch": "Локальный ID ''$1'' и центральный ID ''$2'' относятся к разным участникам.",
-	"jade-user-ip-invalid": "IP-адрес ''$1'' недействителен.",
-	"jade-db-error": "Ошибка базы данных: $1"
-}
diff --git a/i18n/sat.json b/i18n/sat.json
deleted file mode 100644
index 89a4005..0000000
--- a/i18n/sat.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"R Ashwani Banjan Murmu"
-		]
-	},
-	"apihelp-query+jade-getjudgments-generator-example": "ᱡᱩᱫᱟᱹ #᱓ ᱞᱟᱹᱜᱤᱫ ᱵᱤᱪᱟᱹᱨ ᱥᱟᱛᱟᱢ ᱧᱟᱢ ᱢᱮ"
-}
diff --git a/i18n/skr-arab.json b/i18n/skr-arab.json
deleted file mode 100644
index 2ae56c4..0000000
--- a/i18n/skr-arab.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Saraiki"
-		]
-	},
-	"jade-delete": "مٹاؤ",
-	"jade-bad-title-format": "عنوان دا غلط فارمیٹ",
-	"jade-cannot-create-page": "تساں ایہ ورقہ نہوے بݨا سڳدے۔",
-	"jade-user": "ورتݨ آلا"
-}
diff --git a/i18n/sl.json b/i18n/sl.json
deleted file mode 100644
index 4ce3e90..0000000
--- a/i18n/sl.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"HairyFotr"
-		]
-	},
-	"jade-user": "Uporabnik"
-}
diff --git a/i18n/sr-ec.json b/i18n/sr-ec.json
deleted file mode 100644
index f0c2587..0000000
--- a/i18n/sr-ec.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"BadDog"
-		]
-	},
-	"jade-contentquality-scale-1-label": "Чланак класе „Клица”",
-	"jade-contentquality-scale-2-label": "Чланак класе „Зачетак”",
-	"jade-contentquality-scale-3-label": "Чланак класе III",
-	"jade-contentquality-scale-4-label": "Чланак класе II",
-	"jade-contentquality-scale-5-label": "Добар чланак",
-	"jade-contentquality-scale-6-label": "Изабрани чланак",
-	"jade-contentquality-generic": "Квалитет садржаја „$1”",
-	"jade-bad-title-format": "Неважећи формат наслова",
-	"jade-non-canonical-title": "Наслов треба да има канонски облик „$1”.",
-	"jade-bad-entity-type": "Неважећи тип ентитета: „$1”",
-	"jade-bad-entity-id-format": "Неважећи формат ID ентитета „$1”",
-	"jade-bad-revision-id": "Није могуће пронаћи измену по ID-у: „$1”",
-	"jade-bad-content-generic": "Синтаксне грешаке у садржају JSON-а.",
-	"jade-illegal-schema": "Шема „$1” није дозвољена за овај тип ентитета.",
-	"jade-user-local-id-invalid": "Кориснички локални ID „$1” не постоји.",
-	"jade-user-central-id-invalid": "Кориснички централни ID „$1” не постоји.",
-	"jade-user-ip-invalid": "IP адреса „$1” није важећа.",
-	"jade-cannot-create-page": "Не можете да направите ову страницу.",
-	"jade-cannot-edit-page": "Не можете да уређујете ову страницу.",
-	"jade-db-error": "Грешка у бази података: $1",
-	"jade-endorsement": "Потврђивање",
-	"jade-endorsements": "Потврђивања",
-	"jade-user": "Корисник"
-}
diff --git a/i18n/sv.json b/i18n/sv.json
deleted file mode 100644
index b3a91a8..0000000
--- a/i18n/sv.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"WikiPhoenix"
-		]
-	},
-	"jade-desc": "Bedömnings- och dialogmotor",
-	"jade-damaging-scale-true-label": "Skadlig",
-	"jade-damaging-scale-false-label": "Inte skadlig",
-	"jade-goodfaith-scale-true-label": "God avsikt",
-	"jade-goodfaith-scale-false-label": "Ond avsikt",
-	"jade-contentquality-scale-5-label": "Bra artikel",
-	"jade-contentquality-scale-6-label": "Utmärkt artikel",
-	"jade-contentquality-generic": "Innehållskvalitet \"$1\"",
-	"jade-new-judgment": "Ny bedömning",
-	"jade-add-judgment": "Lägg till bedömning",
-	"jade-delete": "Radera",
-	"jade-bad-title-format": "Ogiltigt titelformat",
-	"jade-user-ip-invalid": "IP-adressen ''$1'' är ogiltig.",
-	"jade-cannot-create-page": "Du kan inte skapa denna sida.",
-	"jade-cannot-edit-page": "Du kan inte redigera denna sida.",
-	"jade-db-error": "Databasfel: $1",
-	"jade-user": "Användare"
-}
diff --git a/i18n/ta.json b/i18n/ta.json
deleted file mode 100644
index 1ac5e3e..0000000
--- a/i18n/ta.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"ElangoRamanujam"
-		]
-	},
-	"jade-user": "பயனர்"
-}
diff --git a/i18n/tcy.json b/i18n/tcy.json
deleted file mode 100644
index e9e2408..0000000
--- a/i18n/tcy.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Ravi Mundkur"
-		]
-	},
-	"jade-created-timestamp-invalid": "ಅನುಮೋದನೆ ರಚಿತ ಕಾಲಮುದ್ರೆ ಅಮಾನ್ಯವಾದುಂಡು:\"$1\""
-}
diff --git a/i18n/th.json b/i18n/th.json
deleted file mode 100644
index 45bf766..0000000
--- a/i18n/th.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"B20180"
-		]
-	},
-	"jade-bad-contentquality-value": "ดัชนี ''$1'' ไม่ถูกต้องในรูปแบบคุณภาพเนื้อหา ซึ่งต้องเป็นระดับคุณภาพระหว่าง 1 ถึง $2",
-	"jade-endorsement": "การรับรอง",
-	"jade-endorsements": "การรับรอง",
-	"jade-user": "ผู้ใช้"
-}
diff --git a/i18n/tr.json b/i18n/tr.json
deleted file mode 100644
index 6f1d934..0000000
--- a/i18n/tr.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Hedda"
-		]
-	},
-	"jade-desc": "Yargı ve diyalog motoru"
-}
diff --git a/i18n/uk.json b/i18n/uk.json
deleted file mode 100644
index f0bc952..0000000
--- a/i18n/uk.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Piramidion",
-			"Vlad5250"
-		]
-	},
-	"jade-desc": "Рушій для оцінок і діалогів",
-	"jade-damaging-scale-true-label": "Шкідливе",
-	"jade-damaging-scale-false-label": "Нешкідливе",
-	"jade-goodfaith-scale-true-label": "З добрими намірами",
-	"jade-goodfaith-scale-false-label": "Зловмисне",
-	"jade-contentquality-scale-1-label": "Стаття класу «заготовка»",
-	"jade-contentquality-scale-2-label": "Стаття класу «початок»",
-	"jade-contentquality-scale-3-label": "Стаття класу C",
-	"jade-contentquality-scale-4-label": "Стаття класу B",
-	"jade-contentquality-scale-5-label": "Добра стаття",
-	"jade-contentquality-scale-6-label": "Вибрана стаття",
-	"jade-contentquality-generic": "Якість вмісту «$1»",
-	"jade-new-judgment": "Нова оцінка",
-	"jade-add-judgment": "Додати оцінку",
-	"jade-notes-placeholder": "Примітки щодо оцінки",
-	"jade-delete": "Вилучити",
-	"jade-bad-title-format": "Недійсний формат назви",
-	"jade-bad-title-namespace": "Недійсний простір назв для назви оцінки.",
-	"jade-bad-entity-type": "Недійсний тип сутності ''$1''",
-	"jade-bad-entity-id-format": "Недійсний формат ідентифікатора сутності ''$1''",
-	"jade-bad-revision-id": "Не вдалося знайти версію за ідентифікатором: ''$1''",
-	"jade-bad-content-generic": "Синтаксичні помилки у вмісті JSON.",
-	"jade-bad-content": "Оцінка не узгоджується зі схемою: $1",
-	"jade-too-many-preferred": "Бажано, щоб було кілька оцінок, але одна теж може бути.",
-	"jade-none-preferred": "Жодна оцінка не позначена як бажана, але одну слід вибрати.",
-	"jade-illegal-schema": "Схема ''$1'' не дозволена для цього типу сутності.",
-	"jade-user-local-id-invalid": "Локальний ідентифікатор користувача ''$1'' не існує.",
-	"jade-user-central-id-invalid": "Центральний ідентифікатор користувача ''$1'' не існує.",
-	"jade-user-id-mismatch": "Локальний ідентифікатор користувача ''$1'' і центральний ідентифікатор ''$2'' ідентифікують різних користувачів.",
-	"jade-user-ip-invalid": "IP-адреса ''$1'' — недійсна.",
-	"jade-created-timestamp-invalid": "Мітка часу, створена підтвердженням, є недійсною: ''$1''",
-	"jade-bad-contentquality-value": "Поганий індекс ''$1'' у схему якості вмісту; це має бути рівень якості між 1 і $2.",
-	"jade-cannot-create-page": "Ви не можете створити цю сторінку.",
-	"jade-cannot-edit-page": "Ви не можете редагувати цю сторінку.",
-	"jade-invalid-move-any": "Перейменування сторінок з оцінками не дозволене.",
-	"jade-db-error": "Помилка бази даних: $1",
-	"jade-content-model-error": "Неправильна контентна модель для оцінки.",
-	"jade-user": "Користувач"
-}
diff --git a/i18n/vi.json b/i18n/vi.json
deleted file mode 100644
index 75525ec..0000000
--- a/i18n/vi.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Minh Nguyen"
-		]
-	},
-	"jade-desc": "Máy xét xử và đối thoại",
-	"jade-damaging-scale-true-label": "Gây hại",
-	"jade-damaging-scale-false-label": "Không gây hại",
-	"jade-goodfaith-scale-true-label": "Thiện ý",
-	"jade-goodfaith-scale-false-label": "Ác ý",
-	"jade-new-judgment": "Xét xử mới",
-	"jade-add-judgment": "Thêm xét xử",
-	"jade-notes-placeholder": "Ghi chú về xét xử",
-	"jade-delete": "Xóa"
-}
diff --git a/i18n/zh-hans.json b/i18n/zh-hans.json
deleted file mode 100644
index b4026d6..0000000
--- a/i18n/zh-hans.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Liuxinyu970226",
-			"Endermoon",
-			"夢蝶葬花",
-			"A Chinese Wikipedian",
-			"Phenolla"
-		]
-	},
-	"jade-desc": "判断和会话引擎",
-	"jade-damaging-scale-true-label": "有害",
-	"jade-damaging-scale-false-label": "无害",
-	"jade-goodfaith-scale-true-label": "善意",
-	"jade-goodfaith-scale-false-label": "恶意",
-	"jade-contentquality-scale-1-label": "小作品级条目",
-	"jade-contentquality-scale-3-label": "丙级条目",
-	"jade-contentquality-scale-4-label": "乙级条目",
-	"jade-contentquality-scale-5-label": "优良条目",
-	"jade-contentquality-scale-6-label": "典范条目",
-	"jade-new-judgment": "新判断",
-	"jade-add-judgment": "添加判断",
-	"jade-notes-placeholder": "有关判断的说明",
-	"jade-delete": "删除",
-	"jade-bad-title-format": "无效标题格式",
-	"jade-bad-entity-type": "无效实体类型“$1”",
-	"jade-bad-revision-id": "找不到ID为“$1”的修订版本",
-	"jade-bad-content-generic": "JSON内容中有语法错误。",
-	"jade-none-preferred": "没有优先选项,但必须选择一个。",
-	"jade-illegal-schema": "模式“$1”不允许用于此实体类型。",
-	"jade-bad-contentquality-value": "用于文章质量模式的值“$1”有误,可用值有:$2",
-	"jade-cannot-create-page": "您不可以创建此页面。",
-	"jade-cannot-edit-page": "您不能编辑此页面。",
-	"jade-user": "用户"
-}
diff --git a/i18n/zh-hant.json b/i18n/zh-hant.json
deleted file mode 100644
index 73b7b85..0000000
--- a/i18n/zh-hant.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-	"@metadata": {
-		"authors": [
-			"Kly"
-		]
-	},
-	"jade-desc": "判斷與對話引擎(Judgment and dialog engine、JADE)",
-	"jade-damaging-scale-true-label": "毀謗",
-	"jade-damaging-scale-false-label": "非毀謗",
-	"jade-goodfaith-scale-true-label": "善意",
-	"jade-goodfaith-scale-false-label": "惡意",
-	"jade-contentquality-scale-1-label": "小作品條目",
-	"jade-contentquality-scale-2-label": "初級條目",
-	"jade-contentquality-scale-3-label": "丙級條目",
-	"jade-contentquality-scale-4-label": "乙級條目",
-	"jade-contentquality-scale-5-label": "優良條目",
-	"jade-contentquality-scale-6-label": "典範條目",
-	"jade-contentquality-generic": "內容品質「$1」",
-	"jade-new-judgment": "新的判斷",
-	"jade-add-judgment": "添加判斷",
-	"jade-notes-placeholder": "有關判斷的註釋",
-	"jade-delete": "刪除",
-	"jade-bad-title-format": "無效的標題格式",
-	"jade-bad-title-namespace": "用於判斷標題的無效命名空間。",
-	"jade-non-canonical-title": "標題應包含自''$1''的規範形式。",
-	"jade-bad-entity-type": "無效項目類型''$1''",
-	"jade-bad-entity-id-format": "無效項目 ID 格式「$1」",
-	"jade-bad-revision-id": "找不到 ID 為:''$1'' 的修訂",
-	"jade-bad-content-generic": "JSON 內容裡語法錯誤。",
-	"jade-bad-content": "判斷不符合架構:$1",
-	"jade-too-many-preferred": "多個判斷裡僅能採用一個作為優先。",
-	"jade-none-preferred": "必須選擇一個優先判斷。",
-	"jade-illegal-schema": "架構''$1''在此項目類型不被允許。",
-	"jade-user-local-id-invalid": "使用者本地 ID「$1」不存在。",
-	"jade-user-central-id-invalid": "使用者中心 ID「$1」不存在。",
-	"jade-user-id-mismatch": "使用者本地 ID「$1」與中心 ID「$2」兩方識別成是不同的使用者。",
-	"jade-user-ip-invalid": "IP 地址「$1」無效。",
-	"jade-created-timestamp-invalid": "簽署建立的時間戳無效:「$1」",
-	"jade-bad-contentquality-value": "內容品質架構中的錯誤索引「''$1''」,品質等級必須介於 1 與 $2 之間。",
-	"jade-cannot-create-page": "您不能建立此頁面。",
-	"jade-cannot-edit-page": "您不能編輯此頁面。",
-	"jade-invalid-move-any": "不允許移動判斷頁面。",
-	"jade-db-error": "資料庫錯誤:$1",
-	"jade-content-model-error": "用於判斷的錯誤內容模組。",
-	"jade-endorsement": "簽署",
-	"jade-endorsements": "簽署",
-	"jade-user": "使用者"
-}
diff --git a/includes/ApiGetJudgments.php b/includes/ApiGetJudgments.php
deleted file mode 100644
index 92f5bad..0000000
--- a/includes/ApiGetJudgments.php
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade;
-
-use ApiBase;
-use ApiPageSet;
-use ApiQueryGeneratorBase;
-use Title;
-
-/**
- *
- * @ingroup API
- */
-class ApiGetJudgments extends ApiQueryGeneratorBase {
-
-	public function __construct( $query, $moduleName ) {
-		parent::__construct( $query, $moduleName, 'gj' );
-	}
-
-	public function execute() {
-		$this->run();
-	}
-
-	public function executeGenerator( $resultPageSet ) {
-		$this->run( $resultPageSet );
-	}
-
-	/**
-	 * @param ApiPageSet|null $resultPageSet
-	 */
-	private function run( $resultPageSet = null ) {
-		$user = $this->getUser();
-		$params = $this->extractRequestParams();
-		$titles = [];
-
-		$status = JudgmentEntityType::sanitizeEntityType( $params['entitytype'] );
-		if ( !$status->isOK() ) {
-			// Should be unreachable due to API parameter validation.
-			$this->dieStatus( $status );
-		}
-		$entityType = $status->value;
-		$target = new JudgmentTarget( $entityType, $params['entityid'] );
-		$title = TitleHelper::buildJadeTitle( $target );
-		$dbTitle = Title::newFromTitleValue( $title );
-		if ( $dbTitle->exists() ) {
-			$titles[] = $dbTitle;
-		}
-
-		if ( is_null( $resultPageSet ) ) {
-			if ( count( $titles ) > 0 ) {
-				$data = [];
-				foreach ( $titles as $title ) {
-					self::addTitleInfo( $data, $title );
-				}
-				$this->getResult()->addValue( [ 'query', $this->getModuleName() ], null, $data );
-			}
-			$this->getResult()->addIndexedTagName( [
-				'query', $this->getModuleName()
-			], 'judgment' );
-		} else {
-			$resultPageSet->populateFromTitles( $titles );
-		}
-	}
-
-	public function getAllowedParams() {
-		global $wgJadeEntityTypeNames;
-
-		return [
-			'entitytype' => [
-				ApiBase::PARAM_TYPE => array_keys( $wgJadeEntityTypeNames ),
-				ApiBase::PARAM_REQUIRED => true,
-			],
-			'entityid' => [
-				ApiBase::PARAM_TYPE => 'integer',
-				ApiBase::PARAM_REQUIRED => true,
-				ApiBase::PARAM_MIN => 1,
-			],
-		];
-	}
-
-	public function getCacheMode( $params ) {
-		return 'public';
-	}
-
-	protected function getExamplesMessages() {
-		return [
-			'action=query&list=getjudgments&gjentitytype=diff&gjentityid=3'
-				=> 'apihelp-query+jade-getjudgments-list-example',
-			'action=query&generator=getjudgments&ggjentitytype=diff&ggjentityid=3&' .
-			'prop=revisions&rvprop=content&rvslots=*'
-				=> 'apihelp-query+jade-getjudgments-generator-example'
-		];
-	}
-
-	public function getHelpUrls() {
-		return 'https://www.mediawiki.org/wiki/Extension:JADE';
-	}
-
-}
diff --git a/includes/Content/JudgmentContent.php b/includes/Content/JudgmentContent.php
deleted file mode 100644
index 4205030..0000000
--- a/includes/Content/JudgmentContent.php
+++ /dev/null
@@ -1,146 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade\Content;
-
-use Jade\JadeServices;
-use Jade\JudgmentPageWikitextRenderer;
-use JsonContent;
-use MediaWiki\MediaWikiServices;
-use ParserOptions;
-use ParserOutput;
-use Status;
-use StatusValue;
-use Title;
-use User;
-use WikiPage;
-
-class JudgmentContent extends JsonContent {
-	const CONTENT_MODEL_JUDGMENT = 'JadeJudgment';
-	const JUDGMENT_SCHEMA = '/../../jsonschema/judgment/v1.json';
-	const SCORING_SCHEMA_ROOT = '/../../jsonschema/scoring';
-
-	public function __construct( $text, $modelId = self::CONTENT_MODEL_JUDGMENT ) {
-		parent::__construct( $text, $modelId );
-	}
-
-	/**
-	 * Hook to validate `save` operation.
-	 *
-	 * Our implementation enforces the page title, making sure it's consistent
-	 * with the wiki entity and what's being judged.
-	 *
-	 * @param WikiPage $page The page to be saved.
-	 * @param int $flags Bitfield for use with EDIT_XXX constants, see
-	 * WikiPage::doEditContent()
-	 * @param int $parentRevId The ID of the current revision
-	 * @param User $user User taking action, for permissions checks.
-	 *
-	 * @return Status A status object, which isOK() if we can continue
-	 * with the save.
-	 *
-	 * @see Content::prepareSave
-	 */
-	public function prepareSave( WikiPage $page, $flags, $parentRevId, User $user ) {
-		// Note that we don't call the parent because isValid() is redundant
-		// here.  This may change if additional tests or side-effects are added to
-		// AbstractContent::prepareSave in the future.
-
-		$status = $this->validateContent();
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-
-		$data = $this->getData()->getValue();
-		$validator = JadeServices::getJudgmentValidator();
-		return $validator->validatePageTitle( $page, $data );
-	}
-
-	/**
-	 * Check that the judgment content is well-formed.
-	 *
-	 * @return bool True if the content is valid.
-	 *
-	 * @see Content::isValid
-	 */
-	public function isValid() {
-		$status = $this->validateContent();
-		return $status->isOK();
-	}
-
-	/**
-	 * Use instead of isValid() when you care about the specific validation errors.
-	 *
-	 * @return StatusValue isOK if valid.
-	 */
-	public function validateContent() {
-		if ( !parent::isValid() ) {
-			return Status::newfatal( 'jade-bad-content-generic' );
-		}
-
-		// Special case to allow for empty content when first creating a page.
-		if ( $this->isEmpty() ) {
-			return Status::newGood();
-		}
-
-		$data = $this->getData()->getValue();
-		$validator = JadeServices::getJudgmentValidator();
-		return $validator->validateJudgmentContent( $data );
-	}
-
-	public function isEmpty() {
-		return count( (array)$this->getData()->getValue() ) === 0;
-	}
-
-	/**
-	 * @see AbstractContent::fillParserOutput
-	 *
-	 * @param Title $title Context title for parsing
-	 * @param int|null $revId Revision ID (for {{REVISIONID}})
-	 * @param ParserOptions $options Funny things to tell the parser.
-	 * @param bool $generateHtml Whether or not to generate HTML
-	 * @param ParserOutput &$output The output object to fill (reference).
-	 */
-	public function fillParserOutput(
-		Title $title,
-		$revId,
-		ParserOptions $options,
-		$generateHtml,
-		ParserOutput &$output
-	) {
-		if ( !$this->isValid() ) {
-			// We can't proceed.  JsonContent has a TODO mentioning that this
-			// condition will be deprecated in the future.
-			$output->setText( '' );
-			return;
-		}
-
-		$parser = MediaWikiServices::getInstance()->getParser();
-		$renderer = new JudgmentPageWikitextRenderer;
-		$wikitext = $renderer->getWikitext( $this->getData()->getValue() );
-
-		$output = $parser->parse( $wikitext, $title, $options, true, true, $revId );
-
-		if ( !$generateHtml ) {
-			$output->setText( '' );
-		}
-	}
-
-}
diff --git a/includes/Content/JudgmentContentHandler.php b/includes/Content/JudgmentContentHandler.php
deleted file mode 100644
index 8ca0dfd..0000000
--- a/includes/Content/JudgmentContentHandler.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade\Content;
-
-use JsonContentHandler;
-use ParserOutput;
-use Sanitizer;
-use SearchEngine;
-use Title;
-use WikiPage;
-
-class JudgmentContentHandler extends JsonContentHandler {
-
-	public function __construct( $modelId = JudgmentContent::CONTENT_MODEL_JUDGMENT ) {
-		parent::__construct( $modelId );
-	}
-
-	protected function getContentClass() {
-		return JudgmentContent::class;
-	}
-
-	public function canBeUsedOn( Title $title ) {
-		return $title->inNamespace( NS_JUDGMENT );
-	}
-
-	/**
-	 * Rewrite the text that will show up in the search results summary, as its
-	 * rendered form rather than raw JSON.
-	 *
-	 * TODO: This is where we would populate additional indexes into the data
-	 * itself.
-	 *
-	 * @param WikiPage $page Page to index
-	 * @param ParserOutput $output Rendered page
-	 * @param SearchEngine $engine Search engine for which we are indexing
-	 *
-	 * @return array Map of name=>value for fields
-	 */
-	public function getDataForSearchIndex(
-		WikiPage $page,
-		ParserOutput $output,
-		SearchEngine $engine
-	) {
-		$fields = parent::getDataForSearchIndex( $page, $output, $engine );
-
-		$text = $output->getText();
-		$stripped = trim( Sanitizer::stripAllTags( $text ) );
-
-		$fields['text'] = $stripped;
-
-		return $fields;
-	}
-
-}
diff --git a/includes/EntityJudgmentSetStorage.php b/includes/EntityJudgmentSetStorage.php
deleted file mode 100644
index d7d3e0c..0000000
--- a/includes/EntityJudgmentSetStorage.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use StatusValue;
-
-interface EntityJudgmentSetStorage {
-
-	/**
-	 * Store a revision of judgment content.
-	 *
-	 * Overwrites the page without merging.
-	 *
-	 * TODO: editRevId for conflict detection?
-	 * @param JudgmentTarget $target identity of target wiki entity.
-	 * @param array $judgmentSet All judgments on this entity, as nested
-	 * associative arrays, normalized for storage.
-	 * @param string $summary Edit summary.
-	 * @param array $tags Optional list of change tags to set on the revision being created.
-	 *
-	 * @return StatusValue isOK if stored successfully.
-	 */
-	public function storeJudgmentSet(
-		JudgmentTarget $target,
-		array $judgmentSet,
-		$summary,
-		array $tags );
-
-	/**
-	 * @param JudgmentTarget $target identity of target wiki entity.
-	 *
-	 * @return StatusValue with array value containing all judgments for this
-	 *         entity.
-	 */
-	public function loadJudgmentSet( JudgmentTarget $target );
-
-}
diff --git a/includes/Hooks/DatabaseSchemaHooks.php b/includes/Hooks/DatabaseSchemaHooks.php
deleted file mode 100644
index 0350e4b..0000000
--- a/includes/Hooks/DatabaseSchemaHooks.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade\Hooks;
-
-use DatabaseUpdater;
-
-class DatabaseSchemaHooks {
-
-	public static function onLoadExtensionSchemaUpdates( DatabaseUpdater $updater ) {
-		$sqlDir = __DIR__ . '/../../sql';
-
-		$updater->addExtensionTable(
-			'jade_diff_judgment',
-			$sqlDir . '/jade_diff_judgment.sql' );
-		$updater->addExtensionTable(
-			'jade_revision_judgment',
-			$sqlDir . '/jade_revision_judgment.sql' );
-	}
-
-}
diff --git a/includes/Hooks/LinkSummaryHooks.php b/includes/Hooks/LinkSummaryHooks.php
deleted file mode 100644
index 3f2cf7e..0000000
--- a/includes/Hooks/LinkSummaryHooks.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade\Hooks;
-
-use Content;
-use Jade\JadeServices;
-use Jade\JudgmentSummarizer;
-use Jade\TitleHelper;
-use MediaWiki\Logger\LoggerFactory;
-use Revision;
-use Status;
-use User;
-use WikiPage;
-
-class LinkSummaryHooks {
-
-	/**
-	 * Update link summary after a judgment page is edited.
-	 *
-	 * @param WikiPage &$judgmentPage WikiPage modified
-	 * @param User &$user User performing the modification
-	 * @param Content $content New content
-	 * @param string $summary Edit summary/comment
-	 * @param bool $isMinor Whether or not the edit was marked as minor
-	 * @param bool $isWatch (No longer used)
-	 * @param string $section (No longer used)
-	 * @param int $flags Flags passed to WikiPage::doEditContent()
-	 * @param Revision $revision Revision object of the saved content. If the
-	 * save did not result in the creation of a new revision (e.g. the
-	 * submission was equal to the latest revision), this parameter may be null
-	 * (null edits, or "no-op"). However, there are reports (see phab:T128838)
-	 * that it's instead set to that latest revision.
-	 * @param Status $status Status object about to be returned by doEditContent()
-	 * @param int|bool $baseRevId the rev ID (or false) this edit was based on
-	 * @param int $undidRevId the rev ID (or 0) this edit undid - added in MW 1.30
-	 */
-	public static function onPageContentSaveComplete(
-		WikiPage &$judgmentPage,
-		User &$user,
-		Content $content,
-		$summary,
-		$isMinor,
-		$isWatch,
-		$section,
-		$flags,
-		Revision $revision,
-		Status $status,
-		$baseRevId,
-		$undidRevId
-	) {
-		$status = TitleHelper::parseTitleValue( $judgmentPage->getTitle()->getTitleValue() );
-		if ( !$status->isOK() ) {
-			return;
-		}
-		$target = $status->value;
-
-		$status = JudgmentSummarizer::getSummaryFromContent( $content );
-		if ( !$status->isOK() ) {
-			LoggerFactory::getInstance( 'Jade' )
-				->warning( 'Failed to extract judgment summary: {status}', [ 'status' => $status ] );
-
-			return;
-		}
-		$summaryValues = $status->value;
-		$status = JadeServices::getJudgmentIndexStorage()
-			->updateSummary( $target, $summaryValues );
-
-		if ( !$status->isOK() ) {
-			LoggerFactory::getInstance( 'Jade' )
-				->warning( 'Failed to update judgment summary: {status}', [ 'status' => $status ] );
-		}
-	}
-
-}
diff --git a/includes/Hooks/LinkTableHooks.php b/includes/Hooks/LinkTableHooks.php
deleted file mode 100644
index 5c58765..0000000
--- a/includes/Hooks/LinkTableHooks.php
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade\Hooks;
-
-use Content;
-use Jade\JadeServices;
-use Jade\JudgmentTarget;
-use Jade\TitleHelper;
-use LogEntry;
-use MediaWiki\Logger\LoggerFactory;
-use Revision;
-use Title;
-use TitleValue;
-use User;
-use WikiPage;
-
-class LinkTableHooks {
-
-	/**
-	 * Update link tables after a new judgment page is inserted.
-	 *
-	 * @param WikiPage &$judgmentPage WikiPage created
-	 * @param User &$user User creating the article
-	 * @param Content $content New content as a Content object
-	 * @param string $summary Edit summary/comment
-	 * @param bool $isMinor Whether or not the edit was marked as minor
-	 * @param null $isWatch (No longer used)
-	 * @param null $section (No longer used)
-	 * @param int &$flags Flags passed to WikiPage::doEditContent()
-	 * @param Revision $revision New Revision of the article
-	 *
-	 * TODO: move to a deferred update?
-	 */
-	public static function onPageContentInsertComplete(
-		WikiPage &$judgmentPage,
-		User &$user,
-		Content $content,
-		$summary,
-		$isMinor,
-		$isWatch,
-		$section,
-		&$flags,
-		Revision $revision
-	) {
-		$target = self::judgmentTarget( $judgmentPage->getTitle()->getTitleValue() );
-		if ( !$target ) {
-			return;
-		}
-
-		JadeServices::getJudgmentIndexStorage()
-			->insertIndex( $target, $judgmentPage );
-	}
-
-	/**
-	 * Remove link when judgment page is deleted.
-	 *
-	 * @param WikiPage &$judgmentPage the article that was deleted.
-	 * @param User &$user the user that deleted the article
-	 * @param string $reason the reason the article was deleted
-	 * @param int $id id of the article that was deleted
-	 * @param Content|null $content the content of the deleted article, or null in case of an error
-	 * @param LogEntry $logEntry the log entry used to record the deletion
-	 */
-	public static function onArticleDeleteComplete(
-		WikiPage &$judgmentPage,
-		User &$user,
-		$reason,
-		$id,
-		Content $content,
-		LogEntry $logEntry
-	) {
-		$target = self::judgmentTarget( $judgmentPage->getTitle()->getTitleValue() );
-		if ( !$target ) {
-			return;
-		}
-
-		JadeServices::getJudgmentIndexStorage()
-			->deleteIndex( $target, $judgmentPage );
-	}
-
-	/**
-	 * Restore link when a judgment page is undeleted.
-	 *
-	 * @param Title $title the article being restored
-	 * @param bool $create Whether or not the restoration caused the page to be
-	 *        created (i.e. it didn't exist before)
-	 * @param string $comment Comment explaining the undeletion
-	 * @param int $oldPageId ID of page previously deleted (from archive
-	 *        table). This ID will be used for the restored page.
-	 * @param array $restoredPages Set of page IDs that have revisions restored
-	 *        for the undelete, with keys being page IDs and values are 'true'.
-	 */
-	public static function onArticleUndelete(
-		Title $title,
-		$create,
-		$comment,
-		$oldPageId,
-		array $restoredPages
-	) {
-		if ( !$create ) {
-			// Page already exists, don't create a new link.
-			return;
-		}
-		$target = self::judgmentTarget( $title->getTitleValue() );
-		if ( !$target ) {
-			return;
-		}
-
-		$judgmentPage = WikiPage::newFromID( $oldPageId );
-		JadeServices::getJudgmentIndexStorage()
-			->insertIndex( $target, $judgmentPage );
-	}
-
-	/**
-	 * Wrapper around TitleHelper::parseTitleValue, logging errors if appropriate.
-	 *
-	 * @param TitleValue $title judgment page title to parse.
-	 *
-	 * @return JudgmentTarget|null Judgment target, or null if the title
-	 *         couldn't be parsed.
-	 */
-	private static function judgmentTarget( TitleValue $title ) {
-		$status = TitleHelper::parseTitleValue( $title );
-		if ( !$status->isOK() ) {
-			if ( $title->getNamespace() === NS_JUDGMENT ) {
-				// Should be unreachable thanks to JudgmentValidator.  If
-				// something did go wrong, it should be logged and
-				// investigated.
-				// TODO: Should this be a responsibility of TitleHelper::parseTitleValue()?
-				$logger = LoggerFactory::getInstance( 'Jade' );
-				$logger->error( "Cannot parse judgment title: {$status}" );
-			}
-			return null;
-		}
-		return $status->value;
-	}
-
-}
diff --git a/includes/Hooks/MoveHooks.php b/includes/Hooks/MoveHooks.php
deleted file mode 100644
index 8cf0c08..0000000
--- a/includes/Hooks/MoveHooks.php
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade\Hooks;
-
-use Status;
-use Title;
-
-class MoveHooks {
-
-	/**
-	 * @param Title $oldTitle object of the current (old) location
-	 * @param Title $newTitle object of the new location
-	 * @param Status $status object to pass error messages to
-	 * FIXME: hook signature should be StatusValue
-	 * TODO: Is there also a higher-level hook, which can disable the "Move"
-	 * menu item?
-	 */
-	public static function onMovePageIsValidMove(
-		Title $oldTitle,
-		Title $newTitle,
-		Status $status
-	) {
-		// Deny all moves within or into JudgmentPage.
-		// TODO: In the future, we may allow some movements after validating.
-		if ( $oldTitle->getNamespace() === NS_JUDGMENT
-			|| $newTitle->getNamespace() === NS_JUDGMENT
-		) {
-			$status->error( 'jade-invalid-move-any' );
-			$status->setOK( false );
-			return;
-		}
-	}
-
-}
diff --git a/includes/JadeServices.php b/includes/JadeServices.php
deleted file mode 100644
index 5016bda..0000000
--- a/includes/JadeServices.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use MediaWiki\MediaWikiServices;
-
-class JadeServices {
-
-	public static function getEntityJudgmentSetStorage() : EntityJudgmentSetStorage {
-		return MediaWikiServices::getInstance()->getService( 'JadeEntityJudgmentSetStorage' );
-	}
-
-	public static function getJudgmentIndexStorage() : JudgmentIndexStorage {
-		return MediaWikiServices::getInstance()->getService( 'JadeJudgmentIndexStorage' );
-	}
-
-	public static function getJudgmentValidator() : JudgmentValidator {
-		return MediaWikiServices::getInstance()->getService( 'JadeJudgmentValidator' );
-	}
-
-}
diff --git a/includes/JudgmentEntityType.php b/includes/JudgmentEntityType.php
deleted file mode 100644
index d567219..0000000
--- a/includes/JudgmentEntityType.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-namespace Jade;
-
-use Status;
-use StatusValue;
-
-/**
- * Typesafe enum for entity type.
- */
-class JudgmentEntityType {
-
-	private $entityType;
-
-	/**
-	 * @param string $entityType Sanitized entity type identifier.
-	 */
-	private function __construct( $entityType ) {
-		$this->entityType = $entityType;
-	}
-
-	/**
-	 * @param string $entityType Name of wiki entity type, in lowercase.
-	 * @return StatusValue Sanitized type if good.
-	 */
-	public static function sanitizeEntityType( $entityType ) {
-		global $wgJadeEntityTypeNames;
-
-		if ( !array_key_exists( (string)$entityType, $wgJadeEntityTypeNames ) ) {
-			return Status::newFatal( 'jade-bad-entity-type', $entityType );
-		}
-
-		return Status::newGood( new self( $entityType ) );
-	}
-
-	/**
-	 * Cast entity type to raw string.
-	 */
-	public function __toString() {
-		return $this->entityType;
-	}
-
-	/**
-	 * @return string Localized title component for this type.
-	 */
-	public function getLocalizedName() {
-		global $wgJadeEntityTypeNames;
-
-		return $wgJadeEntityTypeNames[$this->entityType];
-	}
-
-}
diff --git a/includes/JudgmentIndexStorage.php b/includes/JudgmentIndexStorage.php
deleted file mode 100644
index 9eacaa0..0000000
--- a/includes/JudgmentIndexStorage.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade;
-
-use StatusValue;
-use WikiPage;
-
-/**
- * Low-level service responsible for storing secondary indexes to judgments.
- */
-interface JudgmentIndexStorage {
-
-	/**
-	 * Create any indexes needed to associate a judgment with its target.
-	 *
-	 * @param JudgmentTarget $target Wiki entity being judged.
-	 * @param WikiPage $judgmentPage Page where judgment is recorded.
-	 */
-	public function insertIndex( JudgmentTarget $target, WikiPage $judgmentPage );
-
-	/**
-	 * Delete any indexes associating a judgment with its target.
-	 *
-	 * @param JudgmentTarget $target Wiki entity being judged.
-	 * @param WikiPage $judgmentPage Page where judgment is recorded.
-	 */
-	public function deleteIndex( JudgmentTarget $target, WikiPage $judgmentPage );
-
-	/**
-	 * Update summary columns
-	 *
-	 * @param JudgmentTarget $target Wiki entity being judged.
-	 * @param array $summaryValues Map of fields to update.
-	 *
-	 * @return StatusValue indicates success.
-	 */
-	public function updateSummary( JudgmentTarget $target, array $summaryValues ) : StatusValue;
-
-}
diff --git a/includes/JudgmentLinkTable.php b/includes/JudgmentLinkTable.php
deleted file mode 100644
index d3fa3d6..0000000
--- a/includes/JudgmentLinkTable.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade;
-
-use Status;
-use StatusValue;
-use Wikimedia\Rdbms\DBError;
-use Wikimedia\Rdbms\LoadBalancer;
-use WikiPage;
-
-/**
- * Judgment index storage implemented using a RDBMS link table and indexes.
- */
-class JudgmentLinkTable implements JudgmentIndexStorage {
-
-	private $loadBalancer;
-
-	public function __construct( LoadBalancer $loadBalancer ) {
-		$this->loadBalancer = $loadBalancer;
-	}
-
-	public function insertIndex( JudgmentTarget $target, WikiPage $judgmentPage ) {
-		$tableHelper = new JudgmentLinkTableHelper( $target->entityType );
-
-		// Create row linking the judgment and its target.
-		$dbw = $this->loadBalancer->getConnection( DB_MASTER );
-		$row = [
-			$tableHelper->getTargetColumn() => $target->entityId,
-			$tableHelper->getJudgmentColumn() => $judgmentPage->getId(),
-		];
-		$dbw->insert( $tableHelper->getLinkTable(), $row, __METHOD__, [ 'IGNORE' ] );
-	}
-
-	public function deleteIndex( JudgmentTarget $target, WikiPage $judgmentPage ) {
-		$tableHelper = new JudgmentLinkTableHelper( $target->entityType );
-
-		// Delete row linking the judgment and its target.  Select the primary
-		// key first, to avoid long queries on the master database.
-		$dbr = $this->loadBalancer->getConnection( DB_REPLICA );
-		$conds = [
-			$tableHelper->getTargetColumn() => $target->entityId,
-			$tableHelper->getJudgmentColumn() => $judgmentPage->getId(),
-		];
-		$id = $dbr->selectField(
-			$tableHelper->getLinkTable(),
-			$tableHelper->getIdColumn(),
-			$conds,
-			__METHOD__ );
-
-		if ( $id !== false ) {
-			$dbw = $this->loadBalancer->getConnection( DB_MASTER );
-			$dbw->delete(
-				$tableHelper->getLinkTable(),
-				[ $tableHelper->getIdColumn() => $id ],
-				__METHOD__ );
-		}
-	}
-
-	public function updateSummary( JudgmentTarget $target, array $summaryValues ) : StatusValue {
-		if ( !$summaryValues ) {
-			// Nothing to do.
-			return Status::newGood();
-		}
-
-		$tableHelper = new JudgmentLinkTableHelper( $target->entityType );
-
-		$row = [];
-		foreach ( $summaryValues as $key => $value ) {
-			$summaryColumn = $tableHelper->getSummaryColumn( $key );
-			$row[$summaryColumn] = $value;
-		}
-
-		try {
-			$dbw = $this->loadBalancer->getConnection( DB_MASTER );
-			$dbw->update(
-				$tableHelper->getLinkTable(),
-				$row,
-				[ $tableHelper->getTargetColumn() => $target->entityId ],
-				__METHOD__
-			);
-			return Status::newGood();
-		} catch ( DBError $ex ) {
-			return Status::newFatal( 'jade-db-error', $ex->getMessage() );
-		}
-	}
-
-}
diff --git a/includes/JudgmentLinkTableHelper.php b/includes/JudgmentLinkTableHelper.php
deleted file mode 100644
index bee8550..0000000
--- a/includes/JudgmentLinkTableHelper.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade;
-
-class JudgmentLinkTableHelper {
-
-	/** @var JudgmentEntityType */
-	private $entityType;
-
-	/**
-	 * @param JudgmentEntityType $entityType Link table will be for this type.
-	 */
-	public function __construct( JudgmentEntityType $entityType ) {
-		$this->entityType = $entityType;
-	}
-
-	public function getLinkTable() {
-		// Dynamic link table name per entity type, e.g. "jade_diff_judgment".
-		return "jade_{$this->entityType}_judgment";
-	}
-
-	public function getColumnPrefix() {
-		// Table column prefix is constructed using the first letter of the entity type name.
-		$entityTypeString = (string)$this->entityType;
-		return "jade{$entityTypeString[0]}";
-	}
-
-	public function getIdColumn() {
-		$columnPrefix = $this->getColumnPrefix();
-		return "{$columnPrefix}_id";
-	}
-
-	public function getJudgmentColumn() {
-		$columnPrefix = $this->getColumnPrefix();
-		// Column linking to judgment pages, e.g. "jaded_judgment" for the diff link table.
-		return "{$columnPrefix}_judgment";
-	}
-
-	public function getTargetColumn() {
-		$columnPrefix = $this->getColumnPrefix();
-		// Column linking to judgment target revisions, e.g. "jaded_revision".
-		return "{$columnPrefix}_revision";
-	}
-
-	public function getSummaryColumn( $schema ) {
-		$columnPrefix = $this->getColumnPrefix();
-		return "{$columnPrefix}_{$schema}";
-	}
-
-}
diff --git a/includes/JudgmentPageWikitextRenderer.php b/includes/JudgmentPageWikitextRenderer.php
deleted file mode 100644
index b8a68c4..0000000
--- a/includes/JudgmentPageWikitextRenderer.php
+++ /dev/null
@@ -1,193 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use CentralIdLookup;
-use LogicException;
-use MediaWiki\MediaWikiServices;
-use TemplateParser;
-use User;
-
-/**
- * Renders judgments into wikitext, suitable for rendering a judgment page.
- *
- * TODO: Review whether we should be using content language, e.g. if translate
- * tags are present in the freeform wikitext fields.
- */
-class JudgmentPageWikitextRenderer {
-
-	const TEMPLATES_PATH = '../templates';
-
-	/** Template to render a judgment page as wikitext. */
-	const JUDGMENT_PAGE_TEMPLATE = 'judgment_page.wiki';
-
-	private $templateRenderer;
-
-	public function __construct() {
-		$templatePath = __DIR__ . '/' . self::TEMPLATES_PATH;
-		$this->templateRenderer = new TemplateParser( $templatePath );
-	}
-
-	/**
-	 * Render as wikitext.
-	 *
-	 * @param object $judgmentData Judgment page content, decoded as a stdClass.
-	 *
-	 * @return string Wikitext representation.
-	 */
-	public function getWikitext( $judgmentData ) {
-		// Transform raw judgment data into parameters and wikitext suitable
-		// for use in the template.
-		$judgmentList = [];
-		foreach ( $judgmentData->judgments as $rawJudgment ) {
-			$judgment = [];
-
-			// Notes are literal wikitext, or a placeholder if empty.
-			$judgment['notes'] = $rawJudgment->notes ?? '';
-
-			$judgment['value'] = $this->getSchemaSummary( $rawJudgment->schema );
-
-			$judgment['preferred'] = $rawJudgment->preferred;
-
-			if ( property_exists( $rawJudgment, 'endorsements' ) ) {
-				$judgment['hasEndorsements'] = true;
-				$judgment['endorsements'] = $this->getEndorsements( $rawJudgment->endorsements );
-			}
-
-			$judgmentList[] = $judgment;
-		}
-		$params = [ 'judgments' => $judgmentList ];
-
-		// Translated strings.
-		$params['msg-jade-endorsement'] = wfMessage( 'jade-endorsement' )->plain();
-		$params['msg-jade-endorsements'] = wfMessage( 'jade-endorsements' )->plain();
-		$params['msg-jade-user'] = wfMessage( 'jade-user' )->plain();
-
-		return $this->templateRenderer->processTemplate(
-			self::JUDGMENT_PAGE_TEMPLATE,
-			$params );
-	}
-
-	/**
-	 * Produce a human-readable summary of the judgment schema value.
-	 *
-	 * @param object $schemaList Judgment's schema values, as a map from schema
-	 *        name to judgment value for that schema.
-	 *
-	 * @return string Wikitext snippet summarizing the values.
-	 */
-	private function getSchemaSummary( $schemaList ) {
-		$contentLanguage = MediaWikiServices::getInstance()->getContentLanguage();
-
-		// Convert schema values to a human-readable summary of the judgment.
-		$schemaTextList = [];
-		foreach ( $schemaList as $schemaName => $value ) {
-			// Human text for this judgment schema's value.
-			$schemaTextList[] = $this->getSchemaValueText( $schemaName, $value );
-		}
-		return $contentLanguage->listToText( $schemaTextList );
-	}
-
-	private function getSchemaValueText( $schemaName, $value ) {
-		if ( is_bool( $value ) ) {
-			$valueStr = $value ? 'true' : 'false';
-		} else {
-			$valueStr = strtolower( strval( $value ) );
-		}
-
-		$calculatedMessageKey = "jade-{$schemaName}-scale-{$valueStr}-label";
-		$message = wfMessage( $calculatedMessageKey );
-
-		if ( $message->exists() ) {
-			// If a message exists for this exact value, use it.
-			return $message->inContentLanguage()->text();
-		} elseif ( $schemaName === 'contentquality' ) {
-			// Generic statement for an unknown content quality key.  For wikis
-			// that override the article quality scale, we'll need to figure
-			// out if it's appropriate to include the custom keys in the
-			// extension, or if these should be provided as local wiki strings.
-			return wfMessage( 'jade-contentquality-generic', $value )->inContentLanguage()->text();
-		}
-
-		// It should be impossible to get here.  Fall through by displaying the
-		// regular missing translation message.
-		return $message->inContentLanguage()->text();
-	}
-
-	/**
-	 * Return a human-readable list of endorsements.
-	 *
-	 * @param array $endorsementList Endorsements as a list of stdClass.
-	 *
-	 * @return string[] Wikitext list of endorsements, usually multi-line.
-	 */
-	private function getEndorsements( array $endorsementList ) {
-		$endorsementTextList = [];
-		foreach ( $endorsementList as $rawEndorsement ) {
-			$endorsement = [];
-
-			// Build a user label for the endorsement author.
-			$endorsement['user'] = $this->getUserWikitext( $rawEndorsement->user );
-
-			// Comments are literal wikitext.
-			$endorsement['comment'] = $rawEndorsement->comment ?? '';
-
-			$endorsementTextList[] = $endorsement;
-		}
-		return $endorsementTextList;
-	}
-
-	/**
-	 * Render global user as wikitext.
-	 *
-	 * @param object $user Contains either an IP or CentralAuth user ID.
-	 *
-	 * @return string Linked wikitext for the user.
-	 */
-	private function getUserWikitext( $user ) {
-		if ( property_exists( $user, 'cid' ) ) {
-			// Look up central user.
-			$username = CentralIdLookup::factory()->nameFromCentralId( $user->cid );
-			if ( $username === null ) {
-				// Missing users or suppressed usernames will be stubbed.
-				// FIXME: We probably want an i18n message here like "User <id> missing".
-				return "⧼{$user->cid}⧽";
-			} else {
-				return "[[User:{$username}]]";
-			}
-		} elseif ( property_exists( $user, 'id' ) ) {
-			// Look up local ID.
-			$localUsername = User::whoIs( $user->id );
-			if ( $localUsername === false || User::newFromId( $user->id )->isHidden() ) {
-				// Missing or blocked user.
-				// FIXME: Make the error more helpful.
-				return "⧼{$user->id}⧽";
-			} else {
-				return "[[User:{$localUsername}]]";
-			}
-		} elseif ( property_exists( $user, 'ip' ) ) {
-			return "[[User:{$user->ip}]]";
-		}
-
-		throw new LogicException( 'Broken user data structure' );
-	}
-
-}
diff --git a/includes/JudgmentSummarizer.php b/includes/JudgmentSummarizer.php
deleted file mode 100644
index 5676ce0..0000000
--- a/includes/JudgmentSummarizer.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade;
-
-use Content;
-use Jade\Content\JudgmentContent;
-use Status;
-use StatusValue;
-
-class JudgmentSummarizer {
-
-	/**
-	 * Extract preferred judgment values.
-	 *
-	 * @param Content $content Judgment page content to summarize.
-	 * @return StatusValue When successful, includes a map from schema to preferred value.
-	 */
-	public static function getSummaryFromContent( Content $content ) {
-		if ( JudgmentContent::CONTENT_MODEL_JUDGMENT !== $content->getModel() ) {
-			return Status::newFatal( 'jade-content-model-error' );
-		}
-		// FIXME: Relies on duck typing, unfriendly to static analysis.
-		$data = $content->getData()->getValue();
-
-		$preferred = self::extractPreferredJudgment( $data );
-		return Status::newGood( (array)$preferred->schema );
-	}
-
-	/**
-	 * @param object $data Judgment page content as an object.
-	 *
-	 * @return object preferred judgment
-	 */
-	private static function extractPreferredJudgment( $data ) {
-		$preferredList = array_filter(
-			$data->judgments,
-			function ( $judgment ) {
-				return $judgment->preferred;
-			}
-		);
-		return $preferredList[0];
-	}
-
-}
diff --git a/includes/JudgmentTarget.php b/includes/JudgmentTarget.php
deleted file mode 100644
index 710922a..0000000
--- a/includes/JudgmentTarget.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-namespace Jade;
-
-/**
- * Pointer to wiki entity type and ID.
- */
-class JudgmentTarget {
-
-	// Only friend classes should be accessing these :-/
-	/** @var JudgmentEntityType */
-	public $entityType;
-	/** @var int */
-	public $entityId;
-
-	/**
-	 * Create a judgment target from type name and ID.
-	 *
-	 * @param JudgmentEntityType $entityType Name of wiki entity type, in lowercase.
-	 * @param int $entityId Page ID or Revision ID of the entity.
-	 */
-	public function __construct( JudgmentEntityType $entityType, $entityId ) {
-		$this->entityType = $entityType;
-		$this->entityId = intval( $entityId );
-	}
-
-}
diff --git a/includes/JudgmentValidator.php b/includes/JudgmentValidator.php
deleted file mode 100644
index 4829b2e..0000000
--- a/includes/JudgmentValidator.php
+++ /dev/null
@@ -1,338 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use CentralIdLookup;
-use Config;
-use DateTime;
-use IP;
-use JsonSchema\Constraints\Constraint;
-use JsonSchema\Exception\ValidationException;
-use JsonSchema\Validator;
-use MediaWiki\Revision\RevisionStore;
-use Psr\Log\LoggerInterface;
-use Status;
-use StatusValue;
-use User;
-use WikiPage;
-
-class JudgmentValidator {
-	const JUDGMENT_SCHEMA = '/../jsonschema/judgment/v1.json';
-	const SCORING_SCHEMA_ROOT = '/../jsonschema/scoring';
-
-	/**
-	 * @var Config
-	 */
-	private $config;
-
-	/**
-	 * @var LoggerInterface
-	 */
-	private $logger;
-
-	/**
-	 * @var RevisionStore
-	 */
-	private $revisionStore;
-
-	public function __construct(
-		Config $config,
-		LoggerInterface $logger,
-		RevisionStore $revisionStore
-	) {
-		$this->config = $config;
-		$this->logger = $logger;
-		$this->revisionStore = $revisionStore;
-	}
-
-	/**
-	 * Check that the judgment content is well-formed.
-	 *
-	 * @param object $data Data structure to validate.
-	 *
-	 * @return StatusValue isOK if the content is valid.
-	 */
-	public function validateJudgmentContent( $data ) {
-		$status = $this->validateBasicSchema( $data );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-
-		$status = $this->validateEndorsementUsers( $data );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-
-		$status = $this->validateEndorsementTimestamps( $data );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-
-		$status = $this->validateContentQualityScale( $data );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-
-		return $this->validatePreferred( $data );
-	}
-
-	/**
-	 * Ensure that the general judgment schema is followed.
-	 *
-	 * @param object $data Data structure to validate.
-	 *
-	 * @return StatusValue isOK?
-	 */
-	protected function validateBasicSchema( $data ) {
-		return $this->validateAgainstSchema( $data, __DIR__ . self::JUDGMENT_SCHEMA );
-	}
-
-	/**
-	 * Ensure that the score schemas are allowed by configuration.
-	 *
-	 * @param JudgmentEntityType $entityType Machine name for entity type.
-	 * @param object $data Data structure to validate.
-	 *
-	 * @return StatusValue isOK if valid.
-	 */
-	protected function validateEntitySchema( JudgmentEntityType $entityType, $data ) {
-		$allowedScoringSchemas = $this->config->get( 'JadeAllowedScoringSchemas' );
-		$entityAllowedSchemas = $allowedScoringSchemas[(string)$entityType];
-
-		foreach ( $data->judgments as $judgment ) {
-			foreach ( $judgment->schema as $schemaName => $value ) {
-				// Schema must be allowed.
-				if ( !in_array( $schemaName, $entityAllowedSchemas ) ) {
-					return Status::newFatal( 'jade-illegal-schema', $schemaName );
-				}
-			}
-		}
-		return Status::newGood();
-	}
-
-	/**
-	 * Check that exactly one judgment is preferred.
-	 *
-	 * @param object $data Data structure to validate.
-	 *
-	 * @return StatusValue isOK if valid.
-	 */
-	protected function validatePreferred( $data ) {
-		$preferredCount = 0;
-		foreach ( $data->judgments as $judgment ) {
-			if ( $judgment->preferred ?? false ) {
-				$preferredCount++;
-			}
-		}
-		if ( $preferredCount < 1 ) {
-			return Status::newFatal( 'jade-none-preferred' );
-		}
-		if ( $preferredCount > 1 ) {
-			return Status::newFatal( 'jade-too-many-preferred' );
-		}
-
-		return Status::newGood();
-	}
-
-	/**
-	 * Special handling for the contentquality scale, as legal values come from
-	 * configuration and vary per wiki.
-	 *
-	 * @param object $data Data structure to validate.
-	 *
-	 * @return StatusValue isOK if valid.
-	 */
-	protected function validateContentQualityScale( $data ) {
-		global $wgJadeContentQualityLevels;
-
-		foreach ( $data->judgments as $judgment ) {
-			foreach ( $judgment->schema as $schemaName => $value ) {
-				// Only validate the contentquality scale.
-				if ( $schemaName !== 'contentquality' ) {
-					continue;
-				}
-
-				// Does this 1-based index appear in the locally-configured scale?
-				// TODO: Generalize this validation to reuse with other ordinal fields.
-				if ( !in_array( $value, range( 1, $wgJadeContentQualityLevels ) ) ) {
-					return Status::newFatal(
-						'jade-bad-contentquality-value',
-						$value,
-						$wgJadeContentQualityLevels );
-				}
-			}
-		}
-		return Status::newGood();
-	}
-
-	protected function validateEndorsementUsers( $data ) {
-		foreach ( $data->judgments as $judgment ) {
-			if ( !property_exists( $judgment, 'endorsements' ) ) {
-				// No endorsements, pass.
-				continue;
-			}
-
-			foreach ( $judgment->endorsements as $endorsement ) {
-				if ( property_exists( $endorsement->user, 'ip' ) ) {
-					// Check that the IP address is a real thing.
-					if ( !IP::isValid( $endorsement->user->ip ) ) {
-						return Status::newFatal( 'jade-user-ip-invalid', $endorsement->user->ip );
-					}
-				}
-
-				if ( property_exists( $endorsement->user, 'id' ) ) {
-					// Lookup by local user ID.
-					// TODO: Can be optimized by querying all users at once.
-					$localUsername = User::whoIs( intval( $endorsement->user->id ) );
-					if ( $localUsername === false ) {
-						// No such user.
-						return Status::newFatal( 'jade-user-local-id-invalid', $endorsement->user->id );
-					}
-				}
-
-				if ( property_exists( $endorsement->user, 'cid' ) ) {
-					// Lookup by central user ID.
-					$localUser = CentralIdLookup::factory()->localUserFromCentralId(
-						intval( $endorsement->user->cid ),
-						CentralIdLookup::AUDIENCE_RAW );
-					if ( $localUser === null ) {
-						// No such user.
-						return Status::newFatal( 'jade-user-central-id-invalid', $endorsement->user->cid );
-					}
-
-					// Check that the central and local users match.
-					if ( $localUser->getId() !== intval( $endorsement->user->id ) ) {
-						// IDs don't match.
-						return Status::newFatal(
-							'jade-user-id-mismatch', $endorsement->user->id, $endorsement->user->cid );
-					}
-				}
-			}
-		}
-		return Status::newGood();
-	}
-
-	protected function validateEndorsementTimestamps( $data ) {
-		foreach ( $data->judgments as $judgment ) {
-			if ( !property_exists( $judgment, 'endorsements' ) ) {
-				// No endorsements, pass.
-				continue;
-			}
-
-			foreach ( $judgment->endorsements as $endorsement ) {
-				if ( property_exists( $endorsement, 'created' ) ) {
-					$date = DateTime::createFromFormat( DateTime::ATOM, $endorsement->created );
-					if ( $date === false ) {
-						return Status::newFatal(
-							'jade-created-timestamp-invalid', $endorsement->created );
-					}
-				}
-			}
-		}
-		return Status::newGood();
-	}
-
-	/**
-	 * Ensure that we're judging a real entity.
-	 *
-	 * @param string $type Entity type
-	 * @param int $id Entity ID
-	 *
-	 * @return StatusValue results of validation.
-	 */
-	protected function validateEntity( $type, $id ) {
-		switch ( $type ) {
-			case 'diff':
-			case 'revision':
-				// Find Revision.
-				$revision = $this->revisionStore->getRevisionById( $id );
-				if ( $revision === null ) {
-					return Status::newFatal( 'jade-bad-revision-id', $id );
-				}
-				break;
-			default:
-				// This is unreachable, but blow up just in case.
-				return Status::newFatal( 'jade-bad-entity-type', $type );
-		}
-		return Status::newGood();
-	}
-
-	/**
-	 * Ensure that the page title is allowed, the entity exists, and that
-	 * judgment schemas match the entity type.
-	 *
-	 * @param WikiPage $page Page in which we're trying to store this judgment.
-	 * @param object $judgment Judgment data to validate against.
-	 *
-	 * @return StatusValue isOK if the page is valid, or fatal and the error message if invalid.
-	 */
-	public function validatePageTitle( WikiPage $page, $judgment ) {
-		$title = $page->getTitle()->getTitleValue();
-
-		$status = TitleHelper::parseTitleValue( $title );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-		$target = $status->value;
-
-		// Assert that the title has the canonical form and, for example, no
-		// leading zeroes.
-		$expectedTitle = TitleHelper::buildJadeTitle( $target );
-		if ( $expectedTitle->getDBkey() !== $title->getDBkey() ) {
-			return Status::newFatal( 'jade-non-canonical-title', $expectedTitle->getDBkey() );
-		}
-
-		$status = $this->validateEntity( $target->entityType, $target->entityId );
-		if ( !$status->isOK() ) {
-			return $status;
-		}
-		return $this->validateEntitySchema( $target->entityType, $judgment );
-	}
-
-	/**
-	 * Helper for comparing data against a JSON schema.  See
-	 * http://json-schema.org
-	 *
-	 * @param object $data Data structure to validate.
-	 * @param string $schemaPath Relative path to the schema we should use to
-	 * validate.
-	 *
-	 * @return StatusValue isOK if valid.
-	 */
-	protected function validateAgainstSchema( $data, $schemaPath ) {
-		$schemaDoc = (object)[ '$ref' => 'file://' . realpath( $schemaPath ) ];
-
-		$validator = new Validator;
-		try {
-			$validator->validate(
-				$data,
-				$schemaDoc,
-				Constraint::CHECK_MODE_EXCEPTIONS
-			);
-			return Status::newGood();
-		} catch ( ValidationException $ex ) {
-			// FIXME: English-only errors from justinrainbow!  Look into
-			// EventLogging JSON validation for error i18n.
-			return Status::newFatal( 'jade-bad-content', $ex->getMessage() );
-		}
-	}
-
-}
diff --git a/includes/PageEntityJudgmentSetStorage.php b/includes/PageEntityJudgmentSetStorage.php
deleted file mode 100644
index 2ee5214..0000000
--- a/includes/PageEntityJudgmentSetStorage.php
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use ChangeTags;
-use FormatJson;
-use Status;
-use StatusValue;
-use Title;
-use WikiPage;
-
-use Jade\Content\JudgmentContent;
-
-/**
- * Backend to store judgments as wiki pages under a new namespace.
- */
-class PageEntityJudgmentSetStorage implements EntityJudgmentSetStorage {
-
-	/**
-	 * @param JudgmentTarget $target identity of target wiki entity.
-	 * @param array $judgmentSet All judgments on this entity, as nested
-	 * associative arrays, normalized for storage.
-	 * @param string $summary Edit summary.
-	 * @param array $tags Optional list of change tags to set on the revision being created.
-	 *
-	 * @return StatusValue isOK if the edit was successful.
-	 */
-	public function storeJudgmentSet(
-		JudgmentTarget $target,
-		array $judgmentSet,
-		$summary,
-		array $tags
-	) {
-		global $wgUser;
-
-		$title = TitleHelper::buildJadeTitle( $target );
-		$dbTitle = Title::newFromTitleValue( $title );
-		$page = WikiPage::factory( $dbTitle );
-
-		// TODO: Why aren't these permissions checks already handled by
-		// doEditContent?
-		if ( !$page->exists() ) {
-			if ( !$dbTitle->userCan( 'create', $wgUser ) ) {
-				return Status::newFatal( 'jade-cannot-create-page' );
-			}
-		}
-		// `edit` contains checks not present in `create`, do those as well.
-		if ( !$dbTitle->userCan( 'edit', $wgUser ) ) {
-			return Status::newFatal( 'jade-cannot-edit-page' );
-		}
-		if ( count( $tags ) > 0 ) {
-			$status = ChangeTags::canAddTagsAccompanyingChange( $tags, $wgUser );
-			if ( !$status->isOK() ) {
-				return $status;
-			}
-		}
-
-		// Serialize to a new judgment ContentHandler.
-		$judgmentText = FormatJson::encode( $judgmentSet, true, 0 );
-		$content = new JudgmentContent( $judgmentText );
-
-		// TODO: Migrate to use the PageUpdater API once it matures.
-		return $page->doEditContent(
-			$content,
-			$summary,
-			0,
-			false,
-			$wgUser,
-			null,
-			$tags
-		);
-	}
-
-	/**
-	 * @param JudgmentTarget $target identity of target wiki entity.
-	 *
-	 * @return StatusValue with array value containing all judgments for this
-	 *         entity.
-	 */
-	public function loadJudgmentSet( JudgmentTarget $target ) {
-		$title = TitleHelper::buildJadeTitle( $target );
-		$dbTitle = Title::newFromTitleValue( $title );
-		$page = WikiPage::factory( $dbTitle );
-
-		$currentContent = $page->getContent();
-		// Return content as an associative array.
-		if ( $currentContent !== null ) {
-			$currentJudgment = FormatJson::decode( $currentContent->getNativeData(), true );
-		} else {
-			$currentJudgment = [];
-		}
-		return Status::newGood( $currentJudgment );
-	}
-
-}
diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php
deleted file mode 100644
index e5d4a7b..0000000
--- a/includes/ServiceWiring.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use MediaWiki\Logger\LoggerFactory;
-use MediaWiki\MediaWikiServices;
-use RequestContext;
-
-if ( !class_exists( ServiceWiring::class ) ) {
-	class ServiceWiring {
-
-		public static function getWiring() {
-			return [
-
-				'JadeEntityJudgmentSetStorage' => function ( MediaWikiServices $services ) {
-					return new PageEntityJudgmentSetStorage();
-				},
-
-				'JadeJudgmentIndexStorage' => function ( MediaWikiServices $services ) {
-					return new JudgmentLinkTable(
-						$services->getDBLoadBalancer()
-					);
-				},
-
-				'JadeJudgmentValidator' => function ( MediaWikiServices $services ) {
-					return new JudgmentValidator(
-						RequestContext::getMain()->getConfig(),
-						LoggerFactory::getInstance( 'Jade' ),
-						$services->getRevisionStore()
-					);
-				},
-
-			];
-		}
-
-	}
-}
-
-// @codeCoverageIgnoreStart
-return ServiceWiring::getWiring();
-// @codeCoverageIgnoreEnd
diff --git a/includes/TitleHelper.php b/includes/TitleHelper.php
deleted file mode 100644
index f511431..0000000
--- a/includes/TitleHelper.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade;
-
-use Status;
-use StatusValue;
-use TitleValue;
-
-class TitleHelper {
-
-	/**
-	 * Build Title object for the judgment page on an entity.
-	 *
-	 * @param JudgmentTarget $target Wiki entity to build a judgment page title for.
-	 *
-	 * @return TitleValue Path to where judgments about the given entity should
-	 *         be stored.
-	 */
-	public static function buildJadeTitle( JudgmentTarget $target ) {
-		// Get localized title component.
-		$localTitle = $target->entityType->getLocalizedName();
-
-		return new TitleValue(
-			NS_JUDGMENT,
-			"{$localTitle}/{$target->entityId}"
-		);
-	}
-
-	/**
-	 * Parse Judgment Title object to get target wiki entity information.
-	 *
-	 * @param TitleValue $title Judgment page title.
-	 *
-	 * @return StatusValue with JudgmentTarget value.
-	 */
-	public static function parseTitleValue( TitleValue $title ) {
-		global $wgJadeEntityTypeNames;
-
-		$namespace = $title->getNamespace();
-		if ( $namespace !== NS_JUDGMENT ) {
-			// This is not a judgment, fail.
-			return Status::newFatal( 'jade-bad-title-namespace' );
-		}
-		$titleParts = explode( '/', $title->getDBkey() );
-		if ( count( $titleParts ) !== 2 ) {
-			return Status::newFatal( 'jade-bad-title-format' );
-		}
-		// Find localized title component and get type identifier.
-		$typeName = array_search( $titleParts[0], $wgJadeEntityTypeNames, true );
-		$status = JudgmentEntityType::sanitizeEntityType( $typeName );
-		if ( !$status->isOK() ) {
-			return Status::newFatal( 'jade-bad-entity-type', $titleParts[0] );
-		}
-		$entityType = $status->value;
-		$entityId = intval( $titleParts[1] );
-		if ( $entityId === 0 ) {
-			return Status::newFatal( 'jade-bad-entity-id-format', $titleParts[1] );
-		}
-
-		$target = new JudgmentTarget( $entityType, $entityId );
-		return Status::newGood( $target );
-	}
-
-}
diff --git a/jsonschema/judgment/v1.json b/jsonschema/judgment/v1.json
deleted file mode 100644
index f7ea20b..0000000
--- a/jsonschema/judgment/v1.json
+++ /dev/null
@@ -1,134 +0,0 @@
-{
-	"title": "jade/judgment-set",
-	"$schema": "http://json-schema.org/draft-04/schema#",
-	"id": "https://phabricator.wikimedia.org/diffusion/EJAD/browse/master/jsonschema/judgment/v1.json?view=raw",
-	"type": "object",
-	"properties": {
-		"judgments": {
-			"type": "array",
-			"items": {
-				"$ref": "#/definitions/judgment"
-			}
-		}
-	},
-	"additionalProperties": false,
-	"definitions": {
-		"endorsement": {
-			"type": "object",
-			"properties": {
-				"comment": {
-					"type": "string",
-					"description": "Wikitext explaining why the user is endorsing"
-				},
-				"user": {
-					"$ref": "#/definitions/user",
-					"description": "Endorsement author"
-				},
-				"origin": {
-					"type": "string",
-					"description": "Plain text identifying the tool and workflow used to make this endorsement"
-				},
-				"created": {
-					"type": "string",
-					"description": "Time created in ISO 8601"
-				}
-			},
-			"required": [
-				"user", "created"
-			],
-			"additionalProperties": false
-		},
-		"judgment": {
-			"type": "object",
-			"properties": {
-				"schema": {
-					"oneOf": [
-						{ "$ref": "#/definitions/schema/contentquality" },
-						{ "$ref": "#/definitions/schema/editquality" }
-					]
-				},
-				"notes": {
-					"type": "string",
-					"description": "Wikitext comments or justification of this judgment."
-				},
-				"preferred": {
-					"type": "boolean",
-					"default": false,
-					"description": "True when this judgment best represents a consensus opinion."
-				},
-				"endorsements": {
-					"type": "array",
-					"items": {
-						"$ref": "#/definitions/endorsement"
-					},
-					"minItems": 1
-				}
-			},
-			"required": [
-				"preferred",
-				"schema"
-			],
-			"additionalProperties": false
-		},
-		"schema": {
-			"contentquality": {
-				"type": "object",
-				"properties": {
-					"contentquality": {
-						"type": "integer"
-					}
-				},
-				"additionalProperties": false,
-				"required": [ "contentquality" ]
-			},
-			"editquality": {
-				"type": "object",
-				"properties": {
-					"damaging": {
-						"type": "boolean"
-					},
-					"goodfaith": {
-						"type": "boolean"
-					}
-				},
-				"additionalProperties": false,
-				"required": [
-					"damaging",
-					"goodfaith"
-				]
-			}
-		},
-		"user": {
-			"oneOf": [
-				{
-					"type": "object",
-					"properties": {
-						"id": {
-							"type": "integer",
-							"description": "Local wiki ID for contributor.",
-							"minimum": 0
-						},
-						"cid": {
-							"type": "integer",
-							"description": "Central ID for contributor.",
-							"minimum": 0
-						}
-					},
-					"additionalProperties": false,
-					"required": [ "id" ]
-				},
-				{
-					"type": "object",
-					"properties": {
-						"ip": {
-							"type": "string",
-							"description": "IP address (v4 or v6) for contributor."
-						}
-					},
-					"additionalProperties": false,
-					"required": [ "ip" ]
-				}
-			]
-		}
-	}
-}
diff --git a/maintenance/CleanJudgmentLinks.php b/maintenance/CleanJudgmentLinks.php
deleted file mode 100644
index a6e84b6..0000000
--- a/maintenance/CleanJudgmentLinks.php
+++ /dev/null
@@ -1,249 +0,0 @@
-<?php
-
-namespace Jade\Maintenance;
-
-use Jade\JadeServices;
-use Jade\JudgmentEntityType;
-use Jade\JudgmentLinkTableHelper;
-use Jade\JudgmentSummarizer;
-use Jade\TitleHelper;
-use Maintenance;
-use MediaWiki\MediaWikiServices;
-use Title;
-use Wikimedia\Rdbms\ResultWrapper;
-use WikiPage;
-
-// @codeCoverageIgnoreStart
-require_once getenv( 'MW_INSTALL_PATH' ) !== false
-	? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php'
-	: __DIR__ . '/../../../maintenance/Maintenance.php';
-// @codeCoverageIgnoreEnd
-
-/**
- * Script to enforce data integrity on the judgment link tables.
- *
- * @ingroup Maintenance
- *
- * TODO: We're breaking the JudgmentIndexStorage abstraction here.
- * Database operations could be extracted to a maintenance helper class
- * instead.  However, I'm not sure yet whether an alternative storage backend
- * would have the same concerns, so leaving to future work.
- */
-class CleanJudgmentLinks extends Maintenance {
-
-	const DEFAULT_SQL_SELECT_SIZE = 1000;
-
-	public function __construct() {
-		parent::__construct();
-
-		$this->requireExtension( 'Jade' );
-		$this->addDescription( 'Clean up judgment link tables, looking for orphaned ' .
-			'and missing links.' );
-		$this->addOption( 'dry-run', 'Search but don\'t make changes to the link tables.' );
-
-		$this->setBatchSize( self::DEFAULT_SQL_SELECT_SIZE );
-	}
-
-	public function execute() {
-		$this->output( "Starting Jade cleanup...\n" );
-
-		$this->findAndDeleteOrphanedLinks();
-		$this->findAndConnectUnlinkedJudgments();
-
-		$this->output( "Done.\n" );
-	}
-
-	private function findAndDeleteOrphanedLinks() {
-		global $wgJadeEntityTypeNames;
-		$entityTypes = array_keys( $wgJadeEntityTypeNames );
-
-		foreach ( $entityTypes as $type ) {
-			$skipPastId = 0;
-			$status = JudgmentEntityType::sanitizeEntityType( $type );
-			$entityType = $status->value;
-
-			do {
-				$orphans = $this->findOrphanedLinks( $entityType, $skipPastId );
-				if ( $orphans ) {
-					$this->deleteOrphanedLinks( $orphans, $entityType );
-					$skipPastId = $orphans[count( $orphans ) - 1];
-				}
-			} while ( count( $orphans ) );
-		}
-	}
-
-	/**
-	 * Find link entries for which the judgment page is missing.
-	 *
-	 * @param JudgmentEntityType $type Entity type for this batch.
-	 * @param int $skipPastId Search beginning with this primary key value.
-	 *
-	 * @return array List of primary keys for orphaned link table rows.
-	 */
-	private function findOrphanedLinks( $type, $skipPastId = 0 ) {
-		$tableHelper = new JudgmentLinkTableHelper( $type );
-
-		$dbr = MediaWikiServices::getInstance()
-			->getDBLoadBalancer()->getConnection( DB_REPLICA );
-		$orphans = $dbr->selectFieldValues(
-			[
-				$tableHelper->getLinkTable(),
-				'page',
-			],
-			$tableHelper->getIdColumn(),
-			[
-				'page_id' => null,
-				"{$tableHelper->getIdColumn()} > {$skipPastId}",
-			],
-			__METHOD__,
-			[
-				'LIMIT' => $this->getBatchSize(),
-				'ORDER BY' => $tableHelper->getIdColumn(),
-			],
-			[ 'page' => [
-				'LEFT JOIN', "page_id = {$tableHelper->getJudgmentColumn()}",
-			] ]
-		);
-		return $orphans;
-	}
-
-	/**
-	 * Bulk delete link rows.
-	 *
-	 * @param array $orphans List of primary keys to link rows.
-	 * @param JudgmentEntityType $type Entity type
-	 */
-	private function deleteOrphanedLinks( $orphans, $type ) {
-		$tableHelper = new JudgmentLinkTableHelper( $type );
-
-		$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
-		$dbw = $lbFactory->getMainLB()->getConnection( DB_MASTER );
-		if ( !$this->getOption( 'dry-run' ) ) {
-			$dbw->delete(
-				$tableHelper->getLinkTable(),
-				[ $tableHelper->getIdColumn() => $orphans ],
-				__METHOD__
-			);
-			$lbFactory->waitForReplication();
-		}
-
-		$numDeleted = count( $orphans );
-		$message = "Deleted {$numDeleted} orphaned {$type} links.";
-		if ( $this->getOption( 'dry-run' ) ) {
-			$message .= ' (dry run)';
-		}
-		$this->output( "{$message}\n" );
-	}
-
-	private function findAndConnectUnlinkedJudgments() {
-		global $wgJadeEntityTypeNames;
-		$entityTypes = array_keys( $wgJadeEntityTypeNames );
-
-		foreach ( $entityTypes as $type ) {
-			$skipPastId = 0;
-			do {
-				$status = JudgmentEntityType::sanitizeEntityType( $type );
-				$entityType = $status->value;
-
-				$unlinked = $this->findUnlinkedJudgments( $entityType, $skipPastId );
-				if ( $unlinked->numRows() > 0 ) {
-					$skipPastId = $this->connectUnlinkedJudgments( $unlinked, $entityType );
-				}
-			} while ( $unlinked->numRows() > 0 );
-		}
-	}
-
-	private function findUnlinkedJudgments( JudgmentEntityType $type, $skipPastId ) {
-		$tableHelper = new JudgmentLinkTableHelper( $type );
-		$titlePrefix = $type->getLocalizedName();
-
-		// Find judgments with no matching link row.
-		$dbr = MediaWikiServices::getInstance()
-			->getDBLoadBalancer()->getConnection( DB_REPLICA );
-		$unlinked = $dbr->select(
-			[
-				$tableHelper->getLinkTable(),
-				'page',
-			],
-			[ 'page_id', 'page_namespace', 'page_title', $tableHelper->getIdColumn() ],
-			[
-				'page_namespace = ' . intval( NS_JUDGMENT ),
-				'page_title ' . $dbr->buildLike( "{$titlePrefix}/", $dbr->anyString() ),
-				"page_id > {$skipPastId}",
-				$tableHelper->getJudgmentColumn() => null,
-			],
-			__METHOD__,
-			[
-				'LIMIT' => $this->getBatchSize(),
-				'ORDER BY' => $tableHelper->getIdColumn(),
-			],
-			[ $tableHelper->getLinkTable() => [
-				'LEFT JOIN', "page_id = {$tableHelper->getJudgmentColumn()}",
-			] ]
-		);
-
-		return $unlinked;
-	}
-
-	/**
-	 * Helper to make new links for a list of judgment pages.
-	 *
-	 * @param ResultWrapper $unlinked judgment pages to reconnect.
-	 * @param JudgmentEntityType $entityType Entity type
-	 *
-	 * @return int Highest primary key touched in this batch.
-	 */
-	private function connectUnlinkedJudgments(
-		ResultWrapper $unlinked,
-		JudgmentEntityType $entityType
-	) {
-		$tableHelper = new JudgmentLinkTableHelper( $entityType );
-		$indexStorage = JadeServices::getJudgmentIndexStorage();
-		$lastId = 0;
-
-		foreach ( $unlinked as $row ) {
-			$title = Title::newFromRow( $row );
-			$status = TitleHelper::parseTitleValue( $title->getTitleValue() );
-			if ( !$status->isOK() ) {
-				$this->error( "Failed to parse {$title}: {$status}\n" );
-			} else {
-				$judgmentTarget = $status->value;
-				$judgmentPage = WikiPage::factory( $title );
-
-				// Rebuild the index.
-				if ( !$this->getOption( 'dry-run' ) ) {
-					$indexStorage->insertIndex( $judgmentTarget, $judgmentPage );
-				}
-
-				// Summarize judgment.
-				$judgmentContent = $judgmentPage->getContent();
-				$status = JudgmentSummarizer::getSummaryFromContent( $judgmentContent );
-				if ( !$status->isOK() ) {
-					$this->error( "Can't summarize content for {$title}: {$status}" );
-				} else {
-					$summaryValues = $status->value;
-					if ( !$this->getOption( 'dry-run' ) ) {
-						$indexStorage->updateSummary( $judgmentTarget, $summaryValues );
-					}
-				}
-			}
-
-			$lastId = $row->page_id;
-		}
-		MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->waitForReplication();
-
-		$message = "Connected {$unlinked->numRows()} unlinked {$entityType} judgments.";
-		if ( $this->getOption( 'dry-run' ) ) {
-			$message .= ' (dry run)';
-		}
-		$this->output( "{$message}\n" );
-
-		return $lastId;
-	}
-
-}
-
-// @codeCoverageIgnoreStart
-$maintClass = CleanJudgmentLinks::class;
-require_once RUN_MAINTENANCE_IF_MAIN;
-// @codeCoverageIgnoreEnd
diff --git a/package.json b/package.json
deleted file mode 100644
index f3b1c6b..0000000
--- a/package.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"private": true,
-	"scripts": {
-		"test": "grunt test"
-	},
-	"devDependencies": {
-		"grunt": "1.0.3",
-		"grunt-banana-checker": "0.6.0",
-		"grunt-jsonlint": "1.1.0"
-	}
-}
diff --git a/sql/jade_diff_judgment.sql b/sql/jade_diff_judgment.sql
deleted file mode 100644
index 958410b..0000000
--- a/sql/jade_diff_judgment.sql
+++ /dev/null
@@ -1,33 +0,0 @@
--- Link table between diff judgment pages and the revision they target.
-create table /*_*/jade_diff_judgment (
-	-- Primary key.  This is for internal use and not guaranteed to be stable.
-	jaded_id int unsigned not null primary key auto_increment,
-	-- Revision ID being judged.
-	jaded_revision int unsigned not null,
-	-- Page ID of the judgment.
-	jaded_judgment int unsigned not null,
-	-- Judged to be damaging?
-	jaded_damaging tinyint,
-	-- Judged to be good faith?
-	jaded_goodfaith tinyint
-) /*$wgDBTableOptions*/;
-
--- Only one judgment per revision.
-create unique index /*i*/jaded_revision
-	on /*_*/jade_diff_judgment
-	(jaded_revision);
-
--- Covering index, get all data when joining on target revision.
-create index /*i*/jaded_covering
-	on /*_*/jade_diff_judgment
-	(jaded_revision, jaded_judgment, jaded_damaging, jaded_goodfaith);
-
--- TODO: Review this index once we have an idea of real-world usage statistics.
-create index /*i*/jaded_damaging
-	on /*_*/jade_diff_judgment
-	(jaded_damaging);
-
--- TODO: Review this index once we have an idea of real-world usage statistics.
-create index /*i*/jaded_goodfaith
-	on /*_*/jade_diff_judgment
-	(jaded_goodfaith);
diff --git a/sql/jade_revision_judgment.sql b/sql/jade_revision_judgment.sql
deleted file mode 100644
index 3712187..0000000
--- a/sql/jade_revision_judgment.sql
+++ /dev/null
@@ -1,26 +0,0 @@
--- Link table between revision judgment pages and the revision they target.
-create table /*_*/jade_revision_judgment (
-	-- Primary key.  This is for internal use and not guaranteed to be stable.
-	jader_id int unsigned not null primary key auto_increment,
-	-- Revision ID being judged.
-	jader_revision int unsigned not null,
-	-- Page ID of the judgment.
-	jader_judgment int unsigned not null,
-	-- Content quality
-	jader_contentquality int unsigned
-) /*$wgDBTableOptions*/;
-
--- Only one judgment per revision.
-create unique index /*i*/jader_revision
-	on /*_*/jade_revision_judgment
-	(jader_revision);
-
--- Covering index, get all data when joining on target revision.
-create index /*i*/jader_covering
-	on /*_*/jade_revision_judgment
-	(jader_revision, jader_judgment, jader_contentquality);
-
--- TODO: Review this index once we have an idea of real-world usage statistics.
-create index /*i*/jader_contentquality
-	on /*_*/jade_revision_judgment
-	(jader_contentquality);
diff --git a/templates/judgment_page.wiki.mustache b/templates/judgment_page.wiki.mustache
deleted file mode 100644
index 540e831..0000000
--- a/templates/judgment_page.wiki.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-__NOTOC__
-{{# judgments }}== {{ value }}{{# preferred }} *{{/ preferred }} ==
-{{ notes }}
-{{# hasEndorsements }}
-=== {{ msg-jade-endorsements }} ===
-{| class="wikitable"
-! {{ msg-jade-user }}
-! {{ msg-jade-endorsement }}
-{{# endorsements }}
-|-
-| {{ user }}
-| {{ comment }}
-{{/ endorsements }}
-|}
-{{/ hasEndorsements }}
-
-{{/ judgments }}
diff --git a/tests/data/invalid_judgment_additional_properties.json b/tests/data/invalid_judgment_additional_properties.json
deleted file mode 100644
index c7cafc7..0000000
--- a/tests/data/invalid_judgment_additional_properties.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false
-			},
-			"preferred": true,
-			"nothing": "extra"
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_additional_properties2.json b/tests/data/invalid_judgment_additional_properties2.json
deleted file mode 100644
index 80d703d..0000000
--- a/tests/data/invalid_judgment_additional_properties2.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false
-			},
-			"preferred": true
-		}
-	],
-	"spam": "foo"
-}
diff --git a/tests/data/invalid_judgment_additional_properties3.json b/tests/data/invalid_judgment_additional_properties3.json
deleted file mode 100644
index 0a48310..0000000
--- a/tests/data/invalid_judgment_additional_properties3.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false,
-				"nothing": "extra"
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_contentquality_data.json b/tests/data/invalid_judgment_bad_contentquality_data.json
deleted file mode 100644
index 2f8a1c8..0000000
--- a/tests/data/invalid_judgment_bad_contentquality_data.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"contentquality": 10
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_json.notjson b/tests/data/invalid_judgment_bad_json.notjson
deleted file mode 100644
index 54778c2..0000000
--- a/tests/data/invalid_judgment_bad_json.notjson
+++ /dev/null
@@ -1 +0,0 @@
-judgments: NOT
diff --git a/tests/data/invalid_judgment_bad_score_data.json b/tests/data/invalid_judgment_bad_score_data.json
deleted file mode 100644
index 7dd1725..0000000
--- a/tests/data/invalid_judgment_bad_score_data.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": "gray",
-				"goodfaith": false
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_score_schema.json b/tests/data/invalid_judgment_bad_score_schema.json
deleted file mode 100644
index 457464c..0000000
--- a/tests/data/invalid_judgment_bad_score_schema.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"foo": true
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_type.json b/tests/data/invalid_judgment_bad_type.json
deleted file mode 100644
index a4154eb..0000000
--- a/tests/data/invalid_judgment_bad_type.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": "true",
-				"goodfaith": false
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_user_ip.json b/tests/data/invalid_judgment_bad_user_ip.json
deleted file mode 100644
index a76c3e8..0000000
--- a/tests/data/invalid_judgment_bad_user_ip.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false
-			},
-			"notes": "feeble justification",
-			"endorsements": [
-				{
-					"user": {
-						"ip": "Abcdef"
-					},
-					"comment": "Sounds thorough to me.",
-					"origin": "test: ad-hoc tool",
-					"created": "1999-12-31T23:59:59Z"
-				}
-			],
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_bad_user_ip2.json b/tests/data/invalid_judgment_bad_user_ip2.json
deleted file mode 100644
index 85269a6..0000000
--- a/tests/data/invalid_judgment_bad_user_ip2.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false
-			},
-			"notes": "feeble justification",
-			"endorsements": [
-				{
-					"user": {
-						"ip": "127.0.0.1/1"
-					},
-					"created": "1999-12-31T23:59:59Z"
-				}
-			],
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_disallowed_score_schema.json b/tests/data/invalid_judgment_disallowed_score_schema.json
deleted file mode 100644
index 831af4a..0000000
--- a/tests/data/invalid_judgment_disallowed_score_schema.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"contentquality": 6
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_empty_endorsements.json b/tests/data/invalid_judgment_empty_endorsements.json
deleted file mode 100644
index 52cc9e4..0000000
--- a/tests/data/invalid_judgment_empty_endorsements.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"contentquality": "C"
-			},
-			"preferred": true
-		},
-		{
-			"schema": {
-				"contentquality": "B"
-			},
-			"preferred": false,
-			"endorsements": []
-		},
-		{
-			"schema": {
-				"contentquality": "GA"
-			},
-			"preferred": false,
-			"endorsements": [
-				{
-					"user": {
-						"ip": "::1"
-					},
-					"created": "1999-12-31T23:59:59Z"
-				}
-			]
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_missing_required.json b/tests/data/invalid_judgment_missing_required.json
deleted file mode 100644
index 451befd..0000000
--- a/tests/data/invalid_judgment_missing_required.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-	"judgments": [
-		{
-			"notes": "no data",
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_none_preferred.json b/tests/data/invalid_judgment_none_preferred.json
deleted file mode 100644
index 2eb6ded..0000000
--- a/tests/data/invalid_judgment_none_preferred.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"goodfaith": true,
-				"damaging": true
-			},
-			"preferred": false
-		},
-		{
-			"schema": {
-				"damaging": false,
-				"goodfaith": true
-			},
-			"preferred": false
-		}
-	]
-}
diff --git a/tests/data/invalid_judgment_two_preferred.json b/tests/data/invalid_judgment_two_preferred.json
deleted file mode 100644
index b32c103..0000000
--- a/tests/data/invalid_judgment_two_preferred.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"goodfaith": true,
-				"damaging": true
-			},
-			"preferred": true
-		},
-		{
-			"schema": {
-				"damaging": false,
-				"goodfaith": true
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/spam_blacklist.txt b/tests/data/spam_blacklist.txt
deleted file mode 100644
index 5b2946d..0000000
--- a/tests/data/spam_blacklist.txt
+++ /dev/null
@@ -1 +0,0 @@
-unusual-stringy
diff --git a/tests/data/valid_diff_judgment.json b/tests/data/valid_diff_judgment.json
deleted file mode 100644
index f1e228c..0000000
--- a/tests/data/valid_diff_judgment.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"damaging": true,
-				"goodfaith": false
-			},
-			"notes": "feeble justification",
-			"endorsements": [
-				{
-					"user": {
-						"ip": "127.0.0.1"
-					},
-					"comment": "Sounds thorough to me.",
-					"origin": "test: ad-hoc tool",
-					"created": "1999-12-31T23:59:59Z"
-				}
-			],
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/data/valid_revision_judgment.json b/tests/data/valid_revision_judgment.json
deleted file mode 100644
index ad36f01..0000000
--- a/tests/data/valid_revision_judgment.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"contentquality": 3
-			},
-			"preferred": true
-		},
-		{
-			"schema": {
-				"contentquality": 4
-			},
-			"preferred": false
-		},
-		{
-			"schema": {
-				"contentquality": 5
-			},
-			"preferred": false,
-			"endorsements": [
-				{
-					"user": {
-						"ip": "::1"
-					},
-					"created": "1999-12-31T23:59:59Z"
-				}
-			]
-		}
-	]
-}
diff --git a/tests/data/valid_revision_judgment_v2.json b/tests/data/valid_revision_judgment_v2.json
deleted file mode 100644
index 134da9a..0000000
--- a/tests/data/valid_revision_judgment_v2.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-	"judgments": [
-		{
-			"schema": {
-				"contentquality": 4
-			},
-			"preferred": true
-		}
-	]
-}
diff --git a/tests/phpunit/AbuseFilter/AbuseFilterTest.php b/tests/phpunit/AbuseFilter/AbuseFilterTest.php
deleted file mode 100644
index 2994e37..0000000
--- a/tests/phpunit/AbuseFilter/AbuseFilterTest.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\AbuseFilter;
-
-use ApiTestCase;
-use ExtensionRegistry;
-use Jade\Tests\TestStorageHelper;
-
-/**
- * Check that AbuseFilter integration works in judgment JSON.
- *
- * @group AbuseFilter
- * @group Jade
- * @group Database
- * @group medium
- *
- * @covers AbuseFilter
- */
-class AbuseFilterTest extends ApiTestCase {
-
-	public function setUp() {
-		parent::setUp();
-
-		if ( !ExtensionRegistry::getInstance()->isLoaded( 'Abuse Filter' ) ) {
-			$this->markTestSkipped( 'Can only run test with AbuseFilter enabled' );
-		}
-
-		$this->tablesUsed = [
-			'abuse_filter',
-			'abuse_filter_actions',
-			'abuse_filter_history',
-			'abuse_filter_log',
-			'page',
-		];
-	}
-
-	public function testCanFilterJudgment() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-
-		$content = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'notes' => 'Smash your T.V.!',
-			] ],
-		] );
-
-		$judgmentResult = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Diff/{$revision->getId()}",
-			$content,
-			'a summary'
-		);
-
-		$rcId = $judgmentResult['revision']->getRecentChange()->getAttribute( 'rc_id' );
-		$result = $this->doApiRequest( [
-			'action' => 'abusefiltercheckmatch',
-			'filter' => 'added_lines irlike "\bT\.?V\.?\b"',
-			'rcid' => $rcId,
-		] );
-
-		$this->assertTrue( $result[0]['abusefiltercheckmatch']['result'] );
-	}
-
-}
diff --git a/tests/phpunit/ApiGetJudgmentsTest.php b/tests/phpunit/ApiGetJudgmentsTest.php
deleted file mode 100644
index e9e2229..0000000
--- a/tests/phpunit/ApiGetJudgmentsTest.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use ApiTestCase;
-use FormatJSON;
-
-/**
- * Integration tests for the Jade API.
- *
- * @group API
- * @group Database
- * @group medium
- * @group Jade
- *
- * @covers Jade\ApiGetJudgments
- */
-class ApiGetJudgmentsTest extends ApiTestCase {
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'page',
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-		];
-	}
-
-	public function testGetJudgments_empty() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-
-		$result = $this->doApiRequest( [
-			'action' => 'query',
-			'list' => 'getjudgments',
-			'gjentitytype' => 'diff',
-			'gjentityid' => $revision->getId(),
-		] );
-		$this->assertSame( [], $result[0]['query']['getjudgments'] );
-	}
-
-	public function testGetJudgments_invalidEntityType() {
-		$this->setExpectedApiException(
-			[ 'apierror-unrecognizedvalue', 'gjentitytype', 'foo' ] );
-		$result = $this->doApiRequest( [
-			'action' => 'query',
-			'list' => 'getjudgments',
-			'gjentitytype' => 'foo',
-			'gjentityid' => 123,
-		] );
-	}
-
-	public function testGetJudgments_success() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-		$existingJudgment = [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-			] ],
-		];
-		$status = TestStorageHelper::saveJudgment(
-			"Diff/{$revision->getId()}",
-			$existingJudgment
-		);
-		$this->assertTrue( $status->isOK() );
-
-		$result = $this->doApiRequest( [
-			'action' => 'query',
-			'list' => 'getjudgments',
-			'gjentitytype' => 'diff',
-			'gjentityid' => $revision->getId(),
-		] );
-		$this->assertSame(
-			[ [ 'ns' => NS_JUDGMENT, 'title' => "Judgment:Diff/{$revision->getId()}" ] ],
-			$result[0]['query']['getjudgments']
-		);
-	}
-
-	public function testGetJudgments_generator() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-		$existingJudgment = [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-			] ],
-		];
-		$status = TestStorageHelper::saveJudgment(
-			"Diff/{$revision->getId()}",
-			$existingJudgment
-		);
-		$this->assertTrue( $status->isOK() );
-
-		$result = $this->doApiRequest( [
-			'action' => 'query',
-			'generator' => 'getjudgments',
-			'ggjentitytype' => 'diff',
-			'ggjentityid' => $revision->getId(),
-			'prop' => 'revisions',
-			'rvprop' => 'content',
-			'rvslots' => '*',
-		] );
-		$this->assertNotEmpty( $result[0]['query']['pages'] );
-		$page = array_shift( $result[0]['query']['pages'] );
-		$this->assertNotEmpty( $page['revisions'] );
-		$revision = array_shift( $page['revisions'] );
-		$judgment = FormatJSON::decode( $revision['slots']['main']['content'], true );
-		$this->assertSame( $existingJudgment, $judgment );
-	}
-
-}
diff --git a/tests/phpunit/Content/JudgmentContentHandlerTest.php b/tests/phpunit/Content/JudgmentContentHandlerTest.php
deleted file mode 100644
index 3a08bbe..0000000
--- a/tests/phpunit/Content/JudgmentContentHandlerTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\Content;
-
-use Jade\Tests\TestStorageHelper;
-use MediaWikiLangTestCase;
-use Title;
-use SearchEngine;
-use WikiPage;
-
-/**
- * @group Database
- * @group Jade
- * @group medium
- *
- * @coversDefaultClass Jade\Content\JudgmentContentHandler
- */
-class JudgmentContentHandlerTest extends MediaWikiLangTestCase {
-
-	/**
-	 * @covers ::getDataForSearchIndex
-	 */
-	public function testGetDataForSearchIndex() {
-		// Store a healthy judgment.
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-		$judgmentTitle = Title::newFromDBkey( "Judgment:Revision/{$entityRevision->getId()}" );
-		$status = TestStorageHelper::saveJudgment(
-			$judgmentTitle->getDBkey(),
-			TestStorageHelper::getJudgmentText( 'revision' ) );
-		$this->assertTrue( $status->isOK() );
-
-		$judgmentPage = WikiPage::newFromId( $status->value['revision']->getPage() );
-		$parserOutput = $judgmentPage->getContent()->getParserOutput( $judgmentTitle );
-		$mockEngine = $this->createMock( SearchEngine::class );
-		$data = $judgmentPage->getContentHandler()->getDataForSearchIndex(
-			$judgmentPage, $parserOutput, $mockEngine );
-
-		// Has labels
-		$this->assertRegExp( '/C-class article/', $data['text'] );
-		// No HTML tags
-		$this->assertNotRegExp( '/</', $data['text'] );
-	}
-
-}
diff --git a/tests/phpunit/Content/JudgmentContentTest.php b/tests/phpunit/Content/JudgmentContentTest.php
deleted file mode 100644
index 3f81a57..0000000
--- a/tests/phpunit/Content/JudgmentContentTest.php
+++ /dev/null
@@ -1,259 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\Content;
-
-use Jade\Content\JudgmentContent;
-use Jade\JudgmentValidator;
-use Jade\Tests\TestStorageHelper;
-use MediaWikiLangTestCase;
-use ParserOptions;
-use ParserOutput;
-use Sanitizer;
-use Status;
-use StatusValue;
-use Title;
-
-/**
- * @group Database
- * @group Jade
- * @group medium
- *
- * @coversDefaultClass Jade\Content\JudgmentContent
- */
-class JudgmentContentTest extends MediaWikiLangTestCase {
-
-	public function setUp() {
-		parent::setUp();
-
-		// Mock validation.
-		$this->mockValidation = $this->getMockBuilder( JudgmentValidator::class )
-			->disableOriginalConstructor()
-			->getMock();
-		$this->setService( 'JadeJudgmentValidator', $this->mockValidation );
-
-		$this->judgmentText = TestStorageHelper::getJudgmentText( 'diff' );
-	}
-
-	/**
-	 * @covers ::__construct
-	 */
-	public function testConstruct() {
-		$content = new JudgmentContent( $this->judgmentText );
-
-		$this->assertEquals(
-			JudgmentContent::CONTENT_MODEL_JUDGMENT,
-			$content->getModel() );
-	}
-
-	/**
-	 * @covers ::prepareSave
-	 */
-	public function testPrepareSave_success() {
-		$content = new JudgmentContent( $this->judgmentText );
-		$page = $this->getExistingTestPage();
-		$user = $this->getTestUser()->getUser();
-
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newGood() );
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validatePageTitle' )
-			->willReturn( Status::newGood() );
-
-		$status = $content->prepareSave( $page, 0, 0, $user );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * @covers ::prepareSave
-	 */
-	public function testPrepareSave_badContent() {
-		$content = new JudgmentContent( $this->judgmentText );
-		$page = $this->getExistingTestPage();
-		$user = $this->getTestUser()->getUser();
-
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newFatal( 'jade-bad-content', 'abc' ) );
-
-		$status = $content->prepareSave( $page, 0, 0, $user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-content', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::prepareSave
-	 */
-	public function testPrepareSave_badTitle() {
-		$content = new JudgmentContent( $this->judgmentText );
-		$page = $this->getExistingTestPage();
-		$user = $this->getTestUser()->getUser();
-
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newGood() );
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validatePageTitle' )
-			->willReturn( Status::newFatal( 'jade-bad-entity-type', 'abc' ) );
-
-		$status = $content->prepareSave( $page, 0, 0, $user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-entity-type', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::isValid
-	 */
-	public function testIsValid_success() {
-		$content = new JudgmentContent( $this->judgmentText );
-
-		$this->mockValidation
-			->expects( $this->once() )
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newGood() );
-
-		$this->assertTrue( $content->isValid() );
-	}
-
-	public function provideValidationScenarios() {
-		yield [
-			file_get_contents( __DIR__ . '/../../data/invalid_judgment_bad_json.notjson' ),
-			Status::newFatal( 'jade-bad-content-generic' ),
-		];
-		/* FIXME: HHVM and Zend PHP can't agree on this case, see T207523
-		 * yield [
-		 * 	'',
-		 * 	Status::newFatal( 'jade-bad-content-generic' ),
-		 * ];
-		 */
-		yield [
-			'{}',
-			Status::newGood(),
-		];
-		yield [
-			TestStorageHelper::getJudgmentText( 'diff' ),
-			Status::newFatal( 'abc' ),
-			Status::newFatal( 'abc' ),
-		];
-		yield [
-			TestStorageHelper::getJudgmentText( 'diff' ),
-			Status::newGood(),
-			Status::newGood(),
-		];
-	}
-
-	/**
-	 * @param string $judgmentText Judgment page content to save.
-	 * @param StatusValue $expectedStatus Match this result status.
-	 * @param StatusValue $injectStatus If not null, cause the mock validator
-	 * to return this status.
-	 *
-	 * @covers ::validateContent
-	 * @dataProvider provideValidationScenarios
-	 */
-	public function testValidateContent( $judgmentText, $expectedStatus, $injectStatus = null ) {
-		$content = new JudgmentContent( $judgmentText );
-
-		if ( $injectStatus !== null ) {
-			$this->mockValidation
-				->expects( $this->once() )
-				->method( 'validateJudgmentContent' )
-				->willReturn( $injectStatus );
-		}
-
-		$status = $content->validateContent();
-
-		$this->assertEquals( $expectedStatus, $status );
-	}
-
-	/**
-	 * @covers ::isEmpty
-	 */
-	public function testIsEmpty_empty() {
-		$content = new JudgmentContent( '{}' );
-
-		$this->assertTrue( $content->isEmpty() );
-	}
-
-	/**
-	 * @covers ::isEmpty
-	 */
-	public function testIsEmpty_notEmpty() {
-		$content = new JudgmentContent( $this->judgmentText );
-
-		$this->assertFalse( $content->isEmpty() );
-	}
-
-	/**
-	 * @covers ::fillParserOutput
-	 */
-	public function testFillParserOutput_invalid() {
-		$content = new JudgmentContent( 'FOO' );
-		$output = new ParserOutput;
-
-		$content->fillParserOutput(
-			Title::newFromDBkey( 'Judgment:Diff/123' ),
-			123,
-			ParserOptions::newFromUser( $this->getTestUser()->getUser() ),
-			true,
-			$output
-		);
-
-		$this->assertEquals( '', $output->getRawText() );
-	}
-
-	public function provideFillParserOutput() {
-		yield [ true, '/Damaging/' ];
-		yield [ false, '/^$/' ];
-	}
-
-	/**
-	 * @covers ::fillParserOutput
-	 * @dataProvider provideFillParserOutput
-	 */
-	public function testFillParserOutput( $doGenerateHtml, $expectedPattern ) {
-		$content = new JudgmentContent( $this->judgmentText );
-		$output = new ParserOutput;
-
-		$this->mockValidation
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newGood() );
-		$this->mockValidation
-			->method( 'validatePageTitle' )
-			->willReturn( Status::newGood() );
-
-		$content->fillParserOutput(
-			Title::newFromDBkey( 'Judgment:Diff/123' ),
-			123,
-			ParserOptions::newFromUser( $this->getTestUser()->getUser() ),
-			$doGenerateHtml,
-			$output
-		);
-
-		$strippedHtml = Sanitizer::stripAllTags( $output->getText() );
-		$this->assertRegExp( $expectedPattern, $strippedHtml );
-	}
-
-}
diff --git a/tests/phpunit/Hooks/LinkSummaryHooksTest.php b/tests/phpunit/Hooks/LinkSummaryHooksTest.php
deleted file mode 100644
index ec8c40f..0000000
--- a/tests/phpunit/Hooks/LinkSummaryHooksTest.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\Hooks;
-
-use Jade\Content\JudgmentContent;
-use Jade\Hooks\LinkSummaryHooks;
-use Jade\JudgmentEntityType;
-use Jade\JudgmentLinkTable;
-use Jade\JudgmentTarget;
-use Jade\Tests\TestJudgmentLinkAssertions;
-use Jade\Tests\TestStorageHelper;
-use MediaWikiTestCase;
-use Revision;
-use Status;
-use Title;
-use WikiPage;
-
-/**
- * @group Jade
- * @group Database
- * @group medium
- *
- * @coversDefaultClass Jade\Hooks\LinkSummaryHooks
- */
-class LinkSummaryHooksTest extends MediaWikiTestCase {
-
-	// Include assertions to test judgment links.
-	use TestJudgmentLinkAssertions;
-
-	const DIFF_JUDGMENT = '../../data/valid_diff_judgment.json';
-	const REVISION_JUDGMENT = '../../data/valid_revision_judgment.json';
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-			'page',
-		];
-
-		$this->mockStorage = $this->getMockBuilder( JudgmentLinkTable::class )
-			->disableOriginalConstructor()->getMock();
-		$this->setService( 'JadeJudgmentIndexStorage', $this->mockStorage );
-
-		$this->targetRevId = mt_rand();
-
-		$status = JudgmentEntityType::sanitizeEntityType( 'revision' );
-		$this->assertTrue( $status->isOK() );
-		$this->revisionType = $status->value;
-
-		$this->judgmentPageTitle = Title::newFromText( "Judgment:Revision/{$this->targetRevId}" );
-
-		$this->mockJudgmentPage = $this->getMockBuilder( WikiPage::class )
-			->disableOriginalConstructor()->getMock();
-		$this->mockJudgmentPage->method( 'getTitle' )
-			->willReturn( $this->judgmentPageTitle );
-
-		$this->mockRevision = $this->getMockBuilder( Revision::class )
-			->disableOriginalConstructor()->getMock();
-
-		$this->user = $this->getTestUser()->getUser();
-	}
-
-	/**
-	 * @covers ::onPageContentSaveComplete
-	 */
-	public function testOnPageContentSaveComplete_success() {
-		$flags = 0;
-
-		$expectedSummaryValues = [
-			'damaging' => true,
-			'goodfaith' => false,
-		];
-		$this->mockStorage->expects( $this->once() )
-			->method( 'updateSummary' )
-			->with(
-				new JudgmentTarget( $this->revisionType, $this->targetRevId ),
-				$expectedSummaryValues )
-			->willReturn( Status::newGood() );
-
-		$contentText = TestStorageHelper::getJudgmentText( 'diff' );
-		LinkSummaryHooks::onPageContentSaveComplete(
-			$this->mockJudgmentPage,
-			$this->user,
-			new JudgmentContent( $contentText ),
-			'',
-			false,
-			false,
-			'',
-			$flags,
-			// FIXME: should be the judgment revision, but ignored for now.
-			$this->mockRevision,
-			Status::newGood(),
-			false,
-			0
-		);
-	}
-
-	// TODO:
-	// public function testOnPageContentSaveComplete_badTitle() {
-	// public function testOnPageContentSaveComplete_badContent() {
-	// public function testOnPageContentSaveComplete_cannotUpdateSummary() {
-
-}
diff --git a/tests/phpunit/Hooks/LinkTableHooksTest.php b/tests/phpunit/Hooks/LinkTableHooksTest.php
deleted file mode 100644
index d6fbced..0000000
--- a/tests/phpunit/Hooks/LinkTableHooksTest.php
+++ /dev/null
@@ -1,259 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\Hooks;
-
-use Jade\JudgmentEntityType;
-use Jade\Hooks\LinkTableHooks;
-use Jade\JudgmentLinkTable;
-use Jade\JudgmentTarget;
-use Jade\Tests\TestJudgmentLinkAssertions;
-use LogEntry;
-use MediaWikiTestCase;
-use Revision;
-use TextContent;
-use Title;
-use TitleValue;
-use Wikimedia\TestingAccessWrapper;
-use WikiPage;
-
-/**
- * @group Jade
- * @group Database
- * @group medium
- *
- * @coversDefaultClass Jade\Hooks\LinkTableHooks
- */
-class LinkTableHooksTest extends MediaWikiTestCase {
-
-	// Include assertions to test judgment links.
-	use TestJudgmentLinkAssertions;
-
-	const DIFF_JUDGMENT = '../../data/valid_diff_judgment.json';
-	const REVISION_JUDGMENT = '../../data/valid_revision_judgment.json';
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-			'page',
-		];
-
-		$this->mockStorage = $this->getMockBuilder( JudgmentLinkTable::class )
-			->disableOriginalConstructor()->getMock();
-		$this->setService( 'JadeJudgmentIndexStorage', $this->mockStorage );
-
-		$this->targetRevId = mt_rand();
-
-		$status = JudgmentEntityType::sanitizeEntityType( 'revision' );
-		$this->assertTrue( $status->isOK() );
-		$this->revisionType = $status->value;
-
-		$this->judgmentPageTitle = Title::newFromText( "Judgment:Revision/{$this->targetRevId}" );
-
-		$this->mockJudgmentPage = $this->getMockBuilder( WikiPage::class )
-			->disableOriginalConstructor()->getMock();
-		$this->mockJudgmentPage->method( 'getTitle' )
-			->willReturn( $this->judgmentPageTitle );
-
-		$this->mockRevision = $this->getMockBuilder( Revision::class )
-			->disableOriginalConstructor()->getMock();
-
-		$this->mockLogEntry = $this->getMockBuilder( LogEntry::class )
-			->disableOriginalConstructor()->getMock();
-
-		$this->user = $this->getTestUser()->getUser();
-	}
-
-	/**
-	 * @covers ::onPageContentInsertComplete
-	 */
-	public function testOnPageContentInsertComplete_success() {
-		$flags = 0;
-
-		$this->mockStorage->expects( $this->once() )
-			->method( 'insertIndex' )
-			->with( new JudgmentTarget( $this->revisionType, $this->targetRevId ), $this->mockJudgmentPage );
-
-		LinkTableHooks::onPageContentInsertComplete(
-			$this->mockJudgmentPage,
-			$this->user,
-			new TextContent( '' ),
-			'',
-			false,
-			false,
-			'',
-			$flags,
-			$this->mockRevision
-		);
-	}
-
-	/**
-	 * @covers ::onPageContentInsertComplete
-	 */
-	public function testOnPageContentInsertComplete_noTarget() {
-		$flags = 0;
-
-		$this->mockStorage->expects( $this->never() )
-			->method( 'insertIndex' );
-
-		$nonJudgmentPage = $this->getExistingTestPage( __METHOD__ );
-		LinkTableHooks::onPageContentInsertComplete(
-			$nonJudgmentPage,
-			$this->user,
-			new TextContent( '' ),
-			'',
-			false,
-			false,
-			'',
-			$flags,
-			$this->mockRevision
-		);
-	}
-
-	/**
-	 * @covers ::onArticleDeleteComplete
-	 */
-	public function testOnArticleDeleteComplete_success() {
-		$this->mockStorage->expects( $this->once() )
-			->method( 'deleteIndex' )
-			->with( new JudgmentTarget( $this->revisionType, $this->targetRevId ), $this->mockJudgmentPage );
-
-		LinkTableHooks::onArticleDeleteComplete(
-			$this->mockJudgmentPage,
-			$this->user,
-			'',
-			321,
-			new TextContent( '' ),
-			$this->mockLogEntry
-		);
-	}
-
-	/**
-	 * @covers ::onArticleDeleteComplete
-	 */
-	public function testOnArticleDeleteComplete_noTarget() {
-		$this->mockStorage->expects( $this->never() )
-			->method( 'deleteIndex' );
-
-		$nonJudgmentPage = $this->getExistingTestPage( __METHOD__ );
-		LinkTableHooks::onArticleDeleteComplete(
-			$nonJudgmentPage,
-			$this->user,
-			'',
-			321,
-			new TextContent( '' ),
-			$this->mockLogEntry
-		);
-	}
-
-	/**
-	 * @covers ::onArticleUndelete
-	 */
-	public function testOnArticleUndelete_success() {
-		$page = $this->getExistingTestPage();
-		$pageId = $page->getId();
-
-		$this->mockStorage->expects( $this->once() )
-			->method( 'insertIndex' )
-			->with(
-				new JudgmentTarget( $this->revisionType, $this->targetRevId ),
-				$this->callback( function ( $page ) use ( $pageId ) {
-					return $page->getId() === $pageId;
-				} )
-			);
-
-		LinkTableHooks::onArticleUndelete(
-			$this->judgmentPageTitle,
-			true,
-			'',
-			$pageId,
-			[ $pageId => true ]
-		);
-	}
-
-	/**
-	 * @covers ::onArticleUndelete
-	 */
-	public function testOnArticleUndelete_noTarget() {
-		$page = $this->getExistingTestPage();
-		$pageId = $page->getId();
-
-		$this->mockStorage->expects( $this->never() )
-			->method( 'insertIndex' );
-
-		// Non-judgment page.
-		LinkTableHooks::onArticleUndelete(
-			$page->getTitle(),
-			true,
-			'',
-			$pageId,
-			[ $pageId => true ]
-		);
-	}
-
-	/**
-	 * @covers ::onArticleUndelete
-	 */
-	public function testOnArticleUndelete_nocreate() {
-		$page = $this->getExistingTestPage();
-		$pageId = $page->getId();
-
-		$this->mockStorage->expects( $this->never() )
-			->method( 'insertIndex' );
-
-		LinkTableHooks::onArticleUndelete(
-			$this->judgmentPageTitle,
-			false,
-			'',
-			$pageId,
-			[ $pageId => true ]
-		);
-	}
-
-	public function provideTargets() {
-		$diffType = JudgmentEntityType::sanitizeEntityType( 'diff' )->value;
-		yield [
-			NS_JUDGMENT,
-			'Diff/123',
-			new JudgmentTarget( $diffType, 123 ),
-		];
-		yield [
-			NS_JUDGMENT,
-			'Diff/FOO',
-			null,
-		];
-		yield [
-			NS_MAIN,
-			'No_page' . strval( mt_rand() ),
-			null,
-		];
-	}
-
-	/**
-	 * @covers ::judgmentTarget
-	 * @dataProvider provideTargets
-	 */
-	public function testJudgmentTarget( $namespace, $titleStr, $expectedTarget ) {
-		$hooksStatic = TestingAccessWrapper::newFromClass( LinkTableHooks::class );
-		$title = new TitleValue( $namespace, $titleStr );
-		$target = $hooksStatic->judgmentTarget( $title );
-
-		$this->assertEquals( $expectedTarget, $target );
-	}
-
-}
diff --git a/tests/phpunit/Hooks/MoveHooksTest.php b/tests/phpunit/Hooks/MoveHooksTest.php
deleted file mode 100644
index 8bcbf01..0000000
--- a/tests/phpunit/Hooks/MoveHooksTest.php
+++ /dev/null
@@ -1,149 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\Hooks;
-
-use ApiTestCase;
-use Jade\Content\JudgmentContent;
-use Jade\Tests\TestStorageHelper;
-use Status;
-use WikiPage;
-
-/**
- * @group API
- * @group Database
- * @group Jade
- * @group medium
- *
- * @covers Jade\Hooks\MoveHooks
- */
-class MoveHooksTest extends ApiTestCase {
-	const DIFF_JUDGMENT = '../../data/valid_diff_judgment.json';
-
-	const MAIN_EXISTING = 'main-existing';
-	const MAIN_NEW = 'main-new';
-	const JUDGMENT_EXISTING = 'judgment-existing';
-	const JUDGMENT_NEW = 'judgment-new';
-
-	public function setUp() {
-		parent::setUp();
-		$this->tablesUsed = [
-			'page',
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-		];
-
-		// Create target content page.
-		$this->article = TestStorageHelper::makeEdit(
-			NS_MAIN, 'TestJudgmentActionsPage', 'abcdef', 'some summary' );
-		$revisionId = $this->article['revision']->getId();
-
-		// Create diff judgment.
-		$judgmentTitle = "Diff/{$revisionId}";
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::DIFF_JUDGMENT );
-		$status = TestStorageHelper::saveJudgment(
-			$judgmentTitle,
-			$judgmentText
-		);
-		$this->assertTrue( $status->isOK() );
-		$this->judgmentPage = WikiPage::newFromID( $status->value['revision-record']->getPageId() );
-		$this->assertTrue( $this->judgmentPage->exists() );
-
-		// Provide the articles as a map from enum since data providers don't
-		// have access to the initialized test case.
-		$this->articleMap = [
-			self::MAIN_EXISTING => "{$this->article['page']->getTitle()->getDBkey()}",
-			self::MAIN_NEW => 'New page' . strval( mt_rand() ),
-			self::JUDGMENT_EXISTING => "Judgment:{$this->judgmentPage->getTitle()->getDBkey()}",
-			self::JUDGMENT_NEW => 'Judgment:Diff/321' . strval( mt_rand() ),
-		];
-
-		// Disable validation since that would prevent moving a wiki page into
-		// the Judgment namespace.
-		$this->mockValidation = $this->getMockBuilder( JudgmentValidator::class )
-			->disableOriginalConstructor()
-			->setMethods( [ 'validateJudgmentContent', 'validatePageTitle' ] )
-			->getMock();
-		$this->setService( 'JadeJudgmentValidator', $this->mockValidation );
-
-		$this->mockValidation
-			->method( 'validateJudgmentContent' )
-			->willReturn( Status::newGood() );
-		$this->mockValidation
-			->method( 'validatePageTitle' )
-			->willReturn( Status::newGood() );
-	}
-
-	public function provideNamespaceCombos() {
-		// FIXME: The judgment titles would fail validation, but maybe this is
-		// okay since we're testing for a specific error code.
-		yield [
-			self::MAIN_EXISTING,
-			self::MAIN_NEW,
-		];
-		yield [
-			self::MAIN_EXISTING,
-			self::JUDGMENT_NEW,
-			'jade-invalid-move-any',
-		];
-		yield [
-			self::JUDGMENT_EXISTING,
-			self::MAIN_NEW,
-			[ 'content-not-allowed-here', JudgmentContent::CONTENT_MODEL_JUDGMENT, self::MAIN_NEW, 'main' ],
-		];
-		yield [
-			self::JUDGMENT_EXISTING,
-			self::JUDGMENT_NEW,
-			'jade-invalid-move-any',
-		];
-	}
-
-	/**
-	 * @covers Jade\Hooks\MoveHooks::onMovePageIsValidMove
-	 * @dataProvider provideNamespaceCombos
-	 */
-	public function testOnMovePageIsValidMove(
-		$oldTitleKey,
-		$newTitleKey,
-		$expectedException = null
-	) {
-		$oldTitle = $this->articleMap[$oldTitleKey];
-		$newTitle = $this->articleMap[$newTitleKey];
-
-		if ( $expectedException !== null ) {
-			// FIXME: hack to inject calculated values into the provided message fixture.
-			$expectedException = array_map(
-				function ( $item ) {
-					return $this->articleMap[$item] ?? $item;
-				},
-				(array)$expectedException
-			);
-			$this->setExpectedApiException( $expectedException );
-		}
-
-		$result = $this->doApiRequestWithToken( [
-			'action' => 'move',
-			'from' => $oldTitle,
-			'to' => $newTitle,
-			'ignorewarnings' => true,
-		] );
-
-		if ( $expectedException === null ) {
-			// FIXME: test !$result[0]['move']['error'] instead, but what does move call the error field?
-			$this->assertTrue( $result[0]['move']['redirectcreated'] );
-		}
-	}
-
-}
diff --git a/tests/phpunit/JudgmentActionsTest.php b/tests/phpunit/JudgmentActionsTest.php
deleted file mode 100644
index 165474b..0000000
--- a/tests/phpunit/JudgmentActionsTest.php
+++ /dev/null
@@ -1,218 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use ApiTestCase;
-
-/**
- * Integration tests for page save validation.
- *
- * @group API
- * @group Database
- * @group Jade
- * @group medium
- *
- * TODO: Rewrite to use API calls.
- * @coversNothing
- */
-class JudgmentActionsTest extends ApiTestCase {
-	const REV_JUDGMENT_V1 = '../data/valid_revision_judgment.json';
-	const REV_JUDGMENT_V2 = '../data/valid_revision_judgment_v2.json';
-
-	public function setUp() {
-		// Needs to be before setup since this gets cached
-		$this->mergeMwGlobalArrayValue(
-			'wgGroupPermissions',
-			[ 'sysop' => [ 'deleterevision' => true ] ]
-		);
-
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'page',
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-		];
-	}
-
-	public function testCreateRevisionJudgment() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0, 'TestJudgmentActionsPage' . strval( mt_rand() ), 'abcdef', 'some summary' );
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$rev_id}",
-			$judgmentText,
-			'summary says'
-		);
-		$this->assertNotNull( $judgment['page'] );
-		$this->assertNotNull( $judgment['revision'] );
-	}
-
-	public function testUpdateRevisionJudgment() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0, 'TestJudgmentActionsPage' . strval( mt_rand() ), 'abcdef', 'some summary' );
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create initial revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$rev_id}",
-			$judgmentText,
-			'summary says'
-		);
-		$this->assertNotNull( $judgment['page'] );
-		$this->assertNotNull( $judgment['revision'] );
-
-		// Update the judgment.
-		$judgment2Text = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V2 );
-		$judgment2 = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$rev_id}",
-			$judgment2Text,
-			'summary says'
-		);
-		$this->assertNotNull( $judgment2['page'] );
-		$this->assertNotNull( $judgment2['revision'] );
-	}
-
-	public function testSuppressUnsuppressRevisionJudgment() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0, 'TestJudgmentActionsPage' . strval( mt_rand() ), 'abcdef', 'some summary' );
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create initial revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$rev_id}",
-			$judgmentText,
-			'summary says'
-		);
-
-		// Update the judgment.
-		$judgment2Text = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V2 );
-		$judgment2 = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$rev_id}",
-			$judgment2Text,
-			'summary says'
-		);
-
-		// Suppress the first edit.
-		$sysop = $this->getTestSysop()->getUser();
-		$out = $this->doApiRequest( [
-			'action' => 'revisiondelete',
-			'type' => 'revision',
-			'target' => $judgment['page']->getTitle()->getDbKey(),
-			'ids' => $judgment['revision']->getId(),
-			'hide' => 'content|user|comment',
-			'token' => $sysop->getEditToken(),
-		] );
-		// Check the output
-		$out = $out[0]['revisiondelete'];
-		$this->assertEquals( $out['status'], 'Success' );
-
-		// Unsuppress the first edit.
-		$out = $this->doApiRequest( [
-			'action' => 'revisiondelete',
-			'type' => 'revision',
-			'target' => $judgment['page']->getTitle()->getDbKey(),
-			'ids' => $judgment['revision']->getId(),
-			'show' => 'content|user|comment',
-			'token' => $sysop->getEditToken(),
-		] );
-		// Check the output
-		$out = $out[0]['revisiondelete'];
-		$this->assertEquals( $out['status'], 'Success' );
-	}
-
-	public function testCreateJudgment_badTitleRevId() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0,
-			'TestJudgmentActionsPage' . strval( mt_rand() ),
-			'abcdef',
-			'some summary'
-		);
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$bad_rev_id = $rev_id + 1;
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Revision/{$bad_rev_id}",
-			$judgmentText,
-			'summary says',
-			false
-		);
-		$this->assertNull( $judgment['page'] );
-		$this->assertNull( $judgment['revision'] );
-	}
-
-	public function testCreateJudgment_badTitleType() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0, 'TestJudgmentActionsPage' . strval( mt_rand() ), 'abcdef', 'some summary' );
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Page/{$rev_id}",
-			$judgmentText,
-			'summary says',
-			false
-		);
-		$this->assertNull( $judgment['page'] );
-		$this->assertNull( $judgment['revision'] );
-	}
-
-	public function testCreateJudgment_badTitleFormat() {
-		// Create target page.
-		$article = TestStorageHelper::makeEdit(
-			0, 'TestJudgmentActionsPage' . strval( mt_rand() ), 'abcdef', 'some summary' );
-		$page_id = $article['page']->getId();
-		$rev_id = $article['revision']->getId();
-
-		// Create revision judgment.
-		$judgmentText = file_get_contents( __DIR__ . '/' . self::REV_JUDGMENT_V1 );
-		$judgment = TestStorageHelper::makeEdit(
-			NS_JUDGMENT,
-			"Page/{$rev_id}/Wrongunder",
-			$judgmentText,
-			'summary says',
-			false
-		);
-		$this->assertNull( $judgment['page'] );
-		$this->assertNull( $judgment['revision'] );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentEntityTypeTest.php b/tests/phpunit/JudgmentEntityTypeTest.php
deleted file mode 100644
index 0c7450e..0000000
--- a/tests/phpunit/JudgmentEntityTypeTest.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use MediaWikiLangTestCase;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @group Jade
- *
- * @coversDefaultClass Jade\JudgmentEntityType
- */
-class JudgmentEntityTypeTest extends MediaWikiLangTestCase {
-
-	public function provideTypeNames() {
-		yield [ 'diff', true ];
-		yield [ 'revision', true ];
-		yield [ 'Diff', false ];
-		yield [ '', false ];
-		yield [ 1, false ];
-	}
-
-	/**
-	 * @covers ::__construct
-	 * @covers ::sanitizeEntityType
-	 * @dataProvider provideTypeNames
-	 */
-	public function testSanitizeEntityType( $typeName, $expectedSuccess ) {
-		$status = JudgmentEntityType::sanitizeEntityType( $typeName );
-
-		$this->assertEquals( $expectedSuccess, $status->isOK() );
-		if ( $expectedSuccess ) {
-			$entityType = TestingAccessWrapper::newFromObject( $status->value );
-			$this->assertEquals( $typeName, $entityType->entityType );
-		}
-	}
-
-	/**
-	 * @covers ::__toString
-	 */
-	public function testToString() {
-		$status = JudgmentEntityType::sanitizeEntityType( 'diff' );
-		$entityType = $status->value;
-		$this->assertEquals( 'diff', (string)$entityType );
-	}
-
-	/**
-	 * @covers ::getLocalizedName
-	 */
-	public function testGetLocalizedName() {
-		$this->setMwGlobals( [
-			'wgJadeEntityTypeNames' => [
-				'diff' => 'Diffie',
-			]
-		] );
-		$status = JudgmentEntityType::sanitizeEntityType( 'diff' );
-		$entityType = $status->value;
-		$this->assertEquals( 'Diffie', $entityType->getLocalizedName() );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentLinkTableHelperTest.php b/tests/phpunit/JudgmentLinkTableHelperTest.php
deleted file mode 100644
index 945b9be..0000000
--- a/tests/phpunit/JudgmentLinkTableHelperTest.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use Jade\JudgmentLinkTableHelper;
-use MediaWikiTestCase;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @group Jade
- *
- * @coversDefaultClass Jade\JudgmentLinkTableHelper
- */
-class JudgmentLinkTableHelperTest extends MediaWikiTestCase {
-
-	private $diffType;
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->diffType = JudgmentEntityType::sanitizeEntityType( 'diff' )->value;
-	}
-
-	/**
-	 * @covers ::__construct
-	 */
-	public function testNewFromEntityType() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$helper = TestingAccessWrapper::newFromObject( $helper );
-		$this->assertEquals( $this->diffType, $helper->entityType );
-	}
-
-	/**
-	 * @covers ::getLinkTable
-	 */
-	public function testGetLinkTable() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jade_diff_judgment', $helper->getLinkTable() );
-	}
-
-	/**
-	 * @covers ::getColumnPrefix
-	 */
-	public function testGetColumnPrefix() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jaded', $helper->getColumnPrefix() );
-	}
-
-	/**
-	 * @covers ::getIdColumn
-	 */
-	public function testGetIdColumn() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jaded_id', $helper->getIdColumn() );
-	}
-
-	/**
-	 * @covers ::getJudgmentColumn
-	 */
-	public function testGetJudgmentColumn() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jaded_judgment', $helper->getJudgmentColumn() );
-	}
-
-	/**
-	 * @covers ::getTargetColumn
-	 */
-	public function testGetTargetColumn() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jaded_revision', $helper->getTargetColumn() );
-	}
-
-	/**
-	 * @covers ::getSummaryColumn
-	 */
-	public function testGetSummaryColumn() {
-		$helper = new JudgmentLinkTableHelper( $this->diffType );
-		$this->assertEquals( 'jaded_damaging', $helper->getSummaryColumn( 'damaging' ) );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentLinkTableTest.php b/tests/phpunit/JudgmentLinkTableTest.php
deleted file mode 100644
index c8e429a..0000000
--- a/tests/phpunit/JudgmentLinkTableTest.php
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use Jade\JudgmentLinkTable;
-use Jade\JudgmentTarget;
-use Jade\TitleHelper;
-use MediaWiki\MediaWikiServices;
-use MediaWikiTestCase;
-
-/**
- * @group Jade
- * @group Database
- * @group medium
- *
- * @coversDefaultClass Jade\JudgmentLinkTable
- * @covers ::__construct
- */
-class JudgmentLinkTableTest extends MediaWikiTestCase {
-
-	// Include assertions to test judgment links.
-	use TestJudgmentLinkAssertions;
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-			'page',
-		];
-
-		// Content article and revision fixtures.
-		$article = TestStorageHelper::makeEdit(
-			NS_MAIN,
-			'JudgmentLinkTableTest' . strval( mt_rand() ) );
-		$this->page = $article['page'];
-		$this->revision = $article['revision'];
-
-		/*
-		 * Note: Normal clients should fetch the service rather than directly
-		 * instantiating.
-		 *     $storage = JadeServices::getJudgmentIndexStorage();
-		 */
-		$this->indexStorage = new JudgmentLinkTable(
-			MediaWikiServices::getInstance()->getDBLoadBalancer() );
-
-		// Disable all hooks, so that judgment links can only be altered manually.
-		$this->setMwGlobals( [
-			'wgHooks' => [],
-		] );
-	}
-
-	/**
-	 * @param string $entityType
-	 * @param int $entityId
-	 */
-	private function createJudgment( $entityType, $entityId ) {
-		$status = JudgmentEntityType::sanitizeEntityType( $entityType );
-		$this->assertTrue( $status->isOK() );
-		$target = new JudgmentTarget( $status->value, $entityId );
-		$title = TitleHelper::buildJadeTitle( $target );
-		$judgmentText = TestStorageHelper::getJudgmentText( $entityType );
-		$judgmentStatus = TestStorageHelper::makeEdit(
-			NS_JUDGMENT, $title->getDBkey(), $judgmentText );
-		$this->assertNotNull( $judgmentStatus['page'] );
-		$this->assertNotNull( $judgmentStatus['revision'] );
-
-		return [
-			'target' => $target,
-			'judgmentPage' => $judgmentStatus['page'],
-		];
-	}
-
-	public function provideEntityTypes() {
-		global $wgJadeEntityTypeNames;
-
-		$types = array_keys( $wgJadeEntityTypeNames );
-		foreach ( $types as $type ) {
-			yield [ $type ];
-		}
-	}
-
-	/**
-	 * Test that this class is preparing fixtures as expected.
-	 *
-	 * @coversNothing
-	 */
-	public function testFixtures() {
-		$judgment = $this->createJudgment( 'diff', $this->revision->getId() );
-
-		// Didn't create a link.
-		$this->assertNoJudgmentLink(
-			'diff', $this->revision->getId(), $judgment['judgmentPage']->getId() );
-	}
-
-	/**
-	 * @covers ::insertIndex
-	 * @dataProvider provideEntityTypes
-	 */
-	public function testInsertIndex_normal( $type ) {
-		$judgment = $this->createJudgment( $type, $this->revision->getId() );
-
-		$this->indexStorage->insertIndex( $judgment['target'], $judgment['judgmentPage'] );
-
-		$this->assertJudgmentLink( $type, $this->revision->getId(), $judgment['judgmentPage']->getId() );
-	}
-
-	/**
-	 * @covers ::insertIndex
-	 * @dataProvider provideEntityTypes
-	 */
-	public function testInsertIndex_duplicate( $type ) {
-		$judgment = $this->createJudgment( $type, $this->revision->getId() );
-
-		$this->indexStorage->insertIndex( $judgment['target'], $judgment['judgmentPage'] );
-		// Duplicate.  Shouldn't throw an error.
-		$this->indexStorage->insertIndex( $judgment['target'], $judgment['judgmentPage'] );
-
-		// There can be only one.
-		$result = TestLinkTableHelper::selectJudgmentLink(
-			$type, $this->revision->getId(), $judgment['judgmentPage']->getId() );
-		$this->assertEquals( 1, $result->numRows() );
-	}
-
-	/**
-	 * @covers ::deleteIndex
-	 * @dataProvider provideEntityTypes
-	 */
-	public function testDeleteIndex_normal( $type ) {
-		$judgment = $this->createJudgment( $type, $this->revision->getId() );
-		$this->indexStorage->insertIndex( $judgment['target'], $judgment['judgmentPage'] );
-
-		$this->indexStorage->deleteIndex( $judgment['target'], $judgment['judgmentPage'] );
-
-		$this->assertNoJudgmentLink(
-			$type, $this->revision->getId(), $judgment['judgmentPage']->getId() );
-	}
-
-	/**
-	 * @covers ::deleteIndex
-	 * @dataProvider provideEntityTypes
-	 */
-	public function testDeleteIndex_missing( $type ) {
-		$judgment = $this->createJudgment( $type, $this->revision->getId() );
-
-		// No index row yet.
-
-		// Ignores the failure, DWIM.
-		$this->indexStorage->deleteIndex( $judgment['target'], $judgment['judgmentPage'] );
-	}
-
-	/**
-	 * @covers ::updateSummary
-	 */
-	public function testUpdateSummary_normal() {
-		$judgment = $this->createJudgment( 'diff', $this->revision->getId() );
-
-		// Prepare the row.
-		$this->indexStorage->insertIndex( $judgment['target'], $judgment['judgmentPage'] );
-		$this->assertJudgmentLink( 'diff', $this->revision->getId(), $judgment['judgmentPage']->getId() );
-
-		$this->indexStorage->updateSummary( $judgment['target'], [
-			'damaging' => true,
-			'goodfaith' => false,
-		] );
-
-		$result = TestLinkTableHelper::selectJudgmentLink(
-			'diff',
-			$this->revision->getId(),
-			$judgment['judgmentPage']->getId(),
-			[ 'damaging', 'goodfaith' ] );
-		$this->assertEquals( 1, $result->numRows() );
-		foreach ( $result as $row ) {
-			$this->assertEquals( 1, $row->jaded_damaging );
-			$this->assertEquals( 0, $row->jaded_goodfaith );
-		}
-	}
-
-}
diff --git a/tests/phpunit/JudgmentPageWikitextRendererTest.php b/tests/phpunit/JudgmentPageWikitextRendererTest.php
deleted file mode 100644
index 25924db..0000000
--- a/tests/phpunit/JudgmentPageWikitextRendererTest.php
+++ /dev/null
@@ -1,245 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Block;
-use CentralIdLookup;
-use Jade\JudgmentPageWikitextRenderer;
-use LocalIdLookup;
-use LogicException;
-use MediaWikiLangTestCase;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @group Database
- * @group Jade
- * @group medium
- *
- * @coversDefaultClass Jade\JudgmentPageWikitextRenderer
- *
- * TODO: Could make some tests more unit-y, calling the methods through a
- * TestingAccessWrapper rather than going through the public getWikitext.
- */
-class JudgmentPageWikitextRendererTest extends MediaWikiLangTestCase {
-
-	public static function provideBasicSamples() {
-		// Renders the damaging schema.
-		yield [
-			[ 'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-			] ] ],
-			'/Not damaging and Good faith/',
-		];
-		// Notes as unescaped wikitext.
-		yield [
-			[ 'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'notes' => '[[Main page]]',
-				'preferred' => true,
-			] ] ],
-			'/\[\[Main page\]\]/',
-		];
-		// IP user.
-		yield [
-			[ 'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [ 'user' => [ 'ip' => '127.0.0.1' ] ] ],
-			] ] ],
-			'/\[\[User:127.0.0.1\]\]/',
-		];
-	}
-
-	/**
-	 * @dataProvider provideBasicSamples
-	 * @covers ::getWikitext
-	 * @covers ::getSchemaSummary
-	 * @covers ::getUserWikitext
-	 */
-	public function testBasicRendering( $judgment, $regex ) {
-		// Cheesy recursive conversion from array to stdClass.
-		$judgmentObject = json_decode( json_encode( $judgment ) );
-
-		$renderer = new JudgmentPageWikitextRenderer;
-		$wikitext = $renderer->getWikitext( $judgmentObject );
-
-		$this->assertRegExp( $regex, $wikitext );
-	}
-
-	/**
-	 * @covers ::getEndorsements
-	 * @covers ::getUserWikitext
-	 */
-	public function testLocalUser() {
-		$user = $this->getTestUser()->getUser();
-
-		$judgment = [ 'judgments' => [ [
-			'schema' => [
-				'damaging' => false,
-				'goodfaith' => true,
-			],
-			'preferred' => true,
-			'endorsements' => [ [
-				'user' => [
-					'id' => $user->getId(),
-				]
-			] ],
-		] ] ];
-		$judgmentObject = json_decode( json_encode( $judgment ) );
-
-		$renderer = new JudgmentPageWikitextRenderer;
-		$wikitext = $renderer->getWikitext( $judgmentObject );
-
-		$this->assertRegExp( "/\[\[User:{$user->getName()}\]\]/", $wikitext );
-	}
-
-	/**
-	 * @covers ::getEndorsements
-	 * @covers ::getUserWikitext
-	 */
-	public function testSuppressedUser() {
-		$this->tablesUsed[] = 'ipblocks';
-
-		$user = $this->getTestUser()->getUser();
-
-		// Suppress username.
-		$block = new Block();
-		$block->setTarget( $user->getName() );
-		$block->setBlocker( $this->getTestSysop()->getUser() );
-		$block->mHideName = true;
-		$block->insert();
-
-		$judgment = [ 'judgments' => [ [
-			'schema' => [
-				'damaging' => false,
-				'goodfaith' => true,
-			],
-			'preferred' => true,
-			'endorsements' => [ [
-				'user' => [
-					'id' => $user->getId(),
-				]
-			] ],
-		] ] ];
-		$judgmentObject = json_decode( json_encode( $judgment ) );
-
-		$renderer = new JudgmentPageWikitextRenderer;
-		$wikitext = $renderer->getWikitext( $judgmentObject );
-
-		$this->assertRegExp( "/⧼{$user->getId()}⧽/", $wikitext );
-	}
-
-	/**
-	 * @covers ::getEndorsements
-	 * @covers ::getUserWikitext
-	 */
-	public function testCentralUser() {
-		// Disable CentralAuth to simplify bookkeeping.
-		$this->setMwGlobals( [
-			'wgCentralIdLookupProviders' => [
-				'local' => [ 'class' => LocalIdLookup::class ],
-			],
-			'wgCentralIdLookupProvider' => 'local',
-		] );
-
-		$user = $this->getTestUser()->getUser();
-		$centralUserId = CentralIdLookup::factory()->centralIdFromLocalUser( $user );
-
-		$judgment = [ 'judgments' => [ [
-			'schema' => [
-				'damaging' => false,
-				'goodfaith' => true,
-			],
-			'preferred' => true,
-			'endorsements' => [ [
-				'user' => [
-					'id' => $user->getId(),
-					'cid' => $centralUserId,
-				]
-			] ],
-		] ] ];
-		$judgmentObject = json_decode( json_encode( $judgment ) );
-
-		$renderer = new JudgmentPageWikitextRenderer;
-		$wikitext = $renderer->getWikitext( $judgmentObject );
-
-		$this->assertRegExp( "/\[\[User:{$user->getName()}\]\]/", $wikitext );
-	}
-
-	public function provideSchemaValueMessages() {
-		// TODO: Test is sensitive to the English string.  Include messages in
-		// the test.
-		yield [ 'damaging', true, 'Damaging' ];
-		yield [ 'damaging', false, 'Not damaging' ];
-		yield [ 'contentquality', 2, 'Start-class article' ];
-		yield [ 'contentquality', '0', 'Content quality "0"' ];
-		yield [ 'missing', true, '⧼jade-missing-scale-true-label⧽' ];
-	}
-
-	/**
-	 * @dataProvider provideSchemaValueMessages
-	 * @covers ::getSchemaValueText
-	 * @covers ::__construct
-	 */
-	public function testGetSchemaValueText( $schemaName, $value, $expectedText ) {
-		$renderer = TestingAccessWrapper::newFromObject(
-			new JudgmentPageWikitextRenderer );
-		$text = $renderer->getSchemaValueText( $schemaName, $value );
-
-		$this->assertEquals( $expectedText, $text );
-	}
-
-	/**
-	 * @covers ::getUserWikitext
-	 */
-	public function testGetUserWikitext_missingCentralUser() {
-		$badCentralId = mt_rand();
-
-		$renderer = TestingAccessWrapper::newFromObject(
-			new JudgmentPageWikitextRenderer );
-		$userObj = (object)[
-			'cid' => $badCentralId,
-			'id' => $this->getTestUser()->getUser()->getId(),
-		];
-		$output = $renderer->getUserWikitext( $userObj );
-
-		$expected = "⧼{$badCentralId}⧽";
-
-		$this->assertEquals( $expected, $output );
-	}
-
-	/**
-	 * @covers ::getUserWikitext
-	 * @expectedException LogicException
-	 */
-	public function testGetUserWikitext_badStruct() {
-		$renderer = TestingAccessWrapper::newFromObject(
-			new JudgmentPageWikitextRenderer );
-		$userObj = new \stdClass;
-		$output = $renderer->getUserWikitext( $userObj );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentSummarizerTest.php b/tests/phpunit/JudgmentSummarizerTest.php
deleted file mode 100644
index f361fb6..0000000
--- a/tests/phpunit/JudgmentSummarizerTest.php
+++ /dev/null
@@ -1,56 +0,0 @@
-<?php
-/**
-* This program is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, either version 3 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-namespace Jade\Tests;
-
-use Jade\Content\JudgmentContent;
-use Jade\JudgmentSummarizer;
-use MediaWikiTestCase;
-use TextContent;
-
-/**
- * @group Jade
- *
- * @coversDefaultClass Jade\JudgmentSummarizer
- */
-class JudgmentSummarizerTest extends MediaWikiTestCase {
-
-	/**
-	 * @covers ::getSummaryFromContent
-	 */
-	public function testGetSummaryFromContent_success() {
-		$content = new JudgmentContent( TestStorageHelper::getJudgmentText( 'diff' ) );
-		$status = JudgmentSummarizer::getSummaryFromContent( $content );
-		$this->assertTrue( $status->isOK() );
-		$this->assertEquals(
-			[
-				'damaging' => true,
-				'goodfaith' => false,
-			],
-			$status->value
-		);
-	}
-
-	/**
-	 * @covers ::getSummaryFromContent
-	 */
-	public function testGetSummaryFromContent_failure() {
-		$badJson = '[abc';
-		$content = new TextContent( $badJson );
-		$status = JudgmentSummarizer::getSummaryFromContent( $content );
-		$this->assertFalse( $status->isOK() );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentTargetTest.php b/tests/phpunit/JudgmentTargetTest.php
deleted file mode 100644
index 167822b..0000000
--- a/tests/phpunit/JudgmentTargetTest.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use Jade\JudgmentTarget;
-use PHPUnit\Framework\TestCase;
-
-/**
- * @group Jade
- *
- * @coversDefaultClass Jade\JudgmentTarget
- */
-class JudgmentTargetTest extends TestCase {
-
-	/**
-	 * @covers ::__construct
-	 */
-	public function testConstruct() {
-		$entityType = JudgmentEntityType::sanitizeEntityType( 'diff' )->value;
-		$entityId = 123;
-		$target = new JudgmentTarget( $entityType, $entityId );
-		$this->assertInstanceOf( JudgmentTarget::class, $target );
-		$this->assertEquals( $entityType, $target->entityType );
-		$this->assertEquals( $entityId, $target->entityId );
-	}
-
-}
diff --git a/tests/phpunit/JudgmentValidatorTest.php b/tests/phpunit/JudgmentValidatorTest.php
deleted file mode 100644
index c88d64d..0000000
--- a/tests/phpunit/JudgmentValidatorTest.php
+++ /dev/null
@@ -1,515 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Block;
-use CentralIdLookup;
-use FormatJson;
-use Jade\JadeServices;
-use LocalIdLookup;
-use MediaWikiTestCase;
-use StatusValue;
-use User;
-use Wikimedia\TestingAccessWrapper;
-
-/**
- * @group Database
- * @group Jade
- * @group medium
- *
- * @coversDefaultClass Jade\JudgmentValidator
- * @covers ::__construct
- *
- * TODO: Should construct directly rather than relying on service wiring.
- */
-class JudgmentValidatorTest extends MediaWikiTestCase {
-
-	const DATA_DIR = '../data';
-
-	/** @var User */
-	private $user;
-
-	public function setUp() {
-		parent::setUp();
-
-		$this->tablesUsed = [
-			'ipblocks',
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-			'page',
-		];
-
-		$this->user = $this->getTestUser()->getUser();
-
-		// Disable CentralAuth provider for CentralIdLookup.
-		$this->setMwGlobals( [
-			'wgCentralIdLookupProviders' => [
-				'local' => [ 'class' => LocalIdLookup::class ],
-			],
-			'wgCentralIdLookupProvider' => 'local',
-		] );
-	}
-
-	public function provideInvalidSchemaContent() {
-		yield [ 'invalid_judgment_missing_required.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_bad_json.notjson', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_bad_score_data.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_bad_score_schema.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_additional_properties.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_additional_properties2.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_additional_properties3.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_empty_endorsements.json', 'jade-bad-content' ];
-		yield [ 'invalid_judgment_none_preferred.json', 'jade-none-preferred' ];
-		yield [ 'invalid_judgment_two_preferred.json', 'jade-too-many-preferred' ];
-		yield [ 'invalid_judgment_bad_contentquality_data.json', 'jade-bad-contentquality-value' ];
-		yield [ 'invalid_judgment_bad_user_ip.json', 'jade-user-ip-invalid' ];
-		yield [ 'invalid_judgment_bad_user_ip2.json', 'jade-user-ip-invalid' ];
-	}
-
-	// These cases have scoring schemas which aren't allowed for the page title.
-	public function provideInvalidWithType() {
-		yield [ 'invalid_judgment_disallowed_score_schema.json', 'diff' ];
-	}
-
-	public function provideValidJudgments() {
-		yield [ 'valid_diff_judgment.json', 'diff' ];
-		yield [ 'valid_revision_judgment.json', 'revision' ];
-	}
-
-	/**
-	 * @dataProvider provideInvalidSchemaContent
-	 *
-	 * @param string $path Path to test fixture, relative to the test data
-	 * directory.
-	 *
-	 * @covers ::validateAgainstSchema
-	 * @covers ::validateContentQualityScale
-	 * @covers ::validateBasicSchema
-	 * @covers ::validateEndorsementUsers
-	 * @covers ::validateJudgmentContent
-	 * @covers ::validatePreferred
-	 */
-	public function testInvalidSchemaContent( $path, $expectedError ) {
-		$status = $this->runValidation( $path );
-
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( $expectedError, $errors[0]['message'] );
-	}
-
-	/**
-	 * @param string $path JSON file with judgment page content to validate.
-	 * @return StatusValue validation success or errors.
-	 */
-	protected function runValidation( $path ) {
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/' . $path );
-
-		$validator = JadeServices::getJudgmentValidator();
-		$data = FormatJson::decode( $text );
-		return $validator->validateJudgmentContent( $data );
-	}
-
-	/**
-	 * @dataProvider provideValidJudgments
-	 *
-	 * @param string $path Path to test fixture, relative to the test data
-	 * directory.
-	 *
-	 * @covers ::validateBasicSchema
-	 * @covers ::validateEndorsementUsers
-	 * @covers ::validateJudgmentContent
-	 * @covers ::validatePreferred
-	 */
-	public function testValidateJudgmentContent( $path ) {
-		$status = $this->runValidation( $path );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * @dataProvider provideValidJudgments
-	 *
-	 * @covers ::validateEntity
-	 * @covers ::validateEntitySchema
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_valid( $path, $type ) {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$ucType = ucfirst( $type );
-		$title = "{$ucType}/{$revision->getId()}";
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/' . $path );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * @dataProvider provideInvalidWithType
-	 *
-	 * @param string $path Path to test fixture, relative to the test data
-	 * directory.
-	 * @param string $type Entity type
-	 *
-	 * @covers ::validateEntity
-	 * @covers ::validateEntitySchema
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_invalidWithType( $path, $type ) {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$ucType = ucfirst( $type );
-		switch ( $type ) {
-			case 'diff':
-			case 'revision':
-				$title = "{$ucType}/{$revision->getId()}";
-				break;
-			default:
-				$this->fail( "Not handling bad entity type {$type}" );
-		}
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/' . $path );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-illegal-schema', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_invalidLong() {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Revision/{$revision->getId()}/foo";
-		$text = file_get_contents(
-			__DIR__ . '/' . self::DATA_DIR . '/valid_revision_judgment.json' );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-title-format', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_invalidShort() {
-		$title = 'Revision';
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/valid_revision_judgment.json' );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-title-format', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_invalidNonCanonicalLeadingZero() {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Revision/0{$revision->getId()}";
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/valid_diff_judgment.json' );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-non-canonical-title', $errors[0]['message'] );
-		$this->assertEquals( "Revision/{$revision->getId()}", $errors[0]['params'][0] );
-	}
-
-	/**
-	 * @covers ::validateEntity
-	 * @covers ::validatePageTitle
-	 */
-	public function testValidatePageTitle_invalidRevision() {
-		// A revision that will "never" exist.  We don't create an entity for this test.
-		$title = 'Revision/999999999';
-		$text = file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/valid_diff_judgment.json' );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-revision-id', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_goodId() {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $this->user->getId(),
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_badId() {
-		$userId = mt_rand();
-		// But never create the user...
-
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $userId,
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-user-local-id-invalid', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_goodCid() {
-		$centralUserId = CentralIdLookup::factory()->centralIdFromLocalUser( $this->user );
-
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $this->user->getId(),
-						'cid' => $centralUserId,
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * Should be able to use suppressed users since we're only showing the ID.
-	 *
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_suppressedCid() {
-		$centralUserId = CentralIdLookup::factory()->centralIdFromLocalUser( $this->user );
-
-		// Suppress username.
-		$block = new Block( [
-			'address' => $this->user->getName(),
-			'by' => $this->getTestSysop()->getUser()->getId(),
-			'hideName' => true,
-		] );
-		$block->insert();
-
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $this->user->getId(),
-						'cid' => $centralUserId,
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertTrue( $status->isOK() );
-	}
-
-	/**
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_badCid() {
-		// Provide a valid local user ID to be sure we're testing the cid.
-		$localUserId = $this->user->getId();
-
-		// Make sure the central user ID is wrong.
-		$centralUserId = mt_rand();
-
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $localUserId,
-						'cid' => $centralUserId,
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-user-central-id-invalid', $errors[0]['message'] );
-	}
-
-	/**
-	 * Local and Global IDs are different users.
-	 *
-	 * @covers ::validateEndorsementUsers
-	 */
-	public function testValidateEndorsementUsers_idMismatch() {
-		// Valid local user ID.
-		$localUserId = $this->user->getId();
-
-		// Different central user's ID.
-		$user2 = $this->getTestSysop()->getUser();
-		$centralUserId = CentralIdLookup::factory()->centralIdFromLocalUser( $user2 );
-
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $localUserId,
-						'cid' => $centralUserId,
-					],
-					'created' => date( DATE_ATOM ),
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-user-id-mismatch', $errors[0]['message'] );
-	}
-
-	public function provideTimestamps() {
-		// Note that we're slightly stricter than ISO 8601.
-		yield [ '2001-04-01T22:22:22Z', true ];
-		yield [ '2001-04-01T22:22:22+01:30', true ];
-		yield [ '2001-04-01', false ];
-		yield [ '2001-04-01T22:22:22', false ];
-		yield [ '20010401T222222Z', false ];
-		yield [ '10-04', false ];
-		yield [ '10-foo', false ];
-	}
-
-	/**
-	 * Timestamp parsing
-	 *
-	 * @dataProvider provideTimestamps
-	 * @covers ::validateEndorsementTimestamps
-	 */
-	public function testValidateTimestamps( $timestamp, $expectedSuccess ) {
-		list( $page, $revision ) = TestStorageHelper::createEntity( $this->user );
-		$title = "Diff/{$revision->getId()}";
-		$text = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'endorsements' => [ [
-					'user' => [
-						'id' => $this->user->getId(),
-					],
-					'created' => $timestamp,
-				] ],
-			] ]
-		] );
-
-		$status = TestStorageHelper::saveJudgment( $title, $text, $this->user );
-		if ( $expectedSuccess ) {
-			$this->assertTrue( $status->isOK() );
-		} else {
-			$this->assertFalse( $status->isOK() );
-			$errors = $status->getErrors();
-			$this->assertCount( 1, $errors );
-			$this->assertEquals( 'jade-created-timestamp-invalid', $errors[0]['message'] );
-		}
-	}
-
-	/**
-	 * @covers ::validateEntity
-	 */
-	public function testValidateEntity_badType() {
-		$validator = JadeServices::getJudgmentValidator();
-
-		$validator = TestingAccessWrapper::newFromObject( $validator );
-		$status = $validator->validateEntity( 'foo', 123 );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-bad-entity-type', $errors[0]['message'] );
-		$this->assertEquals( 'foo', $errors[0]['params'][0] );
-	}
-
-}
diff --git a/tests/phpunit/Maintenance/CleanJudgmentLinksTest.php b/tests/phpunit/Maintenance/CleanJudgmentLinksTest.php
deleted file mode 100644
index b437bdf..0000000
--- a/tests/phpunit/Maintenance/CleanJudgmentLinksTest.php
+++ /dev/null
@@ -1,200 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade\Tests\Maintenance;
-
-use Jade\Maintenance\CleanJudgmentLinks;
-use Jade\Tests\TestJudgmentLinkAssertions;
-use Jade\Tests\TestStorageHelper;
-use MediaWiki\Tests\Maintenance\MaintenanceBaseTestCase;
-use Revision;
-use WikiPage;
-
-/**
- * @group Jade
- * @group Database
- * @group medium
- * @covers Jade\Maintenance\CleanJudgmentLinks
- * @coversDefaultClass Jade\Maintenance\CleanJudgmentLinks
- */
-class CleanJudgmentLinksTest extends MaintenanceBaseTestCase {
-
-	// Include assertions to test judgment links.
-	use TestJudgmentLinkAssertions;
-
-	public function getMaintenanceClass() {
-		return CleanJudgmentLinks::class;
-	}
-
-	public function setUp() {
-		parent::setUp();
-		$this->tablesUsed[] = 'jade_diff_judgment';
-		$this->tablesUsed[] = 'jade_revision_judgment';
-	}
-
-	private function getJudgmentContent( $entityType ) {
-		return file_get_contents( __DIR__ . '/../../data/valid_' . $entityType . '_judgment.json' );
-	}
-
-	private function createRevision() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-		return $revision;
-	}
-
-	private function createJudgment( Revision $revision, $entityType ) {
-		global $wgJadeEntityTypeNames;
-
-		$status = TestStorageHelper::saveJudgment(
-			$wgJadeEntityTypeNames[$entityType] . "/{$revision->getId()}",
-			$this->getJudgmentContent( $entityType )
-		);
-		$this->assertTrue( $status->isOK() );
-
-		return WikiPage::newFromID( $status->value['revision']->getPage() );
-	}
-
-	private function executeMaintenanceScript( $batchSize, $dryRun ) {
-		$options = [ 'batch-size' => $batchSize ];
-		if ( $dryRun ) {
-			$options['dry-run'] = true;
-		}
-
-		$this->maintenance->loadParamsAndArgs(
-			null,
-			$options
-		);
-		$this->maintenance->execute();
-	}
-
-	/**
-	 * Make sure that the starting state has no judgment link rows.
-	 */
-	public function testEmptyNoLinks() {
-		$dbr = wfGetDB( DB_REPLICA );
-		$result = $dbr->select(
-			[ 'jade_diff_judgment' ],
-			[ 'jaded_id' ],
-			null,
-			__METHOD__
-		);
-		$this->assertEquals( 0, $result->numRows() );
-
-		$result = $dbr->select(
-			[ 'jade_revision_judgment' ],
-			[ 'jader_id' ],
-			null,
-			__METHOD__
-		);
-		$this->assertEquals( 0, $result->numRows() );
-	}
-
-	public function entityTypeDryRunProvider() {
-		yield [ 'diff', false ];
-		yield [ 'revision', false ];
-		yield [ 'diff', 'dryRun' ];
-		yield [ 'revision', 'dryRun' ];
-	}
-
-	/**
-	 * @dataProvider entityTypeDryRunProvider
-	 *
-	 * @covers ::findAndDeleteOrphanedLinks
-	 * @covers ::findOrphanedLinks
-	 * @covers ::deleteOrphanedLinks
-	 */
-	public function testDeleteOrphanedLinks( $entityType, $dryRun ) {
-		$noOfTestJudgements = 3;
-		$revisions = [];
-		$pageIds = [];
-
-		// Make sure page deletions don't auto-delete links
-		$this->setTemporaryHook( 'ArticleDeleteComplete', false );
-
-		for ( $i = 0; $i < $noOfTestJudgements; $i++ ) {
-			$revision = $this->createRevision();
-			$page = $this->createJudgment( $revision, $entityType );
-			$pageId = $page->getId();
-
-			// Orphan it by deleting the judgment page
-			$page->doDeleteArticleReal( 'reasonable' );
-
-			// Check that the link still exists.
-			$this->assertJudgmentLink( $entityType, $revision->getId(), $pageId );
-
-			$revisions[] = $revision;
-			$pageIds[] = $pageId;
-		}
-
-		// Run the job (with a batch-size lower than $noOfTestJudgements)
-		$this->executeMaintenanceScript( $noOfTestJudgements - 1, $dryRun );
-
-		// Check that the links were deleted.
-		for ( $i = 1; $i < $noOfTestJudgements; $i++ ) {
-			if ( $dryRun ) {
-				// Links should still be present if this is a dry run
-				$this->assertJudgmentLink( $entityType, $revisions[$i]->getId(), $pageIds[$i] );
-			} else {
-				$this->assertNoJudgmentLink( $entityType, $revisions[$i]->getId(), $pageIds[$i] );
-			}
-		}
-	}
-
-	/**
-	 * @dataProvider entityTypeDryRunProvider
-	 *
-	 * @covers ::findAndConnectUnlinkedJudgments
-	 * @covers ::findUnlinkedJudgments
-	 * @covers ::connectUnlinkedJudgments
-	 */
-	public function testConnectUnlinkedJudgments( $entityType, $dryRun ) {
-		$noOfTestJudgements = 3;
-		$revisions = [];
-		$pageIds = [];
-
-		// Make sure created judgements are not linked
-		$this->setTemporaryHook( 'PageContentInsertComplete', false );
-
-		for ( $i = 0; $i < $noOfTestJudgements; $i++ ) {
-			// Create judgment without link.
-			$revision = $this->createRevision();
-			$page = $this->createJudgment( $revision, $entityType );
-
-			// Check that no link was created.
-			$this->assertNoJudgmentLink( $entityType, $revision->getId(), $page->getId() );
-
-			$revisions[] = $revision;
-			$pageIds[] = $page->getId();
-		}
-
-		// Run the job (with a batch-size lower than $noOfTestJudgements)
-		$this->executeMaintenanceScript( $noOfTestJudgements - 1, $dryRun );
-
-		// Check that the links were inserted.
-		for ( $i = 1; $i < $noOfTestJudgements; $i++ ) {
-			if ( !$dryRun ) {
-				$this->assertJudgmentLink( $entityType, $revisions[$i]->getId(), $pageIds[$i] );
-			} else {
-				// Links should still be absent if this is a dry run
-				$this->assertNoJudgmentLink( $entityType, $revisions[$i]->getId(), $pageIds[$i] );
-			}
-		}
-	}
-
-}
diff --git a/tests/phpunit/PageEntityJudgmentSetStorageTest.php b/tests/phpunit/PageEntityJudgmentSetStorageTest.php
deleted file mode 100644
index 20f8d35..0000000
--- a/tests/phpunit/PageEntityJudgmentSetStorageTest.php
+++ /dev/null
@@ -1,234 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use FormatJSON;
-use Jade\JudgmentEntityType;
-use Jade\JadeServices;
-use Jade\JudgmentTarget;
-use MediaWikiTestCase;
-use WikiPage;
-
-/**
- * @group Database
- * @group Jade
- * @group medium
- *
- * @coversDefaultClass Jade\PageEntityJudgmentSetStorage
- */
-class PageEntityJudgmentSetStorageTest extends MediaWikiTestCase {
-
-	const JUDGMENT_V1 = 'valid_revision_judgment.json';
-	const JUDGMENT_V2 = 'valid_revision_judgment_v2.json';
-	const DATA_DIR = '../data';
-
-	private $storage;
-
-	public function setUp() {
-		$this->storage = JadeServices::getEntityJudgmentSetStorage();
-		$this->tablesUsed = [
-			'jade_diff_judgment',
-			'jade_revision_judgment',
-			'page',
-		];
-
-		parent::setUp();
-
-		$this->revisionType = JudgmentEntityType::sanitizeEntityType( 'revision' )->value;
-	}
-
-	public function tearDown() {
-		global $wgUser;
-
-		parent::tearDown();
-
-		// wgGroupPermissions are cached in the User object, so be sure to reset.
-		$wgUser->clearInstanceCache();
-	}
-
-	/**
-	 * Return sample judgment as an array.
-	 *
-	 * @param string $path Fixture file name.
-	 * @return array Data for a sample judgment page.
-	 */
-	private function getJudgment( $path = self::JUDGMENT_V1 ) {
-		$text = $this->getJudgmentText( $path );
-		return FormatJSON::decode( $text, true );
-	}
-
-	/**
-	 * Return sample judgment text.
-	 * @param string $path Fixture file name.
-	 * @return string Text for a sample judgment page.
-	 */
-	private function getJudgmentText( $path = self::JUDGMENT_V1 ) {
-		return file_get_contents( __DIR__ . '/' . self::DATA_DIR . '/' . $path );
-	}
-
-	/**
-	 * @covers ::storeJudgmentSet
-	 */
-	public function testStoreJudgmentSet_cannotCreate() {
-		global $wgUser;
-		// Prevent page creation.
-		$this->setMwGlobals( [
-			'wgGroupPermissions' => [
-				'*' => [ 'create' => false ],
-			]
-		] );
-		// FIXME: Not sure why we have to flush twice here.
-		$wgUser->clearInstanceCache();
-
-		// Should return a failure status.
-		$status = $this->storage->storeJudgmentSet(
-			new JudgmentTarget( $this->revisionType, mt_rand() ),
-			$this->getJudgment(),
-			'summary',
-			[]
-		);
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-cannot-create-page', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::storeJudgmentSet
-	 */
-	public function testStoreJudgmentSet_cannotEdit() {
-		global $wgUser;
-
-		// Prevent editing.
-		$this->setMwGlobals( [
-			'wgGroupPermissions' => [
-				'*' => [ 'edit' => false ],
-			]
-		] );
-		// FIXME: unknown why we have to flush twice.
-		$wgUser->clearInstanceCache();
-
-		// Create a normal judgment to be edited.
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-		TestStorageHelper::saveJudgment(
-			"Revision/{$entityRevision->getId()}",
-			$this->getJudgmentText() );
-
-		// Should return a failure status.
-		$status = $this->storage->storeJudgmentSet(
-			new JudgmentTarget( $this->revisionType, $entityRevision->getId() ),
-			$this->getJudgment( self::JUDGMENT_V2 ),
-			'summary',
-			[]
-		);
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'jade-cannot-edit-page', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::storeJudgmentSet
-	 */
-	public function testStoreJudgmentSet_cannotAddTag() {
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-
-		// Prevent adding tags.
-		$this->setMwGlobals( [
-			'wgGroupPermissions' => [
-				'*' => [ 'applychangetags' => false ],
-			]
-		] );
-
-		// Should return a failure status.
-		$status = $this->storage->storeJudgmentSet(
-			new JudgmentTarget( $this->revisionType, $entityRevision->getId() ),
-			$this->getJudgment(),
-			'summary',
-			[ 'tag_it' ]
-		);
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( 'tags-apply-no-permission', $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::storeJudgmentSet
-	 */
-	public function testStoreJudgmentSet_success() {
-		// Create an entity to be judged.
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-
-		// Store the judgment.
-		$status = $this->storage->storeJudgmentSet(
-			new JudgmentTarget( $this->revisionType, $entityRevision->getId() ),
-			$this->getJudgment(),
-			'summary',
-			[]
-		);
-		$this->assertTrue( $status->isOK() );
-
-		$title = "Revision/{$entityRevision->getId()}";
-		list( $page, $storedJudgment ) = TestStorageHelper::loadJudgment( $title );
-		$this->assertEquals( $this->getJudgment(), $storedJudgment );
-	}
-
-	/**
-	 * @covers ::loadJudgmentSet
-	 */
-	public function testLoadJudgmentSet_empty() {
-		// Create an entity to be judged.
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-
-		// Store using test helper to isolate function under test.
-		$status = TestStorageHelper::saveJudgment(
-			"Revision/{$entityRevision->getId()}",
-			$this->getJudgmentText() );
-		$this->assertTrue( $status->isOK() );
-
-		// Delete the article so that getContent returns null.
-		$judgmentPageId = $status->value['revision']->getPage();
-		$judgmentPage = WikiPage::newFromID( $judgmentPageId );
-		$success = $judgmentPage->doDeleteArticle( 'reason' );
-		$this->assertTrue( $success );
-
-		$target = new JudgmentTarget( $this->revisionType, $entityRevision->getId() );
-		$status = $this->storage->loadJudgmentSet( $target );
-		$this->assertTrue( $status->isOK() );
-		$this->assertEquals( [], $status->value );
-	}
-
-	/**
-	 * @covers ::loadJudgmentSet
-	 */
-	public function testLoadJudgmentSet_success() {
-		// Create an entity to be judged.
-		list( $entityPage, $entityRevision ) = TestStorageHelper::createEntity();
-
-		// Store using test helper to isolate function under test.
-		$success = TestStorageHelper::saveJudgment(
-			"Revision/{$entityRevision->getId()}",
-			$this->getJudgmentText() );
-		$this->assertTrue( $success->isOK() );
-
-		$target = new JudgmentTarget( $this->revisionType, $entityRevision->getId() );
-		$status = $this->storage->loadJudgmentSet( $target );
-		$this->assertTrue( $status->isOK() );
-		$this->assertEquals( $this->getJudgment(), $status->value );
-	}
-
-}
diff --git a/tests/phpunit/SchemaValidationTest.php b/tests/phpunit/SchemaValidationTest.php
deleted file mode 100644
index e5ecaf1..0000000
--- a/tests/phpunit/SchemaValidationTest.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use PHPUnit\Framework\TestCase;
-use JsonSchema\Validator;
-
-/**
- * @group Jade
- * @coversNothing
- */
-class SchemaValidationTest extends TestCase {
-
-	const ROOT_DIR = '../..';
-
-	public function provideSchemas() {
-		yield [ "jsonschema/judgment/v1.json" ];
-	}
-
-	/**
-	 * Check that included schemas are valid.
-	 *
-	 * @dataProvider provideSchemas
-	 *
-	 * @param string $subject Path to schema being validated.
-	 */
-	public function testSchemas( $subject ) {
-		$data = json_decode( file_get_contents( __DIR__ . '/' . self::ROOT_DIR . '/' . $subject ) );
-
-		$validator = new Validator;
-		$validator->validate( $data );
-
-		if ( !$validator->isValid() ) {
-			print_r( $validator->getErrors() );
-		}
-		$this->assertTrue( $validator->isValid() );
-	}
-
-}
diff --git a/tests/phpunit/ServicesTest.php b/tests/phpunit/ServicesTest.php
deleted file mode 100644
index 8e52be3..0000000
--- a/tests/phpunit/ServicesTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\EntityJudgmentSetStorage;
-use Jade\JudgmentIndexStorage;
-use Jade\JudgmentValidator;
-use Jade\JadeServices;
-use Jade\ServiceWiring;
-use MediaWiki\MediaWikiServices;
-use MediaWikiTestCase;
-
-/**
- * @group Jade
- */
-class ServicesTest extends MediaWikiTestCase {
-
-	public function provideServices() {
-		yield [
-			'getEntityJudgmentSetStorage',
-			'JadeEntityJudgmentSetStorage',
-			EntityJudgmentSetStorage::class
-		];
-		yield [
-			'getJudgmentIndexStorage',
-			'JadeJudgmentIndexStorage',
-			JudgmentIndexStorage::class
-		];
-		yield [
-			'getJudgmentValidator',
-			'JadeJudgmentValidator',
-			JudgmentValidator::class
-		];
-	}
-
-	/**
-	 * @dataProvider provideServices
-	 * @covers Jade\JadeServices
-	 */
-	public function testJadeServices( $funcName, $_serviceKey, $className ) {
-		$service = call_user_func( [ JadeServices::class, $funcName ] );
-		$this->assertInstanceOf( $className, $service );
-	}
-
-	/**
-	 * @dataProvider provideServices
-	 * @covers Jade\ServiceWiring::getWiring
-	 */
-	public function testServiceWiring( $_funcName, $serviceKey, $className ) {
-		$wiring = ServiceWiring::getWiring();
-		$service = $wiring[$serviceKey]( MediaWikiServices::getInstance() );
-
-		$this->assertInstanceOf( $className, $service );
-	}
-
-}
diff --git a/tests/phpunit/SpamBlacklist/SpamBlacklistTest.php b/tests/phpunit/SpamBlacklist/SpamBlacklistTest.php
deleted file mode 100644
index ddbb4bf..0000000
--- a/tests/phpunit/SpamBlacklist/SpamBlacklistTest.php
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests\SpamBlacklist;
-
-use ApiTestCase;
-use BaseBlacklist;
-use ExtensionRegistry;
-use Jade\Tests\TestStorageHelper;
-use ReflectionClass;
-
-/**
- * Check that SpamBlacklist integration works in judgment JSON.
- *
- * @group Jade
- * @group Database
- * @group medium
- * @group SpamBlacklist
- *
- * @covers SpamBlacklist
- */
-class SpamBlacklistTest extends ApiTestCase {
-
-	const BLACKLIST_FILE = 'spam_blacklist.txt';
-
-	public function setUp() {
-		parent::setUp();
-
-		if ( !ExtensionRegistry::getInstance()->isLoaded( 'SpamBlacklist' ) ) {
-			$this->markTestSkipped( 'Can only run test with SpamBlacklist enabled' );
-		}
-
-		$this->tablesUsed = [
-			'page',
-		];
-
-		$blacklistPath = __DIR__ . '/../../data/' . self::BLACKLIST_FILE;
-		$this->setMwGlobals(
-			'wgBlacklistSettings',
-			[ 'spam' => [
-				'files' => [ $blacklistPath ],
-			] ]
-		);
-
-		// Reset the blacklist, which will have already been initialized due to
-		// a hook invoked during setUp.
-		$reflClass = new ReflectionClass( BaseBlacklist::class );
-		$reflProperty = $reflClass->getProperty( 'instances' );
-		$reflProperty->setAccessible( true );
-		$reflProperty->setValue( [] );
-	}
-
-	public function testFilterJudgment_matching() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-
-		$content = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'notes' => 'Visit http://unusual-stringy.tv/',
-			] ],
-		] );
-
-		$result = $this->doApiRequestWithToken( [
-			'action' => 'edit',
-			'title' => "Judgment:Diff/{$revision->getId()}",
-			'text' => $content,
-			'summary' => 'a summary',
-		] );
-
-		$expected = [
-			'spamblacklist' => 'unusual-stringy',
-			'result' => 'Failure',
-		];
-		$this->assertEquals( $expected, $result[0]['edit'] );
-	}
-
-	public function testFilterJudgment_nonmatching() {
-		list( $page, $revision ) = TestStorageHelper::createEntity();
-
-		$content = json_encode( [
-			'judgments' => [ [
-				'schema' => [
-					'damaging' => false,
-					'goodfaith' => true,
-				],
-				'preferred' => true,
-				'notes' => 'Visit http://casino.gov/harmless-real-casino',
-			] ],
-		] );
-
-		$result = $this->doApiRequestWithToken( [
-			'action' => 'edit',
-			'title' => "Judgment:Diff/{$revision->getId()}",
-			'text' => $content,
-			'summary' => 'a summary',
-		] );
-
-		$this->assertEquals( 'Success', $result[0]['edit']['result'] );
-	}
-
-}
diff --git a/tests/phpunit/TestJudgmentLinkAssertions.php b/tests/phpunit/TestJudgmentLinkAssertions.php
deleted file mode 100644
index 170404d..0000000
--- a/tests/phpunit/TestJudgmentLinkAssertions.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-namespace Jade\Tests;
-
-/**
- * Reusable judgment link assertions.
- */
-trait TestJudgmentLinkAssertions {
-
-	/**
-	 * Fail if the given link doesn't exist.
-	 *
-	 * @param string $entityType
-	 * @param int $targetRevisionId rev_id of the target revision.
-	 * @param int $judgmentPageId page_id of the judgment page.
-	 */
-	private function assertJudgmentLink( $entityType, $targetRevisionId, $judgmentPageId ) {
-		$result = TestLinkTableHelper::selectJudgmentLink(
-			$entityType, $targetRevisionId, $judgmentPageId );
-		if ( $result->numRows() < 1 ) {
-			$this->fail( 'Judgment link not present.' );
-		}
-	}
-
-	/**
-	 * Fail if the given link exists.
-	 *
-	 * @param string $entityType
-	 * @param int $targetRevisionId rev_id of the target revision.
-	 * @param int $judgmentPageId page_id of the judgment page.
-	 */
-	private function assertNoJudgmentLink( $entityType, $targetRevisionId, $judgmentPageId ) {
-		$result = TestLinkTableHelper::selectJudgmentLink(
-			$entityType, $targetRevisionId, $judgmentPageId );
-		if ( $result->numRows() > 0 ) {
-			$this->fail( 'Judgment link should not be present.' );
-		}
-	}
-
-}
diff --git a/tests/phpunit/TestLinkTableHelper.php b/tests/phpunit/TestLinkTableHelper.php
deleted file mode 100644
index 802aacc..0000000
--- a/tests/phpunit/TestLinkTableHelper.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use Jade\JudgmentLinkTableHelper;
-use MediaWiki\MediaWikiServices;
-use PHPUnit\Framework\Assert;
-
-/**
- * Break access control as a quick and dirty way to reuse internal string
- * constant functions.  We want to keep the JudgmentLinkTable class closed for
- * production code, since no other classes should know about the implementation
- * details, and we only cheat access in tests.
- */
-class TestLinkTableHelper {
-
-	/**
-	 * @param string $entityType entity type identifier
-	 * @param int $targetRevisionId revision being judged
-	 * @param int $judgmentPageId page ID being linked
-	 * @param array $summaryColumns Any additional summary fields to retrieve.
-	 *
-	 * @return mixed Native or wrapped database query result.
-	 */
-	public static function selectJudgmentLink(
-		$entityType,
-		$targetRevisionId,
-		$judgmentPageId,
-		$summaryColumns = []
-	) {
-		$status = JudgmentEntityType::sanitizeEntityType( $entityType );
-		Assert::assertTrue( $status->isOK() );
-		$helper = new JudgmentLinkTableHelper( $status->value );
-
-		$selectColumns = [
-			$helper->getTargetColumn(),
-			$helper->getJudgmentColumn(),
-		];
-		foreach ( $summaryColumns as $schemaName ) {
-			$selectColumns[] = $helper->getSummaryColumn( $schemaName );
-		}
-
-		$dbr = MediaWikiServices::getInstance()->getDBLoadBalancer()
-			->getConnection( DB_REPLICA );
-		$result = $dbr->select(
-			[ $helper->getLinkTable() ],
-			$selectColumns,
-			[
-				$helper->getTargetColumn() => $targetRevisionId,
-				$helper->getJudgmentColumn() => $judgmentPageId,
-			],
-			__METHOD__
-		);
-		return $result;
-	}
-
-}
diff --git a/tests/phpunit/TestStorageHelper.php b/tests/phpunit/TestStorageHelper.php
deleted file mode 100644
index a3fabf8..0000000
--- a/tests/phpunit/TestStorageHelper.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use ContentHandler;
-use FormatJSON;
-use PHPUnit\Framework\Assert;
-use StatusValue;
-use Title;
-use TitleValue;
-use WikiPage;
-
-class TestStorageHelper {
-
-	const DEFAULT_CONTENT = 'abcdef';
-	const DEFAULT_SUMMARY = 'some summary';
-
-	const DIFF_JUDGMENT = '../data/valid_diff_judgment.json';
-	const REVISION_JUDGMENT = '../data/valid_revision_judgment.json';
-
-	/**
-	 * Coarse wrapper for creating temporary content.
-	 *
-	 * @param User|null $user User to edit as.
-	 *
-	 * @return array [ WikiPage, Revision ]
-	 */
-	public static function createEntity( $user = null ) {
-		global $wgUser;
-
-		if ( is_null( $user ) ) {
-			$user = $wgUser;
-		}
-
-		$editTarget = new TitleValue( 0, 'JadeJudgmentContentTestPage' . strval( mt_rand() ) );
-		$title = Title::newFromLinkTarget( $editTarget );
-		$summary = 'Test edit';
-		$page = WikiPage::factory( $title );
-		$status = $page->doEditContent(
-			ContentHandler::makeContent( __CLASS__, $title ),
-			$summary,
-			0,
-			false,
-			$user
-		);
-
-		Assert::assertTrue( $status->isGood() );
-
-		$revision = $status->value['revision'];
-		Assert::assertNotNull( $revision );
-
-		return [ $page, $revision ];
-	}
-
-	/**
-	 * @param string $titleStr Page title to load.
-	 *
-	 * @return [ WikiPage, array ] Page and decoded content.
-	 */
-	public static function loadJudgment( $titleStr ) {
-		$target = new TitleValue( NS_JUDGMENT, $titleStr );
-		$title = Title::newFromLinkTarget( $target );
-		$page = WikiPage::factory( $title );
-		$content = $page->getContent();
-		$judgments = FormatJSON::decode( $content->getNativeData(), true );
-		return [ $page, $judgments ];
-	}
-
-	/**
-	 * @param string $titleStr Page title.
-	 * @param string|array $text Content to save.
-	 * @param User|null $user User to save as.
-	 *
-	 * @return StatusValue
-	 */
-	public static function saveJudgment( $titleStr, $text, $user = null ) {
-		global $wgUser;
-		if ( is_null( $user ) ) {
-			$user = $wgUser;
-		}
-		if ( is_array( $text ) ) {
-			$text = FormatJSON::encode( $text );
-		}
-		$editTarget = new TitleValue( NS_JUDGMENT, $titleStr );
-		$title = Title::newFromLinkTarget( $editTarget );
-		$summary = 'Test edit';
-		$page = WikiPage::factory( $title );
-		return $page->doEditContent(
-			ContentHandler::makeContent( $text, $title ),
-			$summary,
-			0,
-			false,
-			$user
-		);
-	}
-
-	/**
-	 * Fine control wrapper for making raw edits.
-	 *
-	 * @param int $namespace Integer namespace.
-	 * @param string $title Title without namespace.
-	 * @param string $content New content.
-	 * @param string $summary Edit summary.
-	 * @param bool $expectedStatus Assert that the edit was either successful
-	 *        or a failure.
-	 *
-	 * @return array [ 'page' => WikiPage, 'revision' => Revision ]
-	 */
-	public static function makeEdit(
-		$namespace,
-		$title,
-		$content = self::DEFAULT_CONTENT,
-		$summary = self::DEFAULT_SUMMARY,
-		$expectedStatus = true
-	) {
-		global $wgUser;
-
-		$editTarget = new TitleValue( $namespace, $title );
-		$title = Title::newFromLinkTarget( $editTarget );
-		$page = WikiPage::factory( $title );
-		$status = $page->doEditContent(
-			ContentHandler::makeContent( $content, $title ),
-			$summary,
-			0,
-			false,
-			$wgUser
-		);
-
-		Assert::assertEquals( $expectedStatus, $status->isGood(),
-			'Wrong edit return status: ' . $status );
-
-		if ( $expectedStatus === false ) {
-			// Nothing more to do.
-			return;
-		}
-
-		$revision = $status->value['revision'];
-		Assert::assertNotNull( $revision, 'No revision after edit' );
-
-		return [
-			'page' => $page,
-			'revision' => $revision,
-		];
-	}
-
-	/**
-	 * Load a judgment fixture.
-	 *
-	 * @param string $entityType Entity type key.
-	 *
-	 * @return string file contents
-	 */
-	public static function getJudgmentText( $entityType ) {
-		$textMap = [
-			'diff' => self::DIFF_JUDGMENT,
-			'revision' => self::REVISION_JUDGMENT,
-		];
-		$textPath = __DIR__ . '/' . $textMap[$entityType];
-		return file_get_contents( $textPath );
-	}
-
-}
diff --git a/tests/phpunit/TitleHelperTest.php b/tests/phpunit/TitleHelperTest.php
deleted file mode 100644
index 02f31a2..0000000
--- a/tests/phpunit/TitleHelperTest.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-/**
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-namespace Jade\Tests;
-
-use Jade\JudgmentEntityType;
-use Jade\JudgmentTarget;
-use Jade\TitleHelper;
-use MediaWikiTestCase;
-use TitleValue;
-
-/**
- * @group Jade
- *
- * @coversDefaultClass Jade\TitleHelper
- */
-class TitleHelperTest extends MediaWikiTestCase {
-
-	public function setUp() {
-		parent::setUp();
-		$this->revisionType = JudgmentEntityType::sanitizeEntityType( 'revision' )->value;
-	}
-
-	/**
-	 * @covers ::buildJadeTitle
-	 */
-	public function testBuildJadeTitle_success() {
-		$target = new JudgmentTarget( $this->revisionType, 123 );
-		$title = TitleHelper::buildJadeTitle( $target );
-		$this->assertEquals( 'Revision/123', $title->getDBkey() );
-	}
-
-	public function provideUnparseableTitles() {
-		yield [ NS_TALK, 'Revision/123', 'jade-bad-title-namespace' ];
-		yield [ NS_JUDGMENT, 'Revision/123/321', 'jade-bad-title-format' ];
-		yield [ NS_JUDGMENT, 'Revision', 'jade-bad-title-format' ];
-		yield [ NS_JUDGMENT, 'Foo/123', 'jade-bad-entity-type' ];
-		yield [ NS_JUDGMENT, 'Revision/bar', 'jade-bad-entity-id-format' ];
-	}
-
-	/**
-	 * @dataProvider provideUnparseableTitles
-	 * @covers ::parseTitleValue
-	 */
-	public function testParseTitle_bad( $namespace, $titleStr, $expectedError ) {
-		$title = new TitleValue( $namespace, $titleStr );
-		$status = TitleHelper::parseTitleValue( $title );
-		$this->assertFalse( $status->isOK() );
-		$errors = $status->getErrors();
-		$this->assertCount( 1, $errors );
-		$this->assertEquals( $expectedError, $errors[0]['message'] );
-	}
-
-	/**
-	 * @covers ::parseTitleValue
-	 */
-	public function testParseTitle_success() {
-		// Provide a localization which won't accidentally match the type
-		// identifier.
-		$this->setMwGlobals( [
-			'wgJadeEntityTypeNames' => [
-				'diff' => 'Diffie',
-			],
-		] );
-
-		$title = new TitleValue( NS_JUDGMENT, 'Diffie/123' );
-		$status = TitleHelper::parseTitleValue( $title );
-		$this->assertTrue( $status->isOK() );
-		$target = $status->value;
-		$this->assertEquals( 'diff', $target->entityType );
-		$this->assertEquals( 123, $target->entityId );
-	}
-
-}