---
title: "Model file versions as ordered block hashes"
description: "Represent each file version as an immutable blocklist to support delta sync, restore, deletes, renames, and garbage collection."
canonical_url: "https://fanout.sh/system/archive/blocklist-versioned-file-metadata"
md_url: "https://fanout.sh/system/archive/blocklist-versioned-file-metadata.md"
access: "public"
---

# Model file versions as ordered block hashes

Represent each file version as an immutable blocklist to support delta sync, restore, deletes, renames, and garbage collection.

## Public overview

Blocklist Versioned File Metadata

A blocklist is the ordered list of block hashes that defines a file version.

The metadata layer can be append-only even when files look mutable to users.

namespace id scopes the file tree. relative path identifies the user-visible file path. version id is monotonically increasing within the namespace. blocklist is ordered. rows are appended, not updated in place.

Why Append-Only Works

If video.avi changes from:

the server appends a new row. Clients with the old cursor fetch the new row, notice they only lack h5 , and download one block.

This avoids a full directory tree comparison on every sync cycle.

Modeling Deletes And Renames

Do not delete the old journal row. Append a tombstone or rename event:

This keeps incremental sync simple. A client that was offline can replay every namespace change after its cursor and converge without scanning the whole tree.

The metadata service should check:

caller has write permission for the namespace, parent folder still exists, base version is compatible with current path state, every block hash is present or reported as missing, mutation ID has not already committed.

If validation fails because blocks are missing, return the missing hashes instead of appending a partial version. If validation fails because the base version is stale, return conflict information.

Failure Mitigation --- --- two clients edit same path offline conflict copy or merge policy client retries commit after timeout idempotency key returns committed version block garbage collection races commit mark referenced blocks before deleting old ones rename and edit cross in flight serialize by namespace version order privacy deletion requests old versions retention policy must cover journal and blocks

Is version id generated transactionally? Is the journal scoped per account, namespace, shared folder, or global system? How are deletes represented? How are renames represented? Can clients detect local corruption and ask for missing blocks again? How long are old versions retained? How does privacy deletion interact with immutable blocks and dedupe? Can change listing be paginated without skipping versions? Is the cursor durable across client reinstall or device restore?

---
This representation contains public Fanout content only. Protected Pro lessons, account data, billing, checkout, and pricing are not included.

Browse the public content map: https://fanout.sh/sitemap.md
