diff --git a/generative/pipeline/vault_writer.py b/generative/pipeline/vault_writer.py index 383d84b..30ea202 100644 --- a/generative/pipeline/vault_writer.py +++ b/generative/pipeline/vault_writer.py @@ -591,13 +591,17 @@ def render_merge_stub(note: AtomicNoteDraft, source_file: str, rel_existing = str(existing_path.relative_to(VAULT)).replace("\\", "/") existing_link = existing_path.stem flags_yaml = _yaml_list(["merge-pending"] + note.quality_flags) + # Geschwister von Befund D (#45): fail-closed source_status auch auf dem Merge-Pfad + # rendern — render_note tut es, render_merge_stub ließ es sonst still fallen, sodass + # eine create-Note mit unauflösbarer Quelle + Vault-Titel-Treffer das Flag verlor. + source_status_line = f"\nsource-status: {note.source_status}" if note.source_status else "" frontmatter = f"""--- title: "MERGE: {title_esc}" type: merge-stub merge-target: "[[{existing_link}]]" merge-target-path: "{rel_existing}" -source-file: "{source_file}" +source-file: "{source_file}"{source_status_line} claude-generated: true quality-flags: {flags_yaml} diff --git a/generative/tests/test_vault_writer.py b/generative/tests/test_vault_writer.py index affc2c9..20e437c 100644 --- a/generative/tests/test_vault_writer.py +++ b/generative/tests/test_vault_writer.py @@ -9,7 +9,7 @@ from unittest.mock import patch from pathlib import Path -from generative.pipeline.vault_writer import convert_inline_to_footnotes, build_quellen_block +from generative.pipeline.vault_writer import convert_inline_to_footnotes, build_quellen_block, render_merge_stub, VAULT from generative.schemas.atomic_note import AtomicNoteDraft, TextAnchor @@ -235,5 +235,27 @@ def test_no_existing_concepts_is_noop(self): self.assertEqual(sibling.related, ["[[X]]"]) +class TestMergeStubSourceStatus(unittest.TestCase): + """Geschwister von Befund D ([[Ungelesenes-Pipeline-Signal]], Codex-Hunt 2026-06-23): + `render_merge_stub` ließ das fail-closed-Flag `source_status` fallen, das `render_note` + rendert (#45). Eine create-Note mit unauflösbarer Quelle, die zufällig einen Vault- + Title/Alias-Treffer hat, rendert als Merge-Stub und verlor das Flag still.""" + + def _stub(self, source_status=None): + note = AtomicNoteDraft( + title="Webinar-Wirksamkeit", body="Body", source_anchors=[], related=[], + tags=[], synthesis_confidence="high", action="create", + source_status=source_status, + ) + return render_merge_stub(note, "Ebner 2019.pdf", + VAULT / "04-wissen" / "Webinar Bestehend.md") + + def test_unresolved_source_status_rendered_on_stub(self): + self.assertIn("source-status: unresolved", self._stub("unresolved")) + + def test_no_source_status_line_when_unset(self): + self.assertNotIn("source-status:", self._stub(None)) + + if __name__ == "__main__": unittest.main()