test_lt_integration.py python
137 lines 4.7 KB
Raw
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83 chore(governance): sync handover+roadmap to 84db8c8 (drift:… Human 9 hours ago
1 """Integration tests for LT loop tightening (§LT.10)."""
2
3 from __future__ import annotations
4
5 import json
6 from pathlib import Path
7 from unittest.mock import patch
8
9 import yaml
10
11 from cli.footprint import resolve_footprint
12 from tests.support import FIXTURES, KIT_ROOT, git_status_runner, run_cli
13 from tools.governance_freshness import GovernanceFreshnessReport
14
15 _OK_FRESHNESS = GovernanceFreshnessReport(
16 state="ok",
17 message="patched",
18 remediation=None,
19 d1="aligned",
20 d2="aligned",
21 marker_present=True,
22 )
23
24
25 def _init(tmp_path: Path, runner, config_name: str = "config-git-only.yaml") -> None:
26 assert (
27 run_cli(
28 ["init", "--from-config", str(FIXTURES / config_name), "--non-interactive"],
29 cwd=tmp_path,
30 runner=runner,
31 )
32 == 0
33 )
34
35
36 def test_status_exit_2_when_coverage_missing_dest(tmp_path: Path) -> None:
37 runner = git_status_runner()
38 _init(tmp_path, runner)
39 lock_path = tmp_path / ".overseer" / "version.lock"
40 lock = yaml.safe_load(lock_path.read_text(encoding="utf-8"))
41 lock["footprint"] = lock["footprint"][:5]
42 lock_path.write_text(yaml.dump(lock, sort_keys=False), encoding="utf-8")
43 with patch("cli.commands.status.check_governance_freshness", return_value=_OK_FRESHNESS):
44 code = run_cli(
45 ["status", "--json", "--exit-code"], cwd=tmp_path, runner=runner, json_mode=True
46 )
47 assert code == 2
48
49
50 def test_status_not_2_from_coverage_after_lock_updated(tmp_path: Path) -> None:
51 runner = git_status_runner()
52 _init(tmp_path, runner)
53 with patch("cli.commands.status.check_governance_freshness", return_value=_OK_FRESHNESS):
54 code = run_cli(
55 ["status", "--json", "--exit-code"], cwd=tmp_path, runner=runner, json_mode=True
56 )
57 assert code == 0
58
59
60 def test_session_bookends_in_resolve_when_enabled(tmp_path: Path) -> None:
61 from adapters.config import load_config
62
63 config = load_config(FIXTURES / "config-git-only.yaml")
64 from dataclasses import replace
65
66 off = replace(config, session_bookends=replace(config.session_bookends, enabled=False))
67 on = replace(config, session_bookends=replace(config.session_bookends, enabled=True))
68 off_dests = {f.destination for f in resolve_footprint(off, kit=KIT_ROOT)}
69 on_dests = {f.destination for f in resolve_footprint(on, kit=KIT_ROOT)}
70 hook_dests = {
71 ".cursor/hooks.json",
72 ".cursor/hooks/session-start-next.sh",
73 ".cursor/hooks/session-end-closeout.sh",
74 ".cursor/hooks/README.md",
75 }
76 assert hook_dests.isdisjoint(off_dests)
77 assert hook_dests <= on_dests
78
79
80 def test_compact_write_creates_archive(tmp_path: Path) -> None:
81 runner = git_status_runner()
82 _init(tmp_path, runner)
83 handover = tmp_path / "docs" / "OVERSEER-HANDOVER.md"
84 text = handover.read_text(encoding="utf-8")
85 bullets = "\n\n".join(f"- **2026-01-{day:02d}** — entry {day}" for day in range(1, 21))
86 if "<!-- overseer:anchor:change-log -->" in text:
87 start = text.index("<!-- overseer:anchor:change-log -->")
88 end = text.index("<!-- /overseer:anchor:change-log -->")
89 text = (
90 text[: start + len("<!-- overseer:anchor:change-log -->")]
91 + "\n"
92 + bullets
93 + "\n"
94 + text[end:]
95 )
96 else:
97 text += (
98 "\n<!-- overseer:anchor:change-log -->\n"
99 + bullets
100 + "\n<!-- /overseer:anchor:change-log -->\n"
101 )
102 handover.write_text(text, encoding="utf-8")
103 code = run_cli(
104 ["handover-compact", "--write", "--keep", "15"],
105 cwd=tmp_path,
106 runner=runner,
107 )
108 assert code == 0
109 archive = tmp_path / "docs" / "archive" / "handover" / "CHANGE-LOG.md"
110 assert archive.is_file()
111 living = handover.read_text(encoding="utf-8")
112 assert "Older entries: docs/archive/handover/CHANGE-LOG.md" in living
113 assert living.count("- **2026-") <= 15
114
115
116 def test_handover_compact_both_flags_exit_2(tmp_path: Path) -> None:
117 runner = git_status_runner()
118 _init(tmp_path, runner)
119 code = run_cli(
120 ["handover-compact", "--write", "--dry-run"],
121 cwd=tmp_path,
122 runner=runner,
123 )
124 assert code == 2
125
126
127 def test_status_json_includes_footprint_coverage(tmp_path: Path, capsys) -> None:
128 runner = git_status_runner()
129 _init(tmp_path, runner)
130 capsys.readouterr()
131 with patch("cli.commands.status.check_governance_freshness", return_value=_OK_FRESHNESS):
132 run_cli(["status", "--json"], cwd=tmp_path, runner=runner, json_mode=True)
133 payload = json.loads(capsys.readouterr().out)
134 assert "footprint_coverage" in payload
135 assert "ide_workspace_hint" in payload
136 assert "optional_feature_tips" in payload
137 assert payload["optional_feature_tips"]["tips"]
File History 1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199 fix(ISR): default require_independent_second_reviewer to require Human minor 8 hours ago