-- allium: 1 -- bDS Metadata Diff and Rebuild -- Scope: core (Wave 1) -- Distilled from: src/main/engine/MetadataDiffEngine.ts use "./post.allium" as post use "./media.allium" as media use "./script.allium" as script use "./template.allium" as template surface MetadataMaintenanceSurface { facing _: MaintenanceOperator provides: MetadataDiffRequested(project) RebuildFromFilesystemRequested(project, entity_type) } value DiffField { name: String db_value: String file_value: String } value DiffReport { entity_type: String -- post, media, script, template entity_id: String differences: List } value OrphanReport { file_path: String -- File exists on disk but has no DB record } rule RunMetadataDiff { when: MetadataDiffRequested(project) -- Runs as background task via TaskManager -- Compares DB records against filesystem files for: -- posts, translations, media, scripts, templates -- Detected fields: tags, categories, title, excerpt, author, -- language, status, templateSlug, dates for post in project.posts: let file_data = parse_post_file(post.file_path) let diffs = compare_fields(post, file_data) 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 if matching.count = 0: ensures: OrphanReport.created(file_path: file) -- Same pattern for media sidecar files, scripts, templates } rule RebuildFromFilesystem { when: RebuildFromFilesystemRequested(project, entity_type) -- The inverse of metadata diff: filesystem is treated as truth -- Reads all files and upserts into DB ensures: if entity_type = "post": post/RebuildPostsFromFiles(project) if entity_type = "media": media/RebuildMediaFromFiles(project) if entity_type = "script": script/RebuildScriptsFromFiles(project) if entity_type = "template": template/RebuildTemplatesFromFiles(project) } invariant ThreeWaySync { -- Metadata must stay in sync across three representations: -- 1. Database records -- 2. Filesystem files (frontmatter/sidecars) -- 3. Generated site output -- MetadataDiff detects divergence between (1) and (2) -- Rebuild resolves divergence by treating (2) as truth -- Site generation consumes (1) to produce (3) }