test_print_next_integrity.py
file-level
1
files
1
commits
0
hotspots
0
🧊 dead
0
💥 blast risk
| 1 | """Data integrity — ``ok next`` is read-only and idempotent (§ONS.12 / §NXP.8).""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | import hashlib |
| 6 | from pathlib import Path |
| 7 | |
| 8 | from cli.kit_root import kit_root |
| 9 | from tests.support import FIXTURES, git_status_runner, run_cli, write_config |
| 10 | from tools.print_next.extract import CURRENT_NEXT_HEADING, set_read_at_clock |
| 11 | from tools.governance_hygiene.next_regen import extract_paste_fence_body |
| 12 | |
| 13 | FIXED_READ_AT = "2026-09-04T12:00:00Z" |
| 14 | |
| 15 | |
| 16 | def _sha(path: Path) -> str: |
| 17 | return hashlib.sha256(path.read_bytes()).hexdigest() |
| 18 | |
| 19 | |
| 20 | def test_twice_identical_no_mutation(tmp_path: Path, capsys) -> None: |
| 21 | write_config(tmp_path, "config-git-only.yaml") |
| 22 | docs = tmp_path / "docs" |
| 23 | docs.mkdir(parents=True, exist_ok=True) |
| 24 | handover = docs / "OVERSEER-HANDOVER.md" |
| 25 | roadmap = docs / "ROADMAP.md" |
| 26 | handover.write_text( |
| 27 | (FIXTURES / "print-next-handover.md").read_text(encoding="utf-8"), |
| 28 | encoding="utf-8", |
| 29 | ) |
| 30 | roadmap.write_text("# Roadmap\n", encoding="utf-8") |
| 31 | lock = tmp_path / ".overseer" / "version.lock" |
| 32 | lock.write_text("kit_version: 0.1.0\n", encoding="utf-8") |
| 33 | |
| 34 | before = { |
| 35 | "handover": _sha(handover), |
| 36 | "roadmap": _sha(roadmap), |
| 37 | "lock": _sha(lock), |
| 38 | } |
| 39 | set_read_at_clock(lambda: FIXED_READ_AT) |
| 40 | try: |
| 41 | runner = git_status_runner() |
| 42 | code1 = run_cli(["next"], cwd=tmp_path, runner=runner, kit=kit_root()) |
| 43 | out1 = capsys.readouterr().out |
| 44 | code2 = run_cli(["next"], cwd=tmp_path, runner=runner, kit=kit_root()) |
| 45 | out2 = capsys.readouterr().out |
| 46 | assert code1 == 0 |
| 47 | assert code2 == 0 |
| 48 | assert out1 == out2 |
| 49 | assert _sha(handover) == before["handover"] |
| 50 | assert _sha(roadmap) == before["roadmap"] |
| 51 | assert _sha(lock) == before["lock"] |
| 52 | finally: |
| 53 | set_read_at_clock(None) |
| 54 | |
| 55 | |
| 56 | def test_fence_body_and_heading_byte_identical_to_pre_nxp(tmp_path: Path, capsys) -> None: |
| 57 | """§NXP.8 data-integrity: fence body + CURRENT_NEXT_HEADING unchanged.""" |
| 58 | write_config(tmp_path, "config-git-only.yaml") |
| 59 | docs = tmp_path / "docs" |
| 60 | docs.mkdir(parents=True, exist_ok=True) |
| 61 | text = (FIXTURES / "print-next-handover.md").read_text(encoding="utf-8") |
| 62 | handover = docs / "OVERSEER-HANDOVER.md" |
| 63 | handover.write_text(text, encoding="utf-8") |
| 64 | (docs / "ROADMAP.md").write_text("# Roadmap\n", encoding="utf-8") |
| 65 | |
| 66 | pre_body = extract_paste_fence_body(text) |
| 67 | assert pre_body is not None |
| 68 | assert CURRENT_NEXT_HEADING == "## CURRENT NEXT — paste this" |
| 69 | |
| 70 | set_read_at_clock(lambda: FIXED_READ_AT) |
| 71 | try: |
| 72 | code = run_cli(["next"], cwd=tmp_path, runner=git_status_runner(), kit=kit_root()) |
| 73 | out = capsys.readouterr().out |
| 74 | assert code == 0 |
| 75 | finally: |
| 76 | set_read_at_clock(None) |
| 77 | |
| 78 | # Golden: the pre-NXP nine-step bytes (§ONS.5.4), reconstructed exactly. |
| 79 | expected_body = pre_body if pre_body.endswith("\n") else pre_body + "\n" |
| 80 | pre_nxp_stdout = f"{CURRENT_NEXT_HEADING}\n\n```text\n{expected_body}```\n" |
| 81 | |
| 82 | # §NXP.3.1 adds exactly two lines (provenance + blank) at index 2 and 3. |
| 83 | lines = out.split("\n") |
| 84 | assert lines[0] == CURRENT_NEXT_HEADING |
| 85 | assert lines[1] == "" |
| 86 | assert lines[2].startswith("**Source:** ") |
| 87 | assert lines[3] == "" |
| 88 | |
| 89 | # Removing only those two lines must reproduce pre-NXP stdout byte for byte, |
| 90 | # which pins both the heading and the fence body — no rstrip, no tolerance. |
| 91 | reduced = "\n".join(lines[:2] + lines[4:]) |
| 92 | assert reduced == pre_nxp_stdout |