// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
// ══════════════════════════════════════════════════════════════════
// behavioral_drift_window signal_type (v0.1): TypeScript types
// ══════════════════════════════════════════════════════════════════
// Time-axis extension of single-event behavioral attestations such as
// cognitive_attestation. One envelope bundles N constituent envelope
// hashes for the same subject agent across [window_start, window_end]
// plus summary metrics computed across that window.
//
// What this primitive attests to: the observer (identified by
// observer_id) committed to a specific summary of subject_agent_id's
// behavior over the declared window at the moment of signing. It does
// NOT attest:
//   - That the constituent envelopes are themselves valid (downstream
//     verifies each).
//   - That the metrics are computed correctly (downstream may recompute
//     from constituents).
//   - Whether the drift is significant, malicious, or benign (downstream
//     policy decision).
//
// observer_id MAY equal subject_agent_id (self-attestation, audit-trail
// use case) or MAY differ (third-party monitoring use case). Both shapes
// are valid; the signature is always verified against observer_id.
//
// v0.1 surface: bundle of constituent hashes, decision_count,
// class_distribution over the three v0.1 cognitive_attestation classes,
// optional confidence summary, optional baseline comparison.
//
// v0.2 deferred: SDK-side recomputation of metrics from constituents,
// time-series API, hierarchical/composite drift envelopes, threshold
// policy.
// ══════════════════════════════════════════════════════════════════
const HEX_KEY = /^[0-9a-f]{64}$/;
const HEX_SIGNATURE = /^[0-9a-f]{128}$/;
const HEX_DIGEST = /^[0-9a-f]{64}$/;
function isNonNegativeInteger(n) {
    return typeof n === 'number' && Number.isFinite(n) && Number.isInteger(n) && n >= 0;
}
/**
 * Parse an ISO 8601 timestamp. Returns the millisecond epoch on success
 * or NaN on failure. Native Date.parse accepts ISO 8601 plus some
 * non-ISO forms; we tighten by requiring the input to round-trip through
 * toISOString-style detection (presence of a date and either a 'T' or
 * 'Z' anchor). This is a shape check, not a normalization step.
 */
export function parseIso8601(value) {
    if (typeof value !== 'string' || value.length === 0)
        return NaN;
    // Cheap structural sniff: must contain a digit and either a 'T', '-', or 'Z'
    // and start with a 4-digit year.
    if (!/^\d{4}-\d{2}-\d{2}([T ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?)?$/.test(value)) {
        return NaN;
    }
    const t = Date.parse(value);
    return Number.isFinite(t) ? t : NaN;
}
/**
 * Runtime type guard. Returns true when `value` is structurally a signed
 * behavioral_drift_window envelope at the field-presence and type-tag
 * level. Does NOT verify cross-field invariants (e.g. metrics consistency)
 * or signature validity; use {@link verifyBehavioralDriftWindow} for that.
 *
 * Invariants checked:
 *   - signal_type literal matches.
 *   - observer_id, subject_agent_id are 64 lowercase hex chars.
 *   - signature is 128 lowercase hex chars.
 *   - window_start, window_end are strings.
 *   - constituent_attestations is an array of 64-hex strings.
 *   - metrics has decision_count (non-negative integer) and
 *     class_distribution with three non-negative integer fields.
 *   - confidence_mean / confidence_stddev, when present, are finite numbers.
 *   - baseline_ref, when present, is a 64-hex string; divergence_score,
 *     when present, is a finite number.
 */
export function isBehavioralDriftWindow(value) {
    if (typeof value !== 'object' || value === null)
        return false;
    const v = value;
    if (v.signal_type !== 'behavioral_drift_window')
        return false;
    if (typeof v.subject_agent_id !== 'string' || !HEX_KEY.test(v.subject_agent_id))
        return false;
    if (typeof v.observer_id !== 'string' || !HEX_KEY.test(v.observer_id))
        return false;
    if (typeof v.window_start !== 'string')
        return false;
    if (typeof v.window_end !== 'string')
        return false;
    if (typeof v.signature !== 'string' || !HEX_SIGNATURE.test(v.signature))
        return false;
    if (!Array.isArray(v.constituent_attestations))
        return false;
    for (const h of v.constituent_attestations) {
        if (typeof h !== 'string' || !HEX_DIGEST.test(h))
            return false;
    }
    if (!isBehavioralDriftWindowMetrics(v.metrics))
        return false;
    return true;
}
/**
 * Validate the {@link BehavioralDriftWindowMetrics} shape. Field-presence
 * and per-field type only; cross-field invariants (sum, pairing, range)
 * are enforced by the verifier.
 */
export function isBehavioralDriftWindowMetrics(value) {
    if (typeof value !== 'object' || value === null)
        return false;
    const m = value;
    if (!isNonNegativeInteger(m.decision_count))
        return false;
    if (typeof m.class_distribution !== 'object' || m.class_distribution === null)
        return false;
    const d = m.class_distribution;
    if (!isNonNegativeInteger(d.precondition_set))
        return false;
    if (!isNonNegativeInteger(d.candidate_set))
        return false;
    if (!isNonNegativeInteger(d.decision_path))
        return false;
    if ('confidence_mean' in m && m.confidence_mean !== undefined) {
        if (typeof m.confidence_mean !== 'number' || !Number.isFinite(m.confidence_mean))
            return false;
    }
    if ('confidence_stddev' in m && m.confidence_stddev !== undefined) {
        if (typeof m.confidence_stddev !== 'number' || !Number.isFinite(m.confidence_stddev))
            return false;
    }
    if ('baseline_ref' in m && m.baseline_ref !== undefined) {
        if (typeof m.baseline_ref !== 'string' || !HEX_DIGEST.test(m.baseline_ref))
            return false;
    }
    if ('divergence_score' in m && m.divergence_score !== undefined) {
        if (typeof m.divergence_score !== 'number' || !Number.isFinite(m.divergence_score))
            return false;
    }
    return true;
}
/**
 * Sum of {@link ClassDistribution} values. Used by the verifier to check
 * that decision_count matches the breakdown.
 */
export function classDistributionSum(d) {
    return d.precondition_set + d.candidate_set + d.decision_path;
}
//# sourceMappingURL=types.js.map