De voorpagina van atlasmuseum.net zoals het Internet Archive die op 28 september 2022 vastlegde, naast dezelfde pagina zoals de wiki hem op 11 september 2026 toont. Tussen de twee loopt een naad; wie hem verschuift ziet de commando's, query's en logregels van de migratie.
1.26.4 naar 1.39.10
- PHP 7.4 naar 8.3, MySQL 5.7 naar 8.0
- 43 extensies, elk op PHP 8
- database gered, niet herbouwd
- 26 tot 64 keer sneller op de gemeten pagina's
De regels in de naad, uit het opleverdocument en de logbestanden:
- MediaWiki: 1.26.4
- PHP: 7.4
- MySQL: 5.7
- am_archive.ar_rev_id: 149315 x 8000+ (duplicate)
- am_revision: index rev_timestamp missing (error 1176)
- update.php: a username was usable and an anonymous actor could not be created
- $ php maintenance/update.php
- $ php maintenance/cleanupUsersWithNoId.php --assign --prefix legacy --force
- $ php maintenance/cleanupUsersWithNoId.php --assign --prefix legacy --table revision --force
- $ php maintenance/cleanupUsersWithNoId.php --assign --prefix legacy --table oldimage --force
- $ php maintenance/deduplicateArchiveRevId.php --force
- SET @start := GREATEST(
- (SELECT IFNULL(MAX(rev_id),0) FROM am_revision),
- (SELECT IFNULL(MAX(ar_rev_id),0) FROM am_archive)
- ) + 1;
- SET @bad := 149315;
- UPDATE am_archive a JOIN tmp_dups t ON t.ar_id = a.ar_id
- SET a.ar_rev_id = IF((@i := @i + 1) = 1, a.ar_rev_id, (@n := @n + 1));
- $ php maintenance/sql.php --query "CREATE INDEX rev_timestamp ON am_revision (rev_timestamp);"
- $ php maintenance/populateContentTables.php
- INSERT IGNORE INTO am_updatelog (ul_key, ul_value) VALUES ('patch-change_tag-change_tag_rc_tag_id.sql','applied');
- $ php maintenance/rebuildrecentchanges.php
- $ php maintenance/runJobs.php --maxjobs 500
- $ mysqldump wiki --single-transaction --routines --triggers > wiki_after_mw139.sql
- $ php extensions/SemanticMediaWiki/maintenance/rebuildData.php
- $ php extensions/SemanticMediaWiki/maintenance/updateEntityCollation.php
- $ php maintenance/rebuildLocalisationCache.php --force
- $ MW_NO_EXTENSION_HOOKS=1 php maintenance/importImages.php --overwrite --search-recursively images_clean
- $ php maintenance/rebuildImages.php
- $ php extensions/AtlasQualite/maintenance/rebuildQualityIndex.php
- $ php extensions/AtlasRepair/maintenance/repairFromWikidata.php
- $ php extensions/AtlasRepair/maintenance/repairFromWikidata.php --apply
- "manifest_version": 2,
- "requires": { "MediaWiki": ">= 1.39.0" },
- "AutoloadNamespaces": { "WikidataBundle\\": "includes/" },
- execute(): signature aligned with SpecialPage in 1.39
- trim(null) -> trim((string) $value)
- str_replace on null -> coalesced to empty string
- string concatenation: + replaced by .
- duplicate class definitions removed, autoloader regenerated
- Semantic MediaWiki: 5.1.0
- MediaWiki: 1.39.10
- Storage engine: SMW\SQLStore\SQLStore
- ... checking outdated entities ... ok
- ... checking invalid entities by namespace ... ok
- ... refreshed (IDs) 51277
- ... skipped (IDs) 0
- finished: 2026-09-09 02:03:28 CEST exit=0
- [10:05:37] Map rebuilt: 42713 points written to am_map in 1771 ms.
- PHP 7.4 -> 8.1 -> 8.3
- MySQL 5.7 -> 8.0
- MediaWiki 1.26.4 -> 1.31 -> 1.35 -> 1.39.10
- repeated page load: 26 to 64 times faster
- memoisation within one render + 30 minute disk cache
- loopback removed: the server no longer called its own web API
2025 tot 2026 · MediaWiki · A-Pack, Frankrijk
De opdracht die niemand wilde
In oktober 2025 werd ik gebeld over een site die stuk was. Atlasmuseum is een publieke atlas van kunst in de openbare ruimte in Frankrijk, beheerd door de vereniging A-Pack voor het Franse Ministerie van Cultuur.
Eerst bewijzen, dan pas offreren
De live site was gecompromitteerd door piratenaccounts en draaide op MediaWiki 1.26.4, uitgebracht in 2015. Een eerdere migratiepoging was halverwege gestaakt en had de database achtergelaten met gemengde en ontbrekende tabellen.
Meer dan een partij had ernaar gekeken en gezegd dat het niet te redden was, en dat opnieuw beginnen verstandiger zou zijn.
Ik heb daar niet meteen ja of nee op gezegd. Uit de database-dump van de klant bouwde ik de hele site na in een volledig offline omgeving op mijn eigen machine, zonder enige verbinding met de live site en dus zonder enig risico. Pas toen die test aantoonde dat de inhoud te redden was, kwam er een plan en een offerte.
Dat is hoe ik werk. Ik verkoop geen zekerheid die ik nog niet heb.
Het werk zat in de database
Het pad liep van MediaWiki 1.26.4 naar 1.31, naar 1.35, naar 1.39.10, met MySQL van 5.7 naar 8.0 en PHP van 7.4 via 8.1 naar 8.3. Maar de versienummers zijn niet het werk.
Ruim 8.000 gedupliceerde archiefrevisies hernummerd, op revisie 149315 alleen. Een ontbrekende revisie-tijdstempelindex hersteld. De actor-modelmigratie voltooid. De Multi Content Revision-tabellen, de logging, de change tags, het bestandsarchief en de overlegpagina’s stuk voor stuk gerepareerd.
Tienduizenden spampagina’s verwijderd, met de verwijderlijst drie keer nagelopen voordat er iets wegging, omdat je niets terugkrijgt wat je per ongeluk weggooit.
Daarna de inhoud. In de orde van 100.000 semantische entiteiten opnieuw gegenereerd. Meer dan 4.200 afbeeldingen opnieuw ingelezen met de metadata herbouwd, nadat bleek dat de mediabackend aan de verkeerde tabellen hing.
Een geredde site die traag is, is maar half gered
Toen dat allemaal stond, was de site nog steeds traag. Herhaalde paginalading ging uiteindelijk 26 tot 64 keer sneller dan de uitgangssituatie, op de pagina’s die gebenchmarkt zijn.
Dat kwam niet uit een truc. Een tweelaagse cache rond de upstream API en de SPARQL-aanroepen: memoisatie binnen een paginarender, plus een cache op schijf met een houdbaarheid van dertig minuten. Parser- en paginacache aangezet, met een cache-epoch om gericht een schone hertekening af te dwingen zonder de cache uit te zetten. Zware galerijen achter een IntersectionObserver.
En het weghalen van een constructie waarbij de server zijn eigen web-API aanriep. Die was niet alleen traag, hij kon onder druk de hele worker-pool uitputten.
Het derde ding: zes tools die er niet waren
Een migratie is af als de site draait. Ik vond dat niet genoeg. Ik heb zes tools gebouwd, en ze hebben allemaal hetzelfde doel: dat het platform zichzelf schoon houdt als ik er niet meer ben.
AtlasQualite scant de hele catalogus, ongeveer 4.600 kunstwerknotities, en scoort elke notitie op volledigheid tegen de velden die ertoe doen. Afbeelding, coordinaten, auteur, datum, beschrijving, Wikidata-link. Het resultaat is een geprioriteerde werklijst voor de redactie. Je kunt niet verbeteren wat je niet meet.
AtlasRepair ruimt op wat oude imports hebben achtergelaten. Het patroon is bewust: eerst een droge run die niets verandert en een rapport schrijft, dan een overzicht met elke voorgestelde wijziging van huidige naar gecorrigeerde waarde, en pas dan een toepassing met attributie en een snelheidslimiet. Bij de laatste droge run wees hij 1.343 records aan.
Wikidata Enrich vult lege velden in een klik, en uitsluitend lege velden, altijd met een voorbeeld voordat er wordt opgeslagen. AMAPIStatus roept de zelftest aan en laat per endpoint zien of het werkt. Voor een platform dat aan een publieke instelling wordt overgedragen, is kunnen wijzen op een pagina waar alles groen staat veel waard.
MapSync herbouwt de kaart automatisch bij elke opslag of import, in proces, transactioneel, met een eigen lock zodat twee herbouwen niet kunnen botsen. AtlasNova is de nieuwe skin: 1.478 regels tegenover 3.527 in de voorganger. Minder dan de helft, voor iets dat moderner is en makkelijker te onderhouden.
Bij elkaar schreef ik ruim 27.000 regels eigen code, binnen een installatie van meer dan twee miljoen regels en 43 extensies die stuk voor stuk mee moesten naar 1.39 en naar PHP 8.3.
De regels waar ik me aan hield
Dit is het deel waar een opdrachtgever iets aan heeft. Elke tool die schrijft is afgeschermd voor ingelogde redacteuren. Niets anoniems kan een wijziging starten.
Bulkbewerkingen draaien altijd eerst droog en schrijven pas nadat een mens het rapport heeft beoordeeld. Er is geen pad waarbij een massabewerking gebeurt zonder dat iemand bevestigt. Elk bestand dat ik bewerkte is eerst geback-upt met een tijdstempel, zodat elke afzonderlijke wijziging terug te draaien is. Foutmeldingen staan uit voor bezoekers en aan in de logs voor de beheerder.
En een ontwerpregel die alles draagt: de eigen API-laag leest MediaWiki uitsluitend via de stabiele action API en nooit rechtstreeks uit SQL. Daardoor kan een toekomstige upgrade de backend niet breken. Dat is precies wat er misging bij de installatie die ik erfde.
Wat er nog open staat
Het projectdocument houdt ook bij wat nog niet af is. De kaarttabel bevat 988 rijen terwijl er 4.537 hebben ingestaan, doordat een batch met een time-out ooit als geen resultaten meer werd gelezen. De beveiliging tegen die afkapping zit er nu in, dus een herbouw is veilig. En de coordinateneigenschap is een gewone pagina-eigenschap in plaats van een geografische, waardoor de straalzoekopdracht op eigen data niets oplevert.
Ik heb er een runbook van zestig pagina’s bij geleverd, met de complete foutencatalogus en de openstaande punten erin. Niet omdat het moest, maar omdat de volgende ontwikkelaar niet opnieuw moet uitzoeken wat ik al weet.