test_gs_paste_next_regen.py python
154 lines 4.7 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 13 hours ago
1 """Unit tests for GS-PASTE NEXT / paste regeneration (§GSP.10 unit)."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6
7 from adapters.config import load_config
8 from tools.governance_hygiene.next_regen import (
9 compact_step_id,
10 decide_split_emission,
11 plan_next_regen,
12 render_next_session,
13 render_paste_ready,
14 select_unambiguous_next_row,
15 )
16 from tools.governance_hygiene.patch import _render_next_step_glance
17 from tools.governance_hygiene.types import QueueRow
18
19
20 def _roadmap(*rows: str) -> str:
21 header = (
22 "# Roadmap\n\n## Build queue\n\n"
23 "| Phase | Model | Status | Deliverable |\n"
24 "| --- | --- | --- | --- |\n"
25 )
26 return header + "\n".join(rows) + "\n"
27
28
29 def test_select_exactly_one_open_row() -> None:
30 text = _roadmap(
31 "| **Done** | Auto | **DONE** | x |",
32 "| **Open** | Auto | **NEXT** | y |",
33 )
34 row, reason = select_unambiguous_next_row(text)
35 assert reason is None
36 assert row is not None
37 assert "Open" in row.phase_label
38
39
40 def test_select_zero_open_rows() -> None:
41 text = _roadmap("| **Done** | Auto | **DONE** | x |")
42 row, reason = select_unambiguous_next_row(text)
43 assert row is None
44 assert reason == "zero_open_rows"
45
46
47 def test_select_multiple_open_rows() -> None:
48 text = _roadmap(
49 "| **A** | Auto | **TODO** | a |",
50 "| **B** | Auto | **WIP** | b |",
51 )
52 row, reason = select_unambiguous_next_row(text)
53 assert row is None
54 assert reason == "multiple_open_rows"
55
56
57 def test_select_invalid_model_ambiguous() -> None:
58 text = _roadmap("| **Open** | Operator choice | **NEXT** | y |")
59 row, reason = select_unambiguous_next_row(text)
60 assert row is None
61 assert reason == "invalid_model_label"
62
63
64 def test_thinking_to_auto_emit_b_when_freeze_pass(tmp_path: Path) -> None:
65 docs = tmp_path / "docs"
66 docs.mkdir()
67 (docs / "PHASE-GS-PASTE-READY-REGEN.md").write_text(
68 "# Freeze\n\n```yaml\nphase: GS-PASTE\nreview_stamp:\n verdict: pass\n```\n",
69 encoding="utf-8",
70 )
71 row = QueueRow(
72 phase_label="**GS-PASTE**",
73 model="Thinking → Auto",
74 status="**NEXT**",
75 deliverable="docs/archive/phases/PHASE-GS-PASTE-READY-REGEN.md",
76 raw_line="",
77 )
78 emit_model, reason, is_b = decide_split_emission(row, tmp_path)
79 assert reason is None
80 assert emit_model == "Auto"
81 assert is_b is True
82
83
84 def test_thinking_to_auto_emit_a_without_freeze_pass(tmp_path: Path) -> None:
85 docs = tmp_path / "docs"
86 docs.mkdir()
87 row = QueueRow(
88 phase_label="**GS-PASTE**",
89 model="Thinking → Auto",
90 status="**NEXT**",
91 deliverable="freeze something",
92 raw_line="",
93 )
94 emit_model, reason, is_b = decide_split_emission(row, tmp_path)
95 assert reason is None
96 assert emit_model == "Thinking"
97 assert is_b is False
98
99
100 def test_rendered_next_contains_h3_h5_h6_substrings(tmp_path: Path) -> None:
101 config = load_config(
102 Path(__file__).resolve().parents[1] / "fixtures" / "config-git-only.yaml"
103 )
104 roadmap = _roadmap(
105 "| **Prior** | Auto | **DONE** | prior work |",
106 "| **GS-PASTE-b** | Auto | **NEXT** | regen paste |",
107 )
108 decision = plan_next_regen(
109 roadmap_text=roadmap,
110 handover_text="## NEXT SESSION — x\n",
111 config=config,
112 repo_root=tmp_path,
113 )
114 assert decision.row is not None
115 body = render_next_session(
116 decision=decision,
117 roadmap_text=roadmap,
118 config=config,
119 sync_date="2026-07-30",
120 )
121 assert "**Date:**" in body
122 assert "**Current position:**" in body
123 assert "**Model:**" in body
124 assert "### THE ONE NEXT STEP — **Model:" in body
125 assert "| **ID** |" in body
126 assert "| **Branch** |" in body
127 assert "| **Repo** |" in body
128 assert "| **Read first** |" in body
129 assert "| **Hard stops** |" in body
130 assert "### Paste-ready prompt" not in body
131
132 paste = render_paste_ready(decision=decision, config=config)
133 assert "### Paste-ready prompt —" in paste
134 assert "Model: Auto" in paste
135 assert "Repo:" in paste
136 assert "Step:" in paste
137 assert "Authority:" in paste
138 assert "build-verification-review" in paste
139
140
141 def test_glance_fail_closed_when_open_count_not_one() -> None:
142 multi = _roadmap(
143 "| **A** | Auto | **TODO** | a |",
144 "| **B** | Auto | **WIP** | b |",
145 )
146 glance = _render_next_step_glance(multi)
147 assert "No unambiguous NEXT row — operator authorship required." in glance
148
149 zero = _roadmap("| **A** | Auto | **DONE** | a |")
150 assert "No unambiguous NEXT row" in _render_next_step_glance(zero)
151
152
153 def test_compact_step_id_uses_first_segment() -> None:
154 assert compact_step_id("**GS-PASTE-b Paste regen**") == "GS-PASTE-b"
File History 1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 13 hours ago