Skip to content
internal/revisions
On this page

Tracking blog post revisions in a sidecar file, appending one only when the rendered body actually changes, so a frontmatter-only edit stays invisible.

#internal/revisions

#internal/revisions

Package revisions tracks post revisions in a sidecar revisions.json.

Content changes to blog posts are tracked using SHA-256 hashes of the rendered body text. A new revision is appended only when the body content actually changes, so a frontmatter-only edit is invisible.

The sidecar file sits in selfdoc's generated-state directory -- separate from the manifest, so no manifest format change can reach it.

#Revision

Go go
type Revision struct

Revision is one recorded revision of a post.

#PostRevisions

Go go
type PostRevisions struct

PostRevisions is one post's recorded revisions, oldest first.

#Document

Go go
type Document struct

Document is the parsed sidecar: every post that has a recorded revision, in the order the file declares them.

The order is part of the document rather than an implementation detail: the sidecar is rewritten whole on every recording, and a rewrite that reordered the posts would produce a diff on every publish.

#ComputePostContentHash

Go go
func ComputePostContentHash(body string) string

ComputePostContentHash computes a deterministic SHA-256 hash of a post's body text.

The body is the rendered content with frontmatter already stripped. Whitespace is normalized (per-line trim plus blank-line collapsing) so that insignificant formatting changes do not trigger false revisions.

Site-context-dependent values (base URLs, theme names) must NOT appear in the input -- callers pass only the body text.

#LoadRevisions

Go go
func LoadRevisions(dirPath string) (*Document, error)

LoadRevisions loads revisions.json from dirPath's generated-state directory.

An absent file is an empty document, not an error: a project that has published nothing yet has no revisions to read. A file that exists and is not readable as the document is an error.

#SaveRevisions

Go go
func SaveRevisions(handle *effects.Handle, document *Document, dirPath string) (string, error)

SaveRevisions writes revisions.json into dirPath's generated-state directory, atomically, and returns the path it wrote.

#RecordRevision

Go go
func RecordRevision(

RecordRevision records a revision for a post when its body content changed.

It computes the content hash, compares it against the latest revision for this slug, and appends a new entry only when the hash differs. The returned bool reports whether a revision was appended; when it is false nothing was written.

dirPath is the project root, slug the post's identifier, body the rendered body text with frontmatter stripped, and summary an optional note that is left out of the document when empty.

#GetPostRevisions

Go go
func GetPostRevisions(dirPath, slug string) ([]Revision, error)

GetPostRevisions returns the recorded revisions for a post, oldest first, and an empty slice for a post with none.

#GetLastUpdated

Go go
func GetLastUpdated(dirPath, slug string) (string, bool, error)

GetLastUpdated returns the timestamp of the most recent revision for a post. The bool reports whether the post has any revision at all.

#Document.Find

Go go
func (d *Document) Find(slug string) *PostRevisions

Find returns the entry for slug, or nil when the document carries none.

More tools from this site

  • claudestream Drive Claude Code from Python: run it as a subprocess and read its output as typed events, with async and sync sessions, sandbox policies, and tools you define in Python
  • claudewheel A TUI Claude Code Launcher that lets you have more than one profile, manage sessions lifecycle, pick the exact CC version, model to use (even older unlisted ones), pick which GitHub account to use, etc.
  • dirstat Fast, single-binary directory statistics CLI: every file under a tree grouped by format, with counts, sizes, and lines of code, as a colored terminal table or as JSON
  • fastware A batteries-included ASGI framework: msgspec JSON, a managed Granian server, dependency injection, SSE, WebSockets, auth, and a test client
  • go-toml-edit Zero-dep TOML editing library for Go with comment preservation
  • howmuchleft The fastest Claude Code statusline: context window, 5-hour, and weekly limit usage as three customizable gradient bars, rendering in about 6 ms
  • orxtra
  • pgdesign
  • predraw Declarative rendering pipeline: describe a scene in JSON and get SVG, PNG and WebP out, with light and dark style tokens, reusable components and text converted to path outlines
  • reposummary Turn a git repository's history into a Markdown journal: pick a time window or revision range and get a readable digest of what changed, optionally narrated by an LLM
  • rlsbl Release orchestration and project scaffolding CLI that bumps versions, validates a structured JSONL changelog, tags only the commit CI verified, and publishes to npm, PyPI, Go and more
  • safegit git wrapper CLI that gives each commit its own temporary index and retries ref updates on conflict, so concurrent agents share one repository
  • saferm Command-line replacement for rm that archives every deletion with a mandatory reason and the context it ran in, so deleted files can be listed, inspected and restored
  • strictcli
  • stricttest An always-on test-isolation floor: a pytest plugin and a Go env-hygiene module that make a test suite structurally unable to reach real credentials, the real HOME, the network, or the development repository.
  • wesktop A Python framework that turns an ASGI web app into a desktop application, serving it from a local Granian server and displaying it in a native OS window via pywebview
Search