Appendix C - 15. `derive-changelog` (reconstruct mutations)

The Structure of derive-changelog (reconstruct mutations) — its shape at a glance:

The command reads the embedded stamps from the finished artifact, orders and groups them by pass, and emits a structured change log a human or tool can read.

flowchart LR
  Art[/Remediated artifact/] -->|read embedded stamps| Reader[Changelog reader]
  Reader -->|group by pass| Log[/ChangeLog JSON/]
  Log --> RCA([RCA / transparency])

Accessible description: the command reads the embedded attribution stamps out of the finished artifact, groups them by the pass that made each change, and emits a structured change log consumed for root-cause analysis and user transparency.

Projected from the catalogue entry provenance-and-attribution / derive-changelog (reconstruct mutations).

On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns

Intent

Intent — A command that reconstructs the document's mutation history from the embedded stamp registry, turning the attribution stamps into a readable, attributed ChangeLog after the fact.

Motivation

The stamps are embedded in the artifact, but embedded data isn't useful until it can be read back into a coherent history. Without a reader, attribution is present but inert — you have the evidence and no way to assemble it into "pass X made change Y." The failure is attribution that exists but can't be consumed, which shows up exactly when someone needs the history for RCA or user transparency.

Applicability

Structure

The Structure diagram appears at the top of this page.

Sample Code

The reader is a projection over the embedded stamps: read them out of the artifact, sort by the order they were applied, and emit one attributed entry per mutation, each carrying its visibility. What a raw before/after diff cannot give you is the who and why — the stamp carries the pass and the visibility, so the reconstruction is attributed, not just a delta.

import json
from dataclasses import dataclass, asdict

@dataclass
class ChangeEntry:
    order: int
    pass_name: str          # who made the change
    target: str             # what was changed
    visibility: str         # "debug" (stripped before delivery) or "preserved"

def derive_changelog(read_stamps) -> str:
    """`read_stamps` yields the embedded provenance records out of the artifact.
    We turn them into an ordered, attributed change log — the who/why a diff omits."""
    stamps = sorted(read_stamps(), key=lambda s: s["order"])
    entries = [ChangeEntry(s["order"], s["pass"], s["target"], s.get("visibility", "debug"))
               for s in stamps]
    return json.dumps([asdict(e) for e in entries], indent=2)

Consequences

Example use within DocAble

Contents
© James C. Davis, 2026–present