"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.backfillPatternEntries = backfillPatternEntries;
exports.backfillNegativeEntries = backfillNegativeEntries;
/**
 * One-shot migration that backfills `failureModeHash` on existing analysis
 * patterns + negative patterns.
 *
 * Defaults to dry-run: read every entry under `logs/`, infer a category via
 * `inferCategoryFromText`, compute the hash, and print a report. Pass
 * `--apply` to actually persist the augmented entries back to disk via
 * atomic tmp-rename.
 *
 * Run: `npx tsx src/agentv3/selfImprove/migrateFailureModeHash.ts [--apply]`
 *
 * The dry-run report is the trustworthy output here — humans audit the
 * inferred categories before letting the migration write back. Anything that
 * lands on `unknown` is excluded from supersede actions in PR9 by design.
 */
const fs = __importStar(require("fs"));
const runtimePaths_1 = require("../../runtimePaths");
const failureTaxonomy_1 = require("./failureTaxonomy");
const PATTERNS_FILE = (0, runtimePaths_1.backendLogPath)('analysis_patterns.json');
const NEGATIVE_PATTERNS_FILE = (0, runtimePaths_1.backendLogPath)('analysis_negative_patterns.json');
function emptyReport() {
    const byCategory = {};
    const samples = {};
    for (const category of failureTaxonomy_1.FAILURE_CATEGORIES) {
        byCategory[category] = 0;
        samples[category] = [];
    }
    return { total: 0, alreadyHashed: 0, newlyHashed: 0, byCategory, samples };
}
function pickArchType(arch) {
    return (arch || 'UNKNOWN').toUpperCase();
}
function pickSceneType(scene) {
    return (scene || 'unknown').toLowerCase();
}
/**
 * Backfill `failureModeHash` on positive analysis-pattern entries.
 *
 * Positive patterns track successful insights, so historical entries usually
 * carry no failure signal. Without an inferred category we still emit a hash
 * keyed on `unknown` so cross-artifact dedupe works on the (sceneType, archType)
 * dimensions; this never trips supersede because the category is `unknown`.
 */
function backfillPatternEntries(entries) {
    const report = emptyReport();
    const out = entries.map(e => {
        report.total += 1;
        if (e.failureModeHash) {
            report.alreadyHashed += 1;
            return e;
        }
        const evidence = e.keyInsights.join(' ');
        const category = (0, failureTaxonomy_1.inferCategoryFromText)(evidence);
        report.byCategory[category] += 1;
        if (report.samples[category].length < 3 && evidence.trim()) {
            report.samples[category].push(evidence.substring(0, 120));
        }
        const failureModeHash = (0, failureTaxonomy_1.computeFailureModeHash)({
            sceneType: pickSceneType(e.sceneType),
            archType: pickArchType(e.architectureType),
            category,
        });
        report.newlyHashed += 1;
        return { ...e, failureModeHash };
    });
    return { entries: out, report };
}
/**
 * Backfill negative-pattern entries. Each entry can carry multiple
 * `failedApproaches`; we hash both the entry-level and per-approach to
 * cover supersede dedupe at either granularity.
 */
function backfillNegativeEntries(entries) {
    const report = emptyReport();
    const out = entries.map(e => {
        report.total += 1;
        const updatedApproaches = e.failedApproaches.map(a => {
            if (a.failureModeHash)
                return a;
            const category = (0, failureTaxonomy_1.inferCategoryFromText)(`${a.reason} ${a.approach}`);
            return {
                ...a,
                failureModeHash: (0, failureTaxonomy_1.computeFailureModeHash)({
                    sceneType: pickSceneType(e.sceneType),
                    archType: pickArchType(e.architectureType),
                    category,
                    toolOrSkillId: failedApproachToolHint(a),
                    errorClass: a.type,
                }),
            };
        });
        if (e.failureModeHash) {
            report.alreadyHashed += 1;
            return { ...e, failedApproaches: updatedApproaches };
        }
        const aggregateText = e.failedApproaches.map(a => `${a.reason} ${a.approach}`).join(' ');
        const category = (0, failureTaxonomy_1.inferCategoryFromText)(aggregateText);
        report.byCategory[category] += 1;
        if (report.samples[category].length < 3 && aggregateText.trim()) {
            report.samples[category].push(aggregateText.substring(0, 120));
        }
        const failureModeHash = (0, failureTaxonomy_1.computeFailureModeHash)({
            sceneType: pickSceneType(e.sceneType),
            archType: pickArchType(e.architectureType),
            category,
        });
        report.newlyHashed += 1;
        return { ...e, failedApproaches: updatedApproaches, failureModeHash };
    });
    return { entries: out, report };
}
function failedApproachToolHint(a) {
    if (a.type === 'tool_failure')
        return a.approach.split(/\s+/)[0]?.toLowerCase();
    return undefined;
}
function formatReport(label, report) {
    const lines = [];
    lines.push(`\n=== ${label} ===`);
    lines.push(`  total entries:      ${report.total}`);
    lines.push(`  already hashed:     ${report.alreadyHashed}`);
    lines.push(`  newly hashed:       ${report.newlyHashed}`);
    lines.push(`  by inferred category:`);
    for (const category of failureTaxonomy_1.FAILURE_CATEGORIES) {
        const count = report.byCategory[category];
        if (count === 0)
            continue;
        lines.push(`    ${category.padEnd(32)} ${count}`);
        for (const sample of report.samples[category]) {
            lines.push(`        sample: ${sample}`);
        }
    }
    return lines.join('\n');
}
function readJsonArray(file) {
    if (!fs.existsSync(file))
        return [];
    try {
        const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
        return Array.isArray(parsed) ? parsed : [];
    }
    catch (err) {
        console.warn(`[migrateFailureModeHash] failed to parse ${file}: ${err.message}`);
        return [];
    }
}
function atomicWrite(file, data) {
    const tmp = `${file}.tmp`;
    fs.writeFileSync(tmp, JSON.stringify(data, null, 2));
    fs.renameSync(tmp, file);
}
async function main() {
    const apply = process.argv.includes('--apply');
    const positives = readJsonArray(PATTERNS_FILE);
    const negatives = readJsonArray(NEGATIVE_PATTERNS_FILE);
    const positiveResult = backfillPatternEntries(positives);
    const negativeResult = backfillNegativeEntries(negatives);
    console.log(formatReport(`positive patterns (${PATTERNS_FILE})`, positiveResult.report));
    console.log(formatReport(`negative patterns (${NEGATIVE_PATTERNS_FILE})`, negativeResult.report));
    if (apply) {
        if (positiveResult.report.newlyHashed > 0) {
            atomicWrite(PATTERNS_FILE, positiveResult.entries);
            console.log(`\n[applied] wrote ${positiveResult.entries.length} entries to ${PATTERNS_FILE}`);
        }
        if (negativeResult.report.newlyHashed > 0) {
            atomicWrite(NEGATIVE_PATTERNS_FILE, negativeResult.entries);
            console.log(`[applied] wrote ${negativeResult.entries.length} entries to ${NEGATIVE_PATTERNS_FILE}`);
        }
    }
    else {
        console.log('\n(dry-run — pass --apply to write changes back to disk)');
    }
}
if (require.main === module) {
    main().catch(err => {
        console.error('[migrateFailureModeHash] failed:', err);
        process.exit(1);
    });
}
//# sourceMappingURL=migrateFailureModeHash.js.map