// Read-only source census. Route presence does not establish workflow or security acceptance. import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import assert from 'node:assert/strict'; import { execFileSync } from 'node:child_process'; import ts from 'typescript'; const root = path.resolve(import.meta.dirname, '../..'); const registerPath = 'docs/pre-phase10-ux/preservation.json'; const registerBytes = fs.readFileSync(path.join(root, registerPath)); const register = JSON.parse(registerBytes); const base = 'd3d338376444b8abdcaf7200f682faa3daf1ad10'; const digest = bytes => crypto.createHash('sha256').update(bytes.toString('utf8').replace(/\r\n/g, '\n')).digest('hex'); assert.equal(digest(registerBytes), digest(execFileSync('git', ['show', `${base}:${registerPath}`], { cwd: root })), 'Original preservation register must remain unchanged'); assert.equal(register.groups.length, 57); assert.equal(register.routes.length, 34); const source = fs.readFileSync(path.join(root, 'job-tracker-ui/src/App.tsx'), 'utf8'); const ast = ts.createSourceFile('App.tsx', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX); const declared = new Set(); function visit(node) { if (ts.isJsxAttribute(node) && node.name.getText(ast) === 'path' && node.initializer && ts.isStringLiteral(node.initializer)) declared.add(node.initializer.text); if (ts.isPropertyAssignment(node) && node.name.getText(ast) === 'path' && ts.isStringLiteral(node.initializer)) declared.add(node.initializer.text); ts.forEachChild(node, visit); } visit(ast); const missing = register.routes.filter(item => !declared.has(item.route)); assert.deepEqual(missing, [], 'All inherited route patterns must remain registered'); const result = { base, policy: 'Source membership and unchanged criteria only; no acceptance promotion.', sourceSha256: digest(source), registerSha256: digest(registerBytes), groups: register.groups.map(({ id, currentStatus, requiredClosure, sourceCriterion }) => ({ id, currentStatus, requiredClosure, sourceCriterion })), routes: register.routes.map(({ route, owners, requiredClosure }) => ({ route, owners, requiredClosure, sourceMembership: 'PRESENT' })), limits: ['57 historical group statuses and original criteria retained, not promoted.', 'Not browser/auth/provider/native/deployed or whole-capability acceptance. CalendarPage retains the original reminder route and owner internally.'], }; const out = path.join(root, 'docs/ui-modernisation/evidence/cross-app'); fs.mkdirSync(out, { recursive: true }); fs.writeFileSync(path.join(out, 'PRESERVATION_CENSUS.json'), JSON.stringify(result, null, 2)); console.log('PASS:57 unchanged preservation groups,34 inherited route patterns present in the TypeScript AST.');