// scripts/verify-phase-6.test.mjs // [unit->REQ-CLI-08] // Locks the orchestrator structure of scripts/verify-phase-6.mjs. // This test asserts the final shape so any future re-ordering or step // addition/removal must update both the orchestrator AND this gate-test // deliberately. // // Usage: node --test scripts/verify-phase-6.test.mjs // OR: pnpm verify:phase-6:test // Exit: 0 on success, 1 on any assertion failure. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { spawnSync } from 'node:child_process'; const SCRIPT = resolve(process.cwd(), 'scripts/verify-phase-6.mjs'); const SOURCE = readFileSync(SCRIPT, 'utf-8'); test('script defines exactly 10 steps', () => { const matches = SOURCE.match(/^\s*\[\s*'.+?',\s*'.+?',\s*\[/gm) ?? []; assert.equal(matches.length, 10, `expected 10 step entries; found ${matches.length}`); }); test('asset-pipeline build runs BEFORE lint:asset-pipeline (BLOCKER-1 regression guard)', () => { const idxBuild = SOURCE.indexOf("'Asset-pipeline: build'"); const idxLint = SOURCE.indexOf("'Lint: asset-pipeline'"); assert.notEqual(idxBuild, -1, 'Asset-pipeline: build step missing'); assert.notEqual(idxLint, -1, 'Lint: asset-pipeline step missing'); assert.ok(idxBuild < idxLint, 'Asset-pipeline: build must appear BEFORE Lint: asset-pipeline (lint reads the manifest the build produces; output dir gitignored, so on a fresh checkout an inverted order would exit 1 before build runs)'); }); test('asset-pipeline postprocess runs AFTER client build AND BEFORE lint:asset-pipeline (WARN-4 regression guard)', () => { const idxClientBuild = SOURCE.indexOf("'Client: build (staging)'"); const idxPostprocess = SOURCE.indexOf("'Asset-pipeline: postprocess'"); const idxLint = SOURCE.indexOf("'Lint: asset-pipeline'"); assert.notEqual(idxPostprocess, -1, 'Asset-pipeline: postprocess step missing'); assert.ok(idxClientBuild < idxPostprocess, 'Client: build (staging) must appear BEFORE Asset-pipeline: postprocess (postprocess reads apps/server/public/.vite/manifest.json)'); assert.ok(idxPostprocess < idxLint, 'Asset-pipeline: postprocess must appear BEFORE Lint: asset-pipeline (the integrity sha256 cross-check needs manifest paths rewritten relative to apps/server/public/)'); }); test('trace:check is the LAST step (CLAUDE.md hard rule #12)', () => { const idxTrace = SOURCE.indexOf("['Traceable-reqs: check'"); assert.notEqual(idxTrace, -1, 'Traceable-reqs: check step missing'); // Find the last step opening bracket const allStepStarts = [...SOURCE.matchAll(/^\s*\[\s*'(?