function asNonEmptyString(v) {
    return typeof v === 'string' && v.length > 0 ? v : undefined;
}
/**
 * Group `friction` events by (session, surface, failureId) and flag groups
 * that repeat at least `minRepeats` times — the signature of an agent hitting
 * the same guard over and over rather than changing approach after the first
 * block. `events` is expected to already be filtered/queried for
 * `eventTypes: ['friction']` (see events.ts `query()`); non-friction records
 * are ignored defensively rather than assumed absent.
 */
export function detectRepeatedGuardBlocks(events, opts = {}) {
    const minRepeats = opts.minRepeats ?? 3;
    const groups = new Map();
    for (const e of events) {
        if (e.event !== 'friction')
            continue;
        const surface = asNonEmptyString(e.surface);
        const failureId = asNonEmptyString(e.failureId);
        if (!surface || !failureId)
            continue;
        const session = e.session ?? 'unknown';
        const key = `${session}\0${surface}\0${failureId}`;
        const bucket = groups.get(key);
        if (bucket)
            bucket.push(e);
        else
            groups.set(key, [e]);
    }
    const out = [];
    for (const [key, evs] of groups) {
        if (evs.length < minRepeats)
            continue;
        const [session, surface, failureId] = key.split('\0');
        const sortedTs = evs.map((e) => e.ts).sort();
        out.push({
            session,
            surface,
            failureId,
            count: evs.length,
            firstTs: sortedTs[0],
            lastTs: sortedTs[sortedTs.length - 1],
        });
    }
    out.sort((a, b) => b.count - a.count);
    return out;
}
