Align checksums with bDS2.

This commit is contained in:
2026-07-21 21:18:47 +02:00
parent 8e78a5fc2b
commit b3bf134980
16 changed files with 162 additions and 110 deletions

View File

@@ -264,6 +264,8 @@ invariant WxrConversionParity {
}
invariant AnalysisClassification {
-- Post/page checksums are lower-hex SHA-256 of converted Markdown; media
-- checksums are lower-hex MD5 of source bytes, matching bDS2.
-- Posts/pages: same slug and checksum => update; same slug with different
-- content => conflict; checksum matching another post => content duplicate;
-- otherwise new. Media applies the same rules by original filename and

View File

@@ -254,7 +254,8 @@ invariant MediaTranslationFileLayout {
rule ImportMedia {
when: ImportMediaRequested(source_path, project, metadata)
-- metadata is optional import context: title, alt, caption, author,
-- language, and tags may be supplied by the caller.
-- language, tags, and a checksum may be supplied by the caller. WXR
-- supplies a lower-hex MD5 checksum; interactive imports leave it nil.
-- 1. Validate file type (must be supported image)
-- 2. Generate UUID v4 filename
-- 3. Copy to media/{YYYY}/{MM}/{uuid}.{ext}
@@ -276,7 +277,7 @@ rule ImportMedia {
tags: metadata.tags,
file_path: format("media/{yyyy}/{mm}/{uuid}.{ext}"),
sidecar_path: format("media/{yyyy}/{mm}/{uuid}.{ext}.meta"),
checksum: sha256(source_path)
checksum: metadata.checksum
)
ensures: ThumbnailsGenerated(media_id)
ensures: SearchIndexUpdated(media_id)

View File

@@ -98,6 +98,8 @@ entity Post {
template_slug: String?
file_path: String
checksum: String?
-- Caller-supplied SHA-256 content change signal. Publish preserves it;
-- filesystem rebuild/sync clears it to match bDS2.
tags: List<String>
categories: List<String>
created_at: Timestamp
@@ -210,6 +212,7 @@ rule PublishPost {
-- Writes frontmatter + markdown to posts/YYYY/MM/{slug}.md
ensures: post.content = null
-- Content cleared from DB; now lives in filesystem only
-- post.checksum is preserved unchanged.
ensures: SearchIndexUpdated(post)
ensures: PostLinksUpdated(post)
-- Parse inter-post links, update link graph
@@ -242,6 +245,7 @@ rule SyncPostFromFile {
-- record from it (the filesystem is treated as truth for that one post).
-- Re-syncs the post's link graph. Errors out if the file is missing.
ensures: PostFieldsUpdated(post, parse_post_file(post.file_path))
ensures: post.checksum = null
ensures: PostLinksUpdated(post)
}

View File

@@ -55,7 +55,7 @@ entity Post {
updated_at: Timestamp
published_at: Timestamp?
file_path: String -- Empty for never-published drafts
checksum: String? -- SHA-256 of content
checksum: String? -- Caller-supplied SHA-256 content change signal; nil after filesystem rebuild
tags: Set<String> -- JSON array stored as text
categories: Set<String> -- JSON array stored as text
template_slug: String? -- User template override
@@ -83,7 +83,7 @@ entity PostTranslation {
updated_at: Timestamp
published_at: Timestamp?
file_path: String
checksum: String?
checksum: String? -- Caller-supplied content change signal; nil after filesystem rebuild
}
entity Media {
@@ -103,7 +103,7 @@ entity Media {
sidecar_path: String -- Path to .meta sidecar file
created_at: Timestamp
updated_at: Timestamp
checksum: String?
checksum: String? -- Lower-hex MD5 of media bytes when known
tags: Set<String> -- JSON array stored as text
language: String? -- ISO 639-1 code
}

View File

@@ -51,6 +51,8 @@ entity PostTranslation {
status: PostTranslationStatus
file_path: String
checksum: String?
-- Caller-supplied content change signal. Publish preserves it;
-- filesystem rebuild/sync clears it to match bDS2.
created_at: Timestamp
updated_at: Timestamp
published_at: Timestamp?
@@ -143,6 +145,7 @@ rule PublishTranslation {
ensures: TranslationFileWritten(translation)
ensures: translation.content = null
-- Content moves to filesystem
-- translation.checksum is preserved unchanged.
}
rule ReopenPublishedTranslation {