Resources & versions
Underneath everything the platform sells sits the content itself, held once in the Content Lake. This page is about the two ideas you need to picture where a piece of content lives and how it changes over time. The first is the Resource — the unit of content. The second is the Version — a saved snapshot of a Resource at a meaningful moment.
A Resource is one document, image, video, audio file, or code repository. A single chapter of a book is a Resource; so is a cover image, a narration track, or the sample-code repository that ships with a title. Each Resource records where it came from — its Source — and which Work it belongs to, and it is through the Work that rights reach the content. Content that is not yet in a Work sits in staging: owner-only, and not usable until it is promoted.
Versioning here is deliberately different from the live, keystroke-level history you get in Google Docs or Word. The platform does not try to be your editor. Instead it snapshots the content at moments that matter — a submitted draft, an approved edition — and leaves the moment-to-moment editing to the tools authors already use. That single design choice is what lets the platform accept content from thousands of different sources without pretending to own the editing experience.
This page covers the five Resource types, how one uploaded file can become many Resources sharing one Source, and how the snapshot model works. Binary payloads — the actual bytes behind images, audio, and video — are handled separately; that mechanism is described in the collapsible near the end.
The five Resource types
Every Resource has a type. There are exactly five, and the type
decides the shape of the content it carries.
| Type | What it holds | Example |
|---|---|---|
DOCUMENT |
Structured text content in Packt Content Format (PCF) | A book chapter, an article, a transcript |
IMAGE |
A still image, with dimensions and accessibility metadata | A figure, a screenshot, a cover |
VIDEO |
A video, with a transcript, captions, and a poster frame | A course lesson, a recorded talk |
AUDIO |
An audio track, with a transcript and chapter markers | An audiobook narration, a podcast |
GIT_REPOSITORY |
A self-contained snapshot of a git repository, pinned to a commit | The sample code for a title |
The distinction that matters most is between DOCUMENT and the other
four. A DOCUMENT is stored as structured content — an ordered
list of blocks (headings, paragraphs, tables, code blocks) in
Packt Content Format, not an opaque file. The
other four types wrap binary payloads — the bytes live in blob
storage and the Resource points at them (see
Binary content below). This
is why you can search, cite, and reuse a paragraph of a document, but
address a video by timestamp rather than by word.
The natural language versus the programming language
Every Resource records a primary natural language — the language of
its prose. A GIT_REPOSITORY may have null here (its content is
code, not prose), while the programming languages it contains are
recorded separately as attributes of the repository. The two are
distinct axes and are never conflated.
Two Resources of the same type sharing content is common and expected:
an audiobook AUDIO Resource points at the DOCUMENT Resource that is
its transcript; a VIDEO lesson references both a transcript and a
captions track. These links are how accessibility and downstream
processing (summarising a talk, for instance) find the text equivalent
of a media asset.
A Resource, abridged (JSON)
A trimmed DOCUMENT Resource. Notice that it points at its
Source, its originating Activity, and its Work rather than
embedding them — each fact lives in exactly one place, and the read
model stitches the resolved equivalents back together for you.
{
"id": "res_ml_go_ch3",
"tenant": "packt",
"work_id": "wk_ml_go",
"type": "DOCUMENT",
"title": "Chapter 3 — Goroutines and Channels",
"language": "en",
"version": "ver_0197ccc",
"uri": "cl://packt/document/res_ml_go_ch3/ver_0197ccc",
"source_id": "src_ml_go_manuscript",
"generated_by": "act_ingest_ml_go",
"rights_basis": [
{ "contract_id": "ctr_chandra_2026", "contract_version": 3 }
],
"hash": "sha256:0f3a9c…",
"hash_content": "sha256:7b21e4…"
}
hash covers content and metadata and serves as the strong
ETag; hash_content covers content only, so a metadata-only edit
leaves it unchanged. rights_basis pins the exact contract
versions the Resource was created under — the full resolved rights
live on the Work.
Sources: where it came from
A Source is the record of the external artefact a Resource was ingested from — the original manuscript file, the video that was uploaded, the repository that was cloned. It captures the origin: which system it came from (SharePoint, a git host, an upload), the original file's hash for fixity, and when it was last seen at the origin.
The relationship is one file to many Resources, but only one Source. When a single manuscript is split into one Resource per chapter during ingestion, every one of those chapter Resources shares the same Source. That is what lets the platform answer "which chapters came from this manuscript?" and "has the original file changed at the origin since we ingested it?" with a single record rather than a copy on every chunk.
flowchart TD
F["manuscript.docx<br/>(one uploaded file)"] --> SRC["Source<br/>src_ml_go_manuscript"]
SRC -->|split into| R1["Resource<br/>Chapter 1"]
SRC --> R2["Resource<br/>Chapter 2"]
SRC --> R3["Resource<br/>Chapter 3"]
The Source is a first-class entity in the Content Lake, not a buried attribute. Because it stands on its own, the origin edge — this file became this Work's content — is explicit and queryable, and the full provenance of how the split happened is recorded on the Activity that performed it rather than smeared across every Resource.
The Resource–Source–Work triangle
Three entities meet on every Resource, and it is worth holding the shape of the triangle in your head. The Source says where the content came from. The Work says what intellectual property it belongs to — and therefore, through the Work's Contract, what may be done with it. The Resource is the content in between.
flowchart TD
R["Resource<br/>the content"]
S["Source<br/>where it came from"]
W["Work<br/>the IP — holds rights"]
R -->|source_id| S
R -->|work_id| W
S -->|originates| W
W -.->|governed by a Contract| C["Contract"]
Rights never live on the Resource. They are held once on the
Work, resolved from the governing Contract, and
projected onto each Resource so that a read or a search result
already knows what may be done with it — which territories, which
formats, whether an AI assistant may retrieve it. Each Resource keeps a
rights_basis recording the exact contract versions it was created
under, so a consequential use can be revalidated against precisely
those terms. When a contract changes, the platform reprojects; you do
not re-key anything.
Staging: content before it has a Work
A Resource can exist before it belongs to a Work — its work_id is
null while it sits in staging. Staged content is owner-only
and cannot appear in a Product; it is a holding area so editorial
work can begin before the paperwork is settled. Promoting the
Resource into a Work is what makes it properly usable. See
Works & rights.
Versions: explicit snapshots, not keystrokes
The Content Lake versions Resources by snapshot. A version is the state of a Resource captured at a chosen moment — and, crucially, capturing that moment is an explicit act, not an automatic side effect of editing.
This is a deliberate boundary. Editors live in Word and Google Docs; those tools already give them real-time collaboration, per-character history, and undo. The platform's job is not to reinvent that. Its job is to snapshot the meaningful moments — the draft that was submitted for review, the edition that was approved for publication — so that products, citations, and rights can pin a stable, named state of the content. Snapshotting keystrokes would be enormous, meaningless noise; snapshotting decisions is exactly the history the business needs.
The working state and named snapshots
Every Resource has a live working state, addressed as latest. This is
the current content as it stands — it moves as ingestion syncs new
edits from the source, or as the content is corrected. latest is a
moving pointer, not a fixed point in history.
A snapshot freezes a copy of the working state into a permanent,
immutable version with its own identifier — a ver_ ID. Once taken, a
ver_ version never changes. Because ver_ identifiers are
time-ordered, they naturally sort into the order they were created.
flowchart LR
W["latest<br/>working state<br/>(moves as edits arrive)"]
V1["ver_0196bbb<br/>submitted draft"]
V2["ver_0197ccc<br/>approved edition"]
W -.->|snapshot| V1
W -.->|snapshot| V2
V1 --> V2
A brand-new Resource has no snapshots at all — its version is null
and only latest exists — until the first snapshot is explicitly taken.
From then on, anything that needs a stable reference (a Product built
from the content, a citation from a search result, a
ContentUnit locator that must not drift) pins a
specific ver_ version rather than the moving latest.
Pin a version wherever stability matters
If you are building anything durable on top of a Resource — a
Product, a stored answer, a compiled edition — reference a ver_
snapshot, not latest. A ver_ version is a promise the bytes will
not move; latest makes no such promise.
Snapshot retention and compaction
Snapshots are created explicitly, but they are not all kept forever. To keep storage in check, the platform may compact old snapshots that nothing depends on. Setting that expectation now matters, so plan around it: do not treat every past snapshot as guaranteed to be retrievable indefinitely.
A snapshot is protected from compaction — and so kept — while any of these is true:
- it is the latest version;
- it is pinned by a Product (a product that pins a version keeps that version alive);
- it is referenced by an Activity — for example a translation, a derivation, or a compilation that was produced from it.
Beyond those, the platform also keeps a rolling window of the most recent snapshots. Old snapshots that are not the latest, not pinned by a product, and not referenced by an activity may be compacted away. When that happens the platform emits a deletion event so downstream consumers stay in step.
If a version must survive, give it an anchor
Pin it from a Product, or make sure an Activity references it. Those are the durable ways to guarantee a specific snapshot is never compacted — a bare snapshot with nothing pointing at it is a candidate for eventual clean-up.
Your source files are never touched
Versioning applies only to the platform's own snapshots of content. The original files in your source systems — the Word document in SharePoint, the Google Doc, the repository at its host — are never modified by the Content Lake. Their full native history stays exactly where it is, in the tools that own it.
Binary content: blobs and the valet-key
Documents are stored as structured blocks, but images, audio, video, and repositories are binary payloads. The Content Lake keeps those bytes in a dedicated blob store and has the Resource point at them, rather than passing large files through its own machinery. For a business reader this is mostly invisible — but the way the bytes are served has one property worth understanding.
How binary content is served — the valet-key idea
The platform never proxies large binary files through its own compute, and it never hands a consumer direct storage credentials. Instead it uses a valet-key pattern: when you need the bytes behind an image or an audio file, the platform first checks that you are allowed to read that Resource, then hands you a short-lived, single-purpose direct link to fetch the bytes yourself. The link opens exactly one door, for a short time, and then expires.
-
Blobs are addressed like everything else. A binary payload is a Blob with its own
blb_identifier and acl://URI, e.g.cl://packt/blob/blb_cover_ml_go/ver_0197aa1. Blob versions use the samever_identifiers as document snapshots — one version grammar across the platform — and are immutable: new bytes always mint a new version, existing versions are never rewritten. The one difference from documents: a blob URI always names an explicit version — blobs have no movinglatest, because the owning Resource states exactly which bytes it uses. -
Access always flows through the owning Resource. There is no such thing as reading a blob "directly". Every blob belongs to exactly one Resource, and the platform authorises the read against that Resource — its tenant, its access grants, its resolved rights — before issuing a link.
-
The link is a short-lived secret. The direct link is valid for a bounded window and is scoped to a single object, read-only. It is a fetch ticket, not a stored address: request it when you are about to use it, fetch immediately, and never persist or log it. Cache the bytes (keyed by blob and version, which are immutable) — never the link.
-
You can fetch just the part you need. For audio and video, the Resource carries a segment map — an ordered list matching each time span of the recording to the byte range that carries it, like the HTTP
Content-Rangeheader. A player that needs the clip at 7:00 asks for exactly those bytes rather than the whole file, which is what makes search's "here's the relevant 30-second clip" results cheap to play. -
The public boundary stays clean. When an end customer downloads an image or an audiobook, the Public API fetches the bytes through this same valet path and streams them out under its own authentication. The direct storage links are an internal-only mechanism and are never exposed publicly.
The pay-off is that the platform moves authorisation decisions, not bytes. Enormous files travel straight between storage and the consumer, while the platform stays in the fast, cheap business of saying yes or no.
Related pages
- Content Lake overview — how the estate fits together.
- Works & rights — where rights live and how they reach each Resource.
- Content format — how a
DOCUMENTis structured as blocks, and how parts of content are addressed. - Ingestion — how a file becomes Resources and the Source that records where it came from.
- Provenance & attribution — the Activity record behind every Resource.
- Explorer — Chapter IV — the lake and its content model, visualised.