"""SLICE-1 integration — the corpus mirror reads sidecars (dual-read) and derives the malformed flag (PUC-6, INV-3/INV-6). Per docs/design/2026-06-06-configurable-collection-metadata.md §6.2-6.3. """ from __future__ import annotations import asyncio import json from fastapi.testclient import TestClient from app import cache, db, gitea as gitea_mod from app.config import load_config from test_propose_vertical import ( # noqa: F401 (fixtures) app_with_fake_gitea, tmp_env, ) def _refresh(): cfg = load_config() asyncio.run(cache.refresh_meta_repo(cfg, gitea_mod.Gitea(cfg))) def _row(slug): return db.conn().execute( "SELECT * FROM cached_rfcs WHERE slug = ?", (slug,) ).fetchone() def test_mirror_reads_metadata_from_sidecar(app_with_fake_gitea): app, fake = app_with_fake_gitea with TestClient(app): # A migrated entry: body-only .md + a sidecar holding the metadata. fake.files[("wiggleverse", "meta", "main", "rfcs/sidecar-one.md")] = { "content": "Just the prose body.\n", "sha": "s1"} fake.files[("wiggleverse", "meta", "main", "rfcs/sidecar-one.meta.yaml")] = { "content": "slug: sidecar-one\ntitle: From Sidecar\nstate: active\ntags:\n- alpha\n", "sha": "m1"} _refresh() row = _row("sidecar-one") assert row is not None assert row["title"] == "From Sidecar" assert row["state"] == "active" assert row["body"].strip() == "Just the prose body." assert row["metadata_malformed"] == 0 def test_malformed_sidecar_flags_but_still_loads(app_with_fake_gitea): app, fake = app_with_fake_gitea with TestClient(app): # .md still has frontmatter; sidecar is malformed (a list, not a map). fake.files[("wiggleverse", "meta", "main", "rfcs/bad-meta.md")] = { "content": "---\nslug: bad-meta\ntitle: Legacy Title\nstate: active\n---\n\nBody.\n", "sha": "b1"} fake.files[("wiggleverse", "meta", "main", "rfcs/bad-meta.meta.yaml")] = { "content": "- not\n- a\n- mapping\n", "sha": "b2"} _refresh() row = _row("bad-meta") assert row is not None # INV-3: still loads assert row["metadata_malformed"] == 1 # Falls back to the legacy .md frontmatter for the metadata. assert row["title"] == "Legacy Title" def test_malformed_flag_surfaces_in_catalog_api(app_with_fake_gitea): app, fake = app_with_fake_gitea with TestClient(app) as client: fake.files[("wiggleverse", "meta", "main", "rfcs/flagged.md")] = { "content": "---\nslug: flagged\ntitle: Flagged\nstate: active\n---\n\nB.\n", "sha": "f1"} fake.files[("wiggleverse", "meta", "main", "rfcs/flagged.meta.yaml")] = { "content": "just a scalar\n", "sha": "f2"} fake.files[("wiggleverse", "meta", "main", "rfcs/clean.md")] = { "content": "---\nslug: clean\ntitle: Clean\nstate: active\n---\n\nB.\n", "sha": "c1"} _refresh() items = {i["slug"]: i for i in client.get("/api/rfcs").json()["items"]} assert items["flagged"]["metadata_malformed"] is True assert items["clean"]["metadata_malformed"] is False # And on the detail view. assert client.get("/api/rfcs/flagged").json()["metadata_malformed"] is True def test_malformed_sidecar_on_migrated_entry_still_loads_flagged(app_with_fake_gitea): # INV-3 regression: a migrated (body-only .md) entry whose sidecar is # corrupt must NOT vanish from the catalog — it loads (slug from the # filename stem) and is flagged malformed. app, fake = app_with_fake_gitea with TestClient(app): fake.files[("wiggleverse", "meta", "main", "rfcs/orphaned.md")] = { "content": "Just the body, no frontmatter.\n", "sha": "o1"} fake.files[("wiggleverse", "meta", "main", "rfcs/orphaned.meta.yaml")] = { "content": "- corrupt\n- list\n", "sha": "o2"} _refresh() row = _row("orphaned") assert row is not None # did not vanish assert row["metadata_malformed"] == 1 assert row["body"].strip() == "Just the body, no frontmatter." def _set_default_fields_schema(schema): # apply_registry leaves the default collection's config_json untouched, so a # schema set here survives a corpus refresh (refresh_meta_repo only). db.conn().execute( "UPDATE collections SET config_json = ? WHERE id = 'default'", (json.dumps({"fields": schema}),)) # ---- §22.4a SLICE-2: advisory schema validation at ingest (INV-3) ---- def test_schema_violation_flags_malformed(app_with_fake_gitea): app, fake = app_with_fake_gitea with TestClient(app): _set_default_fields_schema( {"priority": {"type": "enum", "values": ["P0", "P1", "P2"]}}) fake.files[("wiggleverse", "meta", "main", "rfcs/bad-prio.md")] = { "content": "---\nslug: bad-prio\ntitle: Bad\nstate: active\npriority: P9\n---\n\nB.\n", "sha": "bp1"} fake.files[("wiggleverse", "meta", "main", "rfcs/good-prio.md")] = { "content": "---\nslug: good-prio\ntitle: Good\nstate: active\npriority: P0\n---\n\nB.\n", "sha": "gp1"} _refresh() assert _row("bad-prio")["metadata_malformed"] == 1 # INV-3: flagged assert _row("bad-prio")["title"] == "Bad" # still loads assert _row("good-prio")["metadata_malformed"] == 0 def test_schema_ignores_undeclared_keys(app_with_fake_gitea): # INV-7: keys the schema doesn't declare ride along and never flag malformed. app, fake = app_with_fake_gitea with TestClient(app): _set_default_fields_schema( {"priority": {"type": "enum", "values": ["P0", "P1"]}}) fake.files[("wiggleverse", "meta", "main", "rfcs/extra-key.md")] = { "content": "---\nslug: extra-key\ntitle: Extra\nstate: active\nowner: hasan\n---\n\nB.\n", "sha": "ek1"} _refresh() assert _row("extra-key")["metadata_malformed"] == 0 def test_no_schema_never_flags(app_with_fake_gitea): # INV-5: a collection with no field schema validates nothing, even when an # entry carries values that would fail a schema if one existed. app, fake = app_with_fake_gitea with TestClient(app): fake.files[("wiggleverse", "meta", "main", "rfcs/anything.md")] = { "content": "---\nslug: anything\ntitle: Any\nstate: active\npriority: whatever\n---\n\nB.\n", "sha": "an1"} _refresh() assert _row("anything")["metadata_malformed"] == 0 def test_legacy_collection_without_sidecars_unchanged(app_with_fake_gitea): app, fake = app_with_fake_gitea with TestClient(app): fake.files[("wiggleverse", "meta", "main", "rfcs/legacy.md")] = { "content": "---\nslug: legacy\ntitle: Legacy\nstate: super-draft\n---\n\nPitch.\n", "sha": "l1"} _refresh() row = _row("legacy") assert row is not None assert row["title"] == "Legacy" assert row["state"] == "super-draft" assert row["body"].strip() == "Pitch." assert row["metadata_malformed"] == 0