A CLI for publishing standard.site documents to ATProto sequoia.pub

`publish` change detection ignores cover image changes — regenerated covers never re-upload #47

Closed h.olysh.it
Closed opened by h.olysh.it

Version: sequoia-cli 0.5.7 Command: publish

Summary #

publish decides whether a post needs (re)publishing by hashing only the raw markdown file (frontmatter + body). The cover image is referenced by path in frontmatter, but the image bytes are never part of the hash. As a result, if you regenerate/replace a cover image without editing the post's text or frontmatter, publish reports the post as up to date and the cover blob is never re-uploaded. The coverImage on the site.standard.document record stays stale until some unrelated text edit happens to change the hash.

Where #

packages/cli/src/commands/publish.ts — change detection:

const contentHash = await getContentHash(post.rawContent);
// ...
} else if (postState.contentHash !== contentHash) {
    // Changed post
    postsToPublish.push({ post, action: ..., reason: "content changed" });
}

packages/cli/src/lib/markdown.ts — getContentHash hashes the file string only:

export async function getContentHash(content: string): Promise<string> {
    const data = new TextEncoder().encode(content);
    const hashBuffer = await crypto.subtle.digest("SHA-256", data);
    // ...
}

The update path itself is correct — updateDocument re-uploads the cover and putRecords it in place — it just never fires for a cover-only change.

Reproduction #

  1. Publish a post that has a cover image (ogImage / cover frontmatter). Cover uploads fine.
  2. Regenerate the cover image at the same path (new bytes, same filename), leaving the post's markdown and frontmatter untouched.
  3. Run publish again.

Expected: the post is detected as changed; the new cover blob is uploaded and the document record's coverImage is updated.

Actual: "All posts are up to date. Nothing to publish." The stale cover blob remains on the record. Only an unrelated edit to the post text/frontmatter will trigger the re-upload.

Workaround #

publish --force re-uploads every cover and rewrites every record. Works, but it's all-or-nothing (no per-post force) and churns every record/blob.

Suggested fix #

Fold the cover image's bytes into the change-detection hash when a post has a resolved cover path — e.g. hash rawContent concatenated with the image file contents (or the image's size + mtime as a cheaper proxy). Then a cover-only change naturally trips change detection, no --force needed.

(Resolving the cover path currently happens later in publish.ts, after the hash is computed, so this would mean resolving the image path before hashing.)

Sounds like a great solution - straight forward. Care to submit a PR?

Sorry! Got busy with some other stuff. Need to figure out tangled enough to submit a PR at some point. I'm still a noob or I would have done it as a PR from the start.

Thanks!

Sign up or Sign in to add to the discussion.