/** Injectable schedule seam - the loop depends on this, not the concrete class (DI + testability). */ export interface ReportSchedule { shouldFire(now: Date): { fire: boolean; hourKey: string; }; markFired(hourKey: string): void; /** Anchor timestamp (ISO) of the last SUCCESSFUL full report, for delta-scoped gathers. */ loadLastSuccess(): string | null; /** Persist the anchor after a full report is delivered (failures must never advance it). */ markSuccess(iso: string): void; } /** Persist/restore the last-fired hour key (so a restart within the same hour does not re-send). */ export interface ReportScheduleStore { load(): string | null; save(hourKey: string): void; /** Anchor timestamp (ISO) of the last SUCCESSFUL full report; null before the first one. */ loadLastSuccess(): string | null; /** Persist the success anchor (read-modify-write so it never clobbers the fired-hour key). */ markSuccess(iso: string): void; } /** Local-time "YYYY-MM-DD:HH" bucket. Two ticks in the same local hour share a key. */ export declare function hourKeyLocal(now: Date): string; /** * Parse an env string like "8,13,18" into sorted, deduped LOCAL hours in [0,23]. * Empty/garbage -> [] (feature off). Ports Kagemusha normalizeFullReportHours * (~/project/mama-suite/apps/kagemusha/src/config/ai-config.ts:203) but generic + ASCII, no * personal defaults. */ export declare function parseReportHours(raw: string): number[]; export declare class ReportScheduler implements ReportSchedule { private hours; private store; private lastFiredHourKey; constructor(hours: number[], store: ReportScheduleStore); /** Pure: does a full report fire at now? Robust to ticks not landing on the hour boundary. */ shouldFire(now: Date): { fire: boolean; hourKey: string; }; /** Mark this hour delivered (persist) so we fire once per configured hour, restart-safe. */ markFired(hourKey: string): void; /** Anchor of the last SUCCESSFUL full report (delegates to the store). */ loadLastSuccess(): string | null; /** Persist the success anchor (delegates to the store; called ONLY on a delivered report). */ markSuccess(iso: string): void; } /** File-backed store under ~/.mama - mirrors ConnectorDeltaRepo's atomic cursor file. */ export declare class FileReportScheduleStore implements ReportScheduleStore { private path; constructor(path: string); /** * Read-parse the whole state object. MISSING file -> {} (silent, as today). A corrupt/empty * or non-object state file is disposable bookkeeping: rather than throw and permanently break * the report leg, reset LOUDLY and return {}. Worst case after a reset is one duplicate report * plus a wide gather window - both self-heal on the next successful report. */ private readState; /** Atomic full-object write (tmp+rename) - callers do read-modify-write to preserve sibling fields. */ private writeState; load(): string | null; save(hourKey: string): void; loadLastSuccess(): string | null; markSuccess(iso: string): void; } //# sourceMappingURL=report-scheduler.d.ts.map