/**
 * In-memory execution of a frozen suite against the built artifact — the
 * authenticate step of Tier 1, with no vitest and no filesystem.
 *
 * buildTestProgram() emits a SELF-CONTAINED JavaScript program string:
 * every module (implementation + suite) transpiled by sucrase to CJS, a
 * micro vitest-compatible harness (describe/it/expect), and a module linker.
 * The string form matters: extension pages may not eval, so the extension
 * ships it to a sandboxed page (manifest "sandbox") where dynamic code is
 * legal; Node tests run the same string under new Function(). One program,
 * two hosts, identical semantics.
 */
import { transform } from 'sucrase';
import type { GeneratedFile } from '../core/types';
import {
  ddminFailureEvent,
  ddminHealMinimalSet,
  ddminMinimalFailingSetWithEval,
} from './ddmin';
import type { SeamDump } from './reportEvidence';
import { SEAM_DUMP_RADIUS } from './reportEvidence';

export {
  ddmin,
  ddminFailureEvent,
  ddminHealMinimalSet,
  detectRegexLiteralPoisonPatterns,
  formatMinimalFailingSetEvent,
  formatParsePoisonIncidents,
} from './ddmin';

export interface SuiteRunResult {
  total: number;
  failures: { name: string; message: string }[];
  /** Set when the program itself failed (syntax, import, harness) — not a case failure. */
  crashed?: string;
}

export type SuiteRunner = (files: GeneratedFile[], test: GeneratedFile) => Promise<SuiteRunResult>;

/** The micro-harness: describe/it/expect subset the IR doctrine allows. */
const HARNESS = String.raw`
const __cases = [];
const __beforeEach = [];
const __afterEach = [];
const __names = [];
// SET 35a — execution-position cursor (module + case); 0 tokens.
globalThis.__RHA_CURRENT__ = null;
function __caseName(name) { return [...__names, name].join(' > '); }
function __pushCase(name, fn, skipped) {
  const full = __caseName(name);
  __cases.push({
    name: full,
    fn: async () => {
      if (skipped) return;
      const prev = globalThis.__RHA_CURRENT__;
      globalThis.__RHA_CURRENT__ = {
        module: (prev && prev.module)
          || globalThis.__RHA_SUITE_MODULE__
          || '(suite)',
        caseName: full,
      };
      try { return await fn(); }
      finally { globalThis.__RHA_CURRENT__ = prev; }
    },
  });
}
function __fmtEachName(template, row, index) {
  if (typeof template !== 'string') return String(template) + ' [' + index + ']';
  var name = template;
  if (row && typeof row === 'object' && !Array.isArray(row)) {
    name = name.replace(/\$([A-Za-z_]\w*)/g, function (_, k) {
      return row[k] == null ? '' : String(row[k]);
    });
  } else if (Array.isArray(row)) {
    var i = 0;
    name = name.replace(/%[isdfoj]/g, function () {
      var v = row[i++];
      return v == null ? '' : String(v);
    });
  }
  return name;
}
function __eachBinder(register) {
  return function (table) {
    return function (name, fn) {
      var rows = Array.isArray(table) ? table : [];
      for (var i = 0; i < rows.length; i++) {
        (function (row, index) {
          var caseName = __fmtEachName(name, row, index);
          if (Array.isArray(row)) register(caseName, function () { return fn.apply(null, row); });
          else register(caseName, function () { return fn(row); });
        })(rows[i], i);
      }
    };
  };
}
function describe(name, fn) { __names.push(name); try { fn(); } finally { __names.pop(); } }
// SET 40e — vitest surface: .skip/.todo/.only/.each must be callable (no .call crash).
describe.skip = function (name, _fn) { /* omit body — section skipped */ };
describe.todo = function (name) { describe.skip(name, function () {}); };
describe.only = function (name, fn) { return describe(name, fn); };
describe.each = function (table) {
  return function (name, fn) {
    var rows = Array.isArray(table) ? table : [];
    for (var i = 0; i < rows.length; i++) {
      (function (row, index) {
        var caseName = __fmtEachName(name, row, index);
        if (Array.isArray(row)) describe(caseName, function () { fn.apply(null, row); });
        else describe(caseName, function () { fn(row); });
      })(rows[i], i);
    }
  };
};
function it(name, fn) { __pushCase(name, fn, false); }
it.skip = function (name, fn) { __pushCase(name, fn || function () {}, true); };
it.todo = function (name) { __pushCase(name || 'todo', function () {}, true); };
it.only = function (name, fn) { return it(name, fn); };
it.each = __eachBinder(it);
const test = it;
function beforeEach(fn) { __beforeEach.push(fn); }
function afterEach(fn) { __afterEach.push(fn); }

function __fmt(v) {
  try {
    if (typeof v === 'string') return JSON.stringify(v);
    if (v instanceof Error) return String(v);
    return JSON.stringify(v, (_k, x) => x instanceof Map ? { __map: [...x] } : x instanceof Set ? { __set: [...x] } : x);
  } catch { return String(v); }
}
function __deepEq(a, b) {
  if (Object.is(a, b)) return true;
  if (typeof a !== typeof b) return false;
  if (a == null || b == null) return a === b;
  if (typeof a !== 'object') return false;
  if (a instanceof Date || b instanceof Date) return a instanceof Date && b instanceof Date && a.getTime() === b.getTime();
  if (a instanceof Map || b instanceof Map) {
    if (!(a instanceof Map && b instanceof Map) || a.size !== b.size) return false;
    for (const [k, v] of a) { if (!b.has(k) || !__deepEq(v, b.get(k))) return false; }
    return true;
  }
  if (a instanceof Set || b instanceof Set) {
    if (!(a instanceof Set && b instanceof Set) || a.size !== b.size) return false;
    for (const v of a) { if (![...b].some(x => __deepEq(v, x))) return false; }
    return true;
  }
  if (Array.isArray(a) !== Array.isArray(b)) return false;
  const ka = Object.keys(a), kb = Object.keys(b);
  if (ka.length !== kb.length) return false;
  return ka.every(k => __deepEq(a[k], b[k]));
}
function __matchObj(actual, sub) {
  if (typeof sub !== 'object' || sub == null) return __deepEq(actual, sub);
  if (typeof actual !== 'object' || actual == null) return false;
  return Object.keys(sub).every(k => k in actual && __matchObj(actual[k], sub[k]));
}
class __Fail extends Error {}
function __throwFail(op, actual, expected) {
  throw new __Fail('expect(...).' + op + ' failed — actual: ' + __fmt(actual) + (expected === undefined ? '' : ', expected: ' + __fmt(expected)));
}
function __makeExpect(actual, negate) {
  const check = (ok, op, expected) => {
    if (negate ? ok : !ok) __throwFail((negate ? 'not.' : '') + op, actual, expected);
  };
  const m = {
    toBe: (e) => check(Object.is(actual, e), 'toBe', e),
    toEqual: (e) => check(__deepEq(actual, e), 'toEqual', e),
    toStrictEqual: (e) => check(__deepEq(actual, e), 'toStrictEqual', e),
    toBeTruthy: () => check(!!actual, 'toBeTruthy'),
    toBeFalsy: () => check(!actual, 'toBeFalsy'),
    toBeNull: () => check(actual === null, 'toBeNull'),
    toBeUndefined: () => check(actual === undefined, 'toBeUndefined'),
    toBeDefined: () => check(actual !== undefined, 'toBeDefined'),
    toBeNaN: () => check(Number.isNaN(actual), 'toBeNaN'),
    toBeInstanceOf: (e) => check(actual instanceof e, 'toBeInstanceOf', e && e.name),
    toBeGreaterThan: (e) => check(actual > e, 'toBeGreaterThan', e),
    toBeGreaterThanOrEqual: (e) => check(actual >= e, 'toBeGreaterThanOrEqual', e),
    toBeLessThan: (e) => check(actual < e, 'toBeLessThan', e),
    toBeLessThanOrEqual: (e) => check(actual <= e, 'toBeLessThanOrEqual', e),
    toBeCloseTo: (e, digits = 2) => check(Math.abs(actual - e) < Math.pow(10, -digits) / 2, 'toBeCloseTo', e),
    toHaveLength: (e) => check(actual != null && actual.length === e, 'toHaveLength', e),
    toContain: (e) => check(
      typeof actual === 'string' ? actual.includes(e)
        : actual instanceof Set ? actual.has(e)
        : Array.isArray(actual) && actual.some(x => Object.is(x, e)),
      'toContain', e),
    toContainEqual: (e) => check(Array.isArray(actual) && actual.some(x => __deepEq(x, e)), 'toContainEqual', e),
    toMatch: (e) => check(typeof actual === 'string' && (e instanceof RegExp ? e.test(actual) : actual.includes(e)), 'toMatch', e),
    toMatchObject: (e) => check(__matchObj(actual, e), 'toMatchObject', e),
    toHaveProperty: (path, value) => {
      const parts = Array.isArray(path) ? path : String(path).split('.');
      let cur = actual, present = true;
      for (const p of parts) {
        if (cur != null && (typeof cur === 'object' || typeof cur === 'function') && p in cur) cur = cur[p];
        else { present = false; break; }
      }
      const ok = present && (value === undefined || __deepEq(cur, value));
      check(ok, 'toHaveProperty', path);
    },
    toThrow: (e) => {
      if (typeof actual !== 'function') __throwFail('toThrow(non-function)', actual, e);
      let threw = false, err;
      try { actual(); } catch (x) { threw = true; err = x; }
      let ok = threw;
      if (threw && e !== undefined) {
        const msg = err instanceof Error ? err.message : String(err);
        ok = e instanceof RegExp ? e.test(msg) : typeof e === 'string' ? msg.includes(e) : true;
      }
      check(ok, 'toThrow', e);
    },
  };
  m.toThrowError = m.toThrow;
  Object.defineProperty(m, 'not', { get: () => __makeExpect(actual, !negate) });
  m.resolves = new Proxy({}, { get: (_t, k) => async (...args) => {
    const v = await actual;
    return __makeExpect(v, negate)[k](...args);
  } });
  m.rejects = new Proxy({}, { get: (_t, k) => async (...args) => {
    let err, rejected = false;
    try { await actual; } catch (x) { rejected = true; err = x; }
    if (!rejected) __throwFail('rejects', '(resolved)', undefined);
    if (k === 'toThrow' || k === 'toThrowError') {
      const msg = err instanceof Error ? err.message : String(err);
      const e = args[0];
      const ok = e === undefined ? true : e instanceof RegExp ? e.test(msg) : typeof e === 'string' ? msg.includes(e) : true;
      if (negate ? ok : !ok) __throwFail('rejects.toThrow', msg, e);
      return;
    }
    return __makeExpect(err, negate)[k](...args);
  } });
  return m;
}
function expect(actual) { return __makeExpect(actual, false); }
const vi = {
  fn: (impl) => {
    const calls = [];
    const f = (...args) => { calls.push(args); return impl ? impl(...args) : undefined; };
    f.mock = { calls };
    f.mockImplementation = (i) => { impl = i; return f; };
    f.mockReturnValue = (v) => { impl = () => v; return f; };
    return f;
  },
  spyOn: (obj, method) => {
    const original = obj[method];
    const calls = [];
    let impl = typeof original === 'function' ? original.bind(obj) : undefined;
    const f = (...args) => { calls.push(args); return impl ? impl(...args) : undefined; };
    f.mock = { calls };
    f.mockImplementation = (i) => { impl = i; return f; };
    f.mockReturnValue = (v) => { impl = () => v; return f; };
    f.mockRestore = () => { obj[method] = original; };
    obj[method] = f;
    return f;
  },
};
// SET 35d — suites that call jest.fn under vitest get a harness alias (0 tok).
const jest = vi;
// SET 37c — bare spyOn/fn in the suite sandbox (0 tok; no import required).
const fn = (...args) => vi.fn(...args);
const spyOn = (...args) => vi.spyOn(...args);
`;

