// engine/multi-teammate-review/disagreement-counter.ts — SPEC-727
// Tracks per-(specId, frontmatterSha) disagreement counts, persisted atomically.
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 helper
// ---------------------------------------------------------------------------
function storePath(projectId) {
    return join('planu', 'data', 'projects', projectId, 'disagreements.json');
}
function storeKey(k) {
    return `${k.specId}::${k.frontmatterSha}`;
}
// ---------------------------------------------------------------------------
// Internal I/O helpers
// ---------------------------------------------------------------------------
async function readStore(projectId) {
    const path = storePath(projectId);
    try {
        const raw = await readFile(path, '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 disagreement counter for (projectId, specId, frontmatterSha).
 * Returns the new count.
 * Purges entries older than 7 days lazily before writing.
 */
export async function markDisagreement(projectId, k) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    const key = storeKey(k);
    const existing = purged[key] ?? { count: 0, updatedAt: new Date().toISOString() };
    const updated = {
        count: existing.count + 1,
        updatedAt: new Date().toISOString(),
    };
    purged[key] = updated;
    await writeStore(projectId, purged);
    return updated.count;
}
/**
 * Read the current disagreement count for (projectId, specId, frontmatterSha).
 * Returns 0 if no entry exists or if the entry has been purged.
 * Purges stale entries lazily.
 */
export async function readDisagreement(projectId, k) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    // Write back if anything was purged
    if (Object.keys(purged).length !== Object.keys(raw).length) {
        await writeStore(projectId, purged);
    }
    return purged[storeKey(k)]?.count ?? 0;
}
/**
 * Reset the disagreement counter for (projectId, specId, frontmatterSha).
 */
export async function resetDisagreement(projectId, k) {
    const raw = await readStore(projectId);
    const purged = purgeStale(raw);
    Reflect.deleteProperty(purged, storeKey(k));
    await writeStore(projectId, purged);
}
//# sourceMappingURL=disagreement-counter.js.map