// engine/escalator/retry-counter.ts — SPEC-729
// Persisted retry counter keyed on (role, specId, frontmatterSha).
import { join } from 'node:path';
import { readFile } from 'node:fs/promises';
import { atomicWriteFile } from '../safety/atomic-write-file.js';
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/** Entries older than 7 days are purged lazily on read. */
const PURGE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
// ---------------------------------------------------------------------------
// Path helpers
// ---------------------------------------------------------------------------
function storePath(projectId) {
    return join('planu', 'data', 'projects', projectId, 'retry-counters.json');
}
function storeKey(k) {
    return `${k.role}::${k.specId}::${k.frontmatterSha}`;
}
// ---------------------------------------------------------------------------
// Internal I/O
// ---------------------------------------------------------------------------
async function readStore(projectId) {
    try {
        const raw = await readFile(storePath(projectId), 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return {};
    }
}
function purgeStale(store) {
    const cutoff = Date.now() - PURGE_TTL_MS;
    const result = {};
    for (const [key, entry] of Object.entries(store)) {
        if (new Date(entry.updatedAt).getTime() >= cutoff) {
            result[key] = entry;
        }
    }
    return result;
}
async function writeStore(projectId, store) {
    await atomicWriteFile(storePath(projectId), JSON.stringify(store, null, 2));
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Increment the retry counter for (projectId, role, specId, frontmatterSha).
 * Returns the new count.
 * Purges entries older than 7 days lazily before writing.
 */
export async function incrementCounter(projectId, key) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    const k = storeKey(key);
    const existing = purged[k] ?? { count: 0, updatedAt: new Date().toISOString() };
    const updated = {
        count: existing.count + 1,
        updatedAt: new Date().toISOString(),
    };
    purged[k] = updated;
    await writeStore(projectId, purged);
    return updated.count;
}
/**
 * Read the current retry count.
 * Returns 0 if no entry exists. Purges stale entries lazily.
 */
export async function readCounter(projectId, key) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    if (Object.keys(purged).length !== Object.keys(raw).length) {
        await writeStore(projectId, purged);
    }
    return purged[storeKey(key)]?.count ?? 0;
}
/**
 * Reset the retry counter (e.g. after user answers abort/manual-override).
 */
export async function resetCounter(projectId, key) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    Reflect.deleteProperty(purged, storeKey(key));
    await writeStore(projectId, purged);
}
//# sourceMappingURL=retry-counter.js.map