/** Normalize a module path: strip ./ ../ prefixes relative to importer dir, drop .ts/.js. */
const RESOLVER = String.raw`
function __resolve(from, spec) {
  if (spec === 'vitest') return 'vitest';
  let p = spec.replace(/\.(ts|js|mjs|cjs)$/, '');
  if (!p.startsWith('.')) return p; // bare — looked up as-is
  const base = from.split('/').slice(0, -1);
  for (const part of p.split('/')) {
    if (part === '.' || part === '') continue;
    else if (part === '..') base.pop();
    else base.push(part);
  }
  return base.join('/');
}
`;

/** Convert a source file to its transformed CJS body, or a throwing stub if sucrase rejects it. */
function transformModuleJs(path: string, source: string): string {
  try {
    return transform(source, { transforms: ['typescript', 'imports'] }).code;
  } catch (e) {
    // A module that cannot transpile is a suite-level crash with a clear tag.
    return `throw new Error(${JSON.stringify(`transpile ${path}: ${e instanceof Error ? e.message : String(e)}`)});`;
  }
}

/**
 * SET 31a — statement-isolated module registration. Each module is wrapped in
 * a leading-`;` IIFE and terminated with `;` so trailing expressions in one
 * module (or in the top-level program) cannot re-lex the next module's `/` as
 * division (JS lex is context-dependent; per-module parse validity does NOT
 * compose across seams). The same wrapper is used by `buildTestProgram` and
 * `probeModuleEval` so probe context ≡ program context.
 *
 * Exposed so any future ancillary probe honors the same seam contract.
 */
export function registerModuleSource(key: string, js: string): string {
  // SET 35a — wrap factory so load-time crashes name the module.
  // SET 36a — stash __RHA_LAST__ before finally clears the cursor (load throws
  // clear __RHA_CURRENT__ before the outer catch can read it).
  return `;(function(){ __register(${JSON.stringify(key)}, function (require, module, exports) {
var __rhaPrev = globalThis.__RHA_CURRENT__;
globalThis.__RHA_CURRENT__ = { module: ${JSON.stringify(key)}, caseName: ( __rhaPrev && __rhaPrev.caseName) || null };
try {
${js}
} catch (__rhaE) {
  globalThis.__RHA_LAST__ = globalThis.__RHA_CURRENT__;
  throw __rhaE;
} finally {
  globalThis.__RHA_CURRENT__ = __rhaPrev;
}
}); })();`;
}

/** SET 36a — module line span in the assembled program (1-based, inclusive). */
export interface ModuleLineSpan {
  path: string;
  key: string;
  startLine: number;
  endLine: number;
}

/** Parse `<anonymous>:N` / `eval ...:N` program line from a stack or message. */
export function extractAnonymousProgramLine(stackOrMessage: string): number | null {
  const patterns = [
    /<anonymous>:(\d+)/,
    /eval\s*(?:at\s+[^\n]*?)?:(\d+)/,
    /\(eval[^)]*:(\d+):\d+\)/,
  ];
  for (const re of patterns) {
    const m = re.exec(stackOrMessage);
    if (m) return parseInt(m[1]!, 10);
  }
  return null;
}

/** Map a 1-based program line onto `<file>:<local line>` via the line table. */
export function locateProgramLine(
  spans: ModuleLineSpan[],
  line: number,
): { path: string; localLine: number } | null {
  for (const s of spans) {
    if (line >= s.startLine && line <= s.endLine) {
      return { path: s.path, localLine: line - s.startLine + 1 };
    }
  }
  return null;
}

/**
 * SET 36a — assemble the program and the module line-offset table together so
 * stack frames like `<anonymous>:708` resolve to `src/foo.ts:12`.
 */
