import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { fileURLToPath } from 'node:url' import { createRiskDispositionRequestId, normalizeRiskDisposition, normalizeRiskObservation } from '../src/services/riskObservations.js' const evidenceCard = readFileSync( fileURLToPath(new URL('../src/components/travel/RiskObservationEvidenceCard.vue', import.meta.url)), 'utf8' ) test('risk observation normalizes persisted json evidence and typed disposition', () => { const observation = normalizeRiskObservation({ id: 'risk-1', contribution_scores_json: { S_rule: 90 }, evidence_json: [{ title: '重复票据' }], graph_node_keys_json: ['claim:1'], similar_case_claim_ids_json: ['redacted-for-reviewer-only'], decision_trace_json: { action: 'manual_review' }, disposition: { id: 'disposition-1', observation_id: 'risk-1', adjudication: 'confirmed', lifecycle_status: 'remediation_in_progress', version: 2, events: [{ id: 'event-1', action: 'confirm', version: 1 }] } }) assert.equal(observation.contributionScores.S_rule, 90) assert.equal(observation.evidence[0].title, '重复票据') assert.deepEqual(observation.graphNodeKeys, ['claim:1']) assert.equal(observation.decisionTrace.action, 'manual_review') assert.equal(observation.disposition.lifecycleStatus, 'remediation_in_progress') assert.equal(observation.disposition.events[0].action, 'confirm') }) test('risk disposition normalizer rejects absent projection and keeps version', () => { assert.equal(normalizeRiskDisposition(null), null) assert.equal(normalizeRiskDisposition({}), null) assert.equal(normalizeRiskDisposition({ id: 'd1', version: 4 }).version, 4) }) test('risk evidence card exposes typed actions and never offers direct approval', () => { assert.match(evidenceCard, /executeRiskDispositionAction/) assert.match(evidenceCard, /确认风险/) assert.match(evidenceCard, /标记误报/) assert.match(evidenceCard, /请求补材料/) assert.match(evidenceCard, /启动整改/) assert.match(evidenceCard, /申请豁免/) assert.match(evidenceCard, /确认已解决/) assert.match(evidenceCard, /expectedVersion: currentDisposition\.value\.version/) assert.doesNotMatch(evidenceCard, /自动审批|直接通过|batchApprove/) assert.match(evidenceCard, /RISK_DISPOSITION_VERSION_CONFLICT/) assert.match(evidenceCard, /lifecycle !== 'supplement_requested'/) }) test('risk action request ids bind action and observation', () => { const requestId = createRiskDispositionRequestId('confirm', 'risk-1') assert.match(requestId, /^risk:confirm:risk-1:/) })