"use strict";
/**
 * SUB-08, SUB-09, SUB-10 — consolidated subsystem tests
 *
 * SUB-08: Promotion/scoring (AgentScoring, SkillScoring, SquadScoring,
 *         PerformanceScorecard, ArbitrationScorecard, PromotionPipeline,
 *         PromotionReviewGate, AssetPromotionEngine)
 * SUB-09: Memory layer (LocalMemoryProvider live, Mem0/Mempalace/Redis/Zep
 *         construct-only, OmniMemory facade routes to injected orchestrator)
 * SUB-10: Asset providers (File/Cloud/Composite × Agent/Skill/Squad)
 */
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 });
const fs = __importStar(require("fs"));
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const AgentScoring_1 = require("./orchestrator/AgentScoring");
const SkillScoring_1 = require("./orchestrator/SkillScoring");
const SquadScoring_1 = require("./orchestrator/SquadScoring");
const PerformanceScorecard_1 = require("./orchestrator/PerformanceScorecard");
const ArbitrationScorecard_1 = require("./orchestrator/ArbitrationScorecard");
const PromotionPipeline_1 = require("./orchestrator/PromotionPipeline");
const PromotionReviewGate_1 = require("./orchestrator/PromotionReviewGate");
const AssetPromotionEngine_1 = require("./orchestrator/AssetPromotionEngine");
const LocalMemoryProvider_1 = require("./memory/LocalMemoryProvider");
const Mem0Provider_1 = require("./memory/Mem0Provider");
const MempalaceProvider_1 = require("./memory/MempalaceProvider");
const RedisAgentMemoryProvider_1 = require("./memory/RedisAgentMemoryProvider");
const ZepGraphitiProvider_1 = require("./memory/ZepGraphitiProvider");
const OmniMemory_1 = require("./memory/OmniMemory");
const FileAgentProvider_1 = require("./orchestrator/providers/FileAgentProvider");
const CloudAgentProvider_1 = require("./orchestrator/providers/CloudAgentProvider");
const CompositeAgentProvider_1 = require("./orchestrator/providers/CompositeAgentProvider");
const FileSkillProvider_1 = require("./orchestrator/providers/FileSkillProvider");
const CloudSkillProvider_1 = require("./orchestrator/providers/CloudSkillProvider");
const CompositeSkillProvider_1 = require("./orchestrator/providers/CompositeSkillProvider");
const FileSquadProvider_1 = require("./orchestrator/providers/FileSquadProvider");
const CloudSquadProvider_1 = require("./orchestrator/providers/CloudSquadProvider");
const CompositeSquadProvider_1 = require("./orchestrator/providers/CompositeSquadProvider");
function assert(cond, msg) {
    if (!cond)
        throw new Error(msg);
}
function makeTempDir(prefix) {
    return fs.mkdtempSync(path.join(os.tmpdir(), `openlife-${prefix}-`));
}
// --------------------------------------------------------------------------
// SUB-08 — Scoring & Promotion
// --------------------------------------------------------------------------
async function testAgentScoring() {
    const scoring = new AgentScoring_1.AgentScoring();
    const id = `test-agent-${Date.now()}`;
    scoring.record(id, 'success');
    scoring.record(id, 'success');
    scoring.record(id, 'failed');
    const got = scoring.get(id);
    assert(got, 'AGENT_SCORE_NOT_PERSISTED');
    assert(got.successes === 2 && got.failures === 1, `AGENT_SCORE_COUNTS_WRONG: ${JSON.stringify(got)}`);
    // 2*2 + 0*0.5 - 1*1.5 = 2.5
    assert(Math.abs(got.score - 2.5) < 1e-6, `AGENT_SCORE_FORMULA_WRONG: ${got.score}`);
}
async function testSkillAndSquadScoring() {
    const skill = new SkillScoring_1.SkillScoring();
    const sid = `test-skill-${Date.now()}`;
    skill.record(sid, 'partial');
    const sAll = skill.getAll();
    assert(sAll[sid] && sAll[sid].partials === 1, `SKILL_SCORE_FAIL: ${JSON.stringify(sAll[sid])}`);
    assert(Math.abs(sAll[sid].score - 0.5) < 1e-6, `SKILL_SCORE_FORMULA: ${sAll[sid].score}`);
    const squad = new SquadScoring_1.SquadScoring();
    const qid = `test-squad-${Date.now()}`;
    squad.record(qid, 'success');
    const qAll = squad.getAll();
    assert(qAll[qid] && qAll[qid].successes === 1, `SQUAD_SCORE_FAIL: ${JSON.stringify(qAll[qid])}`);
    assert(Math.abs(qAll[qid].score - 2) < 1e-6, `SQUAD_SCORE_FORMULA: ${qAll[qid].score}`);
}
async function testPerformanceScorecard() {
    const card = new PerformanceScorecard_1.PerformanceScorecard();
    const id = `perf-entity-${Date.now()}`;
    card.record({ entityId: id, entityType: 'agent', status: 'success', durationMs: 1000, reviewScore: 4, fallbackUsed: false, timestamp: new Date().toISOString() });
    card.record({ entityId: id, entityType: 'agent', status: 'failed', durationMs: 2000, reviewScore: 2, fallbackUsed: true, timestamp: new Date().toISOString() });
    const got = card.get(id);
    assert(got, 'PERF_NOT_PERSISTED');
    assert(got.runs === 2, `PERF_RUN_COUNT: ${got.runs}`);
    assert(typeof got.score === 'number' && Number.isFinite(got.score), `PERF_SCORE_TYPE: ${got.score}`);
}
async function testArbitrationScorecard() {
    const card = new ArbitrationScorecard_1.ArbitrationScorecard();
    const branches = [
        'curto',
        'esta é uma resposta um pouco mais elaborada com várias frases\ne uma quebra de linha',
        'X'.repeat(900)
    ];
    const scored = card.score(branches);
    assert(scored.length === 3, `ARB_LENGTH: ${scored.length}`);
    for (const s of scored) {
        assert(typeof s.finalScore === 'number' && Number.isFinite(s.finalScore), `ARB_SCORE_NAN: ${JSON.stringify(s)}`);
        assert(s.relevance >= 0 && s.relevance <= 10, `ARB_RELEVANCE_RANGE: ${s.relevance}`);
        assert(s.clarity >= 0 && s.clarity <= 10, `ARB_CLARITY_RANGE: ${s.clarity}`);
    }
    // Longer branch should not score lower than the shortest.
    assert(scored[2].finalScore >= scored[0].finalScore, `ARB_ORDER_REGRESSION: ${scored[0].finalScore} vs ${scored[2].finalScore}`);
}
async function testPromotionPipelineAndGate() {
    const pipeline = new PromotionPipeline_1.PromotionPipeline();
    const gate = new PromotionReviewGate_1.PromotionReviewGate();
    const candidate = {
        id: `cand-${Date.now()}`,
        type: 'playbook',
        sourceMissionId: 'mission-test-001',
        summary: 'Resumo deterministico com mais de vinte caracteres para aprovacao.',
        createdAt: new Date().toISOString()
    };
    const shortCandidate = { ...candidate, id: candidate.id + '-short', summary: 'curto' };
    assert(gate.approve(candidate) === true, 'GATE_SHOULD_APPROVE_VALID');
    assert(gate.approve(shortCandidate) === false, 'GATE_SHOULD_REJECT_SHORT');
    pipeline.add(candidate);
    const all = pipeline.getAll();
    assert(all.some(c => c.id === candidate.id), 'PIPELINE_NOT_PERSISTED');
}
async function testAssetPromotionEngine() {
    const engine = new AssetPromotionEngine_1.AssetPromotionEngine();
    const cand = {
        id: `promo-${Date.now()}`,
        type: 'agent',
        sourceMissionId: 'mission-promo-001',
        summary: 'Agente promovido para teste deterministico',
        createdAt: new Date().toISOString()
    };
    const result = engine.promote(cand);
    assert(result.id === cand.id, 'PROMO_ID_MISMATCH');
    assert(fs.existsSync(result.filePath), `PROMO_FILE_MISSING: ${result.filePath}`);
    const body = fs.readFileSync(result.filePath, 'utf-8');
    assert(body.includes(cand.summary), 'PROMO_FILE_MISSING_SUMMARY');
    // cleanup
    try {
        fs.unlinkSync(result.filePath);
    }
    catch { /* ignore */ }
}
// --------------------------------------------------------------------------
// SUB-09 — Memory layer
// --------------------------------------------------------------------------
async function testLocalMemoryProviderRoundTrip() {
    const tmp = makeTempDir('memlocal');
    // LocalMemoryProvider resolves its store via OPENLIFE_MEMORY_DIR (or the
    // global ~/.openlife/memory). It ignores the constructor `root` for the
    // primary store, so without this the test writes to — and accumulates in —
    // the shared global store, making the search assertion flaky across runs.
    // Pin the store to the temp dir for true isolation.
    const prevMemoryDir = process.env.OPENLIFE_MEMORY_DIR;
    process.env.OPENLIFE_MEMORY_DIR = path.join(tmp, 'memory');
    try {
        const provider = new LocalMemoryProvider_1.LocalMemoryProvider(tmp);
        assert(provider.name() === 'local', 'LOCAL_NAME_WRONG');
        const rec = {
            id: 'mem-test-1',
            type: 'semantic',
            namespace: { project: 'openlife-test' },
            content: 'unique sentinel phrase XOXOXO',
            summary: 'sentinel summary',
            tags: ['sentinel'],
            createdAt: new Date().toISOString()
        };
        await provider.save(rec);
        const hits = await provider.search({ query: 'XOXOXO' });
        assert(hits.length === 1, `LOCAL_SEARCH_LEN: ${hits.length}`);
        assert(hits[0].content === rec.content, 'LOCAL_SEARCH_CONTENT_MISMATCH');
        // namespace filter respected
        const miss = await provider.search({ query: 'XOXOXO', namespace: { project: 'other' } });
        assert(miss.length === 0, `LOCAL_NAMESPACE_FILTER_LEAK: ${miss.length}`);
    }
    finally {
        if (prevMemoryDir === undefined)
            delete process.env.OPENLIFE_MEMORY_DIR;
        else
            process.env.OPENLIFE_MEMORY_DIR = prevMemoryDir;
    }
}
async function testNetworkMemoryProvidersConstructible() {
    const mem0 = new Mem0Provider_1.Mem0Provider();
    const palace = new MempalaceProvider_1.MempalaceProvider('/nonexistent/path');
    const redis = new RedisAgentMemoryProvider_1.RedisAgentMemoryProvider();
    const zep = new ZepGraphitiProvider_1.ZepGraphitiProvider();
    assert(mem0.name() === 'mem0', 'MEM0_NAME');
    assert(palace.name() === 'mempalace', 'MEMPALACE_NAME');
    assert(redis.name() === 'redis-ams', 'REDIS_NAME');
    assert(zep.name() === 'zep-graphiti', 'ZEP_NAME');
    // All search() implementations must return safely without throwing — no network calls.
    const probe = { query: 'no-network-probe' };
    for (const [label, p] of [['mem0', mem0], ['redis', redis], ['zep', zep]]) {
        const r = await p.search(probe);
        assert(Array.isArray(r) && r.length === 0, `${label.toUpperCase()}_SEARCH_NOT_EMPTY`);
    }
    // Save() is a no-op for stub providers; must not throw.
    const fake = { id: 'x', type: 'semantic', namespace: {}, content: 'x', createdAt: new Date().toISOString() };
    await mem0.save(fake);
    await redis.save(fake);
    await zep.save(fake);
}
async function testOmniMemoryFacadeRouting() {
    const omni = new OmniMemory_1.OmniMemory();
    let searchCalls = 0;
    let saveCalls = 0;
    // Inject a fake orchestrator with the surface OmniMemory uses.
    omni.orchestrator = {
        search: async () => {
            searchCalls++;
            return [{ provider: 'fake', record: { content: 'routed-via-fake', summary: 'routed' } }];
        },
        save: async () => { saveCalls++; }
    };
    const out = await omni.search('anything');
    assert(searchCalls === 1, `OMNI_SEARCH_NOT_ROUTED: ${searchCalls}`);
    assert(out.includes('routed-via-fake') || out.includes('routed'), `OMNI_SEARCH_OUTPUT_WRONG: ${out}`);
    // saveFact also writes evidence_log.md as a side effect — intercept by swapping orchestrator.
    // We avoid writing real files by chdir'ing into a temp dir for this call.
    const cwd = process.cwd();
    const tmp = makeTempDir('omni');
    process.chdir(tmp);
    try {
        await omni.saveFact('fato', { source_uri: 'test://x', timestamp: Date.now() });
        assert(saveCalls === 1, `OMNI_SAVE_NOT_ROUTED: ${saveCalls}`);
        assert(fs.existsSync(path.join(tmp, 'evidence_log.md')), 'OMNI_EVIDENCE_NOT_WRITTEN');
    }
    finally {
        process.chdir(cwd);
    }
}
// --------------------------------------------------------------------------
// SUB-10 — Asset providers
// --------------------------------------------------------------------------
async function testFileProvidersShapeStable() {
    // Empty roots — must return [] without throwing.
    const emptyAgent = new FileAgentProvider_1.FileAgentProvider([]).load();
    const emptySkill = new FileSkillProvider_1.FileSkillProvider([]).load();
    const emptySquad = new FileSquadProvider_1.FileSquadProvider('').load();
    assert(Array.isArray(emptyAgent) && emptyAgent.length === 0, 'FILE_AGENT_EMPTY');
    assert(Array.isArray(emptySkill) && emptySkill.length === 0, 'FILE_SKILL_EMPTY');
    assert(Array.isArray(emptySquad) && emptySquad.length === 0, 'FILE_SQUAD_EMPTY');
    // Populated fixture: agent .md, skill dir with SKILL.md, squad .md
    const tmp = makeTempDir('fileprov');
    // Agent
    const agentDir = path.join(tmp, 'agents');
    fs.mkdirSync(agentDir, { recursive: true });
    fs.writeFileSync(path.join(agentDir, 'alpha.md'), 'name: Alpha\nrole: "tester"\ntags: [foo, bar]\n', 'utf-8');
    const agents = new FileAgentProvider_1.FileAgentProvider([agentDir]).load();
    assert(agents.length === 1 && agents[0].id === 'alpha', `FILE_AGENT_PARSE: ${JSON.stringify(agents)}`);
    assert(agents[0].tags.includes('foo'), `FILE_AGENT_TAGS: ${JSON.stringify(agents[0].tags)}`);
    // Skill
    const skillRoot = path.join(tmp, 'skills');
    const oneSkill = path.join(skillRoot, 'my-skill');
    fs.mkdirSync(oneSkill, { recursive: true });
    fs.writeFileSync(path.join(oneSkill, 'SKILL.md'), '<description>does a thing, also that thing</description>', 'utf-8');
    const skills = new FileSkillProvider_1.FileSkillProvider([skillRoot]).load();
    assert(skills.length === 1 && skills[0].id === 'my-skill', `FILE_SKILL_PARSE: ${JSON.stringify(skills)}`);
    // Squad
    const squadRoot = path.join(tmp, 'squads');
    fs.mkdirSync(squadRoot, { recursive: true });
    fs.writeFileSync(path.join(squadRoot, 'sq1.md'), '# Squad One\nDoes A, B.\n', 'utf-8');
    const squads = new FileSquadProvider_1.FileSquadProvider(squadRoot).load();
    assert(squads.length === 1, `FILE_SQUAD_LEN: ${squads.length}`);
    assert(squads[0].id === 'sq1', `FILE_SQUAD_ID: ${squads[0].id}`);
}
async function testCloudProvidersConstructAndShape() {
    // Without env vars / files, all cloud providers return [] (offline-safe).
    const a = new CloudAgentProvider_1.CloudAgentProvider('').load();
    const s = new CloudSkillProvider_1.CloudSkillProvider('').load();
    const q = new CloudSquadProvider_1.CloudSquadProvider('').load();
    assert(Array.isArray(a) && a.length === 0, 'CLOUD_AGENT_NOENV_EMPTY');
    assert(Array.isArray(s) && s.length === 0, 'CLOUD_SKILL_NOENV_EMPTY');
    assert(Array.isArray(q) && q.length === 0, 'CLOUD_SQUAD_NOENV_EMPTY');
    // Methods present
    assert(typeof new CloudAgentProvider_1.CloudAgentProvider('').load === 'function', 'CLOUD_AGENT_NO_LOAD');
    assert(typeof new CloudSkillProvider_1.CloudSkillProvider('').load === 'function', 'CLOUD_SKILL_NO_LOAD');
    assert(typeof new CloudSquadProvider_1.CloudSquadProvider('').load === 'function', 'CLOUD_SQUAD_NO_LOAD');
    // Pointed at a real file containing records
    const tmp = makeTempDir('cloud');
    const agentFile = path.join(tmp, 'agents.json');
    fs.writeFileSync(agentFile, JSON.stringify([{ id: 'cloudy', name: 'Cloudy', role: 'r', capabilities: [], sourcePath: agentFile, priority: 1, tags: [] }]), 'utf-8');
    const loaded = new CloudAgentProvider_1.CloudAgentProvider(agentFile).load();
    assert(loaded.length === 1 && loaded[0].id === 'cloudy', `CLOUD_AGENT_LOAD_FAIL: ${JSON.stringify(loaded)}`);
}
async function testCompositeProvidersChainPrimaryThenFallback() {
    // Primary empty -> falls back to secondary
    const primaryEmpty = { load: () => [] };
    const fallbackAgents = { load: () => [{ id: 'fb', name: 'FB', role: 'r', capabilities: [], sourcePath: '/x', priority: 1, tags: [] }] };
    const compositeAgent = new CompositeAgentProvider_1.CompositeAgentProvider(primaryEmpty, fallbackAgents).load();
    assert(compositeAgent.length === 1 && compositeAgent[0].id === 'fb', `COMPOSITE_AGENT_FALLBACK: ${JSON.stringify(compositeAgent)}`);
    // Primary non-empty -> fallback skipped
    const primaryFull = { load: () => [{ id: 'pri', name: 'Pri', role: 'r', capabilities: [], sourcePath: '/y', priority: 1, tags: [] }] };
    let fallbackCalled = false;
    const fallbackSpy = { load: () => { fallbackCalled = true; return []; } };
    const composite2 = new CompositeAgentProvider_1.CompositeAgentProvider(primaryFull, fallbackSpy).load();
    assert(composite2.length === 1 && composite2[0].id === 'pri', 'COMPOSITE_AGENT_PRIMARY');
    assert(fallbackCalled === false, 'COMPOSITE_AGENT_FALLBACK_LEAKED');
    // Skill + Squad mirror the same shape
    const skillComp = new CompositeSkillProvider_1.CompositeSkillProvider({ load: () => [] }, { load: () => [{ id: 's', name: 's', sourcePath: '/p', capabilities: [] }] }).load();
    assert(skillComp.length === 1 && skillComp[0].id === 's', 'COMPOSITE_SKILL_FALLBACK');
    const squadComp = new CompositeSquadProvider_1.CompositeSquadProvider({ load: () => [] }, { load: () => [{ id: 'sq', name: 'sq', sourcePath: '/p', domain: 'd', capabilities: [] }] }).load();
    assert(squadComp.length === 1 && squadComp[0].id === 'sq', 'COMPOSITE_SQUAD_FALLBACK');
}
// --------------------------------------------------------------------------
// Entrypoint
// --------------------------------------------------------------------------
async function main() {
    // SUB-08
    await testAgentScoring();
    await testSkillAndSquadScoring();
    await testPerformanceScorecard();
    await testArbitrationScorecard();
    await testPromotionPipelineAndGate();
    await testAssetPromotionEngine();
    // SUB-09
    await testLocalMemoryProviderRoundTrip();
    await testNetworkMemoryProvidersConstructible();
    await testOmniMemoryFacadeRouting();
    // SUB-10
    await testFileProvidersShapeStable();
    await testCloudProvidersConstructAndShape();
    await testCompositeProvidersChainPrimaryThenFallback();
    console.log('TEST_SUBSYSTEMS_PROMOTION_MEMORY_ASSETS_OK');
}
main().catch((err) => {
    console.error('TEST_SUBSYSTEMS_PROMOTION_MEMORY_ASSETS_FAIL:', err?.message || err);
    process.exit(1);
});
