/**
 * RED-GREEN tests for F-NEW-PRODUCT-BUILD-SCORE-DIMENSION (W1.8 of
 * F-NEW-PRODUCT-AGENT-VISIBILITY-CLUSTER-2026-05-12).
 *
 * @connexum/ai-governance  F-NEW-PRODUCT-BUILD-SCORE-DIMENSION
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { extractBuildStructureDimensions } from './build-structure-score.js';
import { scanAgent } from './owasp-agentic-scanner.js';
import { CAPABILITY_CLASS } from './capability-classes.js';
const base = (over = {}) => ({
    agentId: 'agent-test',
    tools: [],
    hooks: { preToolUse: true, postToolUse: true, postResponse: true },
    llmProvider: 'connexum-proxy/anthropic',
    pluginIntegrityVerified: true,
    rateLimitsConfigured: true,
    declaredApprovalGates: [],
    declaredForbiddenCapabilities: [CAPABILITY_CLASS.MCP],
    ...over,
});
describe('F-NEW-PRODUCT-BUILD-SCORE-DIMENSION', () => {
    it('clean manifest produces a near-perfect composite', () => {
        const manifest = base({
            declaredForbiddenCapabilities: [CAPABILITY_CLASS.MCP],
            declaredApprovalGates: [
                { capability: CAPABILITY_CLASS.SHELL_EXEC, reviewer: 'sre' },
            ],
        });
        const scan = scanAgent(manifest);
        const dims = extractBuildStructureDimensions(manifest, scan);
        assert.equal(dims.owasp_agentic_score, 100);
        assert.equal(dims.hook_coverage_count, 3);
        assert.equal(dims.has_human_in_loop, true);
        assert.equal(dims.plugin_integrity_verified, true);
        assert.equal(dims.proxy_routed, true);
        // 2 capability classes declared (out of 7 known) caps the cap-coverage contribution.
        // Math: 100*0.35 + 100*0.20 + round(2/7*100)*0.15 + 100*0.10 + 100*0.10 + 100*0.10 = 89.
        // A manifest that declares all 7 capability classes plus has all hooks + human-in-loop
        // + plugin-verified + proxy-routed would hit 100.
        assert.ok(dims.composite >= 85, `composite should be near 100, got ${dims.composite}`);
    });
    it('Lethal Trifecta manifest produces a low composite', () => {
        const manifest = base({
            tools: ['WebFetch', 'Bash'],
            pluginIntegrityVerified: false,
            llmProvider: 'anthropic/claude-sonnet-4-6',
            declaredForbiddenCapabilities: [],
            declaredApprovalGates: [],
        });
        const scan = scanAgent(manifest);
        const dims = extractBuildStructureDimensions(manifest, scan);
        assert.ok(dims.owasp_agentic_score < 30, `owasp score should be low, got ${dims.owasp_agentic_score}`);
        assert.equal(dims.has_human_in_loop, false);
        assert.equal(dims.plugin_integrity_verified, false);
        assert.equal(dims.proxy_routed, false);
        assert.ok(dims.composite < 50, `composite should be POOR/CRIT band, got ${dims.composite}`);
    });
    it('hook_coverage_count counts each wired hook', () => {
        const cases = [
            { hooks: { preToolUse: false, postToolUse: false, postResponse: false }, expected: 0 },
            { hooks: { preToolUse: true, postToolUse: false, postResponse: false }, expected: 1 },
            { hooks: { preToolUse: true, postToolUse: true, postResponse: false }, expected: 2 },
            { hooks: { preToolUse: true, postToolUse: true, postResponse: true }, expected: 3 },
        ];
        for (const c of cases) {
            const manifest = base({ hooks: c.hooks });
            const scan = scanAgent(manifest);
            const dims = extractBuildStructureDimensions(manifest, scan);
            assert.equal(dims.hook_coverage_count, c.expected, `hooks=${JSON.stringify(c.hooks)}`);
        }
    });
    it('declared_capability_class_count merges forbids and approval gates without duplicates', () => {
        const manifest = base({
            declaredForbiddenCapabilities: [CAPABILITY_CLASS.MCP, CAPABILITY_CLASS.WEB_FETCH],
            declaredApprovalGates: [
                { capability: CAPABILITY_CLASS.WEB_FETCH, reviewer: 'sec' }, // duplicate
                { capability: CAPABILITY_CLASS.SHELL_EXEC, reviewer: 'sre' },
            ],
        });
        const scan = scanAgent(manifest);
        const dims = extractBuildStructureDimensions(manifest, scan);
        assert.equal(dims.declared_capability_class_count, 3); // mcp + web-fetch + shell-exec
    });
    it('proxy_routed flips true only when llmProvider starts with connexum-proxy/', () => {
        const proxyManifest = base({ llmProvider: 'connexum-proxy/anthropic' });
        const directManifest = base({ llmProvider: 'anthropic/claude-sonnet-4-6' });
        const dimsP = extractBuildStructureDimensions(proxyManifest, scanAgent(proxyManifest));
        const dimsD = extractBuildStructureDimensions(directManifest, scanAgent(directManifest));
        assert.equal(dimsP.proxy_routed, true);
        assert.equal(dimsD.proxy_routed, false);
    });
    it('composite formula is reproducible from inputs alone (auditor-grade transparency)', () => {
        const manifest = base({
            tools: ['Bash'], // triggers A08
            declaredApprovalGates: [{ capability: CAPABILITY_CLASS.SHELL_EXEC, reviewer: 'sre' }],
            declaredForbiddenCapabilities: [],
        });
        const scan = scanAgent(manifest);
        const dims = extractBuildStructureDimensions(manifest, scan);
        // Recompute by hand:
        //   owasp_agentic_score * 0.35   (varies by what scan returns)
        //   3/3 hooks => 100 * 0.20 = 20
        //   1 cap / 7 caps => round(14.28) * 0.15 = 2.14 -> 2 after round
        //   has_human_in_loop=true: 100 * 0.10 = 10
        //   plugin_integrity=true:  100 * 0.10 = 10
        //   proxy_routed=true:      100 * 0.10 = 10
        // total = round(owasp*0.35 + 20 + 2.14 + 10 + 10 + 10)
        const owasp = scan.buildStructureScore;
        const capCovPct = Math.round((1 / 7) * 100);
        const expected = Math.round(owasp * 0.35 + 20 + capCovPct * 0.15 + 10 + 10 + 10);
        assert.equal(dims.composite, expected);
    });
});
//# sourceMappingURL=build-structure-score.test.js.map