#!/usr/bin/env node // Release aggregation must reject the intermediate report before the RSS seal. import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const repo = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mt-playable-release-')); const write = (name, value) => fs.writeFileSync(path.join(root, name), JSON.stringify(value)); const fixture = JSON.parse(fs.readFileSync(path.join(repo, 'test/playable/report.valid.json'), 'utf8')); const manifest = { schema_version: 1, candidate: fixture.build, required_runs: { soak: 1 }, runs: [{ run_id: fixture.run_id, suite: 'soak', path: 'run-1' }] }; const report = { ...fixture, suite: 'soak', exit_gate: { checked: true, process_code: 0, timed_out: false, errors: [] } }; const baseline = process.argv.includes('--baseline') ? spawnSync('git', ['show', 'f39a55fd:script/validate_playable_report.mjs'], { cwd: repo, encoding: 'utf8' }).stdout : null; function check(expected, label) { const args = baseline ? ['--input-type=module', '-'] : [path.join(repo, 'script/validate_playable_report.mjs')]; const result = spawnSync(process.execPath, [...args, '--release-dir', root], { input: baseline, encoding: 'utf8' }); assert.equal(result.status, expected, `${label}: ${result.stdout} ${result.stderr}`); assert.equal(JSON.parse(fs.readFileSync(path.join(root, 'release-report.json'))).status, expected === 0 ? 'PASS' : 'FAIL'); console.log(`ok - ${label}`); } try { fs.mkdirSync(path.join(root, 'run-1')); write('release-manifest.json', manifest); write('run-1/report.json', report); check(1, 'soak PASS without external memory seal is rejected'); report.runner_cases = [{ id: 'STB-MEMORY-01', status: 'PASS' }]; write('run-1/report.json', report); check(1, 'memory case alone cannot replace the verdict'); report.memory = { verdict: { status: 'FAIL' } }; write('run-1/report.json', report); check(1, 'contradictory memory verdict is rejected'); report.memory.verdict.status = 'PASS'; write('run-1/report.json', report); check(0, 'clean exit and external memory PASS can be aggregated'); write('run-1/report.json', null); check(1, 'null run report produces a sealed release failure'); write('release-manifest.json', null); check(1, 'null manifest produces a sealed release failure'); } finally { fs.rmSync(root, { recursive: true, force: true }); }