import path from 'node:path';
import { z } from 'zod';
import { GitBlobStructureBatchFooterV1Schema, GitBlobStructureBatchFooterV2Schema, GitBlobStructureBatchHeaderV1Schema, GitBlobStructureBatchHeaderV2Schema, GitBlobStructureBatchV1Schema, GitBlobStructureBatchV2Schema, GitBlobStructureRequestV1Schema, GitBlobStructureResultV1Schema, GitBlobStructureResultV2Schema, } from '../blob-structure.js';
import { OccTestReasonSchema } from '../tests.js';
import { projectEntitiesAtCommit } from './at-ref.js';
import { isEntityEvidenceGapDiagnostic } from './evidence.js';
import { listTreeBlobs, readBlobHeaders, resolveCommit } from './git.js';
import { mapEntityGitError } from './git-error.js';
import { ENTITY_PARSER_CONTRACT, entityStateKey } from './snapshot.js';
import { OccEntityErrorCodeSchema } from './api-types.js';
import { EntityDiagnosticSchema, EntityKindSchema, EntitySourceSpanV2Schema } from './types.js';
const FullGitObjectIdSchema = GitBlobStructureRequestV1Schema.shape.oid;
const RelativePosixPathSchema = GitBlobStructureRequestV1Schema.shape.relativePath;
const StrictOccTestReasonSchema = OccTestReasonSchema.strict();
const StrictEntityDiagnosticSchema = EntityDiagnosticSchema.strict();
export const HistoricalEntityRefV1Schema = z
    .object({
    lineageId: z.string().min(1),
    name: z.string(),
    qualifiedName: z.string(),
    kind: EntityKindSchema,
    relativePath: RelativePosixPathSchema,
    startLine: z.number().int().positive(),
    endLine: z.number().int().positive(),
    signature: z.string().optional(),
    containerName: z.string().optional(),
    isExported: z.boolean(),
    isTest: z.boolean(),
    testReasons: z.array(StrictOccTestReasonSchema).optional(),
    ordinal: z.number().int().nonnegative(),
    declarationIndex: z.number().int().nonnegative(),
})
    .strict();
export const OccBlobLineageDiagnosticCodeV1Schema = z.enum([
    'structure-partial',
    'structure-unavailable',
    'parser-contract-mismatch',
    'path-missing-at-ref',
    'object-mismatch',
    'object-unavailable',
    'lineage-index-partial',
    'declaration-unmatched',
    'state-key-ambiguous',
    'structure-batch-unverified',
    'structure-evidence-mismatch',
]);
export const OccBlobLineageDiagnosticV1Schema = z
    .object({
    code: OccBlobLineageDiagnosticCodeV1Schema,
    message: z.string(),
    declarationIndex: z.number().int().nonnegative().optional(),
})
    .strict();
const OccBlobLineageDeclarationBaseV1Schema = z.object({
    declarationIndex: z.number().int().nonnegative(),
    ordinal: z.number().int().nonnegative(),
});
export const OccBlobLineageDeclarationV1Schema = z.discriminatedUnion('match', [
    OccBlobLineageDeclarationBaseV1Schema.extend({
        match: z.literal('state-key'),
        entity: HistoricalEntityRefV1Schema,
    }).strict(),
    OccBlobLineageDeclarationBaseV1Schema.extend({
        match: z.literal('unmatched'),
    }).strict(),
]);
const OccBlobLineageCoverageStateV1Schema = z.enum(['complete', 'partial', 'unavailable']);
export const OccBlobLineageBlobV1Schema = z
    .object({
    requestIndex: z.number().int().nonnegative(),
    requestId: z.string().min(1),
    oid: FullGitObjectIdSchema,
    relativePath: RelativePosixPathSchema,
    status: OccBlobLineageCoverageStateV1Schema,
    declarations: z.array(OccBlobLineageDeclarationV1Schema),
    diagnostics: z.array(OccBlobLineageDiagnosticV1Schema),
})
    .strict();
export const OccBlobLineageCoverageV1Schema = z
    .object({
    structure: OccBlobLineageCoverageStateV1Schema,
    lineage: OccBlobLineageCoverageStateV1Schema,
    verifiedBlobs: z.number().int().nonnegative(),
    matchedDeclarations: z.number().int().nonnegative(),
    unmatchedDeclarations: z.number().int().nonnegative(),
})
    .strict();