export function assembleTestProgram(
  files: GeneratedFile[],
  test: GeneratedFile,
): { program: string; spans: ModuleLineSpan[] } {
  const preamble = [
    '"use strict";',
    HARNESS,
    RESOLVER,
    String.raw`
const __registry = new Map();
const __instances = new Map();
function __register(key, factory) { __registry.set(key, factory); }
function __nl() { return String.fromCharCode(10); }
function __stackTop3(err) {
  if (!err || !err.stack) return [];
  return String(err.stack).split(__nl()).slice(1).map(function (l) { return l.trim(); }).filter(Boolean).slice(0, 3);
}
function __locateFromFrames(frames, table) {
  if (!table || !table.length) return null;
  for (var i = 0; i < frames.length; i++) {
    var m = /<anonymous>:(\d+)/.exec(frames[i]) || /:(\d+):\d+/.exec(frames[i]);
    if (!m) continue;
    var line = parseInt(m[1], 10);
    for (var j = 0; j < table.length; j++) {
      var s = table[j];
      if (line >= s.startLine && line <= s.endLine) {
        return { path: s.path, localLine: line - s.startLine + 1 };
      }
    }
  }
  return null;
}
function __formatExecCrash(err) {
  var cur = globalThis.__RHA_CURRENT__ || globalThis.__RHA_LAST__;
  var mod = (cur && cur.module) || '(unknown)';
  var caseLabel = (cur && cur.caseName) ? ('"' + cur.caseName + '"') : '"(load)"';
  var frames = __stackTop3(err);
  var msg = err instanceof Error ? err.message : String(err);
  var nl = __nl();
  var table = globalThis.__RHA_LINE_TABLE__;
  // SET 36a — load-time / cleared-cursor: map program line → file:localLine.
  if ((!cur || !cur.caseName) && (mod === '(unknown)' || !cur || !cur.caseName)) {
    var loc = __locateFromFrames(frames, table);
    if (loc) {
      var headLoad = 'crash while loading ' + loc.path + ':' + loc.localLine;
      return frames.length ? (headLoad + nl + '  ' + frames.join(nl + '  ') + nl + msg) : (headLoad + nl + msg);
    }
  }
  var head = 'crash while executing ' + mod + ' # ' + caseLabel;
  return frames.length ? (head + nl + '  ' + frames.join(nl + '  ') + nl + msg) : (head + nl + msg);
}
function __isAssertFail(e) {
  return e && e.constructor && e.constructor.name === '__Fail';
}
function __isRuntimePoison(e) {
  if (!e) return false;
  if (e.name === 'SyntaxError') return true;
  var msg = e instanceof Error ? e.message : String(e);
  return /Invalid regular expression|Invalid or unexpected token/i.test(msg);
}
function __require(from, spec) {
  const key = __resolve(from, spec);
  if (key === 'vitest') return { describe, it, test, expect, beforeEach, afterEach, vi, jest, spyOn, fn };
  if (__instances.has(key)) return __instances.get(key).exports;
  const factory = __registry.get(key);
  if (!factory) throw new Error('unresolved import ' + spec + ' (from ' + from + ')');
  const module = { exports: {} };
  __instances.set(key, module);
  factory((s) => __require(key, s), module, module.exports);
  return module.exports;
}
`,
  ].join('\n');

  const moduleChunks: string[] = [];
  const register = (path: string, source: string) => {
    const key = path.replace(/\.(ts|js)$/, '');
    moduleChunks.push(registerModuleSource(key, transformModuleJs(path, source)));
  };
  for (const f of files) register(f.path, f.content);
  register(test.path, test.content);

  const testKey = test.path.replace(/\.(ts|js)$/, '');
  const epilogue = String.raw`
globalThis.__RHA_LINE_TABLE__ = [];
globalThis.__RHA_RUN__ = async function () {
  const failures = [];
  globalThis.__RHA_SUITE_MODULE__ = ${JSON.stringify(testKey)};
  globalThis.__RHA_LAST__ = null;
  try {
    __require('.', ${JSON.stringify('./' + testKey)});
  } catch (e) {
    return { total: 0, failures: [], crashed: __formatExecCrash(e) };
  }
  for (const c of __cases) {
    // SET 35a — set cursor in the runner loop so finally-blocks inside case
    // wrappers cannot clear it before we format a crash.
    globalThis.__RHA_CURRENT__ = {
      module: globalThis.__RHA_SUITE_MODULE__ || '(suite)',
      caseName: c.name,
    };
    try {
      for (const b of __beforeEach) await b();
      await c.fn();
      for (const a of __afterEach) await a();
    } catch (e) {
      // SET 35a — runtime-poison detonations escalate to program crash with
      // execution-position attribution (assertions stay soft failures).
      if (!__isAssertFail(e) && __isRuntimePoison(e)) {
        return { total: __cases.length, failures, crashed: __formatExecCrash(e) };
      }
      failures.push({ name: c.name, message: e instanceof Error ? e.message : String(e) });
    } finally {
      globalThis.__RHA_CURRENT__ = null;
    }
  }
  return { total: __cases.length, failures };
};
`;

  const modulesBlock = moduleChunks.join('\n');
  const program = [preamble, modulesBlock, epilogue].join('\n');
  const finalSpans: ModuleLineSpan[] = [];
  let searchFrom = 0;
  for (let i = 0; i < moduleChunks.length; i++) {
    const chunk = moduleChunks[i]!;
    const abs = program.indexOf(chunk, searchFrom);
    if (abs < 0) continue;
    const startLine = program.slice(0, abs).split('\n').length;
    const endLine = startLine + chunk.split('\n').length - 1;
    const path = i < files.length ? files[i]!.path : test.path;
    const key = path.replace(/\.(ts|js)$/, '');
    finalSpans.push({ path, key, startLine, endLine });
    searchFrom = abs + chunk.length;
  }
  const patched = program.replace(
    /globalThis\.__RHA_LINE_TABLE__ = \[\];/,
    `globalThis.__RHA_LINE_TABLE__ = ${JSON.stringify(finalSpans.map(s => ({
      path: s.path,
      startLine: s.startLine,
      endLine: s.endLine,
    })))};`,
  );
  return { program: patched, spans: finalSpans };
}

/**
 * Build the self-contained program. When evaluated (any host), it defines
 * globalThis.__RHA_RUN__: () => Promise<SuiteRunResult-shaped object>.
 */
export function buildTestProgram(files: GeneratedFile[], test: GeneratedFile): string {
  return assembleTestProgram(files, test).program;
}

/**
 * SET 35a — format a program crash with the execution-position cursor and
 * the top 3 stack frames (bounded). Deterministic, 0 tokens.
 * SET 36a — optional line table maps load-time stack lines → file:localLine.
 */
export function formatExecutionCrash(
  err: unknown,
  current?: { module?: string | null; caseName?: string | null } | null,
  spans?: ModuleLineSpan[],
): string {
  const msg = err instanceof Error ? err.message : String(err);
  const stack = err instanceof Error && err.stack
    ? err.stack.split('\n').slice(1).map(l => l.trim()).filter(Boolean).slice(0, 3)
    : [];
  const stackText = [err instanceof Error ? err.stack ?? '' : '', ...stack].join('\n');
  const mod = current?.module || '(unknown)';
  const caseName = current?.caseName ?? null;

  if ((!caseName || mod === '(unknown)') && spans?.length) {
    const line = extractAnonymousProgramLine(stackText);
    const loc = line != null ? locateProgramLine(spans, line) : null;
    if (loc) {
      const head = `crash while loading ${loc.path}:${loc.localLine}`;
      return stack.length ? `${head}\n  ${stack.join('\n  ')}\n${msg}` : `${head}\n${msg}`;
    }
  }

  const caseLabel = caseName ? `"${caseName}"` : '"(load)"';
  const head = `crash while executing ${mod} # ${caseLabel}`;
  return stack.length ? `${head}\n  ${stack.join('\n  ')}\n${msg}` : `${head}\n${msg}`;
}

/** Parse SET 35a/36a attribution from a crash message (module + optional case). */
export function parseExecutionCrash(message: string): {
  module: string;
  caseName: string | null;
  localLine?: number;
} | null {
  const first = message.split('\n')[0] ?? '';
  const load = /^crash while loading (.+):(\d+)\s*$/.exec(first);
  if (load) {
    return { module: load[1]!, caseName: null, localLine: parseInt(load[2]!, 10) };
  }
  const m = /^crash while executing (.+?) # "([^"]*)"/.exec(first);
  if (!m) return null;
  const caseName = m[2] === '(load)' ? null : m[2]!;
  return { module: m[1]!, caseName };
}

/**
 * SET 36b — true when source cannot transpile and would become an
 * error-throwing placeholder inside the assembled program.
 */
export function isTranspilePlaceholder(path: string, content: string): boolean {
  try {
    transform(content, { transforms: ['typescript', 'imports'] });
    return false;
  } catch {
    void path;
    return true;
  }
}

/** SET 36b — impl files in the artifact that sit as transpile placeholders. */
export function findTranspilePlaceholders(files: GeneratedFile[]): GeneratedFile[] {
  return files.filter(f => !/\.test\.(ts|js)$/.test(f.path) && isTranspilePlaceholder(f.path, f.content));
}

export type ArtifactVetMode = 'build' | 'full';

/**
 * SET 36c — gate every artifact write.
 * - `build`: 35b lint; transpile failures are placeholder-flagged (36b) and
 *   ALLOWED so authenticate can attribute/heal. Probe deferred to substrate.
 * - `full` (reset / repair winner): lint + transpile-clean + module probe —
 *   a failed reset must not replace the incumbent with a crash-bomb.
 * SET 47a — GATE_UNAVAILABLE (probe infra / CSP) fails OPEN: skip the probe
 * check, never reject the candidate.
 * Returns a rejection reason or null when accepted.
 */
export function vetArtifactWrite(
  candidate: GeneratedFile,
  artifactWithCandidate: GeneratedFile[],
  mode: ArtifactVetMode = 'full',
): string | null {
  return vetArtifactWriteDetailed(candidate, artifactWithCandidate, mode).reason;
}

export type ArtifactVetDetail = {
  reason: string | null;
  gateUnavailable?: boolean;
};

/** SET 47a — same as vetArtifactWrite but surfaces gateUnavailable for dim logs. */
export function vetArtifactWriteDetailed(
  candidate: GeneratedFile,
  artifactWithCandidate: GeneratedFile[],
  mode: ArtifactVetMode = 'full',
): ArtifactVetDetail {
  const lint = dynamicEvalLint(candidate.content);
  if (lint) return { reason: lint };
  const syn = suiteSyntaxError(candidate.content);
  if (syn) {
    if (mode === 'build') return { reason: null }; // SET 36b — placeholder-flagged, keep
    return { reason: `transpile failed: ${syn.split('\n')[0]!.slice(0, 120)}` };
  }
  if (mode === 'full') {
    const probe = probeModuleEval(artifactWithCandidate, candidate.path);
    // SET 47a — infrastructure-unavailable → fail OPEN (never reject).
    if (probe === GATE_UNAVAILABLE) return { reason: null, gateUnavailable: true };
    if (probe) return { reason: `module probe: ${probe.split('\n')[0]!.slice(0, 120)}` };
  }
  return { reason: null };
}

/**
 * Vet a batch of owned-file writes. Each candidate is probed against the base
 * artifact with ONLY itself substituted — a co-owned poison sibling must not
 * reject a clean file (build/repair batches often mix good+bad owned paths).
 */
