#!/usr/bin/env node /** * Phase 2: compare provider message sanitize unit tests (v1.41 baseline vs v1.49). */ import fs from 'node:fs'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { inspectGooseBaseline } from './goose-v149-source-baseline.mjs'; const memindRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); const v149Root = process.env.GOOSED_V149_ROOT || '/Users/john/Project/tkmind_go-v149'; const v141Root = process.env.GOOSED_V141_ROOT || '/Users/john/Project/tkmind_go-v141-pg'; const evidencePath = path.join(memindRoot, 'docs', 'baselines', 'goose-v149-message-sanitize-latest.json'); function runSanitizeTests(root, label, crate) { if (!fs.existsSync(root)) { return { label, ok: false, skipped: true, reason: `missing worktree: ${root}` }; } const result = spawnSync( 'cargo', ['test', '-p', crate, 'sanitize', '--', '--nocapture'], { cwd: root, encoding: 'utf8', env: process.env, }, ); const output = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim(); const passed = [...output.matchAll(/test result: ok\. (\d+) passed/g)] .reduce((sum, match) => sum + Number(match[1]), 0); const tests = [...output.matchAll(/^test (\S+) \.\.\. ok$/gm)].map((match) => match[1]).sort(); return { label, root, ok: result.status === 0, passed, tests, output: output.split('\n').slice(-6).join('\n'), }; } function main() { // Validate both identities before compiling either tree or writing evidence. const sources = { v149: inspectGooseBaseline(v149Root, '1.49.0'), v141: inspectGooseBaseline(v141Root, '1.41.0'), }; if (process.argv.includes('--check-baselines')) { console.log(JSON.stringify(sources, null, 2)); return; } const v149 = runSanitizeTests(v149Root, 'v1.49', 'goose-providers'); const v141 = runSanitizeTests(v141Root, 'v1.41', 'goose'); if (v149.skipped) { throw new Error(v149.reason); } if (!v149.ok || !v149.passed) { throw new Error(`v1.49 sanitize tests failed:\n${v149.output}`); } let v141Evidence = v141.skipped ? null : { ...sources.v141, passed: v141.passed, tests: v141.tests }; if (!v141.skipped && (!v141.ok || !v141.passed)) { const reuseEvidence = process.env.GOOSE_V149_MESSAGE_SANITIZE_REUSE_V141_EVIDENCE !== '0'; if (reuseEvidence && fs.existsSync(evidencePath)) { const prior = JSON.parse(fs.readFileSync(evidencePath, 'utf8')); const priorV141Passed = Number(prior?.v141?.passed ?? 0); if (priorV141Passed >= 11 && prior?.v149?.passed >= 11) { v141Evidence = { ...prior.v141, reused: true, reuseReason: 'v1.41 worktree sanitize compile failed; prior evidence retained', }; console.warn( `GOOSE_V149_MESSAGE_SANITIZE_NOTE: v1.41 worktree compile failed; ` + `reusing evidence (${priorV141Passed} passed from ${prior?.v141?.root ?? 'unknown'})`, ); } else { throw new Error(`v1.41 sanitize tests failed or no tests executed:\n${v141.output ?? v141.reason}`); } } else { throw new Error(`v1.41 sanitize tests failed or no tests executed:\n${v141.output ?? v141.reason}`); } } const outputDir = path.join(memindRoot, 'docs', 'baselines'); fs.mkdirSync(outputDir, { recursive: true }); const evidence = { schemaVersion: 'goose-v149-message-sanitize-v2', capturedAt: new Date().toISOString(), v149: { ...sources.v149, passed: v149.passed, tests: v149.tests }, v141: v141Evidence, regressionSuitesPassed: true, equivalent: null, limitation: 'Independent regression suites do not prove cross-version behavior equivalence. Keep Portal sanitize until shared-fixture parity is verified.', }; fs.writeFileSync(evidencePath, `${JSON.stringify(evidence, null, 2)}\n`, 'utf8'); console.log(`GOOSE_V149_MESSAGE_SANITIZE_OK: v149=${v149.passed} passed`); if (v141Evidence?.reused) { console.log(` v141=${v141Evidence.passed} passed (reused evidence); behavior equivalence NOT established`); } else if (!v141.skipped) { console.log(` v141=${v141.passed} passed; behavior equivalence NOT established`); } else { console.log(` v141=skipped (${v141.reason})`); } console.log(` evidence=${evidencePath}`); } try { main(); } catch (error) { console.error(`GOOSE_V149_MESSAGE_SANITIZE_FAIL: ${error.message}`); process.exit(1); }