Provenance & attribution
Every piece of content on the platform has a history: it was written, imported, translated, narrated, summarised, or compiled from other things. Provenance is that history, recorded as fact rather than reconstructed after the event. Each act of creating or transforming content is written down once, immutably, at the moment it happens — naming what went in, what came out, and who was responsible.
The reason this matters is commercial as much as it is technical. Packt's authors keep publishing because their work is attributed and they are paid for it. When a course is compiled from three books, or a "nano-book" is summarised from a conference keynote, someone is owed a share — and working out who, and how much, must be a lookup against recorded fact, not a forensic exercise. The same record answers the question every rights team now has to answer about AI: what did an AI model actually touch, and under what contract?
The mechanism is a single append-only structure called the Activity graph. Anything that brings content into existence or changes it is recorded as an Activity: a first-class, immutable node that consumes zero or more source nodes, produces one or more output nodes, and names the agent responsible. Because nothing is ever edited or deleted, three questions that used to require an investigation become single queries against the graph:
- What did AI touch?
- What is this derived from?
- Who is owed?
This replaces the old derived-from tag
Earlier drafts of the platform tracked lineage with a
common/derived-from tag listing source IDs. That mechanism is
retired. Lineage lives only in the Activity graph, expressed as
edges between content nodes. If you are migrating from the old
model, stop writing derived-from tags and record an Activity
instead — it captures the source, the agent, the authorising
contract, and the royalty rule in one place.
The agent is the responsible party — never the model
The single most important rule of provenance is who gets named as the
actor. An Activity is always attributable to an agent: a person, an
organisation (such as Packt), or an automated system. An AI model is
never an agent. When an AI model does the work, the organisation is
the agent — recorded with the role GENERATOR — and the model, its
version, and the prompt are logged separately as tooling.
This is a deliberate design choice, not a technicality. An LLM is an
instrument, like a camera or a printing press; responsibility rests
with the party that operated it. Recording it this way keeps "exactly
what AI produced or touched" a one-query question — filter Activities
by role=GENERATOR or by tooling.model — rather than an audit.
flowchart LR
OUT["Output<br/>e.g. a French translation"]
ACT(["Activity<br/>records the transformation"])
SRC["Source(s)<br/>the content consumed"]
AGT["Agent<br/>person · organisation · system"]
TOOL["Tooling<br/>model · version · prompt<br/>(an LLM lives here)"]
OUT -->|was generated by| ACT
ACT -->|used| SRC
ACT -->|was associated with| AGT
ACT -.->|records| TOOL
Agent kinds and roles
An activity agent has a kind — HUMAN, SYSTEM, or
ORGANISATION — and a role describing what it did: AUTHOR,
TRANSLATOR, NARRATOR, GENERATOR, or OPERATOR. This is a
different thing from a contract agent (an author, publisher, or
licensee who is a party to a Contract). See the disambiguation note
at the foot of the Glossary.
The log and the graph
Every Activity is recorded in two places that do different jobs, and the distinction is worth understanding because it governs which activities carry lineage.
The Activity Log holds everything. Without exception, every Activity is written to an append-only, immutable log that is searchable and filterable — by type, by agent, by date range, by tenant, and by the node it touched. This is the audit substrate: "what happened, when, by whom, over what?" is always answerable, and nothing is ever hidden from it.
The Content Lake graph holds only the subset of Activities that form lineage — those that either create a new content node or connect existing content nodes with an edge. This is the structure that provenance and royalty traversals actually run over. The graph is a projection of the log, not a second write: every graph Activity is also a log entry, but the reverse is not true.
flowchart LR
A["Every Activity"] --> LOG[("Activity Log<br/>all activities · searchable")]
A -->|"creates or connects<br/>a content node"| G[("Content Lake graph<br/>lineage subset")]
ENR["Enrichment<br/>product info · entities · cover"] --> LOG
The rule is precise: an Activity reaches the graph if and only if it either creates a new content node — a Work, Expression, Manifestation, or ContentUnit — or creates a new edge between content nodes. Activities that only enrich an existing node — generating product information, extracting entities, producing a cover — create no lineage and stay log-only. In practice that log-only set is small: it is exactly the three enrichment types. Every origination, derivation, expression, manifestation, and fragment activity reaches the graph.
The edges
Three edges run through every graph Activity, and a fourth pair runs directly node-to-node as a shortcut.
| Edge | Runs from → to | Meaning |
|---|---|---|
USED |
Activity → each source | The content this Activity consumed. |
WAS_GENERATED_BY |
output node → Activity | The Activity that produced this node. |
WAS_ASSOCIATED_WITH |
Activity → agent(s) | Who performed it. |
DERIVED_FROM |
output → source | Lineage shortcut, for fast royalty traversal. |
SUPERSEDES |
output → prior node | Replacement shortcut (revisions and editions). |
The first three are the authoritative record. DERIVED_FROM and
SUPERSEDES are materialised shortcuts — derived once at write
time from the Activity, never independently authored — that collapse
the was-generated-by → used path so a royalty walk need not hop
through the Activity at each step. DERIVED_FROM is emitted for every
derivation; SUPERSEDES only when an Activity replaces a prior node —
a Resource for a correction, a Work for a new edition.
One important constraint on used
A USED edge always points at content: a Resource, a Source, or
a ContentUnit. It never points at a Work, because a Work is a
rights grouping, not content — rights are reached through the
consumed Resource's Work, not by consuming the Work directly. This
keeps the lineage graph strictly about content flow.
The eighteen activity types
There are eighteen activity types, grouped by what they do to the
graph. Every one is logged and searchable; the Plane column shows
whether it also reaches the lineage graph (GRAPH) or stays in the log
only (LOG).
| Activity | Group | Creates | Work | Plane |
|---|---|---|---|---|
INGESTION |
Origination | Work | New Work | GRAPH |
AUTHORING |
Origination | Work | New Work | GRAPH |
RECORDING |
Origination | Work | New Work | GRAPH |
ADAPTATION |
Derivation (new Work) | Work | New Work | GRAPH |
EDITION |
Derivation (new Work) | Work | New Work | GRAPH |
COMPILATION |
Derivation (new Work) | Work | New Work | GRAPH |
ASSESSMENT_GENERATION |
Derivation (new Work) | Work | New Work | GRAPH |
SUMMARISATION |
Derivation (per instance) | Work or Expression | instance † | GRAPH |
PERSONALISATION |
Derivation (per instance) | Expression or Work | instance † | GRAPH |
TRANSLATION |
Expression (same Work) | Expression | Same Work | GRAPH |
NARRATION |
Expression (same Work) | Expression | Same Work | GRAPH |
TRANSCRIPTION |
Expression (same Work) | Expression | Same Work | GRAPH |
REVISION |
Expression (correction) | Expression | Same Work | GRAPH |
MANIFESTATION_GENERATION |
Manifestation | Manifestation | Same Work | GRAPH |
EXCERPTION |
Fragment | ContentUnit | Same Work | GRAPH |
PI_GENERATION |
Enrichment | — | n/a | LOG |
ENTITY_EXTRACTION |
Enrichment | — | n/a | LOG |
COVER_GENERATION |
Enrichment | — | n/a | LOG |
† Decided per instance
SUMMARISATION and PERSONALISATION do not have a fixed tier. A
faithful condensation, or a single-source persona edition that
merely selects and re-sequences existing material, stays the same
Work as a new Expression. A re-authored digest, or a persona book
assembled from several Works with new connecting text, becomes a
new Work. The deciding factor is whether substantial new authored
content was introduced.
The groups map onto plain ideas:
- Origination brings brand-new content into being — imported
(
INGESTION), written (AUTHORING), or captured from a live event (RECORDING). Each starts a new Work. - Derivation makes a new Work out of existing content — reworking
it across a medium (
ADAPTATION), publishing a new edition (EDITION), compiling parts of several Works (COMPILATION), or generating assessments (ASSESSMENT_GENERATION). - Expression re-realises the same Work in another language,
mode, or corrected state —
TRANSLATION,NARRATION,TRANSCRIPTION,REVISION. Same content, new form. - Fragment pulls a quotable piece out as a ContentUnit
(
EXCERPTION). - Enrichment attaches metadata — product information
(
PI_GENERATION), entities and tags (ENTITY_EXTRACTION), or a cover image (COVER_GENERATION). These create no lineage node and stay log-only.
The taxonomy is open by design; new product lines will add types over time.
What is deliberately not an Activity
Some things look like activities but are not, because they do not transform content. Pushing a product to a partner is distribution. Overriding a title for one catalogue is catalogue configuration. Review, QA, and approval rounds are a Production concern, modelled separately — there is intentionally no "reviewed-by" record on an Activity. A sale or an API read is a consumption event, attributed to the Product, not the content graph.
Worked example: a course compiled from three books
The clearest way to see why the graph earns its keep is to follow a derived work through it. Suppose a commissioning editor builds a new data-engineering course by selecting one chapter from each of three existing books. The course is genuinely new — it has its own Work, its own Contract, and will sell as its own Product — but it is built entirely from content that other authors wrote and are owed for.
This is a COMPILATION: a new-Work derivation whose USED edges name
each source ContentUnit.
Those edges are exactly what makes the royalty split computable — the
Royalty service can walk them to find every source Work and apply each
one's contract terms.
flowchart TD
CU_A["Chapter 3<br/>Book A"] --> ACT(["Activity · COMPILATION<br/>agent: Commissioning editor"])
CU_B["Chapter 7<br/>Book B"] --> ACT
CU_C["Chapter 2<br/>Book C"] --> ACT
ACT --> WK["New Work<br/>Data Engineering course"]
WK -. DERIVED_FROM .-> CU_A
WK -. DERIVED_FROM .-> CU_B
WK -. DERIVED_FROM .-> CU_C
The solid arrows are the Activity-mediated record: three USED edges
into the Activity, and the new Work generated by it. The dashed
DERIVED_FROM edges are the materialised shortcuts the Royalty service
follows to answer who is owed? — one path back to each source book,
so a share can be attributed to each author under their own contract.
The Activity also records how the royalty should flow. Each
derivation carries a royalty_flow rule on its lineage edge —
INHERIT (use the source's own terms), NET_SHARE (split net receipts
across sources), ADDITIVE, or EXCLUDED. A compilation from several
Works is a NET_SHARE. Crucially, this only records intent: the
Royalty service does the arithmetic by traversing the graph. The
Activity's job is to state the rule on the edge it creates, and to pin
the Contract that
authorised the whole act in its rights_basis.
The COMPILATION Activity (JSON)
A business reader never has to touch this — but this is the exact
record behind the diagram above. Note that no LLM appears as an
agent; the editor is the agent, and each used entry is a source
ContentUnit, version-pinnable for exact reproducibility.
{
"activity_id": "act_compile_data_eng",
"type": "COMPILATION",
"created_at": "2026-03-10T00:00:00Z",
"performed_by": [
{
"agent_id": "agt_ce_data",
"kind": "HUMAN",
"name": "Commissioning editor",
"role": "OPERATOR"
}
],
"used": [
{ "node_id": "cu_book_a_ch3", "node_type": "CONTENT_UNIT", "role": "PRIMARY" },
{ "node_id": "cu_book_b_ch7", "node_type": "CONTENT_UNIT" },
{ "node_id": "cu_book_c_ch2", "node_type": "CONTENT_UNIT" }
],
"generated": [
{ "node_id": "wk_data_eng_course", "node_type": "WORK" },
{ "node_id": "res_data_eng_course", "node_type": "RESOURCE" }
],
"creates_tier": "WORK",
"work_relationship": "NEW_WORK",
"derivation_type": "COMPILATION",
"royalty_flow": "NET_SHARE",
"rights_basis": { "node_id": "ctr_data_eng_2026", "node_type": "CONTRACT" },
"parameters": { "source_works": 3 }
}
When no contract applies: statutory exceptions
Most uses of content are authorised by a contract, and the Activity
pins that contract in its rights_basis. But copyright law also
permits a narrow set of uses with no grant at all: quoting a book in
order to review it, parody, incidental inclusion. A critical review
of a rival publisher's title that quotes three short passages needs
no agreement with that publisher — and there is deliberately no
pretend-contract to reach for
(statutory exceptions are not licences).
These uses are recorded as a statutory-exception rights basis on
the Activity itself. Instead of pointing at a contract, the
rights_basis records which exception is relied on (UK fair dealing
for criticism or review, quotation, US fair use, parody…), the
jurisdictions whose law it stands on, whether the source had been
made public — a legal precondition of several exceptions — a written
justification, and who asserted it. Asserting an exception is a
deliberate, privileged act: it requires its own permission on top of
ordinary write access, and the asserting agent — a tenant user, an
organisation, or a system agent, like any other agent on the record
— is named in the assertion.
The platform records the claim — it never judges it
Whether a use really qualifies depends on jurisdiction, purpose,
publication status, and how much was taken. Those are legal
judgements. What the platform contributes is evidence and
accountability: the used edges pin exactly which content, at
which version, was quoted; the write-time snapshot freezes the
proportions; and the assertion names the agent who made the
call. If the claim is ever disputed, "what exactly did we take,
and on whose say-so?" is a lookup, not an investigation.
Three rules follow from the basis being a defence rather than a grant:
- No royalty flows. An exception-based edge always carries
royalty_flow: EXCLUDED— no contract governs the edge, so nothing accrues through it. - Acknowledgement is required. The shipped exceptions (bar incidental inclusion) legally require sufficient acknowledgement, so the output content must credit the source it quotes.
- The output still needs its own contract. The exception covers consuming the source; the review article itself is a new Work with an ordinary agreement (typically staff or work-for-hire) behind it.
A fair-dealing rights basis (JSON)
The rights_basis of the ADAPTATION Activity that creates the
review — everything else on the Activity (agents, used,
generated, lineage edges) is exactly as usual.
{
"rights_basis": {
"basis_type": "STATUTORY_EXCEPTION",
"statutory_exception": {
"type": "FAIR_DEALING_CRITICISM_REVIEW",
"jurisdictions": ["GB"],
"source_made_public": true,
"justification": "Critical review; three quoted excerpts totalling 412 of 78,500 source words, each accompanied by commentary.",
"asserted_by": {
"agent_id": "agt_rights_ops",
"kind": "ORGANISATION",
"name": "Packt Rights Operations",
"role": "OPERATOR"
}
}
}
}
One boundary worth knowing: for content the platform holds a contract on, promotional excerpting is a contract question — an article walking customers through an upcoming title of your own is authorised by that title's agreement, recorded as an ordinary contract basis. Exceptions are asserted only where no grant covers the use.
What each question becomes
Because the record is complete and immutable, the three headline questions reduce to graph queries.
Every Activity where an AI model did the work names the
organisation as the agent with role GENERATOR and logs the model
in tooling. So "everything AI produced or touched" is a filter —
by role=GENERATOR, or by a specific tooling.model — over the
Activity Log. Because the log is never pruned, this answer is exact
even years later.
Follow DERIVED_FROM edges backwards from the node. Each hop lands
on a source Resource, Source, or ContentUnit; keep walking to reach
the original Works. A TRANSLATION points back to its source text;
a COMPILATION fans out to every source chapter it drew on.
Walk the same DERIVED_FROM edges to every source Work, read each
Work's Contract, and apply the royalty_flow rule recorded on each
lineage edge. The Royalty service does this traversal; the Activity
graph is what makes it a computation rather than an investigation.
Corrections and editions: two kinds of supersession
Not every change is a derivation. A same-content fix — errata, a
corrected reprint — is a REVISION that SUPERSEDES the prior
Resource version without creating a new Work; the old version is
never deleted. A substantial new edition, by contrast, is an
EDITION: it stands as its own Work with its own ISBN and usually a
re-papered contract, carries DERIVED_FROM to the prior edition's
content, and SUPERSEDES the prior edition's Work. The
superseded Work is retained, so the history stays intact.
How it works under the hood
The graph is an append-only directed acyclic graph. Nothing is ever mutated — that immutability is precisely what lets it answer questions about the past reliably. When content must be removed for legal reasons, a purge redacts the content of the Activities that generated it (free text and endpoint snapshots) while keeping the skeleton — the ID, type, timestamps, agents, and edges — so the provenance graph never dangles. Activities that merely used the purged content keep a frozen, write-time snapshot of the few endpoint attributes (medium, language, size) they needed, so the audit trail stays interpretable even after the endpoint is gone.
Related pages
- Enrichment & the Knowledge Graph — the log-only enrichment activities, and how content gains context.
- Works & rights — where rights live, and how
rights_basispins the contract — or records the asserted statutory exception — that authorises each Activity. - Resources & versions — the nodes that Activities consume and generate, and how versions are snapshotted.
- Royalties & commercial terms — how the
royalty_flowrule and the lineage graph turn into money owed. - Core concepts — Activity in the context of the whole model.
- Explorer — Chapter VIII — provenance and derivation, visualised.