fix: more work on metadata-diff

This commit is contained in:
2026-04-27 10:53:56 +02:00
parent 07730dc93e
commit 56c5ec1861
8 changed files with 162 additions and 18 deletions

View File

@@ -88,7 +88,6 @@ config {
value PostFrontmatter {
-- File path: posts/{YYYY}/{MM}/{slug}.md
-- For translations: posts/{YYYY}/{MM}/{slug}.{language}.md
id: String -- UUID v4
title: String
slug: String
@@ -105,6 +104,29 @@ value PostFrontmatter {
categories: List<String> -- Always written, even if empty
}
value TranslationFrontmatter {
-- File path: posts/{YYYY}/{MM}/{slug}.{language}.md
-- Translation files only store language-specific metadata.
-- Shared publication state and timestamps are inherited from the
-- canonical post file and are not duplicated here.
id: String -- UUID v4
translation_for: String -- Canonical post UUID
language: String -- ISO 639-1 language code
title: String -- Translated title
excerpt: String? -- Only written when the translated excerpt differs
}
surface TranslationFrontmatterSurface {
context frontmatter: TranslationFrontmatter
exposes:
frontmatter.id
frontmatter.translation_for
frontmatter.language
frontmatter.title
frontmatter.excerpt when frontmatter.excerpt != null
}
invariant PostFileLayout {
-- Posts are stored in date-based directory structure
-- YYYY and MM derived from created_at (zero-padded)
@@ -125,6 +147,13 @@ invariant PostTranslationFileLayout {
lang: t.language)
}
invariant TranslationFilesInheritCanonicalMetadata {
-- Missing status and timestamp fields in translation files are expected.
-- Rebuild and metadata diff must resolve those values from the canonical post.
for t in PostTranslations where file_path != "":
parse_frontmatter(read_file(t.file_path)) = translation_frontmatter_fields(t)
}
rule WritePostFile {
when: PublishPostRequested(post)
ensures: FileWritten(

View File

@@ -46,6 +46,20 @@ rule RunMetadataDiff {
if diffs.count > 0:
ensures: DiffReport.created(entity_type: "post", entity_id: post.id, differences: diffs)
-- Translation files only carry language-specific metadata. Shared status and
-- timestamp fields come from the canonical post and must not be reported as
-- missing when they are absent from the translation file.
for translation in project.post_translations:
let translation_file_data = parse_post_file(translation.file_path)
let translation_diffs = compare_translation_specific_fields(translation, translation_file_data)
if translation_diffs.count > 0:
ensures:
DiffReport.created(
entity_type: "post_translation",
entity_id: translation.id,
differences: translation_diffs
)
-- Detect orphan files (on disk but not in DB)
for file in scan_directory(project.effective_data_dir + "/posts", "*.md"):
let matching = Posts where file_path = file

View File

@@ -64,6 +64,15 @@ entity PostTranslation {
}
}
invariant TranslationFilesStoreOnlyLanguageSpecificMetadata {
-- Translation markdown files persist only fields that differ by language.
-- Shared metadata such as publication status and timestamps belongs to the
-- canonical post file and is inherited from the canonical post when
-- rebuilding or diffing translation files.
for t in PostTranslations where file_path != "":
translation_file(t).omits_shared_metadata = true
}
surface PostTranslationSurface {
context translation: PostTranslation