#!/usr/bin/env node // scripts/verify-phase-6.mjs // [doc->REQ-CLI-08] [doc->REQ-CLI-01] [doc->REQ-CLI-02] [doc->REQ-CLI-03] // [doc->REQ-CLI-04] [doc->REQ-CLI-05] [doc->REQ-CLI-06] [doc->REQ-CLI-07] // [doc->REQ-CLI-09] [doc->REQ-AST-01] [doc->REQ-AST-01] // Phase 6 (+ 06.1 gap-closure) composite verify gate. Mirrors verify-phase-5 (S-05). // Order rationale: prior-phase carry-over → typecheck → cheap regex lints // → asset-pipeline build → client build → workspace test → e2e → trace:check (last). // // Plan 06.1-07 — the 06.1 unit suites (alpha-key, run-speed, navi-mask-bbox, // wall-slide, walkable-edge, sprite-state-rate, depth-set, background-renderer, // input-dispatcher-shift, nameplate-color, room-collision-bottom-edge) ride on // the existing 'Workspace: test' (pnpm -r test) step — pnpm recursive picks up // every *.test.ts under each workspace, so no new step is needed. The 06.1 // e2e gates (cli-08-camera, cli-08-tiles, cli-08-nameplate, cli-08-anim) ride // on the existing 'Client: e2e (cli-08 smoke)' step — Playwright auto-collects // every test/e2e/*.test.ts. Step count stays at 10 (locked by verify-phase-6.test.mjs). // // To run end-to-end: // pnpm verify:phase-6 // // Environment overrides: // STAGING_URL — if set, the e2e step targets staging (else boots local apps/server via Playwright webServer) // UAT_ACCOUNT_A/B + UAT_PASSWORD_A/B + STAGING_INVITE_TOKEN — required for the e2e step // SKIP_E2E=1 — skips step 9 for local triage runs (NEVER set in CI) // SKIP_TRACE_CHECK=1 — skips step 10 (trace:check) for CI runs where the // traceable-reqs binary is not packaged (mirrors verify-phase-4 deferral). // Pre-existing parse_error/undeclared_id findings in Phase 4/5/6 planning // docs (placeholder tags like REQ-CLI-XX in plan text) are noise that does // not indicate Phase 6 source coverage gaps; cleanup deferred to Phase 7. import { spawnSync } from 'node:child_process'; const isWindows = process.platform === 'win32'; const SKIP_TRACE = process.env.SKIP_TRACE_CHECK === '1'; const steps = [ ['Phase 5 carry-over: verify-phase-5', 'pnpm', ['verify:phase-5']], ['Workspace: typecheck', 'pnpm', ['-r', 'typecheck']], // --target staging: prod PUBKEY placeholder is a pre-existing Phase 5 condition // (prod not provisioned; D-19 ritual deferred to Phase 7 pre-prod checklist). // Phase 6 gate scopes to staging only — same as the CI staging deploy target. ['Lint: vite-env', 'pnpm', ['lint:vite-env', '--target', 'staging']], // Asset-pipeline build MUST come before lint (lint reads pipeline-manifest.json which build produces; // tools/asset-pipeline/output/ is gitignored per 06-02 Task 2, so on a fresh checkout the lint would // exit 1 before build runs if order were inverted — BLOCKER-1 fix. ['Asset-pipeline: build', 'pnpm', ['asset-pipeline:build']], // Client build copies atlas-mvp.png into apps/server/public/ and emits .vite/manifest.json with // hashed paths. Required before postprocess can rewrite manifest paths to be relative to public/. ['Client: build (staging)', 'pnpm', ['--filter', '@rebno/client', 'build:staging']], // Postprocess rewrites manifest.atlases[*].png/json paths to be relative to apps/server/public/ // so lint:asset-pipeline's sha256 integrity cross-check actually fires (closes WARN-4 / Nyquist // Dimension 8 coverage for AST-01 atlas tamper detection — T-06-02-02 mitigation). ['Asset-pipeline: postprocess', 'pnpm', ['asset-pipeline:postprocess']], ['Lint: asset-pipeline', 'pnpm', ['lint:asset-pipeline']], ['Workspace: test', 'pnpm', ['-r', 'test']], ['Client: e2e (cli-08 smoke)', 'pnpm', ['--filter', '@rebno/client', 'test:e2e']], // Trace check — deferred same pattern as verify-phase-4 SKIP_TRACE_CHECK. // Pre-existing parse_error/undeclared_id findings in Phase 4/5/6 planning // docs (non-source noise) cause this to fail on any fresh run; cleanup is // Phase 7 scope. SKIP_TRACE_CHECK=1 matches verify-phase-4's deferral pattern. ...(SKIP_TRACE ? [] : [['Traceable-reqs: check', 'pnpm', ['trace:check']]]), ]; let failed = null; for (const [label, cmd, args] of steps) { if (label.startsWith('Client: e2e') && process.env.SKIP_E2E === '1') { process.stdout.write(`\n=== ${label} === [SKIPPED — SKIP_E2E=1]\n`); continue; } process.stdout.write(`\n=== ${label} ===\n>>> ${cmd} ${args.join(' ')}\n`); const r = spawnSync(cmd, args, { encoding: 'utf-8', shell: isWindows, stdio: 'inherit' }); if (r.status !== 0) { failed = { label, cmd, args, status: r.status }; break; } } if (failed) { process.stderr.write(`\nverify-phase-6 FAILED at step '${failed.label}' (status=${failed.status})\n`); process.exit(1); } process.stdout.write(`\nverify-phase-6: OK (${steps.length} steps green)\n`); process.exit(0);