First public release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 14:56:00 -04:00
co-authored by Claude Opus 5.5
commit 2a979970ab
18 changed files with 2455 additions and 0 deletions
+191
View File
@@ -0,0 +1,191 @@
import { describe, expect, it } from 'vitest'
import { computeCoverage, detectGaps, qualityScore, toReport, formatTrace } from '../src/index.js'
import { overall, validateReport } from '@extant2000/evidence-record'
import type { TraceInput } from '../src/index.js'
const req = (id: string, parent?: string | null) => ({
id, parent_id: parent ?? null, req_number: `R-${id}`, title: `Requirement ${id}`,
})
describe('computeCoverage', () => {
it('returns an all-zero shape for no requirements', () => {
const c = computeCoverage({ requirements: [] })
expect(c.total_requirements).toBe(0)
expect(c.pct_verified).toBe(0)
})
it('counts a requirement traced by junction OR by verification FK, without double counting', () => {
const input: TraceInput = {
requirements: [req('a'), req('b')],
requirementVerifications: [{ requirement_id: 'a' }],
verificationItems: [{ id: 'v1', requirement_id: 'a', status: 'Passed' }],
}
// 'a' is linked by both routes but must count once.
expect(computeCoverage(input).traced_to_test).toBe(1)
})
it('treats a requirement with zero verifications as NOT verified', () => {
// Guards the vacuous-every() trap: [].every(...) is true, which would
// report a requirement with no evidence at all as fully verified.
const input: TraceInput = { requirements: [req('a')], verificationItems: [] }
expect(computeCoverage(input).verified).toBe(0)
})
it('requires EVERY linked verification to pass or be waived', () => {
const mixed: TraceInput = {
requirements: [req('a')],
verificationItems: [
{ id: 'v1', requirement_id: 'a', status: 'Passed' },
{ id: 'v2', requirement_id: 'a', status: 'Failed' },
],
}
expect(computeCoverage(mixed).verified).toBe(0)
const allGood: TraceInput = {
requirements: [req('a')],
verificationItems: [
{ id: 'v1', requirement_id: 'a', status: 'Passed' },
{ id: 'v2', requirement_id: 'a', status: 'Waived' },
],
}
expect(computeCoverage(allGood).verified).toBe(1)
})
it('computes percentages against the requirement total', () => {
const input: TraceInput = {
requirements: [req('a', 'root'), req('b'), req('c'), req('d')],
}
expect(computeCoverage(input).pct_parent).toBe(25)
})
})
describe('detectGaps', () => {
it('reports nothing for an empty requirement set', () => {
expect(detectGaps({ requirements: [] })).toEqual({ gaps: [], total: 0 })
})
it('flags an untested, unrisked, parentless requirement three ways', () => {
const { gaps } = detectGaps({ requirements: [req('a')] })
expect(gaps.map(g => g.gap_type).sort()).toEqual(['no_risk', 'no_test', 'orphaned'])
})
it('rates a failed verification critical and everything else lower', () => {
const { gaps } = detectGaps({
requirements: [req('a', 'root')],
requirementVerifications: [{ requirement_id: 'a' }],
requirementRisks: [{ requirement_id: 'a' }],
verificationItems: [{ id: 'v1', requirement_id: 'a', status: 'Failed', method: 'Test' }],
})
expect(gaps).toHaveLength(1)
expect(gaps[0]!.gap_type).toBe('failed_verification')
expect(gaps[0]!.severity).toBe('critical')
})
it('flags suspect links', () => {
const { gaps } = detectGaps({
requirements: [req('a', 'root')],
requirementVerifications: [{ requirement_id: 'a' }],
requirementRisks: [{ requirement_id: 'a' }],
suspectLinks: [{ requirement_id: 'a' }],
})
expect(gaps.map(g => g.gap_type)).toEqual(['suspect'])
})
it('falls back to a short id when req_number is absent', () => {
const { gaps } = detectGaps({ requirements: [{ id: 'abcdef1234567890' }] })
expect(gaps[0]!.display_id).toBe('abcdef12')
})
})
describe('qualityScore', () => {
it('applies the documented 0.3/0.3/0.2/0.2 weighting', () => {
const s = qualityScore({ pct_test: 100, pct_verified: 100, pct_risk: 0, pct_parent: 0 })
expect(s.score).toBe(60)
expect(s.grade).toBe('C')
})
it('grades the boundaries inclusively', () => {
const at = (n: number) => qualityScore({
pct_test: n, pct_verified: n, pct_risk: n, pct_parent: n,
}).grade
expect(at(90)).toBe('A')
expect(at(75)).toBe('B')
expect(at(60)).toBe('C')
expect(at(40)).toBe('D')
expect(at(39)).toBe('F')
})
it('accepts custom weights for a different accreditation regime', () => {
const s = qualityScore(
{ pct_test: 0, pct_verified: 100, pct_risk: 0, pct_parent: 0 },
{ traced: 0, verified: 1, risk: 0, parent: 0 },
)
expect(s.score).toBe(100)
expect(s.grade).toBe('A')
})
it('round-trips from computeCoverage output', () => {
const coverage = computeCoverage({
requirements: [req('a', 'root')],
requirementVerifications: [{ requirement_id: 'a' }],
requirementRisks: [{ requirement_id: 'a' }],
verificationItems: [{ id: 'v1', requirement_id: 'a', status: 'Passed' }],
})
expect(qualityScore(coverage).score).toBe(100)
})
})
describe('report — the score has to lead back to the rows', () => {
const input = {
requirements: [
{ id: 'r1-uuid-aaaa', req_number: 'SYS-001', title: 'Deorbit within 25 years', parent_id: 'p1' },
{ id: 'r2-uuid-bbbb', req_number: 'SYS-002', title: 'Survive launch loads' },
],
verificationItems: [
{ id: 'v1-uuid-cccc', requirement_id: 'r1-uuid-aaaa', status: 'Failed', method: 'Test' },
],
}
it('cites the requirement row behind every gap', () => {
// The gap this closes: "quality 50/100, grade D" with no route back to
// the requirements that produced it.
const text = formatTrace(input, { requirementTable: 'mission_requirements', evidence: 'full' })
expect(text).toContain('mission_requirements#r2-uuid-bbbb')
expect(text).toContain('SYS-002')
})
it('cites the verification row behind a failed verification', () => {
const text = formatTrace(input, { verificationTable: 'mission_verification_items', evidence: 'full' })
expect(text).toContain('mission_verification_items#v1-uuid-cccc')
})
it('breaks the composite score into checkable measurements', () => {
const r = toReport(input)
const traced = r.findings.find(f => f.id === 'score.traced')!
expect(traced.evidence[0]!.source).toMatchObject({ kind: 'measurement', samples: 2 })
expect(formatTrace(input)).toContain('composite quality')
})
it('treats an empty requirement set as not-assessed, not as a score of zero', () => {
// computeCoverage correctly returns zeros, but 0% next to grade F reads
// as "traced nothing" when the truth is "loaded nothing".
const r = toReport({ requirements: [] })
expect(overall(r)).toBe('not-assessed')
const text = formatTrace({ requirements: [] })
expect(text).toContain('NOT ASSESSED')
expect(text).toContain('nothing was traced because nothing was read')
expect(text).not.toContain('grade F')
})
it('separates absent evidence from evidence of failure', () => {
const r = toReport(input)
const failed = r.findings.find(f => f.summary.includes('Failed'))!
expect(failed.determination).toBe('fail')
const noTest = r.findings.find(f => f.summary.includes('No verification item'))!
expect(noTest.determination).toBe('not-assessed')
})
it('every conclusion carries a citation', () => {
expect(validateReport(toReport(input))).toEqual([])
})
})