export const OccBlobLineageResolvedResultV1Schema = z
    .object({
    schemaVersion: z.literal(1),
    status: z.literal('resolved'),
    requestedRef: z.string(),
    resolvedCommit: FullGitObjectIdSchema,
    blobs: z.array(OccBlobLineageBlobV1Schema),
    coverage: OccBlobLineageCoverageV1Schema,
    diagnostics: z.array(StrictEntityDiagnosticSchema),
})
    .strict();
export const OccBlobLineageErrorResultV1Schema = z
    .object({
    schemaVersion: z.literal(1),
    status: z.literal('error'),
    requestedRef: z.string(),
    code: OccEntityErrorCodeSchema,
    message: z.string(),
})
    .strict();
export const OccBlobLineageResultV1Schema = z.discriminatedUnion('status', [
    OccBlobLineageResolvedResultV1Schema,
    OccBlobLineageErrorResultV1Schema,
]);
export const OccBlobLineageInputV1Schema = z
    .object({
    ref: z.string().min(1),
    blobs: z.array(GitBlobStructureResultV1Schema),
    header: GitBlobStructureBatchHeaderV1Schema.optional(),
    footer: GitBlobStructureBatchFooterV1Schema.optional(),
})
    .strict()
    .superRefine((input, context) => {
    if ((input.header === undefined) !== (input.footer === undefined)) {
        context.addIssue({
            code: 'custom',
            message: 'Blob-structure header and footer must be supplied together.',
        });
        return;
    }
    if (input.header && input.footer) {
        const receipt = GitBlobStructureBatchV1Schema.safeParse({
            header: input.header,
            blobs: input.blobs,
            footer: input.footer,
        });
        if (!receipt.success) {
            context.addIssue({
                code: 'custom',
                message: `Blob-structure receipt is internally inconsistent: ${z.prettifyError(receipt.error)}`,
            });
        }
    }
});
export const HistoricalEntityRefV2Schema = HistoricalEntityRefV1Schema.extend({
    sourceSpan: EntitySourceSpanV2Schema.optional(),
}).strict();
export const OccBlobLineageDiagnosticCodeV2Schema = z.enum([
    ...OccBlobLineageDiagnosticCodeV1Schema.options,
    'legacy-structure-receipt',
]);
export const OccBlobLineageDiagnosticV2Schema = OccBlobLineageDiagnosticV1Schema.omit({ code: true })
    .extend({ code: OccBlobLineageDiagnosticCodeV2Schema })
    .strict();
const OccBlobLineageDeclarationBaseV2Schema = z.object({
    declarationIndex: z.number().int().nonnegative(),
    ordinal: z.number().int().nonnegative(),
});
export const OccBlobLineageDeclarationV2Schema = z.discriminatedUnion('match', [
    OccBlobLineageDeclarationBaseV2Schema.extend({
        match: z.literal('state-key'),
        entity: HistoricalEntityRefV2Schema,
    }).strict(),
    OccBlobLineageDeclarationBaseV2Schema.extend({ match: z.literal('unmatched') }).strict(),
]);
export const OccBlobLineageBlobV2Schema = OccBlobLineageBlobV1Schema.omit({
    declarations: true,
    diagnostics: true,
})
    .extend({
    declarations: z.array(OccBlobLineageDeclarationV2Schema),
    diagnostics: z.array(OccBlobLineageDiagnosticV2Schema),
})
    .strict();
export const OccBlobLineageCoverageV2Schema = OccBlobLineageCoverageV1Schema;
export const OccBlobLineageResolvedResultV2Schema = OccBlobLineageResolvedResultV1Schema.omit({
    schemaVersion: true,
    blobs: true,
})
    .extend({
    schemaVersion: z.literal(2),
    structureSchemaVersion: z.union([z.literal(1), z.literal(2)]),
    blobs: z.array(OccBlobLineageBlobV2Schema),
})
    .strict();
export const OccBlobLineageErrorResultV2Schema = OccBlobLineageErrorResultV1Schema.omit({ schemaVersion: true })
    .extend({ schemaVersion: z.literal(2) })
    .strict();
