# Mole Cache Expiration Policy: TTL Rules and Grace Windows Explained

> Understand Mole's cache expiration policy. Learn about TTL rules for snapshots and directory caches, stale cache durations, and grace windows for modifications.

- Repository: [Tw93/Mole](https://github.com/tw93/Mole)
- Tags: deep-dive
- Published: 2026-03-20

---

**Mole's cache expiration policy uses time-based TTLs of 7 days for overview snapshots and standard directory caches, 3 days for stale caches, and includes 30-minute grace windows for directory modification detection.**

Mole, an open-source disk usage analyzer by tw93, maintains multiple layers of on-disk caches to avoid rescanning large directory trees. Understanding the **Mole cache expiration policy** is crucial for developers extending the tool or troubleshooting why certain directories trigger fresh scans versus cache hits.

## Overview of Mole's Cache Layers

Mole implements three distinct cache types in the `cmd/analyze` package, each serving different performance and accuracy requirements:

- **Overview size cache**: Quick lookup for directory sizes without full scans
- **Standard directory cache**: Complete scan data persisted to disk
- **Stale cache**: Fallback data used for fast UI rendering before background refresh

Each layer enforces its own expiration logic based on TTL constants defined in the source code.

## Cache Expiration Rules by Type

### Overview Size Cache (7-Day TTL)

The overview size cache stores snapshots for rapid size lookups. According to the source in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go), the `loadStoredOverviewSize` function validates these entries against a hard TTL.

The cache expires when:
- The stored snapshot is older than `overviewCacheTTL` (7 days)
- The path is explicitly invalidated through the API

```go
// From cmd/analyze/cache.go
if time.Since(snapshot.Updated) < overviewCacheTTL {
    // Cache valid, return overview size
}

```

### Standard Directory Cache (7-Day Maximum with Grace Windows)

The standard directory cache, loaded via `loadCacheFromDisk`, implements the most complex expiration logic. It combines absolute age limits with modification-time detection to balance performance against data freshness.

**Hard expiration (7 days):**
If the cache's `ScanTime` exceeds 7 days, it expires immediately regardless of directory state.

**Modification-based expiration:**
When the target directory's `ModTime` is newer than the cached `ModTime`, Mole applies two protective windows before invalidating:

1. **30-minute grace window** (`cacheModTimeGrace`): Ignores minor timestamp changes under 30 minutes
2. **24-hour reuse window** (`cacheReuseWindow`): Uses the cache anyway if it's less than 24 hours old, even if the directory changed

```go
// From cmd/analyze/cache.go
if scanAge > 7*24*time.Hour {
    return nil, fmt.Errorf("cache expired: too old")
}

if info.ModTime().After(entry.ModTime) {
    if cacheModTimeGrace <= 0 || info.ModTime().Sub(entry.ModTime) > cacheModTimeGrace {
        if cacheReuseWindow <= 0 || scanAge > cacheReuseWindow {
            return nil, fmt.Errorf("cache expired: directory modified")
        }
    }
}

```

### Stale Cache (3-Day TTL)

The stale cache provides immediate UI rendering while background scans refresh data. Loaded via `loadStaleCacheFromDisk`, it uses a shorter TTL of 3 days (`staleCacheTTL`) and ignores directory modification checks.

This cache expires only when its `ScanTime` exceeds the 3-day threshold, making it ideal for the "fast first paint" use case.

```go
// From cmd/analyze/cache.go
if time.Since(entry.ScanTime) > staleCacheTTL {
    return nil, fmt.Errorf("stale cache expired")
}

```

## Where Cache TTL Constants Are Defined

All expiration durations are centralized in [`cmd/analyze/constants.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/constants.go) as constant declarations:

```go
// From cmd/analyze/constants.go
const (
    overviewCacheTTL  = 7 * 24 * time.Hour   // 7‑day TTL for overview snapshots
    cacheModTimeGrace = 30 * time.Minute     // grace window for dir mtime changes
    cacheReuseWindow  = 24 * time.Hour       // reuse recent cache despite dir changes
    staleCacheTTL     = 3 * 24 * time.Hour   // TTL for "stale" cache loads
)

```

These constants control the behavior documented in the `loadCacheFromDisk` and `loadStoredOverviewSize` functions.

## How Cache Expiration Is Enforced

The enforcement logic resides primarily in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go). When Mole attempts to load cached data, it follows this validation sequence:

1. **File existence check**: Verify the cache file exists on disk
2. **Deserialization**: Unmarshal the JSON/ msgpack data into cache entries
3. **TTL validation**: Apply the time-based expiration rules specific to the cache type
4. **Modification validation**: For standard caches, compare directory modification times against grace windows

If any check fails, the function returns an error, triggering Mole's fallback to a full directory scan.

## Practical Usage Examples

When integrating with Mole's cache system programmatically, you handle expiration through error checking:

```go
// Load a fresh cache for a path
entry, err := loadCacheFromDisk("/Users/me/Projects/my-repo")
if err != nil {
    // Cache miss or expired: perform full scan
    entry, _ = runFullScan("/Users/me/Projects/my-repo")
}

// Load stale cache for fast UI rendering
stale, err := loadStaleCacheFromDisk("/Users/me/Projects/my-repo")
if err != nil {
    // No recent stale cache available
    // Show loading state and start background scan
}

```

The error messages returned from `loadCacheFromDisk` specifically indicate whether expiration was due to age ("too old"), directory modification, or the stale cache TTL.

## Summary

- **Overview size caches** expire after **7 days** or when explicitly invalidated
- **Standard directory caches** have a hard limit of **7 days**, with additional expiration triggered by directory modifications outside **30-minute grace windows** and **24-hour reuse windows**
- **Stale caches** persist for **3 days** to enable fast UI rendering before background refresh
- All TTL constants are defined in [`cmd/analyze/constants.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/constants.go) and enforced in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go)

## Frequently Asked Questions

### How long does Mole keep cached directory scan data?

Mole retains standard directory cache entries for a maximum of **7 days**. However, caches may expire earlier if the directory modification time changes by more than 30 minutes and the cache is older than 24 hours.

### What is the difference between standard cache and stale cache in Mole?

The **standard cache** provides accurate scan data subject to strict expiration rules including modification time checks. The **stale cache** ignores directory modifications and uses a shorter **3-day TTL** specifically to provide immediate data for UI rendering while background scans refresh the data.

### Where are the cache expiration values configured in Mole?

All cache TTL values are hardcoded as constants in [`cmd/analyze/constants.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/constants.go). This includes `overviewCacheTTL` (7 days), `cacheModTimeGrace` (30 minutes), `cacheReuseWindow` (24 hours), and `staleCacheTTL` (3 days).

### Does Mole check file modification times or just directory modification times?

Mole primarily checks **directory modification times** (`ModTime`) against cached values. The `loadCacheFromDisk` function in [`cmd/analyze/cache.go`](https://github.com/tw93/Mole/blob/main/cmd/analyze/cache.go) compares the target directory's current `ModTime` with the cached `ModTime` to determine if the directory structure has changed since the last scan.