diff --git a/src/portfolio_optimiser/ingest.py b/src/portfolio_optimiser/ingest.py index 4437e95..02fa2c8 100644 --- a/src/portfolio_optimiser/ingest.py +++ b/src/portfolio_optimiser/ingest.py @@ -50,6 +50,10 @@ _INGESTED_AT_RE = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$") _LOGGER = logging.getLogger("portfolio_optimiser.ingest") +# §6: index.md is managed by the materializer (and reserved — the extraction-id grammar +# keeps generated names disjoint from it by construction). +_INDEX_NAME = "index.md" + class IngestError(RuntimeError): """A materialization-time refusal (cap exceeded, curated collision, malformed source).""" @@ -242,6 +246,49 @@ def _write_bytes(bundle_dir: Path, name: str, content: str) -> Path: return resolved +def _is_ingest_owned(path: Path) -> bool: + # §3/§5 ownership: the ingest stamp is `generated: true` AND an `ingest_manifest` + # reference. parse_frontmatter returns STRINGS ("true", never booleans). Promoted + # verdict files carry neither key, so they can never classify as ingest-owned. + frontmatter = okf.parse_frontmatter(path) + return frontmatter.get("generated") == "true" and "ingest_manifest" in frontmatter + + +# One managed index line: `- [