import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import test from 'node:test'; const root = process.cwd(); const read = (relative: string) => fs.readFileSync(path.join(root, relative), 'utf8'); const closing = read('src/inspection-closing/inspection-closing.service.ts'); const lifecycle = read('src/inspection-visits/inspection-visit-lifecycle.service.ts'); const acts = read('src/inspection-acts/inspection-acts.service.ts'); const findings = read('src/inspection-findings/inspection-findings.service.ts'); const actEntity = read('src/database/entities/inspection-act.entity.ts'); test('F4 keeps finalized acts irreversible', () => { const reopenBody = closing.slice(closing.indexOf(' async reopen('), closing.indexOf(' async signInspector(')); assert.match(reopenBody, /INSPECTION_ACT_LOCK_IS_IMMUTABLE/); assert.match(reopenBody, /throw new ConflictException/); assert.doesNotMatch(reopenBody, /UPDATE inspection_acts/); assert.doesNotMatch(reopenBody, /InspectionActStatus\.DRAFT/); }); test('F4 permits multiple acts per inspection but only one simultaneous draft', () => { assert.match(actEntity, /uq_inspection_acts_one_draft_per_visit/); assert.match(actEntity, /where: "status = 'DRAFT'"/); assert.doesNotMatch(actEntity, /uq_inspection_acts_visit['"]/); }); test('F4 act locking is independent from inspection-wide verification completion', () => { const prepareBody = closing.slice(closing.indexOf(' async prepare('), closing.indexOf(' async reopen(')); assert.doesNotMatch(prepareBody, /inspection_finding_verification_visits/); assert.doesNotMatch(prepareBody, /INSPECTION_VERIFICATION_RESULTS_REQUIRED/); assert.match(prepareBody, /status='LOCKED'/); }); test('F4 blocks act header and inventory mutations once the act leaves draft', () => { const updateBody = acts.slice(acts.indexOf(' async update('), acts.indexOf(' async cancel(')); const cancelBody = acts.slice(acts.indexOf(' async cancel('), acts.indexOf(' async getById(')); assert.match(updateBody, /this\.assertActDraft\(act\)/); assert.match(cancelBody, /this\.assertActDraft\(act\)/); }); test('F4 blocks finding creation and editing once the act is locked', () => { const editableGuard = findings.slice( findings.indexOf(' private assertActEditable('), findings.indexOf(' private assertFindingOpen('), ); assert.match(editableGuard, /act\.status !== InspectionActStatus\.DRAFT/); assert.match(editableGuard, /visit\.status !== InspectionVisitStatus\.IN_PROGRESS/); assert.match(editableGuard, /INSPECTION_FINDING_ACT_NOT_EDITABLE/); const createBody = findings.slice(findings.indexOf(' async create('), findings.indexOf(' async update(')); const updateBody = findings.slice(findings.indexOf(' async update('), findings.indexOf(' async updateFollowUp(')); assert.match(createBody, /this\.assertActEditable\(act, visit\)/); assert.match(updateBody, /this\.assertActEditable\(act, visit\)/); }); test('F4 sealing requires inspector signature and exactly one resolved company manifestation', () => { const closeBody = closing.slice(closing.indexOf(' async close('), closing.indexOf(' async signatureContent(')); assert.match(closeBody, /INSPECTION_ACT_INSPECTOR_SIGNATURE_REQUIRED/); assert.match(closeBody, /companyOutcomes\.length !== 1/); assert.match(closeBody, /INSPECTION_ACT_COMPANY_OUTCOME_REQUIRED/); assert.match(closeBody, /InspectionActSignatureStatus\.ABSENT/); assert.match(closeBody, /INSPECTION_ACT_COMPANY_MANIFESTATION_PENDING/); assert.match(closeBody, /status='SEALED'/); }); test('F4 inspection close is the aggregate gate for every non-cancelled act and verification result', () => { const closeBody = lifecycle.slice(lifecycle.indexOf(' async close('), lifecycle.indexOf(' async cancel(')); assert.match(closeBody, /WHERE visit_id=\$1 AND status<>'CANCELLED'/); assert.match(closeBody, /acts\.length === 0/); assert.match(closeBody, /INSPECTION_REQUIRES_ACT/); assert.match(closeBody, /acts\.filter\(\(act\) => act\.status !== 'SEALED'\)/); assert.match(closeBody, /INSPECTION_ACTS_NOT_SEALED/); assert.match(closeBody, /pendingActs: pending\.map/); assert.match(closeBody, /assertVerificationResultsComplete\(manager, id\)/); assert.match(closeBody, /InspectionVisitStatus\.CLOSED/); }); test('F4 prevents cancelling an inspection that already has any sealed act', () => { const cancelBody = lifecycle.slice(lifecycle.indexOf(' async cancel('), lifecycle.indexOf(' private async lockVisit(')); assert.match(cancelBody, /WHERE visit_id=\$1 AND status='SEALED'/); assert.match(cancelBody, /INSPECTION_WITH_SEALED_ACT_CANNOT_CANCEL/); });