Index: test/archive-audio.test.js
===================================================================
--- test/archive-audio.test.js	(revision 6c4ff7e385f99367e75efde44e5b671992c43e88)
+++ test/archive-audio.test.js	(revision 6c4ff7e385f99367e75efde44e5b671992c43e88)
@@ -0,0 +1,190 @@
+// Audio overleeft een verhuizing. Formaat v2.
+//
+// Dit bestand bestaat door wat er op soundfabrics.nl gebeurde: 36 berichten
+// kwamen goed over, 14 van de 140 nummers stonden er, en 13 daarvan speelden
+// niet af. Drie oorzaken, alle drie hier vastgelegd:
+//
+//   1. Gehoste audio leeft BUITEN MEDIA_ROOT (eigen gated route). Het archief
+//      droeg alleen bestanden onder media/, dus de exporter rekende er een
+//      /media/../audio/x.mp3 van en de importer weigerde dat pad. Terecht: het
+//      wijst buiten de mediamap. Gevolg was wel dat audio nooit kon aankomen.
+//   2. De importer maakte een audio_tracks-rij aan ZONDER te kijken of het
+//      bestand er was. Een nummer dat in de lijst staat en 404't bij play is
+//      erger dan een nummer dat ontbreekt: het ziet eruit alsof het gelukt is,
+//      dus je gooit je oude instantie weg.
+//   3. Alleen audio die met [[track:]] in een bericht stond ging mee. Losse
+//      nummers en playlists bleven achter (126 respectievelijk 11 stuks).
+//
+// Een verhuizing die je bibliotheek achterlaat is geen verhuizing.
+
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+import fs from 'fs';
+import os from 'os';
+import path from 'path';
+
+const TMP = fs.mkdtempSync(path.join(os.tmpdir(), 'klonkt-audio-'));
+const MEDIA = path.join(TMP, 'media');
+const AUDIO = path.join(TMP, 'audio');
+fs.mkdirSync(MEDIA, { recursive: true });
+fs.mkdirSync(AUDIO, { recursive: true });
+
+process.env.DATABASE_PATH = ':memory:';
+process.env.PUBLIC_BASE_URL = 'https://oud.test';
+process.env.MEDIA_PATH = MEDIA;
+process.env.AUDIO_PATH = AUDIO;      // MOET voor de import van paths.js staan
+
+const dbMod = await import('../src/config/database.js');
+const db = dbMod.default;
+{ const stil = console.log; console.log = () => {}; try { dbMod.initializeDatabase(); } finally { console.log = stil; } }
+const AX = await import('../src/services/ArchiveExportService.js');
+const AI = await import('../src/services/ArchiveImportService.js');
+const { AUDIO_ROOT } = await import('../src/config/paths.js');
+
+db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)')
+  .run('u1', 'u1', 'u1@test', 'x', 'god');
+db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('s1', 'me', 'Mijn site', 'u1');
+
+const BYTES = (s) => Buffer.from(`RIFF${s}`.padEnd(64, '.'));
+
+/** Schone lei: tabellen leeg en de audiomap leeg. Tests lekken anders in elkaar. */
+function leeg() {
+  for (const t of ['playlist_tracks', 'playlists', 'audio_tracks', 'media']) {
+    try { db.prepare(`DELETE FROM ${t}`).run(); } catch { /* tabel bestaat niet */ }
+  }
+  for (const f of fs.readdirSync(AUDIO)) { try { fs.unlinkSync(path.join(AUDIO, f)); } catch { /* niets */ } }
+}
+
+/** Een nummer met zijn bestand op de plek waar de SPELER het zoekt. */
+function track(id, titel, { padInDb = null, schrijf = true } = {}) {
+  const naam = `${id}.mp3`;
+  const echt = path.join(AUDIO, naam);
+  if (schrijf) fs.writeFileSync(echt, BYTES(id));
+  db.prepare('INSERT OR REPLACE INTO media (id, site_id, filename, mime_type, size, storage_path) VALUES (?,?,?,?,?,?)')
+    .run(`m-${id}`, 's1', naam, 'audio/mpeg', 1, padInDb || echt);
+  db.prepare('INSERT OR REPLACE INTO audio_tracks (id, site_id, title, artist, media_id) VALUES (?,?,?,?,?)')
+    .run(id, 's1', titel, 'Robin', `m-${id}`);
+  return echt;
+}
+
+test('een nummer met een VEROUDERD pad in de database gaat gewoon mee', () => {
+  leeg();
+  // Dit is de stille moordenaar. Op sound-fabrics.com wees storage_path voor
+  // 124 van de 139 nummers nog naar /srv/prutfolio/storage/audio, van voor een
+  // dataverhuizing. De speler merkte niets (die zoekt op bestandsnaam in
+  // AUDIO_ROOT), de exporter vond niets en liet ze weg. Zonder klacht.
+  track('oudpad', 'Verouderd pad', { padInDb: '/srv/ergens/anders/oudpad.mp3' });
+  const uit = AX.buildArchive('me');
+  const rij = JSON.parse(uit.files.get('tracks.json').toString('utf8')).orderedItems.find((x) => x.id === 'oudpad');
+  assert.equal(rij['shaer:availability'], 'included',
+    'de exporter hoort te zoeken zoals de speler zoekt, niet zoals de database onthoudt');
+  assert.deepEqual(uit.files.get(rij['shaer:file']), BYTES('oudpad'));
+});
+
+test('de hele rondgang: exporteren, importeren, en het geluid staat er', () => {
+  leeg();
+  track('a', 'Nummer A');
+  track('b', 'Nummer B');
+  const uit = AX.buildArchive('me');
+  assert.equal(uit.counts.tracks, 2);
+
+  // Een LEGE tweede installatie, met zijn eigen mappen.
+  const TMP2 = fs.mkdtempSync(path.join(os.tmpdir(), 'klonkt-audio2-'));
+  const doelAudio = path.join(TMP2, 'audio');
+  fs.mkdirSync(doelAudio, { recursive: true });
+
+  // AUDIO_ROOT ligt vast bij import, dus we importeren in DEZELFDE map en
+  // controleren daarna dat het bestand er staat onder de naam uit het archief.
+  leeg();
+  assert.equal(fs.readdirSync(AUDIO).length, 0, 'schone lei');
+
+  const rapport = AI.importArchive(uit.files, { slug: 'me', origin: 'https://nieuw.test' });
+  assert.equal(rapport.tracks, 2, 'beide nummers komen terug');
+  assert.equal(rapport.tracksMissing, 0);
+
+  const rijen = db.prepare('SELECT t.id, t.title, m.storage_path, m.size FROM audio_tracks t JOIN media m ON m.id = t.media_id ORDER BY t.id').all();
+  assert.equal(rijen.length, 2);
+  for (const r of rijen) {
+    assert.ok(fs.existsSync(r.storage_path), `${r.title}: het bestand hoort er ECHT te staan`);
+    assert.ok(r.size > 0, 'en de grootte klopt, geen 0 zoals bij de kapotte import');
+    assert.ok(r.storage_path.startsWith(path.resolve(AUDIO_ROOT) + path.sep),
+      'audio hoort in AUDIO_ROOT, niet onder de publieke mediamap');
+  }
+  fs.rmSync(TMP2, { recursive: true, force: true });
+});
+
+test('een nummer zonder bestand wordt NIET aangemaakt', () => {
+  // De kern van de klacht: 13 nummers die bestonden en niet speelden. Liever
+  // eerlijk weg dan zichtbaar kapot.
+  leeg();
+  track('zoek', 'Zoekgeraakt', { padInDb: '/bestaat/echt/niet.mp3', schrijf: false });
+  const uit = AX.buildArchive('me');
+  assert.equal(uit.counts.audioMissing, 1);
+
+  leeg();
+  const rapport = AI.importArchive(uit.files, { slug: 'me', origin: 'https://nieuw.test' });
+  assert.equal(rapport.tracks, 0);
+  assert.equal(rapport.tracksMissing, 1);
+  assert.equal(db.prepare('SELECT COUNT(*) n FROM audio_tracks').get().n, 0,
+    'geen rij zonder geluid: dat is precies de val die soundfabrics.nl opleverde');
+  assert.ok(rapport.waarschuwingen.some((w) => /Zoekgeraakt/.test(w)),
+    'en de gebruiker hoort te weten welk nummer er niet is');
+});
+
+test('playlists komen mee, met hun volgorde', () => {
+  leeg();
+
+  track('p1', 'Eerste');
+  track('p2', 'Tweede');
+  track('p3', 'Derde');
+  db.prepare("INSERT INTO playlists (id, site_id, title, artist, kind) VALUES ('pl1','s1','Mijn plaat','Robin','album')").run();
+  // Bewust NIET op alfabet: de volgorde is de hele playlist.
+  db.prepare("INSERT INTO playlist_tracks (playlist_id, track_id, position) VALUES ('pl1','p3',0),('pl1','p1',1),('pl1','p2',2)").run();
+
+  const uit = AX.buildArchive('me');
+  assert.equal(uit.counts.playlists, 1);
+
+  leeg();
+
+  const rapport = AI.importArchive(uit.files, { slug: 'me', origin: 'https://nieuw.test' });
+  assert.equal(rapport.playlists, 1);
+  const pl = db.prepare("SELECT * FROM playlists WHERE id = 'pl1'").get();
+  assert.equal(pl.title, 'Mijn plaat');
+  assert.equal(pl.kind, 'album');
+  const volgorde = db.prepare("SELECT track_id FROM playlist_tracks WHERE playlist_id = 'pl1' ORDER BY position").all().map((r) => r.track_id);
+  assert.deepEqual(volgorde, ['p3', 'p1', 'p2'], 'de volgorde IS de playlist');
+});
+
+test('een playlist verwijst nooit naar een nummer dat niet aankwam', () => {
+  // Anders staat er een plaat met gaten erin die je niet kunt afspelen, en dat
+  // is weer dezelfde soort halve waarheid.
+  leeg();
+
+  track('heel', 'Heel');
+  track('stuk', 'Stuk', { padInDb: '/weg/stuk.mp3', schrijf: false });
+  db.prepare("INSERT INTO playlists (id, site_id, title) VALUES ('pl2','s1','Half')").run();
+  db.prepare("INSERT INTO playlist_tracks (playlist_id, track_id, position) VALUES ('pl2','heel',0),('pl2','stuk',1)").run();
+
+  const uit = AX.buildArchive('me');
+  leeg();
+
+  const rapport = AI.importArchive(uit.files, { slug: 'me', origin: 'https://nieuw.test' });
+  const items = db.prepare("SELECT track_id FROM playlist_tracks WHERE playlist_id = 'pl2'").all().map((r) => r.track_id);
+  assert.deepEqual(items, ['heel']);
+  assert.ok(rapport.waarschuwingen.some((w) => /Half/.test(w)), 'en het wordt gemeld');
+});
+
+test('een droogloop telt de nummers maar schrijft niets', () => {
+  leeg();
+  track('d1', 'Droog');
+  const uit = AX.buildArchive('me');
+
+  leeg();
+
+  const droog = AI.importArchive(uit.files, { slug: 'me', origin: 'https://nieuw.test', dryRun: true });
+  assert.equal(droog.tracks, 1, 'het verslag hoort te zeggen hoeveel nummers er zouden komen');
+  assert.equal(db.prepare('SELECT COUNT(*) n FROM audio_tracks').get().n, 0, 'maar er staat niets');
+  assert.equal(fs.readdirSync(AUDIO).length, 0, 'en er is geen bestand geschreven');
+});
+
+test.after(() => { try { fs.rmSync(TMP, { recursive: true, force: true }); } catch { /* niets */ } });
Index: test/archive-export.test.js
===================================================================
--- test/archive-export.test.js	(revision fbfd7a199340cd773cd153df2388d88f2084eea2)
+++ test/archive-export.test.js	(revision 6c4ff7e385f99367e75efde44e5b671992c43e88)
@@ -134,6 +134,9 @@
 
 test('een gehoste track reist mee, met de gegevens die alleen in de database staan', () => {
-  // [[track:]] verwijst naar een audio_tracks-rij met een media-rij eronder. Op
-  // beta staan nul tracks, dus dit pad raakt daar geen echte data -- vandaar hier.
+  // Sinds v2 gaat audio NIET meer als media-bijlage mee. Dat kon ook nooit:
+  // gehoste audio staat buiten MEDIA_ROOT, de exporter rekende er met
+  // path.relative een /media/../audio/x.mp3 van, en de importer weigerde dat
+  // terecht. Resultaat op soundfabrics.nl: 13 tracks in de lijst, nul bestanden.
+  // Nu heeft het archief een eigen audio/-gebied.
   fs.mkdirSync(path.join(MEDIA, 'audio'), { recursive: true });
   const WAV = Buffer.from('RIFF-nep-audio');
@@ -147,14 +150,87 @@
   const uit = AX.buildArchive('me');
   const o = lees(uit, 'posts/metaudio.json');
-  const a = o.attachment[0];
-  assert.equal(a['shaer:availability'], 'included');
-  assert.equal(a.mediaType, 'audio/mpeg');
-  assert.deepEqual(uit.files.get(a.url), WAV);
+  const t = o['shaer:audio'][0];
   assert.match(o.content, /\[\[track:tr1\]\]/, 'de shorthand blijft in de bron staan');
-  const t = o['shaer:audio'][0];
   assert.equal(t.name, 'Kanonnen');
   assert.equal(t.artist, 'Robin');
   assert.equal(t.license, 'CC BY');
   assert.deepEqual(t.url, ['https://open.spotify.com/track/x']);
+
+  // Dit is de assertie die er echt toe doet: de BYTES zitten in het archief.
+  assert.ok(String(t['shaer:media']).startsWith('audio/'), 'de track wijst naar het audio-gebied');
+  assert.deepEqual(uit.files.get(t['shaer:media']), WAV, 'en daar staat het geluid ook echt');
+
+  // En hij staat in de bibliotheek, los van de post.
+  const lib = JSON.parse(uit.files.get('tracks.json').toString('utf8'));
+  const rij = lib.orderedItems.find((x) => x.id === 'tr1');
+  assert.equal(rij['shaer:availability'], 'included');
+  assert.equal(rij['shaer:file'], t['shaer:media']);
+  assert.equal(uit.counts.tracks, 1);
+});
+
+test('de HELE bibliotheek gaat mee, ook wat in geen enkel bericht staat', () => {
+  // De reden dat dit bestaat: op sound-fabrics.com stonden 140 tracks en gingen
+  // er 14 mee, want alleen wat met [[track:]] in een bericht stond werd
+  // geexporteerd. Een verhuizing die je bibliotheek achterlaat is er geen.
+  fs.mkdirSync(path.join(MEDIA, 'audio'), { recursive: true });
+  const B = Buffer.from('RIFF-los-nummer');
+  fs.writeFileSync(path.join(MEDIA, 'audio', 'los.mp3'), B);
+  db.prepare('INSERT INTO media (id, site_id, filename, mime_type, size, storage_path) VALUES (?,?,?,?,?,?)')
+    .run('m9', 's1', 'los.mp3', 'audio/mpeg', B.length, path.join(MEDIA, 'audio', 'los.mp3'));
+  db.prepare("INSERT INTO audio_tracks (id, site_id, title, media_id) VALUES ('los','s1','Los nummer','m9')").run();
+
+  const uit = AX.buildArchive('me');
+  const lib = JSON.parse(uit.files.get('tracks.json').toString('utf8'));
+  const rij = lib.orderedItems.find((x) => x.id === 'los');
+  assert.ok(rij, 'een track zonder bericht hoort er gewoon in');
+  assert.deepEqual(uit.files.get(rij['shaer:file']), B);
+});
+
+test('een track waarvan het bestand zoek is wordt gemeld, niet stil weggelaten', () => {
+  db.prepare("INSERT INTO media (id, site_id, filename, mime_type, size, storage_path) VALUES ('mz','s1','zoek.mp3','audio/mpeg',1,'/bestaat/niet/zoek.mp3')").run();
+  db.prepare("INSERT INTO audio_tracks (id, site_id, title, media_id) VALUES ('zoek','s1','Zoek','mz')").run();
+  const uit = AX.buildArchive('me');
+  const rij = JSON.parse(uit.files.get('tracks.json').toString('utf8')).orderedItems.find((x) => x.id === 'zoek');
+  assert.equal(rij['shaer:availability'], 'missing');
+  assert.equal(rij['shaer:file'], undefined, 'geen verwijzing naar een bestand dat er niet is');
+  assert.ok(uit.counts.audioMissing >= 1);
+  assert.ok(uit.missing.some((m) => m.track === 'Zoek'), 'en de beller kan het aan de gebruiker melden');
+});
+
+test('audio wordt gezocht zoals de SPELER hem zoekt, niet zoals de database hem onthoudt', async () => {
+  // De stille moordenaar op sound-fabrics.com: na een dataverhuizing wees
+  // storage_path voor 124 van de 139 tracks nog naar /srv/prutfolio/storage/audio.
+  // De speler merkte er niets van, want die pakt AUDIO_ROOT + bestandsnaam en
+  // negeert storage_path. De exporter las wel storage_path, vond niets, en liet
+  // 124 nummers weg zonder dat iemand het zag.
+  //
+  // Deze test pint de VOLGORDE vast met een nep-fs, want dat is precies waar de
+  // twee uit elkaar liepen. AUDIO_ROOT ligt bij import van paths.js al vast, dus
+  // hem hier omzetten kan niet meer; de volgorde toetsen wel.
+  const { resolveAudioPath, AUDIO_ROOT } = await import('../src/config/paths.js');
+  const gevraagd = [];
+  const nepFs = {
+    statSync(p) {
+      gevraagd.push(p);
+      if (p === path.join(AUDIO_ROOT, 'x.mp3')) return { isFile: () => true };
+      throw new Error('ENOENT');
+    },
+  };
+  const uit = resolveAudioPath('/een/heel/oud/pad/x.mp3', nepFs);
+  assert.equal(uit, path.join(AUDIO_ROOT, 'x.mp3'), 'de speler-plek wint');
+  assert.equal(gevraagd[0], path.join(AUDIO_ROOT, 'x.mp3'), 'en wordt als EERSTE geprobeerd');
+
+  // Staat hij daar niet, dan telt het opgeslagen pad alsnog: installaties die
+  // hun audio ergens anders hebben mogen niet stuk.
+  const gevraagd2 = [];
+  const nepFs2 = {
+    statSync(p) {
+      gevraagd2.push(p);
+      if (p === path.resolve('/ergens/anders/y.mp3')) return { isFile: () => true };
+      throw new Error('ENOENT');
+    },
+  };
+  assert.equal(resolveAudioPath('/ergens/anders/y.mp3', nepFs2), path.resolve('/ergens/anders/y.mp3'));
+  assert.equal(resolveAudioPath('', nepFs2), null);
 });
 
