summaryrefslogtreecommitdiff
path: root/.claude/workflows/test/test-code-verify.mjs
diff options
context:
space:
mode:
Diffstat (limited to '.claude/workflows/test/test-code-verify.mjs')
-rw-r--r--.claude/workflows/test/test-code-verify.mjs216
1 files changed, 216 insertions, 0 deletions
diff --git a/.claude/workflows/test/test-code-verify.mjs b/.claude/workflows/test/test-code-verify.mjs
new file mode 100644
index 000000000..aae588003
--- /dev/null
+++ b/.claude/workflows/test/test-code-verify.mjs
@@ -0,0 +1,216 @@
+import assert from 'node:assert/strict'
+import { readdirSync, readFileSync } from 'node:fs'
+
+const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor
+const source = readFileSync(new URL('../code-verify.js', import.meta.url), 'utf8')
+const workflowBody = source.replace(/^export /m, '')
+
+const RESULT = {
+ type: 'object', additionalProperties: false,
+ required: ['answer'],
+ properties: { answer: { type: 'string' } },
+}
+const answers = {
+ codex: { answer: 'codex' },
+ claude: { answer: 'claude' },
+}
+
+async function run(args, provided = answers) {
+ const calls = []
+ let parallelCalls = 0
+ const agent = async (prompt, options) => {
+ const provider = options.agentType === 'code-verifier' ? 'claude'
+ : options.agentType === 'codex-code-verifier' ? 'codex' : 'unknown'
+ calls.push({ provider, prompt, options })
+ const answer = provided[provider]
+ if (answer instanceof Error) throw answer
+ if (answer && typeof answer.answer !== 'string') throw new Error('schema mismatch')
+ return structuredClone(answer)
+ }
+ const parallel = async (thunks) => {
+ parallelCalls++
+ return Promise.all(thunks.map(fn => Promise.resolve().then(fn).catch(() => null)))
+ }
+ const fn = new AsyncFunction(
+ 'args', 'agent', 'pipeline', 'parallel', 'phase', 'log', 'workflow', 'budget',
+ workflowBody,
+ )
+ const result = await fn(args, agent, null, parallel, () => {}, () => {}, null, null)
+ return { result, calls, parallelCalls }
+}
+
+let failed = 0
+async function check(name, fn) {
+ try {
+ await fn()
+ console.log(` ok ${name}`)
+ } catch (error) {
+ failed++
+ console.log(` FAIL ${name}\n ${error.stack || error}`)
+ }
+}
+
+await check('defaults to codex', async () => {
+ const { result, calls, parallelCalls } = await run({ prompt: 'review', schema: RESULT })
+ assert.deepEqual(result, answers.codex)
+ assert.deepEqual(calls.map(c => c.provider), ['codex'])
+ assert.equal(parallelCalls, 0)
+ assert.equal(calls[0].options.agentType, 'codex-code-verifier')
+ assert.deepEqual(calls[0].options.schema, RESULT)
+ assert.deepEqual(JSON.parse(calls[0].prompt), { prompt: 'review', schema: RESULT })
+})
+
+await check('bridge owns the Codex subprocess contract', async () => {
+ const bridge = readFileSync(new URL('../../agents/codex-code-verifier.md', import.meta.url), 'utf8')
+ assert.match(bridge, /model: haiku/)
+ assert.match(bridge, /effort: low/)
+ assert.match(bridge, /\.codex\/agents\/code-verifier\.toml/)
+ assert.match(bridge, /tomllib/)
+ assert.match(bridge, /timeout 600s codex exec/)
+ assert.match(bridge, /--sandbox read-only/)
+ assert.match(bridge, /--output-schema/)
+ assert.match(bridge, /--output-last-message/)
+})
+
+await check('selects claude', async () => {
+ const { result, calls, parallelCalls } = await run(
+ { prompt: 'review', schema: RESULT, provider: 'claude', label: 'check' })
+ assert.deepEqual(result, answers.claude)
+ assert.deepEqual(calls.map(c => c.provider), ['claude'])
+ assert.equal(parallelCalls, 0)
+ assert.equal(calls[0].prompt, 'review')
+ assert.equal(calls[0].options.label, 'check:claude')
+ assert.deepEqual(calls[0].options.schema, RESULT)
+})
+
+await check('runs both independently', async () => {
+ const { result, calls, parallelCalls } = await run(
+ { prompt: 'review', schema: RESULT, provider: 'both' })
+ assert.deepEqual(result, { codex: answers.codex, claude: answers.claude })
+ assert.deepEqual(calls.map(c => c.provider).sort(), ['claude', 'codex'])
+ assert.equal(parallelCalls, 1)
+})
+
+await check('rejects invalid input before dispatch', async () => {
+ for (const args of [null, {}, { prompt: '', schema: RESULT }, { prompt: 'x', schema: [] }]) {
+ await assert.rejects(run(args), /args must be/)
+ }
+ for (const provider of ['', 'auto']) await assert.rejects(
+ run({ prompt: 'review', schema: RESULT, provider }),
+ /provider must be codex, claude, or both/,
+ )
+})
+
+await check('fails closed when codex dies', async () => {
+ await assert.rejects(
+ run({ prompt: 'review', schema: RESULT }, { ...answers, codex: null }),
+ /codex verifier failed/,
+ )
+ await assert.rejects(
+ run({ prompt: 'review', schema: RESULT }, { ...answers, codex: new Error('broken') }),
+ /codex verifier failed: broken/,
+ )
+ await assert.rejects(
+ run({ prompt: 'review', schema: RESULT, provider: 'both' },
+ { ...answers, codex: new Error('broken') }),
+ /codex verifier failed/,
+ )
+ await assert.rejects(
+ run({ prompt: 'review', schema: RESULT }, { ...answers, codex: { answer: 1 } }),
+ /codex verifier failed: schema mismatch/,
+ )
+})
+
+await check('only validate bypasses the router for one-level nesting', async () => {
+ const dir = new URL('.', import.meta.url)
+ const offenders = readdirSync(dir)
+ .filter(name => name.endsWith('.js') && !['code-verify.js', 'validate.js'].includes(name))
+ .filter(name => /agentType:\s*['"](?:codex-)?code-verifier['"]/.test(
+ readFileSync(new URL(name, dir), 'utf8')))
+ assert.deepEqual(offenders, [])
+})
+
+await check('router rejections preserve caller null-result contracts', async () => {
+ for (const name of ['fanout-dev.js', 'pr-babysit.js']) {
+ const src = readFileSync(new URL(`../${name}`, import.meta.url), 'utf8')
+ assert.match(src, /workflow\('code-verify',[\s\S]*?\}\)\.catch\(\(\) => null\)\s*\.then/)
+ }
+})
+
+await check('driver review drops a failed routed scanner', async () => {
+ const src = readFileSync(new URL('../driver-review.js', import.meta.url), 'utf8').replace(/^export /m, '')
+ const fn = new AsyncFunction(
+ 'args', 'agent', 'pipeline', 'parallel', 'phase', 'log', 'workflow', 'budget', src)
+ const pipeline = async (items, ...stages) => Promise.all(items.map(async item => {
+ let value = item
+ for (const stage of stages) value = await stage(value, item)
+ return value
+ }))
+ const result = await fn(
+ { dirs: ['src/portable/test'], dimensions: ['correctness'] },
+ null, pipeline, null, () => {}, () => {}, async () => { throw new Error('verifier died') }, null,
+ )
+ assert.deepEqual(result, [])
+})
+
+await check('validate dispatches directly to stay within one workflow level', async () => {
+ const src = readFileSync(new URL('../validate.js', import.meta.url), 'utf8')
+ assert.equal((src.match(/workflow\(['"]code-verify['"]/g) || []).length, 0)
+ assert.match(src, /const reviewProvider = reviewStageNames\.length === 2 \? 'both'/)
+ assert.match(src, /agentType:\s*'codex-code-verifier'/)
+ assert.match(src, /agentType:\s*'code-verifier'/)
+ assert.doesNotMatch(src, /codex review --base/)
+ assert.doesNotMatch(src, /model:\s*['"]opus['"][^}]*schema:\s*REVIEW/)
+})
+
+await check('validate keeps provider results and gates separate', async () => {
+ const src = readFileSync(new URL('../validate.js', import.meta.url), 'utf8').replace(/^export /m, '')
+ const calls = []
+ let failCodex = false
+ let blocking = false
+ const fn = new AsyncFunction(
+ 'args', 'agent', 'pipeline', 'parallel', 'phase', 'log', 'workflow', 'budget', src)
+ const agent = async (prompt, options) => {
+ calls.push(options.agentType)
+ if (options.agentType === 'code-verifier') return {
+ pass: true, detail: 'claude',
+ findings: [{ file: 'a.c', line: 1,
+ severity: blocking ? 'CONFIRMED P1 safety' : 'CONFIRMED P2 correctness', summary: 'bug' }],
+ }
+ if (options.agentType === 'codex-code-verifier') return failCodex ? null : {
+ pass: true, detail: 'codex',
+ findings: [{ file: 'b.c', line: 2,
+ severity: blocking ? 'CONFIRMED P1 safety' : 'CONFIRMED P1 quality', summary: 'bug' }],
+ }
+ assert.equal(options.agentType, 'builder')
+ return { board: 'test', pass: true, builtCount: 1, failures: [] }
+ }
+ const workflow = async () => { throw new Error('validate cannot nest a workflow') }
+ const parallel = thunks => Promise.all(thunks.map(run => run()))
+ const result = await fn(
+ { boards: ['test'], skip: ['unit', 'size', 'pvs'], maxCycles: 1 },
+ agent, null, parallel, () => {}, () => {}, workflow, null,
+ )
+ assert.deepEqual(calls.sort(), ['builder', 'code-verifier', 'codex-code-verifier'])
+ assert.equal(result.stages.find(s => s.stage === 'review').pass, true)
+ assert.equal(result.stages.find(s => s.stage === 'codex').pass, true)
+
+ blocking = true
+ const blocked = await fn(
+ { boards: ['test'], skip: ['unit', 'size', 'pvs'], maxCycles: 1 },
+ agent, null, parallel, () => {}, () => {}, workflow, null,
+ )
+ assert.equal(blocked.stages.find(s => s.stage === 'review').pass, false)
+ assert.equal(blocked.stages.find(s => s.stage === 'codex').pass, false)
+
+ failCodex = true
+ const partial = await fn(
+ { boards: ['test'], skip: ['unit', 'size', 'pvs'], maxCycles: 1 },
+ agent, null, parallel, () => {}, () => {}, workflow, null,
+ )
+ assert.equal(partial.stages.find(s => s.stage === 'review').detail, 'claude')
+ assert.equal(partial.stages.find(s => s.stage === 'codex').detail, 'stage agent died')
+})
+
+console.log(failed ? `\n${failed} FAILED` : '\nall checks passed')
+process.exit(failed ? 1 : 0)