export function vetArtifactWrites(
  candidates: GeneratedFile[],
  baseArtifact: GeneratedFile[],
  mode: ArtifactVetMode = 'full',
): { ok: GeneratedFile[]; rejected: { path: string; reason: string }[]; gateUnavailable?: boolean } {
  const ok: GeneratedFile[] = [];
  const rejected: { path: string; reason: string }[] = [];
  let gateUnavailable = false;
  const candPaths = new Set(candidates.map(c => c.path));
  for (const c of candidates) {
    const trial = [
      ...baseArtifact.filter(f => f.path !== c.path && !candPaths.has(f.path)),
      ...ok,
      c,
    ];
    const detail = vetArtifactWriteDetailed(c, trial, mode);
    if (detail.gateUnavailable) gateUnavailable = true;
    if (detail.reason) rejected.push({ path: c.path, reason: detail.reason });
    else ok.push(c);
  }
  return { ok, rejected, gateUnavailable: gateUnavailable || undefined };
}

/**
 * SET 47a — async vet using sandbox module probe when installed.
 * Same fail-OPEN law for GATE_UNAVAILABLE.
 */
export async function vetArtifactWritesAsync(
  candidates: GeneratedFile[],
  baseArtifact: GeneratedFile[],
  mode: ArtifactVetMode = 'full',
): Promise<{ ok: GeneratedFile[]; rejected: { path: string; reason: string }[]; gateUnavailable?: boolean }> {
  const ok: GeneratedFile[] = [];
  const rejected: { path: string; reason: string }[] = [];
  let gateUnavailable = false;
  const candPaths = new Set(candidates.map(c => c.path));
  for (const c of candidates) {
    const trial = [
      ...baseArtifact.filter(f => f.path !== c.path && !candPaths.has(f.path)),
      ...ok,
      c,
    ];
    const lint = dynamicEvalLint(c.content);
    if (lint) { rejected.push({ path: c.path, reason: lint }); continue; }
    const syn = suiteSyntaxError(c.content);
    if (syn) {
      if (mode === 'build') { ok.push(c); continue; }
      rejected.push({ path: c.path, reason: `transpile failed: ${syn.split('\n')[0]!.slice(0, 120)}` });
      continue;
    }
    if (mode === 'full') {
      const probe = await probeModuleEvalAsync(trial, c.path);
      if (probe === GATE_UNAVAILABLE) {
        gateUnavailable = true;
        ok.push(c);
        continue;
      }
      if (probe) {
        rejected.push({ path: c.path, reason: `module probe: ${probe.split('\n')[0]!.slice(0, 120)}` });
        continue;
      }
    }
    ok.push(c);
  }
  return { ok, rejected, gateUnavailable: gateUnavailable || undefined };
}

// ---------------------------------------------------------------------------
// SET 38a — Incremental whole-program parse validation
// ---------------------------------------------------------------------------

/**
 * SET 38a / 36a alias — assemble the full test program (harness + modules +
 * epilogue). Integration and parse gates compose with this.
 */
export function assembleProgram(
  files: GeneratedFile[],
  test: GeneratedFile,
): { program: string; spans: ModuleLineSpan[] } {
  return assembleTestProgram(files, test);
}

/**
 * Modules-only parse program (harness + isolated IIFEs, no run epilogue).
 * Used by ddmin subset evaluates and early-build parse gates.
 */
export function assembleProgramModules(files: GeneratedFile[]): string {
  const modules = files.map(f =>
    registerModuleSource(f.path.replace(/\.(ts|js)$/, ''), transformModuleJs(f.path, f.content)));
  return [
    '"use strict";',
    HARNESS,
    RESOLVER,
    String.raw`
const __registry = new Map();
function __register(key, factory) { __registry.set(key, factory); }
`,
    modules.join('\n'),
  ].join('\n');
}

/**
 * SET 40a — sentinel when the parse *gate* cannot run (CSP / EvalError).
 * Distinguishes "program failed to parse" from "parser failed to run".
 * Never attribute this to a candidate.
 */
export const GATE_UNAVAILABLE = 'GATE_UNAVAILABLE';

/** True when `new Function`/`eval` itself is forbidden (gate infra), not SyntaxError. */
export function isGateInfrastructureError(e: unknown): boolean {
  if (e instanceof EvalError) return true;
  const msg = e instanceof Error ? e.message : String(e);
  return /unsafe-eval/i.test(msg);
}

/** Map a construct-time catch to a candidate crash msg or GATE_UNAVAILABLE. */
export function gateOrParseMessage(e: unknown): string {
  if (isGateInfrastructureError(e)) return GATE_UNAVAILABLE;
  return e instanceof Error ? e.message : String(e);
}

/** Assemble the program string used by sync/async parse probes. */
export function assembleProgramForParse(
  files: GeneratedFile[],
  test?: GeneratedFile | null,
): string {
  if (test) {
    return assembleTestProgram(files, test).program;
  }
  const suite = files.find(f => /\.test\.(ts|js)$/.test(f.path));
  if (suite) {
    const impls = files.filter(f => f.path !== suite.path);
    return assembleTestProgram(impls, suite).program;
  }
  return assembleProgramModules(files);
}

/**
 * SET 40a — optional sandbox-channel probe (Integration wires via offscreen).
 * null = parse ok; string = crash message or GATE_UNAVAILABLE.
 */
export type ProgramParseProbe = (program: string) => Promise<string | null>;

let programParseProbe: ProgramParseProbe | null = null;

/** Install/clear the async parse probe (sandbox channel). Default null = sync Node path. */
export function setProgramParseProbe(probe: ProgramParseProbe | null): void {
  programParseProbe = probe;
}

/**
 * SET 47a — optional sandbox-channel module probe (same offscreen sandbox as parse).
 * Assembled probe program in → null (clean) | crash msg | GATE_UNAVAILABLE.
 */
export type ModuleEvalProbe = (program: string) => Promise<string | null>;

let moduleEvalProbe: ModuleEvalProbe | null = null;

/** Install/clear the async module-eval probe (sandbox channel). */
export function setModuleEvalProbe(probe: ModuleEvalProbe | null): void {
  moduleEvalProbe = probe;
}

/**
 * SET 102 — sucrase rejects unterminated `/…` as "Unterminated regular expression"
 * and `transformModuleJs` wraps that as a runtime throw, so `new Function` would
 * otherwise fail-open. Surface the V8-equivalent construct-time message so the
 * write-acceptance delimiter-oracle heal can run (maxim 1 — substrate before model).
 */
function unterminatedRegexParseMessage(files: GeneratedFile[]): string | null {
  for (const f of files) {
    const syn = suiteSyntaxError(f.content);
    if (syn && /Unterminated regular expression/i.test(syn)) {
      return 'Invalid regular expression: missing /';
    }
  }
  return null;
}

/** Return construct-time crash message for a file set, or null if `new Function` succeeds. */
export function programParseError(files: GeneratedFile[], test?: GeneratedFile | null): string | null {
  const unterm = unterminatedRegexParseMessage(files);
  if (unterm) return unterm;
  try {
    const program = assembleProgramForParse(files, test);
    // eslint-disable-next-line no-new-func -- allowlisted Node/sync parse probe (SET 40a/40b)
    new Function(program);
    return null;
  } catch (e) {
    return gateOrParseMessage(e);
  }
}

/**
 * SET 40a — async parse probe. Uses sandbox probe when set; else sync `new Function`
 * with GATE_UNAVAILABLE discrimination.
 */
export async function programParseErrorAsync(
  files: GeneratedFile[],
  test?: GeneratedFile | null,
): Promise<string | null> {
  // SET 102 — check before the sandbox probe; assemble wraps unterminated
  // regex as a transpile throw that would otherwise parse-clean.
  const unterm = unterminatedRegexParseMessage(files);
  if (unterm) return unterm;
  const program = assembleProgramForParse(files, test);
  if (programParseProbe) {
    try {
      return await programParseProbe(program);
    } catch (e) {
      return gateOrParseMessage(e);
    }
  }
  try {
    // eslint-disable-next-line no-new-func -- allowlisted Node/sync parse probe (SET 40a/40b)
    new Function(program);
    return null;
  } catch (e) {
    return gateOrParseMessage(e);
  }
}

export type ProgramParseVetResult =
  | { ok: true; gateUnavailable?: boolean }
  | { ok: false; message: string; event: string };

function vetFromParseMessage(
  msg: string | null,
  justWrittenPath: string,
): ProgramParseVetResult {
  if (msg == null) return { ok: true };
  // SET 40a — fail OPEN when the gate cannot run (CSP). Not a candidate rejection.
  if (msg === GATE_UNAVAILABLE) return { ok: true, gateUnavailable: true };
  const event = `program-parse regression: ${justWrittenPath} rejected (crash: ${msg})`;
  return { ok: false, message: msg, event };
}

/**
 * SET 38a — after every artifact write: assemble the full program and
 * `new Function(program)` (0 tok). On fail, reject the write (caller keeps
 * incumbent). Event string is exactly:
 *   `program-parse regression: <file> rejected (crash: <msg>)`
 * SET 40a — GATE_UNAVAILABLE → fail open `{ ok: true, gateUnavailable: true }`.
 */
export function vetProgramParse(
  artifact: GeneratedFile[],
  justWrittenPath: string,
): ProgramParseVetResult {
  return vetFromParseMessage(programParseError(artifact), justWrittenPath);
}

