/** * Audit log pruning with optional archive-before-delete. * * Prunes audit_log rows older than a configurable retention period. * When archiveBeforePrune is enabled, exports prunable rows to * a gzip-compressed JSONL file before deletion. * * Never throws — logs warnings on failure. Safe for fire-and-forget * startup wiring. * * @task T5339 */ import type { LoggingConfig } from '@cleocode/contracts'; import { type SQL } from 'drizzle-orm'; import type { auditLog } from './store/schema/audit.js'; import type { tasksAuditLog } from './store/schema/cleo-project/audit.js'; export interface PruneResult { rowsArchived: number; rowsDeleted: number; archivePath?: string; } /** * Audit actions that age-based pruning never deletes, whatever their age: * receipts code reads back. * * - `ac.bindings.pruned`: the only surviving record of an evidence binding * whose acceptance criterion was removed. Alias-drift detection * (`E_AC_ALIAS_DRIFTED`, ADR-079-r2 §3) reads them to know what `AC` used * to mean; pruning them would silently turn a drifted alias into a rebind * (T12790). * - `saga_reconciled`: a saga's reconcile receipt (`SAGA_RECONCILE_RECEIPT_ACTION`, * sagas/reconcile.ts). * - `ranking_changed`: the ranking-input audit trail `cleo history ranking` * lists and `cleo history revert` undoes (`RANKING_CHANGED_ACTION`, D11161). * * Literals, not imports: the startup prune must not load those modules * (a test pins them to the constants). `gate.verify.typed` is kept only for an * open task ({@link auditPruneCondition}). * * @task T12790 * @task T13777 */ export declare const AUDIT_PRUNE_EXEMPT_ACTIONS: readonly string[]; /** * The typed-gate receipt completion reads back (gate-runner.ts): kept while * its task is neither done nor cancelled. * * @task T13777 */ export declare const AUDIT_GATE_RECEIPT_ACTION = "gate.verify.typed"; /** * The shortest retention age-based pruning honours. The prune deletes rows * that sync, so the delete reaches every device: one device or agent set to a * day must not erase the fleet's recent history. A smaller * `auditRetentionDays` is clamped up to it. * * @task T13777 */ export declare const AUDIT_RETENTION_FLOOR_DAYS = 30; /** An audit table age-based pruning may target: legacy `audit_log` or `tasks_audit_log`. */ export type PrunableAuditTable = typeof auditLog | typeof tasksAuditLog; /** * The row predicate for age-based pruning of `table`: older than `cutoff`, not * an {@link AUDIT_PRUNE_EXEMPT_ACTIONS} action, and not a * {@link AUDIT_GATE_RECEIPT_ACTION} receipt of a task still open. * * Every prune — of either audit table — selects and deletes through this one * predicate, so retargeting the prune cannot drop the exemption. * * @param table - The audit table being pruned * @param cutoff - ISO-8601 instant; rows strictly older are prunable * @returns The drizzle `WHERE` condition * @task T12790 */ export declare function auditPruneCondition(table: PrunableAuditTable, cutoff: string): SQL; /** * Prune old audit_log rows from tasks.db. * * 1. If auditRetentionDays is 0 or undefined, skip age-based pruning. * 2. Compute cutoff timestamp from auditRetentionDays, clamped up to * {@link AUDIT_RETENTION_FLOOR_DAYS}: the deletes sync to every device. * 3. If archiveBeforePrune, select rows older than cutoff and write to * .cleo/backups/logs/audit-YYYY-MM-DD.jsonl.gz. * 4. Delete rows older than cutoff from audit_log. * * Rows whose action is in {@link AUDIT_PRUNE_EXEMPT_ACTIONS} are never * selected, archived or deleted (T12790). * * Idempotent — safe to call multiple times. * Never throws — returns zero counts on any error. * * @param cleoDir - Absolute path to .cleo directory * @param config - LoggingConfig with auditRetentionDays and archiveBeforePrune */ export declare function pruneAuditLog(cleoDir: string, config: LoggingConfig): Promise; /** File under `.cleo/logs/` holding the time of the last automatic prune (T13828). */ export declare const AUTO_AUDIT_PRUNE_STAMP = "audit-prune.last"; /** The least time between two automatic prunes of one project: a day (T13828). */ export declare const AUTO_AUDIT_PRUNE_INTERVAL_MS = 86400000; /** * The automatic audit prune (T13828): {@link pruneAuditLog} with the project's * `logging` config, at most once per {@link AUTO_AUDIT_PRUNE_INTERVAL_MS} per * project. Session end runs it after its snapshot; `cleo admin cleanup * --target logs` still prunes on demand. * * The stamp is written before the prune, so concurrent session ends skip * rather than all prune. Never throws. * * @param projectRoot - The project root. * @param now - The current time (tests). * @returns The prune result, or `null` when a prune ran within the interval or it failed. */ export declare function autoPruneAuditLog(projectRoot: string, now?: Date): Promise; //# sourceMappingURL=audit-prune.d.ts.map