DesktopArticleTarget#rebuildCategories says:
```
// We need to fetch this from the API because the category list is skin-
// dependent, so the HTML output could be absolutely anything.
```
…and then it doesn't pass 'useskin', rendering itself pointless.
//(Furthermore, it is impossible to do correctly when the article content comes from a different wiki, as it might in ContentTranslation. Querying the local API is incorrect, because the categories probably don't exist (so we'd have incorrect redlinks); querying the content API is incorrect, because that wiki might be using a different skin (and might not even have the one we want installed). This is theoretical though, ContentTranslation doesn't use this method.)//
Luckily, as far as I can tell, that comment is only technically true. While skins could override this (Skin::getCategories()), none of them does. Skins that render categories differently (Minerva and Timeless) have a separate method, they don't override this one.
Given the hopelessness otherwise, and the TODO comment below, we should probably replace this API call with hardcoded generation of the default HTML that we expect. If the #catlinks element is missed, we should do nothing. We could mention this behavior on https://www.mediawiki.org/wiki/VisualEditor/Skin_requirements (it already talks about #catlinks).
In fact, we already do this in the wikitext preview code – MWSaveDialog#showPreview just generates `<div class="catlinks">` and its contents. (Although that doesn't handle hidden categories right, that would have to be added.)
(Originally noticed during code review of https://gerrit.wikimedia.org/r/#/c/430906/)