/**
 * SET 38a — parallel gate for Integration: call after every write with the
 * candidate already substituted into the artifact. Reject semantics match
 * 36c (caller keeps incumbent).
 */
export function vetProgramParseAfterWrite(
  candidate: GeneratedFile,
  artifactWithCandidate: GeneratedFile[],
): ProgramParseVetResult {
  return vetProgramParse(artifactWithCandidate, candidate.path);
}

/** SET 40a — async vet using sandbox probe when installed. */
export async function vetProgramParseAsync(
  artifact: GeneratedFile[],
  justWrittenPath: string,
): Promise<ProgramParseVetResult> {
  return vetFromParseMessage(await programParseErrorAsync(artifact), justWrittenPath);
}

/** SET 40a — async after-write vet for Integration. */
export async function vetProgramParseAfterWriteAsync(
  candidate: GeneratedFile,
  artifactWithCandidate: GeneratedFile[],
): Promise<ProgramParseVetResult> {
  return vetProgramParseAsync(artifactWithCandidate, candidate.path);
}

/** Distill a lesson key from a rejected program-parse write. */
export function distillProgramParseLessonKey(
  justWrittenPath: string,
  crashMessage: string,
): string {
  const core = (crashMessage.split('\n')[0] ?? crashMessage).slice(0, 80);
  return `program-parse|${justWrittenPath}|${core}`;
}

/**
 * SET 35b — reject case bodies (and flag impls) that synthesize code at
 * runtime: `eval(`, `new Function(`, or `new RegExp(` with a non-literal
 * argument. Frozen tests must never contain runtime code synthesis.
 * Returns a human reason or null when clean.
 */
