claude-dev-env 1.59.0 → 1.61.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.
- package/CLAUDE.md +4 -0
- package/audit-rubrics/category_rubrics/category-b-selector-engine-compat.md +1 -1
- package/audit-rubrics/category_rubrics/category-e-dead-code.md +1 -0
- package/audit-rubrics/category_rubrics/category-f-silent-failures.md +1 -1
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
- package/audit-rubrics/prompts/category-b-selector-engine-compat.md +2 -2
- package/audit-rubrics/prompts/category-e-dead-code.md +17 -4
- package/audit-rubrics/prompts/category-f-silent-failures.md +1 -0
- package/docs/CODE_RULES.md +2 -2
- package/hooks/blocking/code_rules_annotations_length.py +189 -10
- package/hooks/blocking/code_rules_dead_module_constant.py +321 -0
- package/hooks/blocking/code_rules_duplicate_body.py +152 -0
- package/hooks/blocking/code_rules_enforcer.py +38 -15
- package/hooks/blocking/code_rules_orphan_css_class.py +196 -0
- package/hooks/blocking/code_rules_typeddict_stub.py +172 -0
- package/hooks/blocking/config/__init__.py +5 -0
- package/hooks/blocking/config/verified_commit_constants.py +118 -0
- package/hooks/blocking/destructive_command_blocker.py +483 -61
- package/hooks/blocking/test_code_rules_enforcer_annotations.py +240 -0
- package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +1 -0
- package/hooks/blocking/test_code_rules_enforcer_cross_skill_duplicate.py +146 -0
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +188 -0
- package/hooks/blocking/test_code_rules_enforcer_dispatch_wiring.py +82 -0
- package/hooks/blocking/test_code_rules_enforcer_orphan_css_class.py +196 -0
- package/hooks/blocking/test_code_rules_enforcer_zero_payload_alias.py +415 -0
- package/hooks/blocking/test_code_rules_enforcer_zero_payload_alias_hook_routing.py +156 -0
- package/hooks/blocking/test_destructive_command_blocker.py +213 -0
- package/hooks/blocking/test_verdict_directory_write_blocker.py +720 -0
- package/hooks/blocking/test_verification_verdict_store.py +490 -0
- package/hooks/blocking/test_verified_commit_gate.py +495 -0
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -0
- package/hooks/blocking/test_verifier_verdict_minter.py +193 -0
- package/hooks/blocking/verdict_directory_write_blocker.py +667 -0
- package/hooks/blocking/verification_verdict_store.py +686 -0
- package/hooks/blocking/verified_commit_gate.py +535 -0
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +152 -0
- package/hooks/blocking/verifier_verdict_minter.py +221 -0
- package/hooks/diagnostic/test_hook_log_extractor.py +3 -3
- package/hooks/hooks.json +43 -1
- package/hooks/hooks_constants/blocking_check_limits.py +1 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +6 -0
- package/hooks/hooks_constants/dead_module_constant_constants.py +20 -0
- package/hooks/hooks_constants/destructive_command_segment_constants.py +15 -0
- package/hooks/hooks_constants/duplicate_function_body_constants.py +22 -5
- package/hooks/hooks_constants/orphan_css_class_constants.py +40 -0
- package/hooks/hooks_constants/precommit_code_rules_gate_constants.py +1 -1
- package/hooks/validation/mypy_validator.py +59 -7
- package/hooks/validation/test_mypy_validator.py +94 -0
- package/package.json +1 -1
- package/rules/file-global-constants.md +7 -1
- package/rules/no-cross-skill-duplicate-helpers.md +29 -0
- package/rules/orphan-css-class.md +23 -0
- package/skills/_shared/pr-loop/scripts/preflight_worktree.py +392 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +70 -0
- package/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +263 -0
- package/skills/autoconverge/SKILL.md +54 -17
- package/skills/autoconverge/reference/closing-report.md +59 -17
- package/skills/autoconverge/workflow/aggregate_runs.py +371 -0
- package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +192 -76
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +76 -0
- package/skills/autoconverge/workflow/converge.contract.test.mjs +395 -206
- package/skills/autoconverge/workflow/converge.mjs +520 -57
- package/skills/autoconverge/workflow/convergence_summary.py +110 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +2 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +7 -0
- package/skills/autoconverge/workflow/render_report.py +488 -397
- package/skills/autoconverge/workflow/test_aggregate_runs.py +134 -0
- package/skills/autoconverge/workflow/test_convergence_summary.py +132 -0
- package/skills/autoconverge/workflow/test_render_report.py +518 -259
- package/skills/pr-converge/reference/per-tick.md +28 -8
- package/skills/rebase/SKILL.md +2 -4
- package/system-prompts/software-engineer.xml +2 -6
- package/hooks/blocking/content_search_to_zoekt_redirector.py +0 -59
- package/hooks/blocking/content_search_zoekt_bash_block_reason.py +0 -25
- package/hooks/blocking/content_search_zoekt_block_payload.py +0 -21
- package/hooks/blocking/content_search_zoekt_indexed_paths.py +0 -24
- package/hooks/blocking/content_search_zoekt_indexed_roots_config.py +0 -131
- package/hooks/blocking/content_search_zoekt_redirect_guidance.py +0 -52
- package/hooks/blocking/test_content_search_to_zoekt_redirector_integration.py +0 -61
- package/hooks/blocking/test_content_search_to_zoekt_redirector_unit.py +0 -92
- package/hooks/blocking/test_content_search_zoekt_indexed_roots_config.py +0 -102
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Tests for the agent-type gate in verifier_verdict_minter.
|
|
2
|
+
|
|
3
|
+
The minter mints a verdict only for a code-verifier stop event. The
|
|
4
|
+
SubagentStop payload names the stopping subagent's own transcript
|
|
5
|
+
(``agent_transcript_path``), which sits beside a harness-written
|
|
6
|
+
``agent-<id>.meta.json`` sidecar naming the spawning ``agentType``. These
|
|
7
|
+
tests build that sidecar and assert the minter gates on the resolved type and
|
|
8
|
+
on the shared MINTING_AGENT_TYPE constant, so a rename in config propagates to
|
|
9
|
+
the minter without a second edit. A malformed or non-string sidecar resolves
|
|
10
|
+
nothing, and an absent sidecar mints nothing — the main session writes neither
|
|
11
|
+
the transcript nor the sidecar, so it cannot forge a passing verdict. A
|
|
12
|
+
further test holds the shipped settings.json to the minter docstring's
|
|
13
|
+
anti-forgery claim: the main session is denied writes to the verdict
|
|
14
|
+
directory, so only this hook can mint a passing verdict.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import importlib.util
|
|
18
|
+
import json
|
|
19
|
+
import pathlib
|
|
20
|
+
import subprocess
|
|
21
|
+
import sys
|
|
22
|
+
|
|
23
|
+
_HOOK_DIR = pathlib.Path(__file__).parent
|
|
24
|
+
if str(_HOOK_DIR) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(_HOOK_DIR))
|
|
26
|
+
|
|
27
|
+
_SETTINGS_PATH = _HOOK_DIR.parent.parent / "settings.json"
|
|
28
|
+
|
|
29
|
+
minter_spec = importlib.util.spec_from_file_location(
|
|
30
|
+
"verifier_verdict_minter",
|
|
31
|
+
_HOOK_DIR / "verifier_verdict_minter.py",
|
|
32
|
+
)
|
|
33
|
+
assert minter_spec is not None
|
|
34
|
+
assert minter_spec.loader is not None
|
|
35
|
+
minter_module = importlib.util.module_from_spec(minter_spec)
|
|
36
|
+
minter_spec.loader.exec_module(minter_module)
|
|
37
|
+
mint_for_payload = minter_module.mint_for_payload
|
|
38
|
+
resolved_subagent_type = minter_module.resolved_subagent_type
|
|
39
|
+
|
|
40
|
+
constants_spec = importlib.util.spec_from_file_location(
|
|
41
|
+
"verified_commit_constants",
|
|
42
|
+
_HOOK_DIR / "config" / "verified_commit_constants.py",
|
|
43
|
+
)
|
|
44
|
+
assert constants_spec is not None
|
|
45
|
+
assert constants_spec.loader is not None
|
|
46
|
+
constants_module = importlib.util.module_from_spec(constants_spec)
|
|
47
|
+
constants_spec.loader.exec_module(constants_module)
|
|
48
|
+
MINTING_AGENT_TYPE = constants_module.MINTING_AGENT_TYPE
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _write_sidecar(agent_transcript_file: pathlib.Path, agent_type: str) -> None:
|
|
52
|
+
sidecar_file = agent_transcript_file.with_name(f"{agent_transcript_file.stem}.meta.json")
|
|
53
|
+
sidecar_file.write_text(
|
|
54
|
+
json.dumps({"agentType": agent_type, "description": "Verify"}) + "\n",
|
|
55
|
+
encoding="utf-8",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_resolves_subagent_type_from_sidecar(tmp_path: pathlib.Path) -> None:
|
|
60
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
61
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
62
|
+
_write_sidecar(agent_transcript, MINTING_AGENT_TYPE)
|
|
63
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
64
|
+
assert resolved_subagent_type(payload) == MINTING_AGENT_TYPE
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def test_resolves_none_when_sidecar_absent(tmp_path: pathlib.Path) -> None:
|
|
68
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
69
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
70
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
71
|
+
assert resolved_subagent_type(payload) is None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_resolves_none_when_agent_transcript_path_empty() -> None:
|
|
75
|
+
assert resolved_subagent_type({"agent_transcript_path": ""}) is None
|
|
76
|
+
assert resolved_subagent_type({}) is None
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_resolves_none_when_sidecar_names_no_string_type(tmp_path: pathlib.Path) -> None:
|
|
80
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
81
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
82
|
+
sidecar_file = agent_transcript.with_name("agent-7.meta.json")
|
|
83
|
+
sidecar_file.write_text(json.dumps({"agentType": 123}), encoding="utf-8")
|
|
84
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
85
|
+
assert resolved_subagent_type(payload) is None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_unparseable_sidecar_resolves_nothing(tmp_path: pathlib.Path) -> None:
|
|
89
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
90
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
91
|
+
sidecar_file = agent_transcript.with_name("agent-7.meta.json")
|
|
92
|
+
sidecar_file.write_text("{not valid json", encoding="utf-8")
|
|
93
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
94
|
+
assert resolved_subagent_type(payload) is None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_invalid_utf8_sidecar_resolves_nothing(tmp_path: pathlib.Path) -> None:
|
|
98
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
99
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
100
|
+
sidecar_file = agent_transcript.with_name("agent-7.meta.json")
|
|
101
|
+
sidecar_file.write_bytes(b'{"agentType": "\xff\xfe bad"}')
|
|
102
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
103
|
+
assert resolved_subagent_type(payload) is None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_non_object_json_sidecar_resolves_nothing(tmp_path: pathlib.Path) -> None:
|
|
107
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
108
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
109
|
+
sidecar_file = agent_transcript.with_name("agent-7.meta.json")
|
|
110
|
+
sidecar_file.write_text(json.dumps(["agentType", "code-verifier"]), encoding="utf-8")
|
|
111
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
112
|
+
assert resolved_subagent_type(payload) is None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_non_verifier_agent_type_mints_nothing(tmp_path: pathlib.Path) -> None:
|
|
116
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
117
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
118
|
+
_write_sidecar(agent_transcript, "general-purpose")
|
|
119
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
120
|
+
assert mint_for_payload(payload) is None
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_verifier_type_without_a_verdict_mints_nothing(tmp_path: pathlib.Path) -> None:
|
|
124
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
125
|
+
agent_transcript.write_text("", encoding="utf-8")
|
|
126
|
+
_write_sidecar(agent_transcript, MINTING_AGENT_TYPE)
|
|
127
|
+
payload = {"agent_transcript_path": str(agent_transcript)}
|
|
128
|
+
assert mint_for_payload(payload) is None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _init_repo_with_upstream_and_edit(repo_root: pathlib.Path) -> None:
|
|
132
|
+
subprocess.run(["git", "-C", str(repo_root), "init", "-q"], check=True)
|
|
133
|
+
subprocess.run(
|
|
134
|
+
["git", "-C", str(repo_root), "config", "user.email", "verifier@test"], check=True
|
|
135
|
+
)
|
|
136
|
+
subprocess.run(["git", "-C", str(repo_root), "config", "user.name", "verifier"], check=True)
|
|
137
|
+
(repo_root / "module.py").write_text("answer = 1\n", encoding="utf-8")
|
|
138
|
+
subprocess.run(["git", "-C", str(repo_root), "add", "-A"], check=True)
|
|
139
|
+
subprocess.run(["git", "-C", str(repo_root), "commit", "-qm", "init"], check=True)
|
|
140
|
+
subprocess.run(["git", "-C", str(repo_root), "branch", "-f", "origin/main", "HEAD"], check=True)
|
|
141
|
+
(repo_root / "module.py").write_text("answer = 2\n", encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_clean_verifier_verdict_mints_a_verdict_file(tmp_path: pathlib.Path) -> None:
|
|
145
|
+
repo_root = tmp_path / "repo"
|
|
146
|
+
repo_root.mkdir()
|
|
147
|
+
_init_repo_with_upstream_and_edit(repo_root)
|
|
148
|
+
agent_transcript = tmp_path / "agent-7.jsonl"
|
|
149
|
+
agent_transcript.write_text(
|
|
150
|
+
json.dumps(
|
|
151
|
+
{
|
|
152
|
+
"type": "assistant",
|
|
153
|
+
"message": {
|
|
154
|
+
"content": [
|
|
155
|
+
{
|
|
156
|
+
"type": "text",
|
|
157
|
+
"text": 'ok\n```verdict\n{"all_pass": true, "findings": []}\n```\n',
|
|
158
|
+
}
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
+ "\n",
|
|
164
|
+
encoding="utf-8",
|
|
165
|
+
)
|
|
166
|
+
_write_sidecar(agent_transcript, MINTING_AGENT_TYPE)
|
|
167
|
+
payload = {
|
|
168
|
+
"agent_transcript_path": str(agent_transcript),
|
|
169
|
+
"cwd": str(repo_root),
|
|
170
|
+
"agent_id": "a02b9583eedc74093",
|
|
171
|
+
}
|
|
172
|
+
verdict_path = mint_for_payload(payload)
|
|
173
|
+
try:
|
|
174
|
+
assert verdict_path is not None
|
|
175
|
+
verdict_record = json.loads(verdict_path.read_text(encoding="utf-8"))
|
|
176
|
+
assert verdict_record["all_pass"] is True
|
|
177
|
+
assert verdict_record["minted_from_agent_id"] == "a02b9583eedc74093"
|
|
178
|
+
finally:
|
|
179
|
+
if verdict_path is not None and verdict_path.exists():
|
|
180
|
+
verdict_path.unlink()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _deny_rules() -> list[str]:
|
|
184
|
+
settings_record = json.loads(_SETTINGS_PATH.read_text(encoding="utf-8"))
|
|
185
|
+
return settings_record["permissions"]["deny"]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_settings_deny_verdict_directory_write() -> None:
|
|
189
|
+
assert "Write($HOME/.claude/verification/**)" in _deny_rules()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_settings_deny_verdict_directory_edit() -> None:
|
|
193
|
+
assert "Edit($HOME/.claude/verification/**)" in _deny_rules()
|