export const OccBlobLineageResultV2Schema = z.discriminatedUnion('status', [
    OccBlobLineageResolvedResultV2Schema,
    OccBlobLineageErrorResultV2Schema,
]);
export const OccBlobLineageInputV2Schema = z
    .object({
    ref: z.string().min(1),
    blobs: z.array(GitBlobStructureResultV2Schema),
    header: GitBlobStructureBatchHeaderV2Schema.optional(),
    footer: GitBlobStructureBatchFooterV2Schema.optional(),
})
    .strict()
    .superRefine((input, context) => {
    if ((input.header === undefined) !== (input.footer === undefined)) {
        context.addIssue({ code: 'custom', message: 'Blob-structure header and footer must be supplied together.' });
        return;
    }
    if (input.header && input.footer) {
        const receipt = GitBlobStructureBatchV2Schema.safeParse({
            header: input.header,
            blobs: input.blobs,
            footer: input.footer,
        });
        if (!receipt.success) {
            context.addIssue({
                code: 'custom',
                message: `Blob-structure V2 receipt is internally inconsistent: ${z.prettifyError(receipt.error)}`,
            });
        }
    }
});
export const OccBlobLineageCompatibleInputSchema = z.union([OccBlobLineageInputV2Schema, OccBlobLineageInputV1Schema]);
function safeMessage(error, repoRoot) {
    const raw = error instanceof Error ? error.message : String(error);
    return raw.split(path.resolve(repoRoot)).join('<repository>');
}
function errorResult(requestedRef, error, repoRoot) {
    const mapped = mapEntityGitError(error);
    return {
        schemaVersion: 2,
        status: 'error',
        requestedRef,
        code: mapped.code,
        message: safeMessage(mapped.message, repoRoot),
    };
}
/** Use both redundant V1 signals conservatively for hand-constructed inputs. */
function structureCoverage(blob, receiptVerified, structureSchemaVersion) {
    if (blob.status === 'unavailable' || blob.coverage.structure === 'unavailable')
        return 'unavailable';
    if (structureSchemaVersion === 2 &&
        receiptVerified &&
        blob.status === 'complete' &&
        blob.coverage.structure === 'complete') {
        return 'complete';
    }
    return 'partial';
}
function aggregateCoverage(states) {
    if (states.length === 0 || states.every(state => state === 'complete'))
        return 'complete';
    if (states.every(state => state === 'unavailable'))
        return 'unavailable';
    return 'partial';
}
function historicalRef(entity) {
    const result = {
        lineageId: entity.ref.lineageId,
        name: entity.record.name,
        qualifiedName: entity.record.qualifiedName,
        kind: entity.record.kind,
        relativePath: entity.record.relativePath,
        startLine: entity.record.startLine,
        endLine: entity.record.endLine,
        isExported: entity.record.isExported,
        isTest: entity.ref.isTest,
        ordinal: entity.record.ordinal,
        declarationIndex: entity.record.declarationIndex,
    };
    if (entity.record.signature)
        result.signature = entity.record.signature;
    if (entity.record.containerName)
        result.containerName = entity.record.containerName;
    if (entity.ref.testReasons)
        result.testReasons = entity.ref.testReasons;
    if (entity.record.sourceSpan)
        result.sourceSpan = entity.record.sourceSpan;
    return result;
}
function structureDiagnostic(state) {
    if (state === 'complete')
        return undefined;
    return state === 'partial'
        ? {
            code: 'structure-partial',
            message: 'The blob structure result is partial; identities apply only to emitted declarations.',
        }
        : {
            code: 'structure-unavailable',
            message: 'The blob structure result is unavailable; no declaration identity can be attached.',
        };
}
function sameOptionalString(left, right) {
    return left === right;
}
function isV2DeclarationSpan(span) {
    return 'version' in span;
}
function declarationMatchesHistorical(relativePath, declaration, entity) {
    const record = entity.record;
    return (record.relativePath === relativePath &&
        record.name === declaration.name &&
        record.qualifiedName === declaration.qualifiedName &&
        record.kind === declaration.kind &&
        sameOptionalString(record.containerName, declaration.containerName) &&
        sameOptionalString(record.signature, declaration.signature) &&
        record.isExported === declaration.isExported &&
        record.ordinal === declaration.ordinal &&
        record.declarationIndex === declaration.declarationIndex &&
        record.startLine === declaration.span.startLine &&
        record.endLine === declaration.span.endLine &&
        (!isV2DeclarationSpan(declaration.span) ||
            (declaration.span.exact &&
                record.sourceSpan !== undefined &&
                declaration.span.startByte === record.sourceSpan.startByte &&
                declaration.span.endByte === record.sourceSpan.endByte &&
                declaration.span.startColumn === record.sourceSpan.startColumn &&
                declaration.span.endColumn === record.sourceSpan.endColumn)));
}
/**
 * Attach already-proved historical lineage identities to isolated blob facts.
 *
 * The operation resolves its ref once, verifies the pinned physical tree in
 * one listing, and batch-checks local blob presence. It never reads checkout
 * contents and never runs the lineage matcher over body-free structure data.
 * A verified header/footer receipt proves completeness only across one trusted
 * local producer process; it does not cryptographically authenticate a
 * transported payload. Hostile-payload authentication would require rereading
 * and reparsing the physical blob and is intentionally outside V2.
 */