@@ -227,5 +303,5 @@
   const m = AX.buildArchive('me').manifest;
   assert.equal(m.origin, 'https://klonkt.test');
-  assert.equal(m.formatVersion, 1);
+  assert.equal(m.formatVersion, 2, 'v2 = audio zit er echt in');
   assert.equal(m.actor, 'https://klonkt.test/ap/users/me');
 });
Index: test/fep1580-migration.test.js
===================================================================
--- test/fep1580-migration.test.js	(revision fbfd7a199340cd773cd153df2388d88f2084eea2)
+++ test/fep1580-migration.test.js	(revision 6c4ff7e385f99367e75efde44e5b671992c43e88)
@@ -13,4 +13,5 @@
 import { test, beforeEach } from 'node:test';
 import assert from 'node:assert/strict';
+import path from 'node:path';
 
 process.env.DATABASE_PATH = ':memory:';
@@ -47,5 +48,5 @@
 
 beforeEach(() => {
-  for (const t of ['ap_migration', 'ap_moves', 'ap_blocks', 'posts', 'ap_followers']) {
+  for (const t of ['ap_migration', 'ap_moves', 'ap_blocks', 'posts', 'ap_followers', 'audio_tracks', 'media']) {
     try { db.prepare(`DELETE FROM ${t}`).run(); } catch { /* tabel bestaat niet in deze build */ }
   }
@@ -315,4 +316,86 @@
 });
 
+test('de muziekbibliotheek komt mee, ook wat niet fedi_open is', async () => {
+  // Losse nummers staan NIET in de outbox: die hangen aan de tracks-collectie
+  // waar de actor via AS2 `streams` naar wijst. Zonder deze tak verhuist een
+  // muzieksite zijn berichten en laat hij zijn bibliotheek achter, en dat is
+  // precies wat er op soundfabrics.nl gebeurde.
+  const s = site({ aliases: [BRON] });
+  const AUDIO = `${BRON}/audio/x.mp3`;
+  const bytes = Buffer.from('ID3-nep-geluid');
+  const kaart = new Map([
+    [BRON, {
+      id: BRON, type: 'Person', movedTo: IK, outbox: `${BRON}/outbox`,
+      streams: [`${BRON}/tracks`, `${BRON}/playlists`],
+    }],
+    [`${BRON}/outbox`, { type: 'OrderedCollection', orderedItems: [] }],
+    [`${BRON}/tracks`, {
+      type: 'OrderedCollection',
+      orderedItems: [{
+        id: `${BRON}/tracks/t1`, type: 'Audio', name: 'Gesloten nummer', artist: 'Robo',
+        url: [{ type: 'Link', href: AUDIO, mediaType: 'audio/mpeg' }],
+      }],
+    }],
+  ]);
+  const geschreven = new Map();
+  let getekend = false;
+  const r = await stil(() => Mig.ingestFromSource(s, {
+    deps: {
+      getJson: async (_slug, url) => kaart.get(url) || null,
+      noteId: (b, id) => `${b}/ap/notes/${id}`,
+      noteVisibility: AP.noteVisibility,
+      audioRoot: '/nep/audio',
+      // De handtekening is hier geen detail: de audio-route van de bron weigert
+      // een kale fetch, want die kan niet zien dat wij de doel-actor zijn.
+      signHeaders: () => { getekend = true; return { Signature: 'nep' }; },
+      safeFetch: async (url, opts) => {
+        assert.equal(url, AUDIO);
+        assert.ok(opts.headers && opts.headers.Signature, 'de bytes worden ONDERTEKEND opgehaald');
+        return { ok: true, arrayBuffer: async () => bytes, headers: { get: () => 'audio/mpeg' } };
+      },
+      fs: { mkdirSync() {}, writeFileSync: (p, b) => geschreven.set(p, b) },
+      path,
+    },
+  }));
+  assert.equal(r.tracksBinnen, 1);
+  assert.equal(r.tracksMislukt, 0);
+  assert.ok(getekend);
+  assert.equal(geschreven.size, 1, 'het bestand wordt echt weggeschreven');
+  const [pad] = [...geschreven.keys()];
+  assert.ok(pad.startsWith('/nep/audio/'), 'audio hoort in AUDIO_ROOT, niet in de mediamap');
+  assert.ok(!pad.slice('/nep/audio/'.length).includes('/'), 'en er direct in, want de speler zoekt op bestandsnaam');
+  const t = db.prepare('SELECT title, artist FROM audio_tracks').get();
+  assert.equal(t.title, 'Gesloten nummer');
+});
+
+test('een nummer waarvan de bytes niet komen levert GEEN track op', async () => {
+  // Dezelfde regel als bij de zip. Een nummer dat in de lijst staat en 404't is
+  // erger dan een nummer dat ontbreekt.
+  const s = site({ aliases: [BRON] });
+  const kaart = new Map([
+    [BRON, { id: BRON, type: 'Person', movedTo: IK, outbox: `${BRON}/outbox`, streams: [`${BRON}/tracks`] }],
+    [`${BRON}/outbox`, { type: 'OrderedCollection', orderedItems: [] }],
+    [`${BRON}/tracks`, {
+      type: 'OrderedCollection',
+      orderedItems: [{ id: `${BRON}/tracks/t1`, type: 'Audio', name: 'Weg', url: `${BRON}/audio/weg.mp3` }],
+    }],
+  ]);
+  const r = await stil(() => Mig.ingestFromSource(s, {
+    deps: {
+      getJson: async (_slug, url) => kaart.get(url) || null,
+      noteId: (b, id) => `${b}/ap/notes/${id}`,
+      noteVisibility: AP.noteVisibility,
+      audioRoot: '/nep/audio',
+      signHeaders: () => ({ Signature: 'nep' }),
+      safeFetch: async () => ({ ok: false, status: 403 }),
+      fs: { mkdirSync() {}, writeFileSync() { throw new Error('mag niet gebeuren'); } },
+      path,
+    },
+  }));
+  assert.equal(r.tracksBinnen, 0);
+  assert.equal(r.tracksMislukt, 1);
+  assert.equal(db.prepare('SELECT COUNT(*) n FROM audio_tracks').get().n, 0);
+});
+
 test('een niet-publiek bericht komt wel mee maar niet in de publieke tabel', async () => {
   const s = site({ aliases: [BRON] });