export function dynamicEvalLint(source: string): string | null {
  if (/\beval\s*\(/.test(source)) return 'dynamic-eval: eval( is forbidden in frozen tests/impls';
  if (/\bnew\s+Function\s*\(/.test(source)) {
    return 'dynamic-eval: new Function( is forbidden in frozen tests/impls';
  }
  // new RegExp( with a non-literal first arg — allow new RegExp('a'), new RegExp("a"), new RegExp(`a`).
  const re = /\bnew\s+RegExp\s*\(\s*([^)\n]+)/g;
  let m: RegExpExecArray | null;
  while ((m = re.exec(source)) !== null) {
    const arg = (m[1] ?? '').trim();
    if (!arg) continue;
    // Literal string/regex or simple string concat of literals — reject identifiers/calls.
    if (/^(['"`]|\/)/.test(arg)) continue;
    return 'dynamic-eval: new RegExp( with non-literal argument is forbidden';
  }
  return null;
}

/**
 * SET 35d — deterministic jest→vi rewrite for suites (accept iff re-parse
 * and the only identifier change is jest→vi). Returns null when no rewrite.
 * Kept jest-only so substrate's stripped-equality gate stays sound.
 */
export function rewriteJestToVi(content: string): string | null {
  if (!/\bjest\s*\./.test(content) && !/\bjest\b/.test(content)) return null;
  // Only rewrite jest. API calls and bare jest bindings — leave the word in comments alone when possible.
  const next = content
    .replace(/\bjest\s*\./g, 'vi.')
    .replace(/(\{[^}]*)\bjest\b(\s*,)/g, '$1vi$2')
    .replace(/(,\s*)\bjest\b(\s*\})/g, '$1vi$2')
    .replace(/import\s*\{\s*jest\s*\}\s*from\s*['"]vitest['"]/, "import { vi } from 'vitest'")
    .replace(/import\s*\{\s*([^}]*)\bjest\b([^}]*)\}\s*from\s*['"]vitest['"]/, (_a, a, b) => {
      const inner = `${a}vi${b}`.replace(/,\s*,/g, ',').replace(/^\s*,|,\s*$/g, '');
      return `import { ${inner} } from 'vitest'`;
    });
  if (next === content) return null;
  return next;
}

/**
 * SET 37c — full mock-API surface rewrite (0 tok): jest→vi PLUS bare
 * spyOn/fn → vi.spyOn/vi.fn fallback. Harness already binds bare names;
 * this is the mechanical suite-text fallback. Returns null when unchanged.
 */
export function rewriteMockApiSurface(content: string): string | null {
  let next = rewriteJestToVi(content) ?? content;
  if (/\bspyOn\s*\(/.test(next) && !/\bvi\.spyOn\s*\(/.test(next) && !/import\s*\{[^}]*\bspyOn\b/.test(next)) {
    next = next.replace(/\bspyOn\s*\(/g, 'vi.spyOn(');
  }
  // Bare mock-factory `fn(` only — skip when a local fn binding exists.
  if (
    /\bfn\s*\(/.test(next)
    && !/\bvi\.fn\s*\(/.test(next)
    && !/import\s*\{[^}]*\bfn\b/.test(next)
    && !/\b(?:const|let|var|function)\s+fn\b/.test(next)
  ) {
    next = next.replace(/(^|[^.\w$])fn\s*\(/g, '$1vi.fn(');
  }
  if (next === content) return null;
  return next;
}

/**
 * Syntax gates — sucrase is already aboard; use it as the IR freeze gate the
 * doctrine requires (Tier 2 uses the ts compiler; this is its browser twin).
 */
export function suiteSyntaxError(content: string): string | null {
  try {
    transform(content, { transforms: ['typescript', 'imports'] });
    return null;
  } catch (e) {
    return e instanceof Error ? e.message : String(e);
  }
}

/** Pinpoint syntactically broken case BODIES (matches harness assembly). */
export function caseSyntaxErrors(cases: { name: string; body: string }[]): { name: string; error: string }[] {
  return cases.flatMap(c => {
    try {
      transform(`async function __t() {
${c.body}
}`, { transforms: ['typescript'] });
      return [];
    } catch (e) {
      return [{ name: c.name, error: e instanceof Error ? e.message : String(e) }];
    }
  });
}

/**
 * Direct evaluator — for hosts where dynamic code is allowed (Node tests,
 * the sandboxed extension page). Runs the program in a fresh Function scope.
 */
export function makeEvalSuiteRunner(): SuiteRunner {
  return async (files, test) => {
    const { program, spans } = assembleTestProgram(files, test);
    const g = globalThis as Record<string, unknown>;
    delete g.__RHA_RUN__;
    delete g.__RHA_LINE_TABLE__;
    delete g.__RHA_LAST__;
    try {
      // eslint-disable-next-line no-new-func -- allowlisted Node suite runner (SET 40a/40b)
      new Function(program)();
    } catch (e) {
      // SET 40a — gate infra (CSP) must never be attributed to the candidate.
      if (isGateInfrastructureError(e)) {
        return { total: 0, failures: [], crashed: GATE_UNAVAILABLE };
      }
      // SET 6a — malformed regex literals fail at Function construct time
      // (nested bodies are parsed eagerly), not inside __RHA_RUN__.
      // SET 36a — attribute construct-time crashes via the line-offset table.
      return {
        total: 0,
        failures: [],
        crashed: formatExecutionCrash(e, null, spans),
      };
    }
    const run = g.__RHA_RUN__ as (() => Promise<SuiteRunResult>) | undefined;
    if (!run) return { total: 0, failures: [], crashed: 'program did not define __RHA_RUN__' };
    try {
      return await run();
    } finally {
      delete g.__RHA_RUN__;
      delete g.__RHA_LINE_TABLE__;
      delete g.__RHA_LAST__;
    }
  };
}

/** Assemble the self-contained module-probe program (shared by sync + sandbox). */
export function assembleModuleProbeProgram(files: GeneratedFile[], targetPath: string): string {
  const key = targetPath.replace(/\.(ts|js)$/, '');
  const modules: string[] = [];
  const register = (path: string, source: string) => {
    const k = path.replace(/\.(ts|js)$/, '');
    modules.push(registerModuleSource(k, transformModuleJs(path, source)));
  };
  for (const f of files) register(f.path, f.content);
  return [
    '"use strict";',
    HARNESS,
    RESOLVER,
    String.raw`
const __registry = new Map();
const __instances = new Map();
function __register(key, factory) { __registry.set(key, factory); }
function __require(from, spec) {
  const key = __resolve(from, spec);
  if (key === 'vitest') return { describe, it, test, expect, beforeEach, afterEach, vi, jest, spyOn, fn };
  if (__instances.has(key)) return __instances.get(key).exports;
  const factory = __registry.get(key);
  if (!factory) throw new Error('unresolved import ' + spec + ' (from ' + from + ')');
  const module = { exports: {} };
  __instances.set(key, module);
  factory((s) => __require(key, s), module, module.exports);
  return module.exports;
}
`,
    modules.join('\n'),
    `globalThis.__RHA_PROBE__ = function () {
  try { __require('.', ${JSON.stringify('./' + key)}); return null; }
  catch (e) { return e instanceof Error ? e.message : String(e); }
};`,
  ].join('\n');
}

/**
 * SET 6a — probe one module (+ its dep closure from `files`) with no test.
 * Returns the eval crash message, or null if the module loads clean.
 * SET 40a/47a — gate infra → GATE_UNAVAILABLE (never attributed to candidate).
 */
export function probeModuleEval(files: GeneratedFile[], targetPath: string): string | null {
  const program = assembleModuleProbeProgram(files, targetPath);
  const g = globalThis as Record<string, unknown>;
  delete g.__RHA_PROBE__;
  try {
    // eslint-disable-next-line no-new-func -- allowlisted Node module probe (SET 40a/40b)
    new Function(program)();
    const probe = g.__RHA_PROBE__ as (() => string | null) | undefined;
    return probe ? probe() : 'probe did not define __RHA_PROBE__';
  } catch (e) {
    // SET 40a — gate infra must never be attributed to the candidate.
    return gateOrParseMessage(e);
  } finally {
    delete g.__RHA_PROBE__;
  }
}

/**
 * SET 47a — async module probe. Uses sandbox channel when set; else sync path
 * with GATE_UNAVAILABLE discrimination.
 */
export async function probeModuleEvalAsync(
  files: GeneratedFile[],
  targetPath: string,
): Promise<string | null> {
  const program = assembleModuleProbeProgram(files, targetPath);
  if (moduleEvalProbe) {
    try {
      return await moduleEvalProbe(program);
    } catch (e) {
      return gateOrParseMessage(e);
    }
  }
  return probeModuleEval(files, targetPath);
}

/** SET 47a — treat GATE_UNAVAILABLE as "probe skipped" (fail open). */
export function probeErrOrNull(err: string | null): string | null {
  if (err == null || err === GATE_UNAVAILABLE) return null;
  return err;
}

/**
 * SET 64d — runtime trace: deterministic replay of literal-arg calls against
 * the real module, capturing return/thrown values at the symbol boundary.
 * Piggybacks the module-probe channel: the trace program's __RHA_PROBE__
 * returns `TRACE:<json>` instead of an error string, so the sandboxed host
 * path needs no protocol change. Any failure → null (trace omitted, fail open).
 */
export interface TraceCall { symbol: string; argsSrc: string }
export interface TraceLine { call: string; outcome: string }

const TRACE_MARK = 'TRACE:';

function assembleTraceProgram(
  files: GeneratedFile[],
  targetPath: string,
  calls: TraceCall[],
): string {
  const base = assembleModuleProbeProgram(files, targetPath);
  const key = targetPath.replace(/\.(ts|js)$/, '');
  return base + String.raw`
globalThis.__RHA_PROBE__ = function () {
  const CALLS = ${JSON.stringify(calls)};
  const MARK = ${JSON.stringify(TRACE_MARK)};
  const out = [];
  function ser(v) {
    if (typeof v === 'function') return '(function)';
    if (v && typeof v.then === 'function') return '(promise)';
    if (typeof v === 'bigint') return String(v) + 'n';
    try {
      const s = JSON.stringify(v, function (k, x) {
        if (typeof x === 'function') return '(function)';
        if (typeof x === 'bigint') return String(x) + 'n';
        return x;
      });
      return String(s).slice(0, 80);
    } catch (e) { return '(unserializable)'; }
  }
  let mod;
  try { mod = __require('.', ${JSON.stringify('./' + key)}); }
  catch (e) {
    return MARK + JSON.stringify([{ call: '(module load)', outcome: 'threw ' + (e && e.message ? e.message : String(e)).slice(0, 120) }]);
  }
  for (const c of CALLS) {
    const call = c.symbol + '(' + c.argsSrc + ')';
    try {
      const args = (0, eval)('[' + c.argsSrc + ']');
      const fn = mod[c.symbol];
      if (typeof fn !== 'function') { out.push({ call: call, outcome: 'is not a function (' + typeof fn + ')' }); continue; }
      out.push({ call: call, outcome: '→ ' + ser(fn.apply(null, args)) });
    } catch (e) {
      out.push({ call: call, outcome: '→ threw ' + (e && e.message ? e.message : String(e)).slice(0, 120) });
    }
  }
  return MARK + JSON.stringify(out);
};`;
}

function parseTraceResult(raw: string | null): TraceLine[] | null {
  if (!raw || !raw.startsWith(TRACE_MARK)) return null;
  try {
    const arr: unknown = JSON.parse(raw.slice(TRACE_MARK.length));
    return Array.isArray(arr) ? (arr as TraceLine[]) : null;
  } catch {
    return null;
  }
}

/** Sync trace replay (Node / eval-allowed hosts). 0 tokens. */
export function traceSymbolCalls(
  files: GeneratedFile[],
  targetPath: string,
  calls: TraceCall[],
): TraceLine[] | null {
  if (!calls.length) return null;
  const program = assembleTraceProgram(files, targetPath, calls);
  const g = globalThis as Record<string, unknown>;
  delete g.__RHA_PROBE__;
  try {
    // eslint-disable-next-line no-new-func -- allowlisted trace replay (SET 64d)
    new Function(program)();
    const probe = g.__RHA_PROBE__ as (() => string) | undefined;
    return probe ? parseTraceResult(probe()) : null;
  } catch {
    return null;
  } finally {
    delete g.__RHA_PROBE__;
  }
}

/** Async trace replay — sandbox channel when wired, else sync path. */
export async function traceSymbolCallsAsync(
  files: GeneratedFile[],
  targetPath: string,
  calls: TraceCall[],
): Promise<TraceLine[] | null> {
  if (!calls.length) return null;
  if (moduleEvalProbe) {
    try {
      return parseTraceResult(await moduleEvalProbe(assembleTraceProgram(files, targetPath, calls)));
    } catch {
      return null;
    }
  }
  return traceSymbolCalls(files, targetPath, calls);
}

/** Strip SET 35a/36a execution-position wrapper so probes can match program crashes. */
function crashCoreMessage(msg: string): string {
  const first = msg.split('\n')[0] ?? '';
  if (!/^crash while (?:executing|loading) /.test(first)) return msg;
  const lines = msg.split('\n').filter(l =>
    !/^crash while (?:executing|loading) /.test(l) && !/^\s*at\s/.test(l));
  return lines.join('\n').trim() || msg;
}

function sameCrashClass(a: string, b: string): boolean {
  const aa = crashCoreMessage(a);
  const bb = crashCoreMessage(b);
  if (/Invalid regular expression/i.test(aa) && /Invalid regular expression/i.test(bb)) return true;
  const idA = /Identifier '([A-Za-z_$][\w$]*)' has already been declared/i.exec(aa);
  const idB = /Identifier '([A-Za-z_$][\w$]*)' has already been declared/i.exec(bb);
  if (idA && idB) return idA[1] === idB[1];
  return aa.split('\n')[0]!.slice(0, 60) === bb.split('\n')[0]!.slice(0, 60);
}

/**
 * SET 20a — probe every implementation module (full artifact registry).
 * Returns the first eval crash message, or null if all modules load clean.
 */
export function probeWholeArtifactEval(files: GeneratedFile[]): string | null {
  for (const f of files) {
    if (/\.test\.(ts|js)$/.test(f.path)) continue;
    const err = probeErrOrNull(probeModuleEval(files, f.path));
    if (err) return err;
  }
  return null;
}

/** Resolve a module's import closure within `all` (static from/import specs). */
function moduleClosure(all: GeneratedFile[], targetPath: string): GeneratedFile[] {
  const byKey = new Map(all.map(f => [f.path.replace(/\.(ts|js)$/, ''), f]));
  const out = new Map<string, GeneratedFile>();
  const visit = (path: string) => {
    if (out.has(path)) return;
    const f = all.find(x => x.path === path);
    if (!f) return;
    out.set(path, f);
    const key = path.replace(/\.(ts|js)$/, '');
    for (const m of f.content.matchAll(/from\s+['"](\.[^'"]+)['"]/g)) {
      const spec = m[1]!.replace(/\.(ts|js)$/, '');
      // Resolve relative to importer key (simplified — same-dir ./x or ../x).
      const importerDir = key.includes('/') ? key.slice(0, key.lastIndexOf('/')) : '';
      let resolved = spec;
      if (spec.startsWith('./')) {
        resolved = importerDir ? `${importerDir}/${spec.slice(2)}` : spec.slice(2);
      } else if (spec.startsWith('../')) {
        const ups = spec.match(/^(?:\.\.\/)+/)![0].length / 3;
        const rest = spec.replace(/^(?:\.\.\/)+/, '');
        const parts = importerDir.split('/').filter(Boolean);
        resolved = [...parts.slice(0, Math.max(0, parts.length - ups)), rest].join('/');
      }
      const dep = byKey.get(resolved);
      if (dep) visit(dep.path);
    }
  };
  visit(targetPath);
  return [...out.values()];
}

/** Result of a detailed attribution attempt — carries miss diagnostics when no probe matches. */
export interface AttributeEvalCrashResult {
  file: string | null;
  /** Present only when the invariant trips: program crashed but no single-module probe reproduced it. */
  miss?: string;
}

/**
 * SET 25c — probe the suite file against the FULL program registry (impl +
 * suite), the same set `buildTestProgram` bundles. Exposed standalone for
 * callers (e.g. 25d quarantine heals) that want to check "does the suite
 * reproduce this crash once every real import resolves" without walking the
 * whole `attributeEvalCrashDetailed` ladder.
 */
export function probeSuiteInProgram(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage: string,
): boolean {
  const all = [...files, test];
  const err = probeModuleEval(all, test.path);
  return !!err && sameCrashClass(err, crashMessage);
}

/**
 * SET 6a/25c — when the suite crashes at eval with no module attribution,
 * find the true offending module. For each candidate (every impl `files`
 * entry, THEN the suite — files first so a suite that merely *imports* a
 * broken impl file is never blamed ahead of the impl file itself):
 *  1. Probe with the candidate's own static import closure (narrow registry)
 *     — a defect native to the candidate (bad literal, failed transpile)
 *     throws immediately and can't be masked by an unrelated broken sibling
 *     module (registering an unrelated syntactically-invalid file in the
 *     SAME probe would itself crash `new Function`, contaminating the read).
 *  2. If the narrow probe only reports an `unresolved import` artifact (the
 *     closure's simplified static resolver under-included a real dependency
 *     — an orphan the executed program still bundles), escalate that ONE
 *     candidate to the FULL program registry so its real crash — not the
 *     resolution artifact — can be reproduced and attributed.
 * Every file in `files` + `test` is probed at least once, so the probe set
 * is always the exact program set `buildTestProgram` assembles.
 */
export function attributeEvalCrashDetailed(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage: string,
): AttributeEvalCrashResult {
  const all = [...files, test];
  const probed = new Set<string>();

  // SET 36b — known transpile placeholder is the PRESUMED offender; never
  // park crash|unattributed while a broken file sits in the program.
  const placeholders = findTranspilePlaceholders(files);
  if (placeholders.length === 1) {
    return { file: placeholders[0]!.path };
  }

  // SET 36a — crash while loading path:line → attribute without probes.
  const execPos = parseExecutionCrash(crashMessage);
  if (execPos?.localLine != null && execPos.module) {
    const hint = execPos.module.endsWith('.ts') || execPos.module.endsWith('.js')
      ? execPos.module
      : `${execPos.module}.ts`;
    const hit = all.find(f => f.path === hint || f.path.replace(/\.(ts|js)$/, '') === execPos.module);
    if (hit) return { file: hit.path };
  }

  // SET 36a — stack program line → module via line-offset table.
  const line = extractAnonymousProgramLine(crashMessage);
  if (line != null) {
    const { spans } = assembleTestProgram(files, test);
    const loc = locateProgramLine(spans, line);
    if (loc) {
      const hit = all.find(f => f.path === loc.path);
      if (hit) return { file: hit.path };
    }
  }

  // SET 36b — multiple placeholders: prefer one named by stack/exec pos, else first.
  if (placeholders.length > 1) {
    if (execPos?.module && execPos.module !== '(unknown)') {
      const hint = execPos.module.endsWith('.ts') || execPos.module.endsWith('.js')
        ? execPos.module
        : `${execPos.module}.ts`;
      const hit = placeholders.find(f => f.path === hint || f.path.replace(/\.(ts|js)$/, '') === execPos.module);
      if (hit) return { file: hit.path };
    }
    return { file: placeholders[0]!.path };
  }

  // SET 35a — if execution-position already names a module path, prefer it
  // when that file is in the program set (still verify via probe when possible).
  if (execPos?.module && execPos.module !== '(unknown)' && execPos.module !== '(suite)') {
    const hint = execPos.module.endsWith('.ts') || execPos.module.endsWith('.js')
      ? execPos.module
      : `${execPos.module}.ts`;
    const hit = all.find(f => f.path === hint || f.path.replace(/\.(ts|js)$/, '') === execPos.module);
    if (hit) {
      probed.add(hit.path);
      const narrow = probeModuleEval(moduleClosure(all, hit.path), hit.path);
      if (!narrow || sameCrashClass(narrow, crashMessage) || execPos.caseName) {
        return { file: hit.path };
      }
    }
  }

  const tryCandidate = (f: GeneratedFile): boolean => {
    probed.add(f.path);
    const closure = moduleClosure(all, f.path);
    const narrow = probeModuleEval(closure.length ? closure : [f], f.path);
    if (narrow && sameCrashClass(narrow, crashMessage)) return true;
    if (narrow != null && /^unresolved import /.test(narrow)) {
      const full = probeModuleEval(all, f.path);
      if (full && sameCrashClass(full, crashMessage)) return true;
    }
    return false;
  };

  for (const f of files) {
    if (tryCandidate(f)) return { file: f.path };
  }
  if (tryCandidate(test)) return { file: test.path };

  const programPaths = all.map(f => f.path);
  const unprobed = programPaths.filter(p => !probed.has(p));
  const diff = unprobed.length ? unprobed.join(', ') : 'none (all probed clean)';
  return {
    file: null,
    miss: `attribution-miss: program crashed, ${probed.size}/${programPaths.length} probes clean — probe set diff: ${diff}`,
  };
}

/** Thin wrapper over {@link attributeEvalCrashDetailed} for call sites that only need the file. */
export function attributeEvalCrash(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage: string,
): string | null {
  return attributeEvalCrashDetailed(files, test, crashMessage).file;
}

// ---------------------------------------------------------------------------
// SET 31b — Recursive seam-fault attribution
//
// When the program crashes and every single-module probe is clean, the fault
// must live in the JOIN between modules (JS `/` lex is context-dependent —
// per-module parse validity does NOT compose across seams). SET 31a's
// statement-isolated wrapper prevents these seams in production; 31b is the
// safety net that ATTRIBUTES the pair O(log n) and offers 0-token spot-heals
// via the delimiter oracle so any regression is diagnosed, not swallowed as
// `attribution-miss`.
// ---------------------------------------------------------------------------

/**
 * SET 31b — Binary-search a linear list of module sources for the minimal
 * adjacent pair whose RAW concatenation (no statement isolation) trips
 * `evaluate`, given that `evaluate([])` is clean and `evaluate(all)` crashes.
 *
 * `evaluate` returns null when the given prefix loads clean, a truthy crash
 * message otherwise. It receives the module sources in the SAME ORDER as
 * `sources`; the returned pair indices refer to those positions.
 *
 * Invariant: exactly one adjacent boundary `(i, i+1)` with `evaluate(prefix[0..i])`
 * clean and `evaluate(prefix[0..i+1])` crashed. If the crash is intrinsic to
 * a single module (module 0 alone crashes) or the concat is monotonically
 * broken, this returns `null` — caller falls back to single-module attribution.
 *
 * Complexity: O(log n) evaluator calls; 0 LLM tokens.
 */
export function findBoundaryPair<T>(
  sources: T[],
  evaluate: (prefix: T[]) => string | null,
): { left: number; right: number; leftCleanPrefix: T[]; crashMessage: string } | null {
  if (sources.length < 2) return null;
  const firstAlone = evaluate([sources[0]!]);
  if (firstAlone != null) return null; // module 0 crashes solo — not a seam.
  const whole = evaluate(sources);
  if (whole == null) return null; // no crash to attribute.
  // Binary-search the largest prefix that stays clean.
  let lo = 1;
  let hi = sources.length;
  // Invariant: evaluate(prefix[0..lo]) is clean; evaluate(prefix[0..hi]) crashes.
  // We stop when hi === lo + 1 → boundary between (lo-1, lo).
  while (hi - lo > 1) {
    const mid = (lo + hi) >>> 1;
    const err = evaluate(sources.slice(0, mid));
    if (err == null) lo = mid;
    else hi = mid;
  }
  return {
    left: lo - 1,
    right: lo,
    leftCleanPrefix: sources.slice(0, lo),
    crashMessage: whole,
  };
}

/**
 * SET 31b — attribute a program-level crash to a specific adjacent module
 * pair by evaluating raw (non-isolated) concatenation prefixes. When a pair
 * is found, apply the delimiter oracle to the tail of A and/or the head of B
 * to produce byte-minimal spot-edits; if the re-probed WHOLE program heals,
 * return the fixes.
 *
 * Returns `null` when the fault is not a genuine seam (e.g. single-module
 * intrinsic crash, or every prefix already clean — the isolation wrapper is
 * already suppressing whatever was concatenating badly).
 *
 * The order-of-modules argument matches `buildTestProgram`: impl files first,
 * suite last.
 */
/** Delimiter-oracle result shape (mirrors delimiterOracle.applyDelimiterOracle). */
export interface BoundaryOracleResult {
  content: string;
  classKey: string;
  edits: number;
}

export type BoundaryOracle = (content: string, errorHint?: string) => BoundaryOracleResult | null;

/**
 * Return the RAW-concatenation program used to LOCATE seams. Deliberately
 * bypasses `registerModuleSource` isolation so the binary-search evaluator
 * can reproduce whatever the pre-31a build style would have crashed on.
 */
function buildRawProbeProgram(prefix: { key: string; js: string }[]): string {
  const body = prefix
    .map(m => `__register(${JSON.stringify(m.key)}, function (require, module, exports) {\n${m.js}\n});`)
    .join('\n');
  return [
    '"use strict";',
    HARNESS,
    RESOLVER,
    String.raw`
const __registry = new Map();
const __instances = new Map();
function __register(key, factory) { __registry.set(key, factory); }
`,
    body,
  ].join('\n');
}

/**
 * SET 31b — Attribute a program-level crash to a specific adjacent module
 * pair by evaluating raw (non-isolated) concatenation prefixes. When a pair
 * is found, invoke the caller-supplied delimiter `oracle` on the tail of A
 * and/or the head of B to produce byte-minimal spot-edits; if the re-probed
 * WHOLE program (under 31a isolation) heals, return the fixes.
 *
 * The oracle is injected to avoid a static import cycle with `delimiterOracle`
 * (which already depends on `testExec` for parse checks). Callers that don't
 * have the oracle can pass `null` to get seam ATTRIBUTION only (no fixes).
 *
 * Returns `null` when the fault is not a genuine seam (single-module intrinsic
 * crash, or every raw prefix already clean — nothing to heal).
 *
 * The order-of-modules argument matches `buildTestProgram`: impl files first,
 * suite last.
 */
export function attributeBoundaryFault(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage: string,
  oracle?: BoundaryOracle | null,
): {
  pair: [string, string] | null;
  fixes?: { path: string; content: string; note: string }[];
  event: string;
} | null {
  const all = [...files, test];
  if (all.length < 2) return null;

  const transformed = all.map(f => ({
    path: f.path,
    key: f.path.replace(/\.(ts|js)$/, ''),
    js: transformModuleJs(f.path, f.content),
  }));

  const evalRawConcat = (prefix: typeof transformed): string | null => {
    try {
      // eslint-disable-next-line no-new-func -- allowlisted Node raw-concat probe (SET 40a/40b)
      new Function(buildRawProbeProgram(prefix));
      return null;
    } catch (e) {
      // SET 40a — gate infra must never be attributed to the candidate.
      return gateOrParseMessage(e);
    }
  };

  const boundary = findBoundaryPair(transformed, evalRawConcat);
  if (!boundary) return null;
  const A = all[boundary.left]!;
  const B = all[boundary.right]!;
  const seamMsg = boundary.crashMessage;
  const event = `boundary-fault: ${A.path} ⨝ ${B.path}`;

  if (!oracle) return { pair: [A.path, B.path], event };

  // Whole-program probe (31a-isolated) — a genuine heal here proves the
  // fix survives the same wrapping the runner uses.
  const trial = (candidates: { path: string; content: string; note: string }[]): boolean => {
    const patched = all.map(f => {
      const hit = candidates.find(c => c.path === f.path);
      return hit ? { path: f.path, content: hit.content } : f;
    });
    const err = probeModuleEval(patched, test.path);
    if (err && sameCrashClass(err, seamMsg)) return false;
    // Also confirm the raw concat is healed (catches seams the isolated
    // wrapper alone was masking).
    const patchedT = patched.map(f => ({
      path: f.path,
      key: f.path.replace(/\.(ts|js)$/, ''),
      js: transformModuleJs(f.path, f.content),
    }));
    const rawErr = evalRawConcat(patchedT);
    if (rawErr && sameCrashClass(rawErr, seamMsg)) return false;
    return true;
  };

  const oracleA = oracle(A.content, seamMsg);
  const oracleB = oracle(B.content, seamMsg);
  const mkFix = (
    file: GeneratedFile,
    r: BoundaryOracleResult,
    side: 'tail' | 'head',
  ) => ({
    path: file.path,
    content: r.content,
    note: `delimiter oracle seam-heal (${r.classKey}, ${r.edits} edit${r.edits === 1 ? '' : 's'}) on ${file.path} ${side}`,
  });

  if (oracleA) {
    const cand = mkFix(A, oracleA, 'tail');
    if (trial([cand])) return { pair: [A.path, B.path], fixes: [cand], event };
  }
  if (oracleB) {
    const cand = mkFix(B, oracleB, 'head');
    if (trial([cand])) return { pair: [A.path, B.path], fixes: [cand], event };
  }
  if (oracleA && oracleB) {
    const combo = [mkFix(A, oracleA, 'tail'), mkFix(B, oracleB, 'head')];
    if (trial(combo)) return { pair: [A.path, B.path], fixes: combo, event };
  }
  return { pair: [A.path, B.path], event };
}

// ---------------------------------------------------------------------------
// SET 34a — Seam dump (±120 chars around each concatenation boundary)
// ---------------------------------------------------------------------------

export type { SeamDump };

/**
 * Dump ±radius characters of the concatenated program around EACH adjacent
 * module boundary, labeled for report/export. Uses the same registration
 * order as `buildTestProgram` (impl files then suite). Default `isolated`
 * matches production (31a IIFE); pass `isolated: false` to inspect raw joins.
 */
export function dumpConcatenationSeams(
  files: GeneratedFile[],
  test: GeneratedFile,
  opts?: { radius?: number; isolated?: boolean },
): SeamDump[] {
  const radius = opts?.radius ?? SEAM_DUMP_RADIUS;
  const isolated = opts?.isolated !== false;
  const all = [...files, test];
  if (all.length < 2) return [];

  const pieces = all.map(f => {
    const key = f.path.replace(/\.(ts|js)$/, '');
    const js = transformModuleJs(f.path, f.content);
    return isolated
      ? registerModuleSource(key, js)
      : `__register(${JSON.stringify(key)}, function (require, module, exports) {\n${js}\n});`;
  });

  const concat = pieces.join('\n');
  const dumps: SeamDump[] = [];
  let pos = 0;
  for (let i = 0; i < pieces.length - 1; i++) {
    pos += pieces[i]!.length;
    // Boundary is the joining `\n` at `pos`.
    const start = Math.max(0, pos - radius);
    const end = Math.min(concat.length, pos + 1 + radius);
    let snippet = concat.slice(start, end);
    if (start > 0) snippet = '…' + snippet;
    if (end < concat.length) snippet = snippet + '…';
    dumps.push({
      leftPath: all[i]!.path,
      rightPath: all[i + 1]!.path,
      snippet,
    });
    pos += 1; // skip the join newline
  }
  return dumps;
}

// ---------------------------------------------------------------------------
// SET 38b — ddmin over module-IIFE sets (quarantine path for Integration)
// ---------------------------------------------------------------------------

/**
 * SET 38b — delta-debug the module set via O(n log n) `new Function` parses.
 * Event is `minimal failing set: [A, B]` or `ddmin-failure: …`.
 */
export function ddminMinimalFailingSet(
  files: GeneratedFile[],
  crashMessage?: string,
): { set: string[]; event: string } {
  return ddminMinimalFailingSetWithEval(
    files,
    subset => {
      const mods = subset
        .map(s => files.find(f => f.path === s.path))
        .filter((f): f is GeneratedFile => !!f);
      const err = programParseError(mods);
      // SET 40a — GATE_UNAVAILABLE is not a candidate parse failure.
      return err === GATE_UNAVAILABLE ? null : err;
    },
    crashMessage,
  );
}

/**
 * SET 38b — true when quarantine has a crash and every single-module probe
 * is clean (the ddmin trigger; subsumes 31b's rarely-firing boundary-fault path).
 */
export function ddminTriggerHolds(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage?: string,
): boolean {
  if (!crashMessage) return false;
  const all = [...files, test];
  return all.every(f => probeModuleEval(all, f.path) == null);
}

/**
 * SET 38b — quarantine entry: when the ddmin trigger holds, MUST emit either
 * `minimal failing set:` or `ddmin-failure` (silent non-fire is a defect).
 * Returns null only when the trigger does NOT hold.
 */
export function ddminForQuarantine(
  files: GeneratedFile[],
  test: GeneratedFile,
  crashMessage?: string,
): { set: string[]; event: string; fixes?: { path: string; content: string; note: string }[] } | null {
  if (!ddminTriggerHolds(files, test, crashMessage)) return null;

  const all = [...files, test];
  // Trigger held — always emit (never silent).
  const result = ddminMinimalFailingSet(all, crashMessage);
  if (!/^minimal failing set:|^ddmin-failure/.test(result.event)) {
    return { set: [], event: ddminFailureEvent('emission contract violated') };
  }
  return result;
}

/**
 * SET 38b — delimiter-oracle over minimal-set members' FULL text, then
 * re-check program parse. Returns fixes that strictly heal the parse.
 */
export function ddminHealWithOracle(
  files: GeneratedFile[],
  minimalPaths: string[],
  oracle: (content: string, errorHint?: string) => { content: string; classKey: string; edits: number } | null,
  crashMessage?: string,
): { path: string; content: string; note: string }[] {
  const candidates = ddminHealMinimalSet(files, minimalPaths, oracle, crashMessage);
  if (candidates.length === 0) return [];
  const patched = files.map(f => {
    const hit = candidates.find(c => c.path === f.path);
    return hit ? { path: f.path, content: hit.content } : f;
  });
  if (programParseError(patched) != null) {
    // Keep fixes that individually improve their file's solo parse, even if
    // the combo still fails — Integration may iterate.
    return candidates.filter(c => {
      const solo = files.map(f => f.path === c.path ? { path: c.path, content: c.content } : f);
      const before = programParseError(files);
      const after = programParseError(solo);
      return before != null && after == null;
    });
  }
  return candidates;
}
