Incognito-Wiki/scripts/compare-previous-wiki.mjs
msa46 c590f77d96
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
feat: publish legacy course archive
2026-08-03 15:12:11 +02:00

78 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
import { readFile, writeFile } from 'node:fs/promises';
import { classifyPreviousPage, destinationForPageId } from './lib/previous-wiki.mjs';
const live = JSON.parse(await readFile('to-be-studied/previous-wiki/2026-08-03/manifest.json', 'utf8'));
const migration = JSON.parse(await readFile('docs/migration-manifest.json', 'utf8'));
const supplemental = JSON.parse(await readFile('docs/supplemental-content.json', 'utf8'));
const publishedLiveCourses = new Map(supplemental
.filter(({ category }) => category === 'live-course-recovery')
.map((entry) => [entry.source, entry.destination]));
const represented = new Map(migration.entries.map((entry) => [
entry.source.replace(/^pages\//, '').replace(/\.txt$/, '').replaceAll('/', ':'),
entry.destination,
]));
const records = [];
for (const page of live.pages) {
const source = await readFile(`to-be-studied/previous-wiki/2026-08-03/${page.localPath}`, 'utf8');
let status = classifyPreviousPage(page.id, new Set(represented.keys()), source);
const plannedDestination = status === 'migrate' ? destinationForPageId(page.id) : '';
if (status === 'migrate' && publishedLiveCourses.get(page.url) === plannedDestination) status = 'migrated';
const destination = status === 'represented'
? represented.get(page.id)
: status === 'migrate' || status === 'migrated'
? plannedDestination
: '';
const reason = {
represented: 'Already represented by the selected export migration.',
migrate: 'Substantive public course page missing from the selected export.',
migrated: 'Substantive public course page migrated from the live DokuWiki.',
empty: 'Explicit placeholder page with no course details.',
excluded: 'Outside the Bachelor, Master AI, and Master DSDM course-detail scope.',
}[status];
records.push({ id: page.id, url: page.url, status, destination, reason, localPath: page.localPath });
}
for (const failure of live.failures) {
records.push({ id: failure.id, url: failure.url, status: 'failed', destination: '', reason: failure.error, localPath: '' });
}
records.sort((a, b) => a.id.localeCompare(b.id));
const header = ['page_id', 'source_url', 'status', 'destination', 'captured_source', 'reason'];
const tsv = [header, ...records.map((record) => [
record.id,
record.url,
record.status,
record.destination,
record.localPath ? `to-be-studied/previous-wiki/2026-08-03/${record.localPath}` : '',
record.reason,
])].map((row) => row.join('\t')).join('\n');
await writeFile('docs/live-course-recovery.tsv', `${tsv}\n`);
const counts = new Map();
for (const record of records) counts.set(record.status, (counts.get(record.status) ?? 0) + 1);
const report = `# Previous live-wiki course recovery
Audit date: 2026-08-03
The previous DokuWiki was crawled recursively through its public sitemap at the pinned Vimmex origin. The crawl was read-only and completed without authentication.
| Outcome | Pages |
| --- | ---: |
| Already represented in the selected export migration | ${counts.get('represented') ?? 0} |
| Course pages migrated | ${counts.get('migrated') ?? 0} |
| Course pages still pending | ${counts.get('migrate') ?? 0} |
| Empty course placeholders | ${counts.get('empty') ?? 0} |
| Outside the course-detail scope | ${counts.get('excluded') ?? 0} |
| Capture failures | ${counts.get('failed') ?? 0} |
| **Total public pages audited** | **${records.length}** |
The selected filesystem export was internally complete for its declared 29-source scope, but it was not a complete export of the public DokuWiki. The recursive live sitemap exposed ${records.length} pages. After excluding ${counts.get('empty') ?? 0} explicit placeholders and non-course material, ${counts.get('migrated') ?? 0} substantive course pages were migrated and ${counts.get('migrate') ?? 0} remain pending.
The machine-readable classification and source-to-destination mappings are in \`docs/live-course-recovery.tsv\`. Captured raw sources and the crawl manifest are under \`to-be-studied/previous-wiki/2026-08-03/\`.
`;
await writeFile('docs/live-course-recovery.md', report);
console.log(`Classified ${records.length} pages: ${counts.get('migrated') ?? 0} migrated, ${counts.get('migrate') ?? 0} pending, ${counts.get('represented') ?? 0} represented, ${counts.get('empty') ?? 0} empty, ${counts.get('excluded') ?? 0} excluded, ${counts.get('failed') ?? 0} failed.`);