/**
 * SET 77 — data inventory (Andy, 2026-07-27: "every detail that we capture,
 * take inventory as to whether we are using the data. and whether that data
 * is decipherable. like if we just have {parse; $token/.mil} or {trope: 50}
 * that's useless").
 *
 * Two standing rules, enforced here:
 *  1. NO WRITE-ONLY CAPTURE — a field we record must be read by something.
 *  2. NO UNDECIPHERABLE OUTPUT — anything shown to a model or a human states
 *     its denominator and its meaning. Bare counts and bare ratios fail.
 *
 * The audit that produced this set found three dead fields: the draw BODIES
 * (captured, never read), `exhibitHash` (captured, never read), and
 * handler-candidate `fixtures` (assembled, never read).
 */
import { describe, expect, it } from 'vitest';
import { buildEpochDigest, formatDigest } from '../src/tier1/watcher';
import { promoteLessonsToHandlerCandidates } from '../src/tier1/handlerCandidate';
import { Tier1Supergit } from '../src/tier1/supergit';
import { corpseCheck } from '../src/tier1/metaSb';

const DEAD_BODY = 'export function add(a: number, b: number): number { return a - b; }';
const LIVE_BODY = 'export function add(a: number, b: number): number { return a + b; }';

describe('SET 77 rule 1 — nothing captured is write-only', () => {
  it('corpse hashes are read as deterministic candidate rejections', () => {
    const run = new Set<string>();
    const persisted = new Set(['dead-shape']);
    expect(corpseCheck('dead-shape', run, persisted)).toBe('meta');
    run.add('fresh-shape');
    expect(corpseCheck('fresh-shape', run, persisted)).toBe('run');
  });

  it('handler-candidate fixtures exist and carry a real before→after pair', () => {
    const promoted = promoteLessonsToHandlerCandidates([
      { classKey: 'assertion|toBe', editShape: 'reset swap-operator', beforeSnippet: DEAD_BODY, afterSnippet: LIVE_BODY },
      { classKey: 'assertion|toBe', editShape: 'reset swap-operator', beforeSnippet: DEAD_BODY, afterSnippet: LIVE_BODY },
      { classKey: 'assertion|toBe', editShape: 'reset swap-operator', beforeSnippet: DEAD_BODY, afterSnippet: LIVE_BODY },
    ]);
    expect(promoted).toHaveLength(1);
    // Previously assembled and read by NOTHING; now the runner emits it.
    expect(promoted[0]!.fixtures[0]).toEqual({ before: DEAD_BODY, after: LIVE_BODY });
  });
});

