02 — Storage Model

From the Burrow™ specification set.

02 — Storage Model

Purpose

Separate where a file exists, what role that location serves, cloud synchronization state, and backup protection. These concepts must never be collapsed into one status.

Location Types

  • INTERNAL_VOLUME
  • EXTERNAL_VOLUME
  • ICLOUD_DRIVE
  • ONEDRIVE
  • OTHER_LOCAL
  • FUTURE_NETWORK
  • FUTURE_CLOUD

A OneDrive or iCloud item may also physically consume internal disk space. Provider classification and physical consumption are separate attributes.

StorageClassifier

StorageClassifier (BurrowEngine) classifies one inventory record without walking the filesystem or writing files. It reuses VolumeClassification for volume-flag types and adds provider location types.

Provider type Location type Cloud state 0.1 protection Allocation
LOCAL on internal, non-removable INTERNAL_VOLUME NOT_CLOUD LOCAL_ONLY pass-through
LOCAL on removable, not internal EXTERNAL_VOLUME NOT_CLOUD LOCAL_ONLY pass-through
LOCAL any other volume flags OTHER_LOCAL NOT_CLOUD LOCAL_ONLY pass-through
ICLOUD (including an item stored locally) ICLOUD_DRIVE observed, else CLOUD_UNKNOWN SYNCED_ONLY pass-through
ONEDRIVE ONEDRIVE observed, else CLOUD_UNKNOWN SYNCED_ONLY pass-through

An iCloud item that occupies internal disk is still ICLOUD_DRIVE. Its allocated_size_bytes stay on the record and are not replaced by the provider type. LOCAL records ignore an observed cloud hint so internal-only files stay NOT_CLOUD / LOCAL.

SYNCED_LOCAL (cloud state) is not BACKED_UP (protection). Release 0.1 emits only LOCAL_ONLY, SYNCED_ONLY, and UNKNOWN.

Storage Roles

ACTIVE

Working data expected to remain readily accessible.

ARCHIVE

Preserved historical data that does not need to remain in active storage.

BACKUP

A secondary copy maintained for recovery.

A volume may support multiple roles, but each configured root should have an explicit intended role.

Cloud State

Where detectable:

  • NOT_CLOUD
  • CLOUD_UNKNOWN
  • CLOUD_ONLY
  • DOWNLOADED
  • PINNED_LOCAL
  • SYNCED_LOCAL
  • ERROR_OR_CONFLICT

Provider-specific details should be retained separately from normalized state.

Protection State

Derived, not manually asserted:

  • UNPROTECTED
  • LOCAL_ONLY
  • SYNCED_ONLY
  • BACKED_UP
  • VERIFIED_BACKUP
  • ARCHIVED
  • MULTI_LOCATION_PROTECTED
  • UNKNOWN

The derivation algorithm must be documented and testable.

0.1 derivation (authoritative)

StorageClassifier.protectionState(forProviderType:) reuses StorageProtectionState. It is the only 0.1 derivation. Catalog and UI labels come from StorageProtectionState.catalogLabel (web: catalogProtectionLabel).

Provider type 0.1 protection Catalog/UI label
LOCAL (including an empty token) LOCAL_ONLY Local only
ICLOUD, ICLOUD_DRIVE SYNCED_ONLY Synced only
ONEDRIVE, ONE_DRIVE SYNCED_ONLY Synced only
Any other token UNKNOWN Unknown

The function never returns BACKED_UP, VERIFIED_BACKUP, UNPROTECTED, ARCHIVED, or MULTI_LOCATION_PROTECTED. Labels never say “backed up” or “protected” for a synced cloud file. Those later-release states remain listed above as future work. The 0.1 constraint is authoritative.

Release 0.1 may only emit states Burrow™ can prove without backup functionality: LOCAL_ONLY, SYNCED_ONLY, and UNKNOWN. Do not describe synchronized cloud files as backed up or protected. BACKED_UP, VERIFIED_BACKUP, ARCHIVED, MULTI_LOCATION_PROTECTED, and UNPROTECTED remain later-release states.

Collection

A Collection is a logical group of data for backup/health purposes, e.g.:

  • Personal Documents
  • Development
  • Photos
  • Financial
  • Archive

Collections reference one or more roots and later one or more protection policies.

Stable Identity

Paths are mutable. Track:

  • volume stable identifier;
  • filesystem identity where available;
  • current path;
  • content hash where calculated.

Do not assume path alone permanently identifies a file.

Logical vs Physical Size

Capture both when possible:

  • logical file size;
  • allocated/physical size.

Cloud placeholders may have a large logical size and minimal local allocation. The UI must not misleadingly count the logical size as immediately reclaimable local disk space. Inventory persists both fields on file_item and treats CLOUD_ONLY logical size as catalog metadata, not locally allocated reclaimable bytes.

The engine persists both columns on file_item (logical_size_bytes, allocated_size_bytes) when a read-only probe can observe them. Query results expose both fields when known. scan.logical_bytes_seen is inventory progress, not local reclaim.

Public size types: FileSizeObservation, FileSizeWrite, FileSizeRecord, FileSizeProbe, ReclaimableLocalBytes. Catalog.persistFileSizes writes the size pair; Catalog.fileSizes() / Catalog.fileSize(fileId:) return it.

Catalog.storageAnalytics() (VLT-32) is the read-only Storage View query: capacity/utilization, largest files/folders, age buckets, file-type summaries, cloud vs local allocation, and scan timestamp/age. It reuses ReclaimableLocalBytes and StorageClassifier. Duplicate recovery is unavailable_until_0_2. There is no HTTP analytics route and no recommendation labeled safe to delete. The 0.1 dashboard binds a typed fixture payload (DashboardAnalyticsPayload) with the same allocated-bytes rule until catalog numbers are supplied.

Reclaimable Space

"Potential recovery" must be conservative.

ReclaimableLocalBytes (and FileSizeRecord.reclaimableLocalBytes) uses allocated size only. If allocated size is unknown, the local estimate is 0 — never the logical placeholder size. A 5 GB cloud placeholder that occupies 4 KB locally contributes 4 KB, not 5 GB.

For exact duplicates, do not sum all copies. A duplicate group with N copies can at most reclaim the size of the copies that are genuinely removable. That N-1 math is release 0.2 and is not implemented here.

Cloud eviction ("free up local space") is different from deletion and should be presented as a separate future action.

Source of Truth

Filesystem/provider state observed during the latest scan is evidence. The SQLite catalog is historical state and analysis.

The UI should display scan age so users know when a conclusion may be stale.