828c2c5fa0
build / build (push) Successful in 1m6s
使用完整筛选范围的当前有效结论计算覆盖率和正确率,人工优先,失效与对应待确认/未评估/不计入排除;零分母返回null,界面展示原始分子分母和排除构成,前端拒绝不守恒或比例不一致的响应。 验证:make verify退出码0,Go658及前端257通过,91项声明可选集成跳过;隔离PG、三包竞态及合成/真实只读源浏览器验证通过。无新增迁移,不接AI模型,不改绩效,不写源库;本批未推送或部署,8088运行版保持0.1.21。
75 lines
3.1 KiB
TypeScript
75 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { parseQAQuality, parseQualitySummary, parseQualityHistory } from './qaQuality'
|
|
import { qualityFixture, summaryFixture, check, review } from './qaQuality.fixture'
|
|
import { parseQARecord, qaCellValue } from './qaOps'
|
|
describe('quality evidence contracts', () => {
|
|
it('renders effective manual labels in agreed columns without changing the rule result', () => {
|
|
const record = parseQARecord({
|
|
id: 'fixture',
|
|
status: 'succeeded',
|
|
question: '示例',
|
|
answer: '暂无已发布',
|
|
asked_at: '2026-10-17T12:00:00Z',
|
|
time_source: 'request_message.created_at',
|
|
asker: '',
|
|
trigger_person: '',
|
|
department: '',
|
|
region: '',
|
|
references: [],
|
|
media: [],
|
|
source_coverage: check.source,
|
|
feedback: { asker_value: '', up: 0, down: 0 },
|
|
coverage: check.result,
|
|
quality: qualityFixture,
|
|
})
|
|
expect(qaCellValue(record, 'coverage')).toBe('是')
|
|
expect(qaCellValue(record, 'is_correct')).toBe('是')
|
|
expect(qaCellValue(record, 'product_category')).toBe('MG400')
|
|
expect(record.coverage.verdict).toBe('uncovered')
|
|
})
|
|
|
|
it('separates immutable rule/source results and explicit human outcomes', () => {
|
|
const v = parseQAQuality(qualityFixture)
|
|
expect(v.effective.coverage).toBe('covered')
|
|
expect(v.automatic.result.verdict).toBe('uncovered')
|
|
})
|
|
it('rejects stale conclusions kept effective and forged revisions', () => {
|
|
expect(() =>
|
|
parseQAQuality({ ...qualityFixture, state: 'stale', input_epoch: 2, automatic: { ...check, input_epoch: 2 } })
|
|
).toThrow()
|
|
expect(() => parseQAQuality({ ...qualityFixture, revision: 2 })).toThrow()
|
|
})
|
|
it('keeps scope counts whole and conservative without made-up rates', () => {
|
|
expect(parseQualitySummary(summaryFixture).summary.total).toBe(3)
|
|
expect(() => parseQualitySummary({ ...summaryFixture, summary: { ...summaryFixture.summary, total: 4 } })).toThrow()
|
|
})
|
|
it('retains pageable human and automatic history independently', () => {
|
|
expect(
|
|
parseQualityHistory({ reviews: [review], checks: [check], next_review: 0, next_check: 0 }).reviews
|
|
).toHaveLength(1)
|
|
})
|
|
})
|
|
|
|
describe('confirmed quality rate contract', () => {
|
|
it('retains raw counts, null rates, scope breakdown and policy version', () => {
|
|
const result = parseQualitySummary(summaryFixture)
|
|
expect(result.summary.rates.coverage.numerator).toBe(1)
|
|
expect(result.summary.rates.coverage.denominator).toBe(2)
|
|
expect(result.summary.rates.correctness.percent).toBe(100)
|
|
})
|
|
it('rejects invalid or inconsistent numerator, denominator, percent and category sums', () => {
|
|
for (const change of [
|
|
(r: any) => (r.coverage.numerator = 3),
|
|
(r: any) => (r.coverage.denominator = 3),
|
|
(r: any) => (r.coverage.percent = 99),
|
|
(r: any) => (r.breakdown.stale = 0),
|
|
(r: any) => (r.correctness.percent = null),
|
|
(r: any) => (r.policy_version = 'unknown'),
|
|
]) {
|
|
const v = structuredClone(summaryFixture)
|
|
change(v.summary.rates)
|
|
expect(() => parseQualitySummary(v)).toThrow()
|
|
}
|
|
})
|
|
})
|