import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { resolve } from 'node:path'; import test from 'node:test'; async function source(relativePath: string): Promise { return readFile(resolve(process.cwd(), 'src', relativePath), 'utf8'); } function policyCalls(value: string): number { return value.match(/assertMobileInspector\(principal\);/g)?.length ?? 0; } test('D5.1 applies the mobile-inspector policy to every field operation', async () => { const [visits, acts, findings, evidence, closing] = await Promise.all([ source('inspection-visits/inspection-visits.service.ts'), source('inspection-acts/inspection-acts.service.ts'), source('inspection-findings/inspection-findings.service.ts'), source('inspection-findings/inspection-evidence.service.ts'), source('inspection-closing/inspection-closing.service.ts'), ]); assert.equal(policyCalls(visits), 2); assert.equal(policyCalls(acts), 3); assert.equal(policyCalls(findings), 2); assert.equal(policyCalls(evidence), 1); assert.equal(policyCalls(closing), 7); assert.match(evidence, /purpose === InspectionEvidencePurpose\.OBSERVATION/); }); test('D5.1 leaves company follow-up outside the field-operation gate', async () => { const findings = await source('inspection-findings/inspection-findings.service.ts'); const followUp = findings.slice(findings.indexOf('async updateFollowUp(')); assert.doesNotMatch(followUp, /assertMobileInspector/); }); test('D5.1 migration grants operational permissions only to inspector', async () => { const migration = await source( 'database/migrations/1787331600000-phase-d5-1-mobile-inspection-policy.ts', ); assert.match(migration, /role\.code <> 'inspector'/); assert.match(migration, /role\.code = 'inspector'/); assert.doesNotMatch(migration, /inspection_findings\.follow_up/); });