test_review_idempotency.py python
100 lines 3.3 KB
Raw
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83 chore(governance): sync handover+roadmap to 84db8c8 (drift:… Human 23 hours ago
1 """Data-integrity tests for review idempotency (§K5.12)."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6 from unittest.mock import patch
7
8 import pytest
9
10 from cli.atomic import WriteFailure
11 from cli.kit_root import kit_root
12 from tests.support import FIXTURES, git_status_runner, pass_provider_factory, run_cli, write_config
13 from tools.freeze_reviewer.artifact import parse_artifact
14 from tools.freeze_reviewer.stamp import reference_digest, write_stamp
15 from tools.freeze_reviewer.types import ReviewerSettings
16
17
18 def _review_pass(path: Path, repo: Path) -> None:
19 rel = path.relative_to(repo).as_posix()
20 run_cli(
21 ["review", "--freeze", rel],
22 cwd=repo,
23 runner=git_status_runner(),
24 kit=kit_root(),
25 review_provider_factory=pass_provider_factory(),
26 )
27
28
29 @pytest.mark.parametrize(
30 "fixture_name",
31 ["freeze-artifact.md", "freeze-artifact.yaml"],
32 )
33 def test_restamp_digest_stable(tmp_path: Path, fixture_name: str) -> None:
34 write_config(tmp_path, "config-git-only.yaml")
35 if fixture_name.endswith(".md"):
36 target = tmp_path / "docs" / "freeze.md"
37 target.parent.mkdir(parents=True)
38 else:
39 target = tmp_path / "freeze.yaml"
40 target.write_text((FIXTURES / fixture_name).read_text(encoding="utf-8"), encoding="utf-8")
41 _review_pass(target, tmp_path)
42 after_first = target.read_bytes()
43 _review_pass(target, tmp_path)
44 assert target.read_bytes() == after_first
45
46
47 def test_operator_forced_md_restamp_stable(tmp_path: Path) -> None:
48 write_config(tmp_path, "config-git-only.yaml")
49 target = tmp_path / "notes.md"
50 target.write_text("# operator forced\n", encoding="utf-8")
51 _review_pass(target, tmp_path)
52 first = target.read_bytes()
53 _review_pass(target, tmp_path)
54 assert target.read_bytes() == first
55
56
57 def test_whitespace_invariant_digest(tmp_path: Path) -> None:
58 loose = tmp_path / "loose.yaml"
59 loose.write_text(
60 "phase: K5b-test\noutputs:\n - id: a\n path: docs/a.md\n frozen: true\n",
61 encoding="utf-8",
62 )
63 parsed_loose = parse_artifact(loose, rel_path="loose.yaml")
64 tight = tmp_path / "tight.yaml"
65 tight.write_text(
66 'phase: "K5b-test"\noutputs:\n - {id: a, path: docs/a.md, frozen: true}\n',
67 encoding="utf-8",
68 )
69 parsed_tight = parse_artifact(tight, rel_path="tight.yaml")
70 assert reference_digest(parsed_loose) == reference_digest(parsed_tight)
71
72
73 def test_dry_run_and_no_stamp_write_zero(tmp_path: Path) -> None:
74 write_config(tmp_path, "config-git-only.yaml")
75 target = tmp_path / "freeze.yaml"
76 target.write_text((FIXTURES / "freeze-artifact.yaml").read_text(encoding="utf-8"), encoding="utf-8")
77 rel = target.relative_to(tmp_path).as_posix()
78 before = target.read_bytes()
79 assert (
80 run_cli(
81 ["review", "--freeze", rel, "--dry-run"],
82 cwd=tmp_path,
83 runner=git_status_runner(),
84 kit=kit_root(),
85 review_provider_factory=pass_provider_factory(),
86 )
87 == 0
88 )
89 assert target.read_bytes() == before
90 assert (
91 run_cli(
92 ["review", "--freeze", rel, "--no-stamp"],
93 cwd=tmp_path,
94 runner=git_status_runner(),
95 kit=kit_root(),
96 review_provider_factory=pass_provider_factory(),
97 )
98 == 0
99 )
100 assert target.read_bytes() == before
File History 1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199 fix(ISR): default require_independent_second_reviewer to require Human minor 22 hours ago