"""Local data contracts that the selected upstream port must preserve.""" import json from pathlib import Path import pytest from obsidian_wiki.cli import main from obsidian_wiki.graph_analysis import parse_vault_graph from obsidian_wiki.lint import lint_vault from obsidian_wiki.provenance import archive_wikilink_relpath, resolve_source_key from obsidian_wiki.vault import iter_md @pytest.mark.parametrize("shape", ["dict", "list"]) def test_cache_cli_preserves_curated_metadata_and_page_associations(tmp_path, shape): source = tmp_path / "source.pdf" source.write_bytes(b"new revision") entry = { "path": "source.pdf", "pages_produced": ["concepts/a.md"], "archive_path": "_sources/archive/a.pdf", "content_hash": "old", "bjd_part_numbers": ["BJD-123"], "competitor_part_numbers": ["OTHER-456"], "series": ["WTB"], "pin_count": [6], "pitch": [2.0], "catalog_paths": ["_sources/catalog/a.md"], "visibility": "internal", } sources = {"source.pdf": entry} if shape == "dict" else [entry] manifest = tmp_path / ".manifest.json" manifest.write_text(json.dumps({"sources": sources, "local_revision": 7})) assert main(["cache-update", str(tmp_path), str(source)]) == 0 updated = json.loads(manifest.read_text()) actual = updated["sources"]["source.pdf"] if shape == "dict" else updated["sources"][0] assert updated["local_revision"] == 7 for key, value in entry.items(): if key != "content_hash": assert actual[key] == value assert actual["content_hash"] != "old" def test_local_sources_are_citable_but_not_knowledge_pages(tmp_path): refs = ["_sources/archive/doc.pdf", "_sources/catalog/products.md"] for rel in [*refs, "_sources/archive/raw.md", "_meta/taxonomy.md", "_inbox/draft.md", "_bot_exports/copy.md"]: p = tmp_path / rel p.parent.mkdir(parents=True, exist_ok=True) p.write_text("Raw source, not a knowledge page") page = tmp_path / "concepts" / "a.md" page.parent.mkdir() page.write_text( "---\ntitle: A\ncategory: concepts\ntags: [a]\nsources: []\n" "created: 2026-10-01\nupdated: 2026-10-01\nsummary: Example\n---\n" + " ".join(f"[[{rel}]]" for rel in refs) ) assert iter_md(tmp_path) == [page] graph, _ = parse_vault_graph(tmp_path) assert set(graph) == {"a"} assert graph["a"] == [] findings = lint_vault(tmp_path, require_trust_ledger=False)["findings"] assert findings["broken_links"] == [] assert resolve_source_key(tmp_path, refs[0]) == refs[0] assert archive_wikilink_relpath(tmp_path, refs[0] + "|PDF") == refs[0] assert archive_wikilink_relpath(tmp_path, "_sources/catalog/products") == refs[1] @pytest.mark.parametrize("target", ["../_sources/archive/a.pdf", "/tmp/_sources/archive/a.pdf"]) def test_local_source_resolution_refuses_paths_outside_vault(tmp_path, target): assert resolve_source_key(tmp_path, target) is None assert archive_wikilink_relpath(tmp_path, target) is None def test_staging_cli_conflict_keeps_reviewed_and_live_files(tmp_path, capsys): staged = tmp_path / "_staging/concepts/a.md" staged.parent.mkdir(parents=True) staged.write_text("Reviewed proposal") assert main(["staging", "list", "--vault", str(tmp_path), "--json"]) == 0 inventory = json.loads(capsys.readouterr().out) # The runtime schema is asserted here so the skill can pin listed revisions. entry = inventory[0] live = tmp_path / "concepts/a.md" live.parent.mkdir() live.write_text("Concurrent live update") assert main([ "staging", "promote", entry["staged_path"], "--vault", str(tmp_path), "--expect-staged", entry["staged_revision"], "--expect-new", ]) == 9 assert live.read_text() == "Concurrent live update" assert staged.read_text() == "Reviewed proposal"