export async function resolveBlobLineage(input, context) {
    const requestedRef = typeof input.ref === 'string' ? input.ref : String(input.ref);
    let parsed;
    try {
        parsed = OccBlobLineageCompatibleInputSchema.parse({
            ref: input.ref,
            blobs: [...input.blobs],
            ...(input.header === undefined ? {} : { header: input.header }),
            ...(input.footer === undefined ? {} : { footer: input.footer }),
        });
    }
    catch (error) {
        return {
            schemaVersion: 2,
            status: 'error',
            requestedRef,
            code: 'invalid-input',
            message: safeMessage(error, context.repoRoot),
        };
    }
    try {
        const result = await resolveValidatedBlobLineage(parsed, context);
        return OccBlobLineageResultV2Schema.parse(result);
    }
    catch (error) {
        // resolveValidatedBlobLineage returns its own typed errors; anything that
        // still throws — including the result self-check — is reported, not thrown.
        return errorResult(requestedRef, error, context.repoRoot);
    }
}
async function resolveValidatedBlobLineage(input, context) {
    const blobs = input.blobs;
    const receiptVerified = input.header !== undefined && input.footer !== undefined;
    const structureSchemaVersion = input.header?.schemaVersion ?? input.blobs[0]?.schemaVersion ?? 2;
    let resolvedCommit;
    try {
        resolvedCommit = await resolveCommit(input.ref, {
            repoRoot: context.repoRoot,
            signal: context.signal,
            counters: context.entityIndex.counters,
        });
    }
    catch (error) {
        return errorResult(input.ref, error, context.repoRoot);
    }
    if (!resolvedCommit) {
        return {
            schemaVersion: 2,
            status: 'error',
            requestedRef: input.ref,
            code: 'invalid-ref',
            message: `Could not resolve "${input.ref}" to a commit.`,
        };
    }
    const atRef = projectEntitiesAtCommit({
        ref: input.ref,
        commit: resolvedCommit,
        entityIndex: context.entityIndex,
        recognizer: context.recognizer,
    });
    if (atRef.status === 'error') {
        return {
            schemaVersion: 2,
            status: 'error',
            requestedRef: input.ref,
            code: atRef.code,
            message: atRef.message,
        };
    }
    const indexDiagnostics = [...context.entityIndex.status.diagnostics];
    if (structureSchemaVersion === 1) {
        indexDiagnostics.push({
            code: 'evidence-unavailable',
            message: 'A persisted blob-structure V1 receipt was decoded, but its line-only spans and parser@1 provenance cannot prove V2 lineage completeness.',
        });
    }
    if (!receiptVerified) {
        indexDiagnostics.push({
            code: 'evidence-unavailable',
            message: 'Blob-structure results were supplied without their batch header/footer receipt; result-only V1 input is compatible but cannot prove complete coverage.',
        });
    }
    if (blobs.length === 0) {
        return {
            schemaVersion: 2,
            status: 'resolved',
            requestedRef: input.ref,
            resolvedCommit,
            structureSchemaVersion,
            blobs: [],
            coverage: {
                structure: receiptVerified && structureSchemaVersion === 2 ? 'complete' : 'unavailable',
                lineage: receiptVerified && structureSchemaVersion === 2 ? 'complete' : 'unavailable',
                verifiedBlobs: 0,
                matchedDeclarations: 0,
                unmatchedDeclarations: 0,
            },
            diagnostics: indexDiagnostics,
        };
    }
    let tree;
    try {
        tree = await listTreeBlobs(resolvedCommit, {
            repoRoot: context.repoRoot,
            signal: context.signal,
            counters: context.entityIndex.counters,
        });
    }
    catch (error) {
        return errorResult(input.ref, error, context.repoRoot);
    }
    const oidByPath = new Map(tree.map(entry => [entry.path, entry.blobSha]));
    const treeMatchedOids = [
        ...new Set(blobs.flatMap(blob => (oidByPath.get(blob.relativePath) === blob.oid ? [blob.oid] : []))),
    ];
    let headers;
    try {
        headers = await readBlobHeaders(treeMatchedOids, {
            repoRoot: context.repoRoot,
            signal: context.signal,
            counters: context.entityIndex.counters,
        });
    }
    catch (error) {
        // A failed batch process provides no trustworthy per-object partition.
        // Ordinary absent promisor objects do not take this path: cat-file reports
        // them as `missing` headers and they become per-item object-unavailable.
        return errorResult(input.ref, error, context.repoRoot);
    }
    const historicalByStateKey = new Map();
    const ambiguousStateKeys = new Set();
    for (const entity of atRef.at.index.all) {
        const stateKey = entityStateKey(entity.record);
        if (ambiguousStateKeys.has(stateKey))
            continue;
        if (historicalByStateKey.has(stateKey)) {
            // Two alive lineages project to one state key. Attaching either identity
            // would be a guess, and the contract is that a mismatch gets no lineage.
            historicalByStateKey.delete(stateKey);
            ambiguousStateKeys.add(stateKey);
            continue;
        }
        historicalByStateKey.set(stateKey, entity);
    }
    const indexComplete = !context.entityIndex.status.truncated &&
        !context.entityIndex.status.diagnostics.some(isEntityEvidenceGapDiagnostic);
    const parserContract = context.entityIndex.parserContract ?? ENTITY_PARSER_CONTRACT;
    let verifiedBlobs = 0;
    let matchedDeclarations = 0;
    let unmatchedDeclarations = 0;
    const structureStates = [];
    const results = [];
    for (const blob of blobs) {
        const diagnostics = [];
        const structureState = structureCoverage(blob, receiptVerified, structureSchemaVersion);
        structureStates.push(structureState);
        const structureGap = structureDiagnostic(structureState);
        if (structureGap)
            diagnostics.push(structureGap);
        if (!receiptVerified) {
            diagnostics.push({
                code: 'structure-batch-unverified',
                message: 'The structure result was supplied without its batch header/footer receipt; lineage may be attached, but complete coverage cannot be claimed.',
            });
        }
        if (structureSchemaVersion === 1) {
            diagnostics.push({
                code: 'legacy-structure-receipt',
                message: 'Blob-structure V1 was decoded for compatibility, but its parser and line-span evidence cannot attach a V2 lineage identity.',
            });
        }
        const actualOid = oidByPath.get(blob.relativePath);
        const pathExists = actualOid !== undefined;
        const oidMatches = pathExists && actualOid === blob.oid;
        if (!pathExists) {
            diagnostics.push({
                code: 'path-missing-at-ref',
                message: `Path "${blob.relativePath}" is not a blob at the pinned commit.`,
            });
        }
        else if (!oidMatches) {
            diagnostics.push({
                code: 'object-mismatch',
                message: `Path "${blob.relativePath}" names object ${actualOid}; the structure result names ${blob.oid}.`,
            });
        }
        const header = oidMatches ? headers.get(blob.oid) : undefined;
        const objectAvailable = oidMatches && header !== undefined && !header.missing && header.type === 'blob';
        if (oidMatches && !objectAvailable) {
            diagnostics.push({
                code: 'object-unavailable',
                message: `Object ${blob.oid} is not physically available as a local Git blob.`,
            });
        }
        if (objectAvailable)
            verifiedBlobs++;
        const parserMatches = blob.provenance.parserName === parserContract.parserName &&
            blob.provenance.parserVersion === parserContract.parserVersion;
        if (!parserMatches) {
            diagnostics.push({
                code: 'parser-contract-mismatch',
                message: `Blob structure used ${blob.provenance.parserName}@${blob.provenance.parserVersion}; ` +
                    `the entity index used ${parserContract.parserName}@${parserContract.parserVersion}.`,
            });
        }
        if (!indexComplete) {
            diagnostics.push({
                code: 'lineage-index-partial',
                message: 'The entity index has an evidence gap, so attached identities cannot make this item complete.',
            });
        }
        const eligible = structureState !== 'unavailable' && objectAvailable && parserMatches;
        const candidates = blob.declarations.map(declaration => {
            const stateKey = entityStateKey({
                relativePath: blob.relativePath,
                kind: declaration.kind,
                qualifiedName: declaration.qualifiedName,
                ordinal: declaration.ordinal,
            });
            const entity = eligible ? historicalByStateKey.get(stateKey) : undefined;
            return {
                declaration,
                stateKey,
                entity,
                exact: entity !== undefined && declarationMatchesHistorical(blob.relativePath, declaration, entity),
            };
        });
        const exactCandidates = candidates.filter(candidate => candidate.exact && candidate.entity !== undefined);
        const missingCandidates = candidates.filter(candidate => !candidate.exact || candidate.entity === undefined);
        let evidenceMismatch = eligible && candidates.some(candidate => candidate.entity !== undefined && !candidate.exact);
        let mismatchDeclarationIndex = candidates.find(candidate => candidate.entity !== undefined && !candidate.exact)
            ?.declaration.declarationIndex;
        if (eligible && exactCandidates.length > 0 && missingCandidates.length > 0) {
            evidenceMismatch = true;
            mismatchDeclarationIndex ??= missingCandidates[0]?.declaration.declarationIndex;
        }
        const claimedLineages = new Set();
        if (eligible) {
            for (const candidate of exactCandidates) {
                const lineageId = candidate.entity?.ref.lineageId;
                if (!lineageId)
                    continue;
                if (claimedLineages.has(lineageId)) {
                    evidenceMismatch = true;
                    mismatchDeclarationIndex ??= candidate.declaration.declarationIndex;
                }
                claimedLineages.add(lineageId);
            }
        }
        if (eligible && receiptVerified && structureState === 'complete' && indexComplete) {
            const historicalAtPath = atRef.at.index.byPath.get(blob.relativePath) ?? [];
            const historicalLineages = new Set(historicalAtPath.map(entity => entity.ref.lineageId));
            const completeSetMatches = historicalLineages.size === historicalAtPath.length &&
                exactCandidates.length === candidates.length &&
                claimedLineages.size === historicalLineages.size &&
                [...historicalLineages].every(lineageId => claimedLineages.has(lineageId));
            if (!completeSetMatches)
                evidenceMismatch = true;
        }
        if (evidenceMismatch) {
            diagnostics.push({
                code: 'structure-evidence-mismatch',
                message: 'The declaration payload conflicts with historical identity evidence for this physical blob; no lineage is attached to any declaration in the blob.',
                ...(mismatchDeclarationIndex === undefined ? {} : { declarationIndex: mismatchDeclarationIndex }),
            });
        }
        const declarations = candidates.map(candidate => {
            const { declaration, entity, stateKey } = candidate;
            if (evidenceMismatch || !candidate.exact || !entity) {
                unmatchedDeclarations++;
                if (eligible && !evidenceMismatch) {
                    diagnostics.push(ambiguousStateKeys.has(stateKey)
                        ? {
                            code: 'state-key-ambiguous',
                            message: `Declaration ${declaration.declarationIndex} matches more than one alive historical ` +
                                `entity at the pinned commit; no lineage is attached.`,
                            declarationIndex: declaration.declarationIndex,
                        }
                        : {
                            code: 'declaration-unmatched',
                            message: `Declaration ${declaration.declarationIndex} has no proved historical entity at the pinned commit.`,
                            declarationIndex: declaration.declarationIndex,
                        });
                }
                return {
                    declarationIndex: declaration.declarationIndex,
                    ordinal: declaration.ordinal,
                    match: 'unmatched',
                };
            }
            matchedDeclarations++;
            return {
                declarationIndex: declaration.declarationIndex,
                ordinal: declaration.ordinal,
                match: 'state-key',
                entity: historicalRef(entity),
            };
        });
        const everyDeclarationMatched = !evidenceMismatch && exactCandidates.length === blob.declarations.length;
        const complete = structureState === 'complete' && objectAvailable && parserMatches && indexComplete && everyDeclarationMatched;
        // An eligible blob was verified against the pinned tree, so evidence was
        // attached even when no declaration found an identity; only an ineligible
        // blob — unverifiable object, wrong parser, no structure — is unavailable.
        const status = complete ? 'complete' : eligible ? 'partial' : 'unavailable';
        results.push({
            requestIndex: blob.requestIndex,
            requestId: blob.requestId,
            oid: blob.oid,
            relativePath: blob.relativePath,
            status,
            declarations,
            diagnostics,
        });
    }
    return {
        schemaVersion: 2,
        status: 'resolved',
        requestedRef: input.ref,
        resolvedCommit,
        structureSchemaVersion,
        blobs: results,
        coverage: {
            structure: aggregateCoverage(structureStates),
            lineage: aggregateCoverage(results.map(result => result.status)),
            verifiedBlobs,
            matchedDeclarations,
            unmatchedDeclarations,
        },
        diagnostics: indexDiagnostics,
    };
}
//# sourceMappingURL=blob-lineage.js.map