mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-15 12:53:31 +08:00
The desktop product needs a repeatable local gate that can prove the core Coding Agent loop still works after changes, not only that unit tests pass. This adds a quality-gate runner with PR, baseline, and release modes, structured reports, explicit quarantine metadata, and fixture-based live baseline cases that can run across provider/model targets. Constraint: Existing check:pr and CI policy behavior must remain usable while the stronger baseline grows around it Constraint: Default PR gates must not require real model credentials or provider quota Rejected: Build a standalone QA platform first | too heavy before the baseline task shape is proven Rejected: Keep unstable server exclusions hardcoded in run-server-tests | hides quarantine policy from reports and future review Confidence: medium Scope-risk: moderate Directive: Expand baseline cases by adding focused fixtures and verifiers; do not make normal PR checks depend on live providers Tested: bun test scripts/quality-gate/*.test.ts scripts/quality-gate/baseline/*.test.ts Tested: bun run check:server Tested: bun run quality:gate --mode baseline --allow-live --provider-model 2944f963-ce75-45b7-bac1-6e4f57df0970:kimi-k2.6:volc-kimi-k2.6 --provider-model 9c78d3df-7fb5-44c7-8436-3a41c3a59231:MiniMax-M2.7-highspeed:minimax-m2.7 Not-tested: desktop UI browser smoke and native release mode in this commit
51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { readFileSync } from 'node:fs'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
export type QuarantineEntry = {
|
|
id: string
|
|
path: string
|
|
reason: string
|
|
owner: string
|
|
reviewAfter: string
|
|
}
|
|
|
|
export type QuarantineManifest = {
|
|
quarantined: QuarantineEntry[]
|
|
}
|
|
|
|
const defaultManifestPath = join(dirname(fileURLToPath(import.meta.url)), 'quarantine.json')
|
|
|
|
export function loadQuarantineManifest(path = defaultManifestPath): QuarantineManifest {
|
|
const manifest = JSON.parse(readFileSync(path, 'utf8')) as QuarantineManifest
|
|
validateQuarantineManifest(manifest)
|
|
return manifest
|
|
}
|
|
|
|
export function validateQuarantineManifest(manifest: QuarantineManifest) {
|
|
if (!Array.isArray(manifest.quarantined)) {
|
|
throw new Error('quarantine manifest must contain a quarantined array')
|
|
}
|
|
|
|
const ids = new Set<string>()
|
|
const paths = new Set<string>()
|
|
|
|
for (const entry of manifest.quarantined) {
|
|
if (!entry.id || !entry.path || !entry.reason || !entry.owner || !entry.reviewAfter) {
|
|
throw new Error(`invalid quarantine entry: ${JSON.stringify(entry)}`)
|
|
}
|
|
if (ids.has(entry.id)) {
|
|
throw new Error(`duplicate quarantine id: ${entry.id}`)
|
|
}
|
|
if (paths.has(entry.path)) {
|
|
throw new Error(`duplicate quarantine path: ${entry.path}`)
|
|
}
|
|
ids.add(entry.id)
|
|
paths.add(entry.path)
|
|
}
|
|
}
|
|
|
|
export function quarantinedPathSet(manifest = loadQuarantineManifest()) {
|
|
return new Set(manifest.quarantined.map((entry) => entry.path))
|
|
}
|