533db535f1
build / build (push) Successful in 1m12s
按已确认需求提供独立安全模型配置、真实探测、正式字典字段评估与原问题译中,持久批次支持只补空白、暂停恢复、有限重试、幂等和逐字段依据。覆盖固定规则、本地语言、组织关联与主表有效看板共用治理侧读模型,保留源生产和冻结历史。 验证:完整 make verify 退出0,702项Go与329项前端通过;默认118项外部/隔离集成明确跳过,另跑完整镜像及组织隔离PG竞态。12并发、输入漂移、过期租约、暂停/恢复及有限重试通过。用户授权的百炼 deepseek-v4.1-flash 完成真实后台与浏览器评估/翻译;552行、16列、11块看板及完整PNG、独立配置页测试/保存、重开恢复和零JS异常通过。仅非业务样本外发,自动处理关闭,原payload不变。 上线前治理库已做导出快照原生备份并真实恢复,60表行数与17个QA表内容哈希一致;不修改DobotAI生产或隧道。本提交时尚未部署,线上验收须独立完成。
66 lines
2.9 KiB
TypeScript
66 lines
2.9 KiB
TypeScript
import { afterEach, expect, it, vi } from 'vitest'
|
|
import { fetchQARecords, parseQARecord, qaCellValue } from './qaOps'
|
|
import { fixtureRecord } from './qaOps.test'
|
|
import { qualityFixture, fields } from './qaQuality.fixture'
|
|
afterEach(() => vi.unstubAllGlobals())
|
|
it('keeps imported historical labels and genuine missing values instead of replacing them with new rule labels', () => {
|
|
const raw = {
|
|
...fixtureRecord,
|
|
record_origin: 'historical_excel',
|
|
master_fields: {
|
|
question_chinese: '',
|
|
coverage: '是',
|
|
is_correct: '待确认',
|
|
product_category: '原分类',
|
|
problem_type: '',
|
|
root_cause: '',
|
|
language: 'en',
|
|
},
|
|
}
|
|
const item = parseQARecord(raw)
|
|
expect(qaCellValue(item, 'coverage')).toBe('是')
|
|
expect(qaCellValue(item, 'is_correct')).toBe('待确认')
|
|
expect(qaCellValue(item, 'question_chinese')).toBeNull()
|
|
expect(qaCellValue(item, 'product_category')).toBe('原分类')
|
|
for (const bad of [null, [], { coverage: 123 }, { unapproved: 'x' }])
|
|
expect(() => parseQARecord({ ...raw, master_fields: bad })).toThrow('响应无效')
|
|
})
|
|
it('accepts explicitly versioned master effective fields without inventing a human review or weakening legacy checks', () => {
|
|
const quality = {
|
|
...qualityFixture,
|
|
state: 'unreviewed',
|
|
revision: 0,
|
|
latest_review: null,
|
|
effective: fields,
|
|
effective_source: 'master-effective-fields-v1',
|
|
}
|
|
const row = {
|
|
...fixtureRecord,
|
|
record_origin: 'historical_excel',
|
|
master_fields: { coverage: '是', is_correct: '是', product_category: 'MG400' },
|
|
quality,
|
|
}
|
|
expect(parseQARecord(row).quality?.effective.product_category).toBe('MG400')
|
|
expect(parseQARecord(row).quality?.state).toBe('unreviewed')
|
|
expect(() => parseQARecord({ ...row, record_origin: undefined })).toThrow()
|
|
expect(() => parseQARecord({ ...row, quality: { ...quality, effective_source: undefined } })).toThrow()
|
|
const tampered = {
|
|
...qualityFixture,
|
|
effective_source: 'master-effective-fields-v1',
|
|
effective: { ...fields, correctness: 'incorrect' },
|
|
}
|
|
expect(() => parseQARecord({ ...row, quality: tampered })).toThrow()
|
|
})
|
|
it('selects the durable master explicitly and leaves original 2.0 callers on their existing dataset', async () => {
|
|
const page = { items: [], columns: [], total: 0, has_more: false, next_cursor: '', as_of: '2026-10-19T00:00:00Z' }
|
|
const mocked = vi
|
|
.fn()
|
|
.mockImplementation(() => Promise.resolve(new Response(JSON.stringify({ data: page }), { status: 200 })))
|
|
vi.stubGlobal('fetch', mocked)
|
|
const query = { start: '2026-10-05T00:00:00Z', end: '2026-10-12T00:00:00Z', keyword: '', cursor: '' }
|
|
await fetchQARecords({ ...query, dataset: 'master' } as Parameters<typeof fetchQARecords>[0])
|
|
await fetchQARecords(query)
|
|
expect(String(mocked.mock.calls[0][0])).toContain('/api/v1/qa-ops/master/records?')
|
|
expect(String(mocked.mock.calls[1][0])).toContain('/api/v1/qa-ops/records?')
|
|
})
|