// Retrieval-suppression predicate.
//
// isMemorySuppressedFromRetrieval is a pure function consumed by the retrieval layer
// (#210) to filter result sets. It maps the discriminated MemoryStatus enum to a
// suppression reason and also applies two derived rules:
//
//   - validity.validUntil <= nowMs   →   "expired"   (regardless of status)
//   - provenance.confidence <= staleConfidenceThreshold  →  "stale-low-confidence"
//
// Default staleConfidenceThreshold is 0.3 — same conservative floor consolidation uses
// (#208 _constants.ts STALE_CONFIDENCE_DEFAULT 0.3) so the two layers agree on what
// counts as low-confidence. The threshold is a `<=` comparison: a record exactly at
// the threshold is suppressed.
//
// The contracts MemoryStatus enum is the single source of truth: every legal status
// branches to a deterministic suppression decision. A future widening of MemoryStatus
// surfaces as an exhaustiveness compile error here.
import { GovernanceError } from "./errors.js";
const DEFAULT_STALE_CONFIDENCE_THRESHOLD = 0.3;
const NOT_SUPPRESSED = { suppressed: false };
function isFiniteInRange(value, min, max) {
    return Number.isFinite(value) && value >= min && value <= max;
}
function resolveThreshold(options) {
    const threshold = options.staleConfidenceThreshold ?? DEFAULT_STALE_CONFIDENCE_THRESHOLD;
    if (isFiniteInRange(threshold, 0, 1))
        return threshold;
    throw new GovernanceError("invalid-threshold", `staleConfidenceThreshold must be a finite number in [0, 1] (got ${String(threshold)})`);
}
function statusSuppression(status) {
    switch (status) {
        case "archived":
            return { suppressed: true, reason: "archived" };
        case "forgotten":
            return { suppressed: true, reason: "forgotten" };
        case "conflicted":
            return { suppressed: true, reason: "conflicted" };
        case "rejected":
            return { suppressed: true, reason: "rejected" };
        case "expired":
            // Validity-based "expired" is checked separately below so an explicit `expired`
            // status carries the same surface reason whether the retrieval index pinned it via
            // status or derived it from the validity window.
            return { suppressed: true, reason: "expired" };
        case "proposed":
            return { suppressed: true, reason: "proposed" };
        case "accepted":
        case "superseded":
            // accepted/superseded are pass-through here. Superseded records are still readable
            // in audit views; the retrieval layer applies its own includeSuperseded toggle on
            // top of this predicate. Review queues surface proposed records through direct
            // status filtering rather than retrieval.
            return null;
        default: {
            const _exhaustive = status;
            void _exhaustive;
            return null;
        }
    }
}
function validitySuppression(memory, nowMs) {
    if (memory.validity.validUntil === undefined)
        return null;
    if (memory.validity.validUntil > nowMs)
        return null;
    return { suppressed: true, reason: "expired" };
}
function confidenceSuppression(memory, threshold) {
    if (memory.provenance.confidence > threshold)
        return null;
    return { suppressed: true, reason: "stale-low-confidence" };
}
export function isMemorySuppressedFromRetrieval(memory, nowMs, options = {}) {
    const threshold = resolveThreshold(options);
    const byStatus = statusSuppression(memory.status);
    if (byStatus !== null)
        return byStatus;
    const byValidity = validitySuppression(memory, nowMs);
    if (byValidity !== null)
        return byValidity;
    const byConfidence = confidenceSuppression(memory, threshold);
    if (byConfidence !== null)
        return byConfidence;
    return NOT_SUPPRESSED;
}
