fix(tests): the re-ingest fixture modelled two manifests, not one edited manifest

CORRECTION TO b33ea00. That commit message called the v0.4.0 behaviour a
regression that "breaks our §6 removal path". That claim is WRONG, and this
commit is the record of it — the history is not rewritten.

What v0.4.0 actually introduced is §10.2 per-manifest ownership.
`_is_ingest_owned` (materialize.py:133-160 at v0.5.0a2) compares the
`ingest_manifest` reference's STEM against the running manifest's stem, and
its own comment says why the stem rather than the whole stamp: an EDITED
manifest (new sha -> new stamp) must still reclaim the files its previous run
wrote, while a DIFFERENT manifest sharing the bundle keeps its own.

Our fixture named manifests `manifest-{len(extractions)}.json`, so "the same
manifest, edited" silently became `manifest-2.json` -> `manifest-1.json` —
two stems, i.e. two rival manifests. Refusing to overwrite was CORRECT
behaviour. The fixture was written when ownership was manifest-agnostic and
the naming was pure convenience; v0.4.0 made that convenience load-bearing.

`_write_project` now takes an optional `filename`, and the re-ingest case
pins one stem across both runs, so it means "an edited manifest" on every
version rather than by accident.

MEASURED both ways: green at the pinned v0.3.2 (the distinction is invisible
there), and the WHOLE suite green at v0.5.0a2 — 668 passed. So there is no
technical blocker to the version move at all. What remains is not technical:

  1. v0.4.0+ makes `llm-ingestion-guard>=0.2,<0.3` a hard runtime dependency
     (v0.3.1/v0.3.2: `dependencies = []`), which moves two invariants this
     repo publishes. Operator's call.
  2. v0.5.0a2 is an alpha its own CHANGELOG scopes to a named pilot set this
     repo is not in. llm-ingestion-okf's call; asked via coord.

The false report was corrected upstream the same hour it was sent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GyAbxJoyypnLLUDcMvnKh8
This commit is contained in:
Kjell Tore Guttormsen 2026-08-05 12:30:08 +02:00
commit 44526254d0

View file

@ -74,7 +74,20 @@ _FILES = {
}
def _write_project(tmp_path: Path, extractions: list[dict[str, Any]]) -> Path:
def _write_project(
tmp_path: Path, extractions: list[dict[str, Any]], *, filename: str | None = None
) -> Path:
"""Write a file-source manifest. ``filename`` overrides the default name-by-count.
The default encodes the extraction count, which keeps unrelated cases in one tmp_path
from overwriting each other. It is the WRONG default for a RE-ingest, though: the
library keys ownership on the manifest's STEM (§10.2), so writing an edited manifest
under a new name models "a second, rival manifest sharing the bundle" rather than "the
same manifest, edited" — and the collision gate then correctly refuses to touch the
files the first name wrote. Pass ``filename`` to keep the stem stable across an edit.
Measured 2026-08-05: this distinction is invisible at the pinned v0.3.2 and load-bearing
from v0.4.0 on, so pinning the stem makes the re-ingest case mean the same thing on both.
"""
catalogue = tmp_path / "catalogue"
catalogue.mkdir(exist_ok=True)
for name, content in _FILES.items():
@ -85,7 +98,7 @@ def _write_project(tmp_path: Path, extractions: list[dict[str, Any]]) -> Path:
"bundle_summary": "Cost extracts from the project archive.",
"extractions": extractions,
}
name = f"manifest-{len(extractions)}.json"
name = filename if filename is not None else f"manifest-{len(extractions)}.json"
manifest_path = tmp_path / name
manifest_path.write_text(json.dumps(manifest), encoding="utf-8")
return manifest_path
@ -194,7 +207,14 @@ def test_reingest_with_active_removal_preserves_promoted_and_curated(tmp_path: P
shutil.copytree(CURATED_BUNDLE, bundle_dir) # promotion + ingest WRITE: throwaway copy
curated_index_lines = (bundle_dir / "index.md").read_text(encoding="utf-8").splitlines()
manifest_two = _write_project(tmp_path, copy.deepcopy(_EXTRACTIONS))
# ONE manifest filename, rewritten in place between the two runs: this case is a
# RE-ingest of an EDITED manifest, and ownership is keyed on the stem (§10.2). Writing
# the reduced form under a second name would make it a rival manifest instead, which the
# collision gate rightly refuses — the scenario this test exists to cover would never run.
_REINGEST_MANIFEST = "reingest-manifest.json"
manifest_two = _write_project(
tmp_path, copy.deepcopy(_EXTRACTIONS), filename=_REINGEST_MANIFEST
)
materialize(manifest_two, bundle_dir, ingested_at=_INGESTED_AT)
promoted_path = promote_verdict(
@ -216,7 +236,9 @@ def test_reingest_with_active_removal_preserves_promoted_and_curated(tmp_path: P
if not p.name.startswith("ingest-") and p.name != "index.md"
}
manifest_one = _write_project(tmp_path, copy.deepcopy(_EXTRACTIONS)[:1]) # drop `meta`
manifest_one = _write_project( # drop `meta` — same file, edited
tmp_path, copy.deepcopy(_EXTRACTIONS)[:1], filename=_REINGEST_MANIFEST
)
materialize(manifest_one, bundle_dir, ingested_at=_INGESTED_AT)
index_after = (bundle_dir / "index.md").read_text(encoding="utf-8")