describe('SET 77 rule 2 — output is decipherable', () => {
  const sg = new Tier1Supergit();
  const f1 = sg.recordNode({ type: 'spec', featureId: 'F1', summary: 'F1 add' });
  const f2 = sg.recordNode({ type: 'spec', featureId: 'F2', summary: 'F2 double' });
  sg.recordEdge(f1, f2);
  const e1 = sg.recordNode({ type: 'error', featureId: 'F1', bugClass: 'assertion|toBe', summary: 'expected 5' });
  sg.recordNode({ type: 'repair', featureId: 'F1', causeId: e1, bugClass: 'assertion|toBe', status: 'healed', summary: 'L1 substrate (0 tok): x' });
  sg.recordNode({ type: 'error', featureId: 'F1', bugClass: 'assertion|toBe', summary: 'expected 5 again' });
  const text = formatDigest(buildEpochDigest({
    epoch: 'rha', rows: sg.allRows(), featureId: 'F1',
    artifact: [{ path: 'src/adder.ts', content: LIVE_BODY }],
  }));

  it('every number carries its denominator and its meaning', () => {
    // Layer mix: shares, not `L1=1 L2=0`.
    expect(text).toContain('1 of 1 were deterministic substrate fixes costing no tokens');
    // Recurrence: says what the number counts.
    expect(text).toContain('by number of separate sightings');
    // Oscillation: states the consequence in words.
    expect(text).toContain('the fix is not holding');
    // Blast radius: says what the arrow meant.
    expect(text).toContain('changing F1 affects 1 dependent node');
    // Artifact: says what the bytes and exports are.
    expect(text).toMatch(/src\/adder\.ts is \d+ bytes and exports add/);
  });

  it('no bare key:number fragments survive in model-facing text', () => {
    // The shapes Andy called out: `{trope: 50}` / `L1=3` / `F1→2` / `x(120b)`.
    expect(text).not.toMatch(/\bL[1-4]=\d/);
    expect(text).not.toMatch(/\w+→\d/);
    expect(text).not.toMatch(/\(\d+b:/);
    expect(text).not.toMatch(/×\d+(,|$)/);
  });

});

describe('SET 79 — the BUILD metric measures the build', () => {
  it('a node whose owned files were all accepted counts as built, even though its contract is born-red', async () => {
    const { runTier1Job } = await import('../src/tier1/runner');
    const { makeEvalSuiteRunner } = await import('../src/tier1/testExec');
    const spec = {
      title: 'Adder', prompt: 'adder',
      features: [{
        id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
        deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
        edgeCases: ['zero'], envVars: [],
        exports: [{ file: 'src/adder.ts', symbol: 'add' }],
        stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
      }],
    } as unknown as import('../src/core/types').FeatureSpec;
    const llm = {
      async encodeFeatures() { return spec; },
      async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
      async fixTestCases(_s: unknown, _f: unknown, req: { name: string }[]) {
        const n = req[0]!.name;
        return { cases: [{ name: n, kind: (n === 'zero' ? 'edge' : 'behavior') as 'edge' | 'behavior',
          body: n === 'zero' ? 'expect(add(7, 0)).toBe(7);' : 'expect(add(2, 3)).toBe(5);' }] };
      },
      // Builds fine, but WRONG — so it is never green on first measure.
      async generateImplementation() { return [{ path: 'src/adder.ts', content: DEAD_BODY }]; },
      async repair() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
    } as unknown as import('../src/core/types').LlmClient;

    const res = await runTier1Job({ prompt: 'adder', llm, runSuite: makeEvalSuiteRunner() });
    // The build DID succeed: one node, all owned files accepted.
    expect(res.metrics.nodesBuildable).toBe(1);
    expect(res.metrics.nodesBuilt).toBe(1);
    // …and it was NOT green on first measure, which is the normal case for a
    // born-red contract and must not be what BUILD scores.
    expect(res.metrics.nodesBuiltCleanFirstPass).toBe(0);
    const { reportScoresFromMetrics } = await import('../src/tier1/statsAggregate');
    const scores = reportScoresFromMetrics(res.metrics as unknown as Record<string, unknown>);
    expect(scores.scoreBuild).toBe(1); // 100% — the build worked
    // BUILD and RHA are now independent: the node still had to enter the
    // bounded loop and be healed there, which is what RHA scores.
    expect(res.metrics.boundedLoopNodes).toBe(1);
    expect(res.metrics.nodesHealed).toBe(1);
  });

  it('records predating the counter fall back to the old formula', async () => {
    const { reportScoresFromMetrics } = await import('../src/tier1/statsAggregate');
    expect(reportScoresFromMetrics({
      nodesTotal: 10, nodesBuiltCleanFirstPass: 3,
    }).scoreBuild).toBeCloseTo(0.3);
  });
});

describe('SET 80/81 — node-compliant repair + readable epochs', () => {
  it('the schema is DERIVED from stubs + the frozen contract, never drawn', async () => {
    const { buildNodeSchema, formatNodeSchema } = await import('../src/tier1/nodeRepair');
    const feature = {
      id: 'F1', name: 'add', files: ['src/adder.ts'],
      exports: [{ file: 'src/adder.ts', symbol: 'add' }],
      stubs: [{ path: 'src/adder.ts', content: 'export function add(a: number, b: number): number { throw new Error("stub"); }' }],
    } as unknown as import('../src/core/types').FeatureNode;
    const parts = { imports: [], cases: [{ name: 'sums', kind: 'behavior' as const, body: 'expect(add(2, 3)).toBe(5);' }] };
    const schema = buildNodeSchema(feature, parts, [{ path: 'src/util.ts', content: '' }]);
    expect(schema.signatures).toEqual(['add(a: number, b: number): number']);
    expect(schema.behaviors[0]).toEqual({ name: 'sums', assertion: 'expect(add(2, 3)).toBe(5);' });
    const text = formatNodeSchema(schema);
    expect(text).toContain('signatures are FIXED');
    expect(text).toContain('Required behaviors, as the frozen contract states them');
  });

  it('the dossier supplies node + schema + all three substrata with a repair-in-place order', async () => {
    const { buildNodeRepairDossier, buildNodeSchema } = await import('../src/tier1/nodeRepair');
    const feature = {
      id: 'F1', name: 'add', files: ['src/adder.ts'],
      exports: [{ file: 'src/adder.ts', symbol: 'add' }],
      stubs: [{ path: 'src/adder.ts', content: 'export function add(a: number, b: number): number { throw new Error("stub"); }' }],
    } as unknown as import('../src/core/types').FeatureNode;
    const d = buildNodeRepairDossier({
      schema: buildNodeSchema(feature, null, []),
      source: DEAD_BODY,
      focusSymbols: ['add'],
      substrate: 'classified as assertion|toBe',
      ledger: 'N0007 [error F1 assertion|toBe] expected 5',
      supercache: 'Shapes already tried and DEAD',
      findings: 'expected 5, received -1',
    });
    expect(d.whole).toBe(true);
    expect(d.text).toContain('REPAIR THIS NODE SO THAT IT COMPLIES WITH THE SCHEMA');
    expect(d.text).toContain('You are editing an existing artifact, not writing a new one');
    expect(d.text).toContain(DEAD_BODY);          // the node itself
    expect(d.text).toContain('SUBSTRATE');        // deterministic substrate
    expect(d.text).toContain('SUPERGIT');         // causal history
    expect(d.text).toContain('SUPERCACHE');       // run + cross-run memory
  });

  it('an oversized node is excerpted to the declarations under repair, not truncated blindly', async () => {
    const { formatNodeUnderRepair } = await import('../src/tier1/nodeRepair');
    const big = `export function other() {\n${'  const pad = 1;\n'.repeat(400)}}\n`
      + 'export function add(a: number, b: number): number { return a - b; }\n';
    const out = formatNodeUnderRepair(big, 'src/adder.ts', ['add']);
    expect(out).toContain('excerpted');
    expect(out).toContain('return a - b;');
    expect(out).not.toContain('const pad = 1;');
  });

  it('feature epochs close with successful/total and tone by outcome', async () => {
    const { t1EventToneCss } = await import('../src/tier1/eventTone');
    const all = t1EventToneCss({ phase: 'auth', message: 'epoch closed: 5/5 cases passing' });
    const some = t1EventToneCss({ phase: 'auth', message: 'epoch closed: 3/5 cases passing — 2 still failing after 4 passes' });
    const none = t1EventToneCss({ phase: 'auth', message: 'epoch closed: 0/5 cases passing — 5 still failing after 8 passes' });
    expect(some).toMatch(/friction/);   // dark orange
    expect(all).not.toBe(some);
    expect(none).not.toBe(some);
  });
});

describe('SET 82/83 — small-model budget + cold-start anchor', () => {
  it('advisory pages are hard-bounded and never outweigh the contract', async () => {
    const { UNION_PAGE_CAP } = await import('../src/tier1/watcher');
    const { STAGE_PAGE_POLICY } = await import('../src/tier1/superbuffer');
    // A 2B model reads what it is given first: contract before advisory.
    for (const stage of ['fill', 'build'] as const) {
      const order = STAGE_PAGE_POLICY[stage];
      expect(order.indexOf('union')).toBeGreaterThan(order.indexOf('contract') >= 0
        ? order.indexOf('contract') : order.indexOf('spec'));
    }
    const repair = STAGE_PAGE_POLICY.repair;
    expect(repair.indexOf('union')).toBeGreaterThan(repair.indexOf('exhibit'));
    expect(repair).not.toContain('meta');
    // Advisory ceilings are a fraction of the old 1400/1800.
    expect(UNION_PAGE_CAP).toBeLessThanOrEqual(400);
  });

  it('the class anchor is derived from the stub — function, class, and const forms', async () => {
    const { deterministicAnchorBody } = await import('../src/tier1/planSuite');
    const fnFeature = {
      stubs: [{ path: 'src/a.ts', content: 'export function add(a: number, b: string): number { throw new Error("stub"); }' }],
    } as unknown as import('../src/core/types').FeatureNode;
    expect(deterministicAnchorBody(fnFeature, 'add')).toBe("expect(() => add(1, 'x')).not.toThrow();");

    const classFeature = {
      stubs: [{ path: 'src/a.ts', content: 'export class Article { constructor(title: string, hits: number) { throw new Error("stub"); } }' }],
    } as unknown as import('../src/core/types').FeatureNode;
    expect(deterministicAnchorBody(classFeature, 'Article'))
      .toBe("expect(() => new Article('x', 1)).not.toThrow();");

    const constFeature = {
      stubs: [{ path: 'src/a.ts', content: 'export const LIMITS = { max: 1 };' }],
    } as unknown as import('../src/core/types').FeatureNode;
    expect(deterministicAnchorBody(constFeature, 'LIMITS')).toBe('expect(LIMITS).toBeDefined();');

    // Nothing derivable → null, and the model draw still happens.
    expect(deterministicAnchorBody({ stubs: [] } as unknown as import('../src/core/types').FeatureNode, 'x')).toBeNull();
  });

});

describe('SET 84 — a stage that never ran says so', () => {
  it('the funnel names where the run stopped, not just that counters are zero', async () => {
    const { runTier1Job } = await import('../src/tier1/runner');
    const { makeEvalSuiteRunner } = await import('../src/tier1/testExec');
    const spec = {
      title: 'Adder', prompt: 'adder',
      features: [{
        id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
        deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
        edgeCases: ['zero'], envVars: [],
        exports: [{ file: 'src/adder.ts', symbol: 'add' }],
        stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
      }],
    } as unknown as import('../src/core/types').FeatureSpec;
    // Every fill draw is unusable → nothing freezes → the ladder never runs.
    const llm = {
      async encodeFeatures() { return spec; },
      async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
      async fixTestCases(_s: unknown, _f: unknown, req: { name: string }[]) {
        return { cases: [{ name: req[0]!.name, kind: 'behavior' as const, body: '' }] };
      },
      async generateImplementation() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
      async repair() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
    } as unknown as import('../src/core/types').LlmClient;

    const res = await runTier1Job({ prompt: 'adder', llm, runSuite: makeEvalSuiteRunner() });
    // The substrate counters are all zero…
    expect(res.metrics.substrateAttempts).toBe(0);
    expect(res.metrics.nodesTotal).toBe(0);
    // …and the log says WHY, in words, rather than leaving a bare 0.
    const funnel = res.log.map(e => e.message).find(m => m.startsWith('funnel:'));
    expect(funnel).toBeTruthy();
    expect(funnel!).toMatch(/1 feature\(s\) planned → \d+ froze a contract/);
    expect(funnel!).toContain('entered the repair ladder');
    expect(funnel!).toContain('The repair ladder never ran, so the substrate had nothing to attempt');
  });

  it('a healthy run reports the funnel without the never-ran clause', async () => {
    const { runTier1Job } = await import('../src/tier1/runner');
    const { makeEvalSuiteRunner } = await import('../src/tier1/testExec');
    const spec = {
      title: 'Adder', prompt: 'adder',
      features: [{
        id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
        deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
        edgeCases: ['zero'], envVars: [],
        exports: [{ file: 'src/adder.ts', symbol: 'add' }],
        stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
      }],
    } as unknown as import('../src/core/types').FeatureSpec;
    const llm = {
      async encodeFeatures() { return spec; },
      async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
      async fixTestCases(_s: unknown, _f: unknown, req: { name: string }[]) {
        const n = req[0]!.name;
        return { cases: [{ name: n, kind: (n === 'zero' ? 'edge' : 'behavior') as 'edge' | 'behavior',
          body: n === 'zero' ? 'expect(add(7, 0)).toBe(7);' : 'expect(add(2, 3)).toBe(5);' }] };
      },
      async generateImplementation() { return [{ path: 'src/adder.ts', content: DEAD_BODY }]; },
      async repair() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
    } as unknown as import('../src/core/types').LlmClient;
    const res = await runTier1Job({ prompt: 'adder', llm, runSuite: makeEvalSuiteRunner() });
    const funnel = res.log.map(e => e.message).find(m => m.startsWith('funnel:'))!;
    expect(funnel).toContain('1 entered the repair ladder');
    expect(funnel).not.toContain('never ran');
    // And the substrate genuinely attempted work.
    expect(res.metrics.substrateAttempts).toBeGreaterThan(0);
  });
});

describe('SET 86 — an invalid regex is attributed, not parked', () => {
  it('attributes the offending file by searching for the literal in the message', async () => {
    const { classifyFailure, attemptMechanicalFix, crashRepairPrecondition } =
      await import('../src/tier1/substrate');
    // The exact shape from Andy's run: one malformed literal in one module.
    const BAD = String.raw`/\(\[\[)(.*?\)\]\)/g`;
    const msg = `Invalid regular expression: ${BAD}: Unmatched ')'`;
    const cls = classifyFailure('__suite__', msg);
    expect(cls.kind).toBe('regex-literal');
    // The pattern is captured from the message…
    expect(cls.detail.pattern).toBe(BAD);
    // …and before attribution there is no file, which is what parked features.
    expect(cls.detail.file).toBeUndefined();
    expect(crashRepairPrecondition(cls, [])).toBe(false);

    const artifact = [
      { path: 'src/other.ts', content: 'export const x = 1;' },
      { path: 'src/markdown.ts', content: `const re = ${BAD};\nexport function render() { return re; }` },
    ];
    const suite = { path: 'tests/markdown.test.ts', content: 'export {};' };
    attemptMechanicalFix(cls, artifact, suite, { title: 't', prompt: 'p', features: [] } as never);
    // Attribution happened by literal search — the crash is now repairable.
    expect(cls.detail.file).toBe('src/markdown.ts');
    expect(crashRepairPrecondition(cls, artifact, suite)).toBe(true);
  });

  it('prefers the implementation file when the literal appears in a test too', async () => {
    const { classifyFailure, attemptMechanicalFix } = await import('../src/tier1/substrate');
    const BAD = String.raw`/\(\[\[)(.*?\)\]\)/g`;
    const cls = classifyFailure('__suite__', `Invalid regular expression: ${BAD}: Unmatched ')'`);
    const artifact = [{ path: 'src/markdown.ts', content: `const re = ${BAD};` }];
    const suite = { path: 'tests/markdown.test.ts', content: `expect(String(${BAD})).toBe('x');` };
    attemptMechanicalFix(cls, artifact, suite, { title: 't', prompt: 'p', features: [] } as never);
    expect(cls.detail.file).toBe('src/markdown.ts');
  });
});

describe('SET 87 — no naked draws, and the relay names its target', () => {
  it('born-red surgery, freeze-gate redraw, and case-relay all carry a buffer', async () => {
    const { runTier1Job } = await import('../src/tier1/runner');
    const { makeEvalSuiteRunner } = await import('../src/tier1/testExec');
    const spec = {
      title: 'Adder', prompt: 'adder',
      features: [{
        id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
        deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
        edgeCases: ['zero'], envVars: [],
        exports: [{ file: 'src/adder.ts', symbol: 'add' }],
        stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
      }],
    } as unknown as import('../src/core/types').FeatureSpec;
    const byPurpose = new Map<string, string[]>();
    const llm = {
      async encodeFeatures() { return spec; },
      async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
      async fixTestCases(
        _s: unknown, _f: unknown, req: { name: string; errors?: string[] }[],
        _i: unknown, _im: unknown, o?: { purpose?: string },
      ) {
        const p = (o?.purpose ?? 'fill').split(':')[0]!;
        byPurpose.set(p, [...(byPurpose.get(p) ?? []), (req[0]!.errors ?? []).join('\n')]);
        // Always vacuous → forces born-red surgery, then the relay.
        return { cases: [{ name: req[0]!.name, kind: 'behavior' as const, body: 'expect(true).toBe(true);' }] };
      },
      async generateImplementation() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
      async repair() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
    } as unknown as import('../src/core/types').LlmClient;

    const res = await runTier1Job({ prompt: 'adder', llm, runSuite: makeEvalSuiteRunner() });
    // Born-red surgery ran, and its request carried the superbuffer.
    const surgery = byPurpose.get('born-red surgery') ?? [];
    expect(surgery.length).toBeGreaterThan(0);
    expect(surgery.some(e => /Superbuffer —/.test(e))).toBe(true);
    // Every superbuffer assembly is announced, so a draw is never unexplained.
    const msgs = res.log.map(e => e.message);
    expect(msgs.filter(m => /^superbuffer: assembled/.test(m)).length).toBeGreaterThan(1);
  });

  it('the relay announces which case it is refilling before it draws', async () => {
    const { runTier1Job } = await import('../src/tier1/runner');
    const { makeEvalSuiteRunner } = await import('../src/tier1/testExec');
    const spec = {
      title: 'Adder', prompt: 'adder',
      features: [{
        id: 'F1', name: 'add', description: 'adds two numbers', parentId: null,
        deps: [], files: ['src/adder.ts'], testFile: 'tests/f1-add.test.ts',
        edgeCases: ['zero'], envVars: [],
        exports: [{ file: 'src/adder.ts', symbol: 'add' }],
        stubs: [{ path: 'src/adder.ts', content: `export function add(a: number, b: number): number { throw new Error('stub: not implemented'); }` }],
      }],
    } as unknown as import('../src/core/types').FeatureSpec;
    const llm = {
      async encodeFeatures() { return spec; },
      async generateTests() { return { content: '', parts: { imports: [], cases: [] } }; },
      async fixTestCases(_s: unknown, _f: unknown, req: { name: string }[]) {
        // Never usable → cases re-enqueue and the relay runs at end-of-run.
        return { cases: [{ name: req[0]!.name, kind: 'behavior' as const, body: '' }] };
      },
      async generateImplementation() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
      async repair() { return [{ path: 'src/adder.ts', content: LIVE_BODY }]; },
    } as unknown as import('../src/core/types').LlmClient;
    const res = await runTier1Job({ prompt: 'adder', llm, runSuite: makeEvalSuiteRunner() });
    const relay = res.log.map(e => e.message).filter(m => /^case-relay: refilling/.test(m));
    for (const line of relay) {
      // Every relay burst names its target BEFORE the draws, with K and reason.
      expect(line).toMatch(/^case-relay: refilling ".+" against the warm world \(K=\d+, .+\)$/);
    }
  });
});
