claude-dev-env 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  2. package/_shared/pr-loop/scripts/test_code_rules_gate.py +0 -26
  3. package/agents/CLAUDE.md +1 -2
  4. package/agents/pr-description-writer.md +11 -81
  5. package/bin/install.mjs +48 -9
  6. package/bin/install.prune.test.mjs +26 -0
  7. package/bin/install.settings-defaults.test.mjs +60 -33
  8. package/bin/install.test.mjs +2 -4
  9. package/commands/sr-loop.md +9 -5
  10. package/docs/CLAUDE.md +0 -1
  11. package/docs/references/CLAUDE.md +0 -1
  12. package/hooks/CLAUDE.md +1 -1
  13. package/hooks/blocking/CLAUDE.md +2 -27
  14. package/hooks/blocking/config/CLAUDE.md +1 -13
  15. package/hooks/blocking/conventional_pr_title_gate.py +1 -2
  16. package/hooks/blocking/send_user_file_open_locally_blocker.py +1 -1
  17. package/hooks/blocking/stop_dispatcher.py +4 -4
  18. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -3
  19. package/hooks/blocking/test_pre_tool_use_dispatcher.py +6 -7
  20. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +4 -3
  21. package/hooks/blocking/test_shared_stdin_adoption.py +0 -2
  22. package/hooks/diagnostic/CLAUDE.md +3 -3
  23. package/hooks/diagnostic/hook_log_extractor.py +2 -36
  24. package/hooks/diagnostic/hook_log_stop_wrapper.py +6 -155
  25. package/hooks/diagnostic/test_hook_log_extractor.py +8 -21
  26. package/hooks/diagnostic/test_hook_log_stop_wrapper.py +3 -331
  27. package/hooks/git-hooks/git_hooks_constants/__init__.py +0 -6
  28. package/hooks/git-hooks/pre_push.py +3 -85
  29. package/hooks/git-hooks/test_pre_push.py +0 -130
  30. package/hooks/hooks.json +0 -35
  31. package/hooks/hooks_constants/CLAUDE.md +0 -9
  32. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -11
  33. package/hooks/hooks_constants/convergence_branch_constants.py +0 -1
  34. package/hooks/hooks_constants/fable_spawn_gate_constants.py +3 -4
  35. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +0 -8
  36. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +1 -6
  37. package/hooks/hooks_constants/stop_dispatcher_constants.py +0 -1
  38. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +1 -26
  39. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +0 -5
  40. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +0 -1
  41. package/hooks/lifecycle/CLAUDE.md +1 -3
  42. package/package.json +1 -1
  43. package/rules/CLAUDE.md +0 -2
  44. package/rules/gh-cli-conventions.md +0 -1
  45. package/rules/git-workflow.md +1 -3
  46. package/scripts/CLAUDE.md +0 -1
  47. package/scripts/_code_review_test_support.py +0 -95
  48. package/scripts/dev_env_scripts_constants/code_review_constants.py +9 -98
  49. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +1 -44
  50. package/scripts/invoke_code_review.py +8 -451
  51. package/scripts/test_invoke_code_review.py +5 -61
  52. package/scripts/test_invoke_code_review_cli.py +1 -45
  53. package/scripts/test_invoke_code_review_contract.py +1 -118
  54. package/settings.json +1 -10
  55. package/skills/CLAUDE.md +8 -0
  56. package/skills/autoconverge/reference/CLAUDE.md +1 -1
  57. package/skills/autoconverge/reference/convergence.md +7 -7
  58. package/skills/autoconverge/reference/gotchas.md +3 -10
  59. package/skills/autoconverge/workflow/converge.contract.test.mjs +53 -1388
  60. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +4 -3
  61. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +33 -493
  62. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +15 -97
  63. package/skills/autoconverge/workflow/converge.mjs +201 -238
  64. package/skills/autoconverge/workflow/converge.precatch.test.mjs +1 -1
  65. package/skills/bugteam/CONSTRAINTS.md +1 -1
  66. package/skills/bugteam/SKILL.md +9 -0
  67. package/skills/bugteam/reference/audit-and-teammates.md +10 -6
  68. package/skills/bugteam/test_skill_additions.py +9 -0
  69. package/skills/comments/SKILL.md +65 -0
  70. package/skills/descriptions/SKILL.md +51 -0
  71. package/skills/emergencies/SKILL.md +42 -0
  72. package/skills/imagegen/SKILL.md +21 -0
  73. package/skills/imagegen/scripts/config/__init__.py +1 -0
  74. package/skills/imagegen/scripts/config/constants.py +28 -0
  75. package/skills/imagegen/scripts/imagegen.py +45 -0
  76. package/skills/imagegen/scripts/imagegen_core.py +528 -0
  77. package/skills/imagegen/scripts/test_imagegen.py +204 -0
  78. package/skills/orchestrator/SKILL.md +2 -4
  79. package/skills/plan-to-pr/SKILL.md +6 -7
  80. package/skills/plan-to-pr/reference/final-validation-tasks.md +1 -1
  81. package/skills/plan-to-pr/reference/process-inventory.md +2 -2
  82. package/skills/plan-to-pr/reference/review-loop.md +2 -2
  83. package/skills/plan-to-pr/reference/run-record.schema.json +1 -1
  84. package/skills/plan-to-pr/reference/task-seeds.md +1 -1
  85. package/skills/plan-to-pr/reference/task-ticket.md +3 -4
  86. package/skills/plan-to-pr/scripts/config/constants.py +1 -2
  87. package/skills/plan-to-pr/scripts/test_validate_protocol.py +1 -1
  88. package/skills/plan-to-pr/test_skill_contract.py +2 -2
  89. package/skills/pr-converge/SKILL.md +13 -16
  90. package/skills/pr-converge/reference/progress-checklist.md +6 -5
  91. package/skills/pr-converge/reference/state-schema.md +1 -27
  92. package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
  93. package/skills/pr-loop-cloud-transport/reference/identity-and-hooks.md +3 -3
  94. package/skills/pr-loop-lifecycle/SKILL.md +1 -1
  95. package/skills/pr-loop-lifecycle/reference/teardown-publish-permissions.md +1 -1
  96. package/skills/prototype/SKILL.md +4 -4
  97. package/skills/prototype/reference/honest-limitations.md +4 -4
  98. package/skills/prototype/reference/promotion-tasks.md +2 -2
  99. package/skills/prototype/workflows/promotion.md +4 -6
  100. package/skills/reviews/SKILL.md +85 -0
  101. package/skills/small-cl/SKILL.md +52 -0
  102. package/agents/code-verifier.md +0 -74
  103. package/docs/PR_DESCRIPTION_GUIDE.md +0 -157
  104. package/docs/references/code-review-enforcement.md +0 -132
  105. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +0 -53
  106. package/hooks/blocking/code_review_gate_deny.py +0 -74
  107. package/hooks/blocking/code_review_pr_create_gate.py +0 -198
  108. package/hooks/blocking/code_review_push_gate.py +0 -145
  109. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +0 -348
  110. package/hooks/blocking/code_review_stamp_store.py +0 -233
  111. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +0 -7
  112. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +0 -15
  113. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +0 -212
  114. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +0 -138
  115. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +0 -49
  116. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +0 -38
  117. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +0 -483
  118. package/hooks/blocking/config/code_review_enforcement_constants.py +0 -143
  119. package/hooks/blocking/config/test_code_review_enforcement_constants.py +0 -166
  120. package/hooks/blocking/config/verified_commit_constants.py +0 -160
  121. package/hooks/blocking/config/verified_commit_context_constants.py +0 -21
  122. package/hooks/blocking/config/verified_commit_gate_output_constants.py +0 -14
  123. package/hooks/blocking/conftest.py +0 -123
  124. package/hooks/blocking/convergence_gate_blocker.py +0 -310
  125. package/hooks/blocking/pr_converge_bugteam_enforcer.py +0 -170
  126. package/hooks/blocking/pr_description_body_audit.py +0 -148
  127. package/hooks/blocking/pr_description_command_parser.py +0 -237
  128. package/hooks/blocking/pr_description_enforcer.py +0 -227
  129. package/hooks/blocking/pr_description_pr_number.py +0 -155
  130. package/hooks/blocking/pr_description_proof_of_work.py +0 -385
  131. package/hooks/blocking/pr_description_readability.py +0 -364
  132. package/hooks/blocking/reviewer_spawn_gate.py +0 -182
  133. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +0 -62
  134. package/hooks/blocking/test_code_review_gate_deny.py +0 -54
  135. package/hooks/blocking/test_code_review_pr_create_gate.py +0 -199
  136. package/hooks/blocking/test_code_review_push_gate.py +0 -205
  137. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +0 -199
  138. package/hooks/blocking/test_code_review_stamp_store.py +0 -205
  139. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +0 -710
  140. package/hooks/blocking/test_code_verifier_tools_contract.py +0 -28
  141. package/hooks/blocking/test_convergence_gate_blocker.py +0 -428
  142. package/hooks/blocking/test_pr_converge_bugteam_enforcer.py +0 -311
  143. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +0 -184
  144. package/hooks/blocking/test_pr_description_enforcer.py +0 -221
  145. package/hooks/blocking/test_pr_description_enforcer_body_audit.py +0 -247
  146. package/hooks/blocking/test_pr_description_enforcer_body_rules.py +0 -493
  147. package/hooks/blocking/test_pr_description_enforcer_command_parser.py +0 -366
  148. package/hooks/blocking/test_pr_description_enforcer_pr_number.py +0 -159
  149. package/hooks/blocking/test_pr_description_enforcer_proof_gate.py +0 -175
  150. package/hooks/blocking/test_pr_description_enforcer_readability.py +0 -443
  151. package/hooks/blocking/test_pr_description_proof_of_work.py +0 -313
  152. package/hooks/blocking/test_reviewer_spawn_gate.py +0 -230
  153. package/hooks/blocking/test_verdict_directory_write_blocker.py +0 -804
  154. package/hooks/blocking/test_verification_verdict_store.py +0 -974
  155. package/hooks/blocking/test_verified_commit_config_bootstrap.py +0 -67
  156. package/hooks/blocking/test_verified_commit_docs_delta.py +0 -176
  157. package/hooks/blocking/test_verified_commit_gate.py +0 -581
  158. package/hooks/blocking/test_verified_commit_gate_additional_context.py +0 -134
  159. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +0 -131
  160. package/hooks/blocking/test_verifier_verdict_minter.py +0 -299
  161. package/hooks/blocking/tests/test_verified_commit_gate.py +0 -41
  162. package/hooks/blocking/verdict_directory_write_blocker.py +0 -687
  163. package/hooks/blocking/verification_verdict_store.py +0 -1039
  164. package/hooks/blocking/verified_commit_config_bootstrap.py +0 -63
  165. package/hooks/blocking/verified_commit_gate.py +0 -113
  166. package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +0 -28
  167. package/hooks/blocking/verified_commit_gate_parts/__init__.py +0 -1
  168. package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +0 -174
  169. package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +0 -53
  170. package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +0 -80
  171. package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +0 -170
  172. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +0 -217
  173. package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +0 -10
  174. package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +0 -94
  175. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +0 -17
  176. package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +0 -38
  177. package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +0 -71
  178. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +0 -96
  179. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +0 -167
  180. package/hooks/blocking/verifier_verdict_minter.py +0 -280
  181. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +0 -64
  182. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +0 -53
  183. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_constants.py +0 -55
  184. package/hooks/hooks_constants/pr_converge_bugteam_enforcer_state.py +0 -67
  185. package/hooks/hooks_constants/pr_description_enforcer_constants.py +0 -167
  186. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -107
  187. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +0 -41
  188. package/hooks/hooks_constants/test_pr_description_enforcer_constants.py +0 -292
  189. package/hooks/lifecycle/pr_converge_bugteam_skill_tracker.py +0 -198
  190. package/hooks/lifecycle/test_pr_converge_bugteam_skill_tracker.py +0 -283
  191. package/rules/proof-of-work-pr-comments.md +0 -22
  192. package/rules/verified-commit-gate-skip.md +0 -4
  193. package/scripts/Show-Asset.ps1 +0 -106
