Files
stablyai--orca/config/scripts/check-reliability-gates.test.mjs
2026-07-13 13:05:33 +08:00

461 lines
16 KiB
JavaScript

import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { main } from './check-reliability-gates.mjs'
const tempDirs = []
function makeTempRoot(manifest) {
const root = mkdtempSync(path.join(tmpdir(), 'orca-reliability-gates-'))
tempDirs.push(root)
const configDir = path.join(root, 'config')
mkdirSync(configDir, { recursive: true })
writeFileSync(path.join(configDir, 'reliability-gates.jsonc'), manifest, 'utf8')
writeFileSync(path.join(root, 'some.test.ts'), '', 'utf8')
return root
}
function validManifest(overrides = {}) {
return JSON.stringify(
{
schemaVersion: 1,
policy: {
maturityLevels: ['experimental', 'soak', 'blocking', 'accepted-gap', 'deprecated'],
blockingPromotion: {
minimumSoakRuns: 100,
minimumSoakDays: 14,
maximumUnexplainedFlakes: 0
}
},
gates: [
{
id: 'terminal-session.snapshot-freshness',
title: 'Stale liveness snapshots cannot close newer PTY bindings',
maturity: 'soak',
protection: 'partial',
owner: 'terminal-runtime',
layer: 'renderer-unit',
surfaces: ['terminal lifecycle'],
platforms: ['macos', 'linux', 'windows'],
providers: ['local', 'daemon'],
coveredPlatforms: ['macos'],
coveredProviders: ['local'],
coverageNotes: 'One local macOS unit run covers the local decision-layer fixture only.',
motivatingLinks: ['https://github.com/stablyai/orca/issues/6773'],
invariant: 'A stale snapshot cannot close a newer binding.',
oracle: 'The test rejects reconciliation when the binding is newer than the snapshot.',
commands: ['pnpm exec vitest run some.test.ts'],
testFiles: ['some.test.ts'],
assertionRefs: [
{
file: 'some.test.ts',
assertions: ['stale liveness snapshots do not close newer PTY bindings']
}
],
evidenceRuns: [
{
date: '2026-07-02',
runner: 'local',
platform: 'macos',
command: 'pnpm exec vitest run some.test.ts',
result: 'passed',
durationSeconds: 1.2,
summary: '1 file passed.'
}
],
runtimeBudget: {
p95Seconds: 10,
scope: 'local unit test'
},
flakeHistory: {
status: 'soaking',
evidence: 'Soak history exists.'
},
redGreenEvidence: {
status: 'complete',
evidence: 'Fails when the guard is removed and passes with the fix.'
},
performanceBudget: {
required: true,
evidence: 'Perf measurement is required before blocking promotion.'
},
promotionCriteria: ['Collect soak history.'],
knownGaps: ['Needs an Electron survival test.'],
demotionRule: 'Demote on unexplained flakes.',
...overrides
}
]
},
null,
2
)
}
afterEach(() => {
vi.restoreAllMocks()
while (tempDirs.length > 0) {
rmSync(tempDirs.pop(), { force: true, recursive: true })
}
})
describe('check-reliability-gates', () => {
it('accepts the checked-in manifest', async () => {
vi.spyOn(console, 'log').mockImplementation(() => {})
await expect(main(process.cwd())).resolves.toBe(0)
})
it('rejects soak gates without executable commands', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ commands: [] }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('Reliability gate manifest check failed')
)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('soak gates must declare at least one command')
)
})
it('rejects soak gates without test files', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ testFiles: [] }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('soak gates must declare at least one test file')
)
})
it('rejects command-backed gates that select tests by title', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({ maturity: 'experimental', commands: ['pnpm vitest -t flaky-title'] })
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('commands must not rely on title selectors')
)
})
it('rejects gates without a protection level', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const manifest = JSON.parse(validManifest())
delete manifest.gates[0].protection
const root = makeTempRoot(JSON.stringify(manifest, null, 2))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection must be one of none, partial, or active')
)
})
it('rejects commandless gates unless they declare protection none', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
protection: 'partial',
commands: [],
testFiles: [],
flakeHistory: { status: 'not-started', evidence: 'Planning entry only.' },
redGreenEvidence: { status: 'missing', evidence: 'No executable proof yet.' }
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('commandless gates must declare protection none')
)
})
it('rejects command-backed gates marked as no protection', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ maturity: 'experimental', protection: 'none' }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection none gates must not declare commands or testFiles')
)
})
it('reserves active protection for stable blocking gates', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ maturity: 'experimental', protection: 'active' }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection active is reserved for blocking gates')
)
})
it('rejects partial gates without a passed evidence run', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ maturity: 'experimental', evidenceRuns: [] }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection partial gates need a passed evidence run')
)
})
it('rejects evidence runs whose command is not declared by the gate', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
evidenceRuns: [
{
date: '2026-07-02',
runner: 'local',
platform: 'macos',
command: 'pnpm exec vitest run other.test.ts',
result: 'passed',
durationSeconds: 1,
summary: 'Wrong command.'
}
]
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('evidenceRuns[0].command must match one of the gate commands')
)
})
it('rejects protection none gates with evidence runs', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
protection: 'none',
commands: [],
testFiles: [],
flakeHistory: { status: 'not-started', evidence: 'Planning entry only.' },
redGreenEvidence: { status: 'missing', evidence: 'No executable proof yet.' }
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection none gates must not declare evidenceRuns')
)
})
it('rejects partial gates without assertion refs', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(validManifest({ maturity: 'experimental', assertionRefs: [] }))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection partial gates need assertionRefs')
)
})
it('rejects assertion refs outside declared test files', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
assertionRefs: [
{
file: 'other.test.ts',
assertions: ['important invariant']
}
]
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('assertionRefs[0].file must be one of the gate testFiles')
)
})
it('rejects protection none gates with assertion refs', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
protection: 'none',
commands: [],
testFiles: [],
evidenceRuns: [],
assertionRefs: [
{
file: 'some.test.ts',
assertions: ['planning entry must not look tested']
}
],
coveredPlatforms: [],
coveredProviders: [],
flakeHistory: { status: 'not-started', evidence: 'Planning entry only.' },
redGreenEvidence: { status: 'missing', evidence: 'No executable proof yet.' }
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection none gates must not declare assertionRefs')
)
})
it('rejects covered scope outside the risk scope', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
coveredPlatforms: ['ios'],
coveredProviders: ['ssh']
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('covered platform is outside risk scope: ios')
)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('covered provider is outside risk scope: ssh')
)
})
it('requires coveredPlatforms to include passed evidence platforms', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
coveredPlatforms: ['linux']
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('coveredPlatforms must include passed evidence platform macos')
)
})
it('rejects covered scope on protection none gates', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
protection: 'none',
commands: [],
testFiles: [],
evidenceRuns: [],
coveredPlatforms: ['macos'],
coveredProviders: [],
flakeHistory: { status: 'not-started', evidence: 'Planning entry only.' },
redGreenEvidence: { status: 'missing', evidence: 'No executable proof yet.' }
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('protection none gates must not declare covered scope')
)
})
it('rejects declared test files that do not exist', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({ maturity: 'experimental', testFiles: ['missing.test.ts'] })
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('test file does not exist: missing.test.ts')
)
})
it('rejects executable gates whose commands do not reference declared test files', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const command = 'pnpm exec vitest run'
const root = makeTempRoot(
validManifest({
maturity: 'experimental',
commands: [command],
evidenceRuns: [
{
date: '2026-07-02',
runner: 'local',
platform: 'macos',
command,
result: 'passed',
durationSeconds: 1,
summary: 'Command did not name the declared file.'
}
]
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('test file is not referenced by any gate command: some.test.ts')
)
})
it('rejects soak gates without mature flake and red/green evidence', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot(
validManifest({
flakeHistory: { status: 'unknown', evidence: 'No soak yet.' },
redGreenEvidence: { status: 'partial', evidence: 'No saved artifact yet.' }
})
)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('soak gates must have soaking or stable flakeHistory')
)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('soak gates must have complete red/green evidence')
)
})
it('rejects malformed JSONC', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = makeTempRoot('{ "schemaVersion": 1, } trailing')
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('JSONC parse error'))
})
it('rejects missing manifests with a structured error', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const root = mkdtempSync(path.join(tmpdir(), 'orca-reliability-gates-'))
tempDirs.push(root)
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('unable to read manifest'))
})
it('uses policy maturity levels as the source of truth', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const manifest = JSON.parse(validManifest())
manifest.policy.maturityLevels = ['experimental']
const root = makeTempRoot(JSON.stringify(manifest, null, 2))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('maturity is invalid'))
})
it('rejects malformed blocking promotion policy', async () => {
vi.spyOn(console, 'error').mockImplementation(() => {})
const manifest = JSON.parse(validManifest())
manifest.policy.blockingPromotion.maximumUnexplainedFlakes = -1
const root = makeTempRoot(JSON.stringify(manifest, null, 2))
await expect(main(root)).resolves.toBe(1)
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining(
'policy.blockingPromotion.maximumUnexplainedFlakes must be a non-negative number'
)
)
})
})