"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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildBinderRootCauseChain = buildBinderRootCauseChain;
/**
 * Binder Victim → Server Root-cause Chain (Spark Plan 12)
 *
 * Joins client-side and server-side binder transactions and walks the chain
 * back to the deepest blocker, producing a `BinderRootCauseChainContract`.
 *
 * Inputs are deliberately minimal: a flat list of hops keyed by transaction
 * id, plus per-hop `blockedOn` strings the caller derives from
 * thread_state aggregations. The walker just sequences hops and picks the
 * leaf when one exists; otherwise it marks the chain truncated rather than
 * inventing a root cause.
 */
const sparkContracts_1 = require("../types/sparkContracts");
function toHop(input) {
    return {
        step: input.step,
        side: input.side,
        pid: input.pid,
        tid: input.tid,
        range: { startNs: input.startNs, endNs: input.endNs },
        ...(input.process ? { process: input.process } : {}),
        ...(input.thread ? { thread: input.thread } : {}),
        ...(input.method ? { method: input.method } : {}),
        ...(input.blockedOn ? { blockedOn: input.blockedOn } : {}),
        ...(input.evidenceArtifactId
            ? { evidence: { artifactId: input.evidenceArtifactId } }
            : {}),
    };
}
/**
 * Build the full chain. The deepest hop becomes `rootCause`; if every hop
 * is blocked on something but there is still a downstream hop pending,
 * the contract is marked truncated.
 */
function buildBinderRootCauseChain(options) {
    const sortedChain = options.chain.slice().sort((a, b) => a.step - b.step);
    const chain = sortedChain.map(toHop);
    const victim = toHop(options.victim);
    let rootCause;
    let truncated = false;
    if (chain.length > 0) {
        const last = chain[chain.length - 1];
        if (last.blockedOn) {
            // The leaf still blocks on something; without further hops we cannot
            // claim a definitive root cause.
            truncated = true;
        }
        else {
            rootCause = last;
        }
    }
    else {
        // Nothing on the server side — the chain itself is incomplete.
        truncated = true;
    }
    return {
        ...(0, sparkContracts_1.makeSparkProvenance)({
            source: 'binder-root-cause',
            ...(truncated ? { unsupportedReason: 'chain truncated; root cause not resolvable' } : {}),
        }),
        victim,
        chain,
        ...(rootCause ? { rootCause } : {}),
        ...(truncated ? { truncated: true } : {}),
        coverage: [{ sparkId: 7, planId: '12', status: 'implemented' }],
    };
}
//# sourceMappingURL=binderRootCauseChain.js.map