@@ -1,67 +0,0 @@
1
- """Regression tests for the verified-commit constants bootstrap.
2
-
3
- These prove the shared constants module resolves to the sibling
4
- ``config/verified_commit_constants.py`` file even when a foreign ``config``
5
- package sits ahead of ``blocking`` on ``sys.path``, and that a registration a
6
- caller placed first is left untouched.
7
- """
8
-
9
- import subprocess
10
- from collections.abc import Callable
11
-
12
- RunUnderConfigShadow = Callable[[str], subprocess.CompletedProcess[str]]
13
-
14
-
15
- def test_register_binds_dotted_name_to_sibling_constants_file(
16
- run_under_config_shadow: RunUnderConfigShadow,
17
- ) -> None:
18
- completed_probe = run_under_config_shadow(
19
- "import verified_commit_config_bootstrap as bootstrap\n"
20
- "bootstrap.register_verified_commit_constants()\n"
21
- "import config.verified_commit_constants as loaded\n"
22
- "print(loaded.__file__)\n"
23
- "print(loaded.DETACHED_HEAD_LABEL)\n"
24
- )
25
- assert completed_probe.returncode == 0, completed_probe.stderr
26
- assert "IS_DECOY_CONFIG" not in completed_probe.stdout
27
- resolved_file_line, detached_head_line = completed_probe.stdout.splitlines()[:2]
28
- assert resolved_file_line.replace("\\", "/").endswith(
29
- "blocking/config/verified_commit_constants.py"
30
- )
31
- assert detached_head_line == "HEAD"
32
-
33
-
34
- def test_register_binds_gate_output_constants_module(
35
- run_under_config_shadow: RunUnderConfigShadow,
36
- ) -> None:
37
- completed_probe = run_under_config_shadow(
38
- "import verified_commit_config_bootstrap as bootstrap\n"
39
- "bootstrap.register_verified_commit_constants()\n"
40
- "import config.verified_commit_gate_output_constants as loaded\n"
41
- "print(loaded.__file__)\n"
42
- "print(loaded.DENY_PERMISSION_DECISION)\n"
43
- )
44
- assert completed_probe.returncode == 0, completed_probe.stderr
45
- resolved_file_line, deny_decision_line = completed_probe.stdout.splitlines()[:2]
46
- assert resolved_file_line.replace("\\", "/").endswith(
47
- "blocking/config/verified_commit_gate_output_constants.py"
48
- )
49
- assert deny_decision_line == "deny"
50
-
51
-
52
- def test_register_leaves_an_already_cached_module_untouched(
53
- run_under_config_shadow: RunUnderConfigShadow,
54
- ) -> None:
55
- completed_probe = run_under_config_shadow(
56
- "import sys\n"
57
- "import types\n"
58
- "sentinel = types.ModuleType('config.verified_commit_constants')\n"
59
- "sentinel.ORIGIN = 'caller-seeded'\n"
60
- "sys.modules['config.verified_commit_constants'] = sentinel\n"
61
- "import verified_commit_config_bootstrap as bootstrap\n"
62
- "bootstrap.register_verified_commit_constants()\n"
63
- "import config.verified_commit_constants as loaded\n"
64
- "print(getattr(loaded, 'ORIGIN', 'displaced'))\n"
65
- )
66
- assert completed_probe.returncode == 0, completed_probe.stderr
67
- assert completed_probe.stdout.strip().splitlines()[-1] == "caller-seeded"
@@ -1,176 +0,0 @@
1
- """Gate behavior for docs-only deltas and the cross-work-tree deny message.
2
-
3
- Each test builds a real git repository with a real origin remote and drives
4
- ``deny_reason_for_directory`` — the same decision the verified_commit_gate hook
5
- runs — so the docs-only exemption, the docs-after-verified-code block, and the
6
- denial message's work-tree keying are asserted against live git state.
7
- """
8
-
9
- import importlib.util
10
- import pathlib
11
- import subprocess
12
- import sys
13
-
14
- import pytest
15
-
16
- _HOOK_DIR = pathlib.Path(__file__).parent
17
- if str(_HOOK_DIR) not in sys.path:
18
- sys.path.insert(0, str(_HOOK_DIR))
19
-
20
- gate_spec = importlib.util.spec_from_file_location(
21
- "verified_commit_gate",
22
- _HOOK_DIR / "verified_commit_gate.py",
23
- )
24
- assert gate_spec is not None
25
- assert gate_spec.loader is not None
26
- gate_module = importlib.util.module_from_spec(gate_spec)
27
- gate_spec.loader.exec_module(gate_module)
28
- deny_reason_for_directory = gate_module.deny_reason_for_directory
29
-
30
- store_spec = importlib.util.spec_from_file_location(
31
- "verification_verdict_store",
32
- _HOOK_DIR / "verification_verdict_store.py",
33
- )
34
- assert store_spec is not None
35
- assert store_spec.loader is not None
36
- store_module = importlib.util.module_from_spec(store_spec)
37
- store_spec.loader.exec_module(store_module)
38
- resolve_merge_base = store_module.resolve_merge_base
39
- branch_surface_manifest = store_module.branch_surface_manifest
40
- manifest_sha256 = store_module.manifest_sha256
41
- write_verdict = store_module.write_verdict
42
-
43
- PRODUCTION_SOURCE = "def add(left: int, right: int) -> int:\n return left + right\n"
44
- BEHAVIORAL_EDIT_SOURCE = "def add(left: int, right: int) -> int:\n return left - right\n"
45
-
46
-
47
- def _run_git(repo_dir: pathlib.Path, *git_arguments: str) -> None:
48
- subprocess.run(
49
- ["git", "-C", str(repo_dir), *git_arguments],
50
- check=True,
51
- capture_output=True,
52
- text=True,
53
- )
54
-
55
-
56
- def _isolate_home(monkeypatch: pytest.MonkeyPatch, fake_home: pathlib.Path) -> None:
57
- home_text = str(fake_home)
58
- monkeypatch.setenv("HOME", home_text)
59
- monkeypatch.setenv("USERPROFILE", home_text)
60
- monkeypatch.delenv("HOMEDRIVE", raising=False)
61
- monkeypatch.delenv("HOMEPATH", raising=False)
62
-
63
-
64
- def _empty_hooks_dir(tmp_path: pathlib.Path) -> pathlib.Path:
65
- hooks_dir = tmp_path / "nohooks"
66
- hooks_dir.mkdir(exist_ok=True)
67
- return hooks_dir
68
-
69
-
70
- def _empty_transcript(tmp_path: pathlib.Path) -> pathlib.Path:
71
- transcript_path = tmp_path / "projects" / "demo" / "sess1.jsonl"
72
- transcript_path.parent.mkdir(parents=True, exist_ok=True)
73
- transcript_path.write_text("", encoding="utf-8")
74
- return transcript_path
75
-
76
-
77
- def _init_pushed_repo(tmp_path: pathlib.Path) -> pathlib.Path:
78
- origin_dir = tmp_path / "origin.git"
79
- work_dir = tmp_path / "work"
80
- work_dir.mkdir()
81
- subprocess.run(
82
- ["git", "init", "--bare", "--initial-branch=main", str(origin_dir)],
83
- check=True,
84
- capture_output=True,
85
- text=True,
86
- )
87
- _run_git(work_dir, "init", "--initial-branch=main")
88
- _run_git(work_dir, "config", "user.email", "tests@example.com")
89
- _run_git(work_dir, "config", "user.name", "Docs Delta Tests")
90
- _run_git(work_dir, "config", "core.hooksPath", str(_empty_hooks_dir(tmp_path)))
91
- (work_dir / "app.py").write_text(PRODUCTION_SOURCE, encoding="utf-8")
92
- (work_dir / "README.md").write_text("# base\n", encoding="utf-8")
93
- _run_git(work_dir, "add", "-A")
94
- _run_git(work_dir, "commit", "-m", "base")
95
- _run_git(work_dir, "remote", "add", "origin", str(origin_dir))
96
- _run_git(work_dir, "push", "-u", "origin", "main")
97
- return work_dir
98
-
99
-
100
- def _make_docs_only_repo(tmp_path: pathlib.Path) -> pathlib.Path:
101
- work_dir = _init_pushed_repo(tmp_path)
102
- (work_dir / "README.md").write_text("# base\n\nUpdated docs.\n", encoding="utf-8")
103
- return work_dir
104
-
105
-
106
- def _make_behavioral_code_repo(tmp_path: pathlib.Path) -> pathlib.Path:
107
- work_dir = _init_pushed_repo(tmp_path)
108
- (work_dir / "app.py").write_text(BEHAVIORAL_EDIT_SOURCE, encoding="utf-8")
109
- return work_dir
110
-
111
-
112
- def _live_surface_hash(work_dir: pathlib.Path) -> str:
113
- merge_base_sha = resolve_merge_base(str(work_dir))
114
- assert merge_base_sha is not None
115
- surface_manifest_text = branch_surface_manifest(str(work_dir), merge_base_sha)
116
- assert surface_manifest_text is not None
117
- return manifest_sha256(surface_manifest_text)
118
-
119
-
120
- def test_pure_docs_only_branch_is_allowed_without_verdict(
121
- monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
122
- ) -> None:
123
- fake_home = tmp_path / "home"
124
- fake_home.mkdir()
125
- _isolate_home(monkeypatch, fake_home)
126
- work_dir = _make_docs_only_repo(tmp_path)
127
- transcript_path = _empty_transcript(tmp_path)
128
- assert deny_reason_for_directory(str(work_dir), str(transcript_path)) is None
129
-
130
-
131
- def test_readme_change_after_verified_code_commit_is_denied(
132
- monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
133
- ) -> None:
134
- fake_home = tmp_path / "home"
135
- fake_home.mkdir()
136
- _isolate_home(monkeypatch, fake_home)
137
- work_dir = _make_behavioral_code_repo(tmp_path)
138
- code_surface_hash = _live_surface_hash(work_dir)
139
- write_verdict(str(work_dir), code_surface_hash, True, [], "agent-x")
140
- transcript_path = _empty_transcript(tmp_path)
141
- assert deny_reason_for_directory(str(work_dir), str(transcript_path)) is None
142
- _run_git(work_dir, "add", "-A")
143
- _run_git(work_dir, "commit", "-m", "verified code change")
144
- (work_dir / "README.md").write_text("# added after verification\n", encoding="utf-8")
145
- deny_reason = deny_reason_for_directory(str(work_dir), str(transcript_path))
146
- assert deny_reason is not None
147
- assert "VERIFIED_COMMIT_GATE" in deny_reason
148
-
149
-
150
- def test_readme_added_beside_unverified_code_is_denied(
151
- monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
152
- ) -> None:
153
- fake_home = tmp_path / "home"
154
- fake_home.mkdir()
155
- _isolate_home(monkeypatch, fake_home)
156
- work_dir = _make_behavioral_code_repo(tmp_path)
157
- (work_dir / "README.md").write_text("# docs beside code\n", encoding="utf-8")
158
- transcript_path = _empty_transcript(tmp_path)
159
- deny_reason = deny_reason_for_directory(str(work_dir), str(transcript_path))
160
- assert deny_reason is not None
161
- assert "VERIFIED_COMMIT_GATE" in deny_reason
162
-
163
-
164
- def test_deny_reason_for_directory_names_worktree_keying_and_remedy(
165
- monkeypatch: pytest.MonkeyPatch, tmp_path: pathlib.Path
166
- ) -> None:
167
- fake_home = tmp_path / "home"
168
- fake_home.mkdir()
169
- _isolate_home(monkeypatch, fake_home)
170
- work_dir = _make_behavioral_code_repo(tmp_path)
171
- transcript_path = _empty_transcript(tmp_path)
172
- deny_reason = deny_reason_for_directory(str(work_dir), str(transcript_path))
173
- assert deny_reason is not None
174
- lowered_reason = deny_reason.lower()
175
- assert "work tree" in lowered_reason
176
- assert "run this command from the work tree" in lowered_reason