claude-dev-env 1.65.0 → 1.66.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/agents/plan-packet-validator.md +34 -0
- package/audit-rubrics/category_rubrics/category-n-test-name-scenario-verifier.md +6 -0
- package/commands/plan.md +6 -52
- package/hooks/blocking/code_rules_dead_module_constant.py +111 -24
- package/hooks/blocking/code_rules_enforcer.py +2 -0
- package/hooks/blocking/code_rules_test_assertions.py +123 -1
- package/hooks/blocking/open_questions_in_plans_blocker.py +8 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_module_constant.py +88 -0
- package/hooks/blocking/test_code_rules_enforcer_split_test_assertions.py +90 -0
- package/hooks/blocking/test_open_questions_in_plans_blocker.py +43 -0
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/dead_module_constant_constants.py +1 -0
- package/hooks/hooks_constants/open_questions_in_plans_blocker_constants.py +4 -0
- package/hooks/hooks_constants/test_open_questions_in_plans_blocker_constants.py +13 -1
- package/package.json +1 -1
- package/skills/anthropic-plan/SKILL.md +46 -85
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/__init__.py +0 -0
- package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/validate_packet_constants.py +33 -0
- package/skills/anthropic-plan/scripts/test_validate_packet.py +405 -0
- package/skills/anthropic-plan/scripts/validate_packet.py +397 -0
- package/skills/anthropic-plan/templates/README.md +20 -0
- package/skills/anthropic-plan/templates/build-prompt.md +9 -0
- package/skills/anthropic-plan/templates/source-map.md +5 -0
- package/skills/anthropic-plan/test_skill_contract.py +53 -0
- package/skills/anthropic-plan/workflow/plan-packet.contract.test.mjs +79 -0
- package/skills/anthropic-plan/workflow/plan-packet.mjs +299 -0
- package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +8 -1
- package/skills/autoconverge/workflow/converge.mjs +9 -1
|
@@ -6,6 +6,8 @@ import sys
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from types import SimpleNamespace
|
|
8
8
|
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
9
11
|
_BLOCKING_DIRECTORY = str(Path(__file__).resolve().parent)
|
|
10
12
|
_HOOKS_DIRECTORY = str(Path(__file__).resolve().parent.parent)
|
|
11
13
|
if _BLOCKING_DIRECTORY not in sys.path:
|
|
@@ -15,14 +17,34 @@ if _HOOKS_DIRECTORY not in sys.path:
|
|
|
15
17
|
|
|
16
18
|
from code_rules_test_assertions import ( # noqa: E402
|
|
17
19
|
check_constant_equality_tests,
|
|
20
|
+
check_flag_gated_scenario_test_naming,
|
|
18
21
|
)
|
|
19
22
|
|
|
20
23
|
code_rules_enforcer = SimpleNamespace(
|
|
21
24
|
check_constant_equality_tests=check_constant_equality_tests,
|
|
25
|
+
check_flag_gated_scenario_test_naming=check_flag_gated_scenario_test_naming,
|
|
22
26
|
)
|
|
23
27
|
|
|
24
28
|
|
|
25
29
|
CONSTANT_EQUALITY_TEST_FILE_PATH = "packages/app/tests/test_constants.py"
|
|
30
|
+
SCENARIO_TEST_FILE_PATH = "packages/app/tests/test_submission_runner_loop.py"
|
|
31
|
+
|
|
32
|
+
_THREE_SIBLINGS_PATCH_THE_FLAG_ONE_SCENARIO_TEST_DOES_NOT = (
|
|
33
|
+
"def test_should_submit_when_gate_passes(monkeypatch) -> None:\n"
|
|
34
|
+
" assert run() == 'submitted'\n"
|
|
35
|
+
"\n"
|
|
36
|
+
"def test_should_fail_when_reader_raises(monkeypatch) -> None:\n"
|
|
37
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
38
|
+
" assert run() == 'failed'\n"
|
|
39
|
+
"\n"
|
|
40
|
+
"def test_should_soft_skip_when_mismatch(monkeypatch) -> None:\n"
|
|
41
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
42
|
+
" assert run() == 'skipped'\n"
|
|
43
|
+
"\n"
|
|
44
|
+
"def test_should_hard_stop_when_unhealthy(monkeypatch) -> None:\n"
|
|
45
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
46
|
+
" assert run() == 'hard_stop'\n"
|
|
47
|
+
)
|
|
26
48
|
|
|
27
49
|
|
|
28
50
|
def test_should_not_flag_two_named_constants_compared_to_each_other() -> None:
|
|
@@ -54,3 +76,71 @@ def test_should_flag_named_constant_compared_to_literal() -> None:
|
|
|
54
76
|
assert any("constant-value test" in issue for issue in issues), (
|
|
55
77
|
f"Expected flag when UPPER_SNAKE compared to literal, got: {issues}"
|
|
56
78
|
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_should_advise_when_scenario_test_omits_flag_its_siblings_patch(
|
|
82
|
+
capsys: pytest.CaptureFixture[str],
|
|
83
|
+
) -> None:
|
|
84
|
+
issues = code_rules_enforcer.check_flag_gated_scenario_test_naming(
|
|
85
|
+
_THREE_SIBLINGS_PATCH_THE_FLAG_ONE_SCENARIO_TEST_DOES_NOT,
|
|
86
|
+
SCENARIO_TEST_FILE_PATH,
|
|
87
|
+
)
|
|
88
|
+
advisory_text = capsys.readouterr().err
|
|
89
|
+
assert issues == [], "Advisory check must never add a blocking issue"
|
|
90
|
+
assert "test_should_submit_when_gate_passes" in advisory_text, (
|
|
91
|
+
f"Expected an advisory naming the un-patched scenario test, got: {advisory_text!r}"
|
|
92
|
+
)
|
|
93
|
+
assert "IS_STAGED_VERIFICATION_ENABLED" in advisory_text, (
|
|
94
|
+
f"Expected the advisory to name the established flag, got: {advisory_text!r}"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_should_stay_silent_when_scenario_test_patches_the_flag(
|
|
99
|
+
capsys: pytest.CaptureFixture[str],
|
|
100
|
+
) -> None:
|
|
101
|
+
source = (
|
|
102
|
+
"def test_should_submit_when_gate_passes(monkeypatch) -> None:\n"
|
|
103
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
104
|
+
" assert run() == 'submitted'\n"
|
|
105
|
+
"\n"
|
|
106
|
+
"def test_should_fail_when_reader_raises(monkeypatch) -> None:\n"
|
|
107
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
108
|
+
" assert run() == 'failed'\n"
|
|
109
|
+
)
|
|
110
|
+
issues = code_rules_enforcer.check_flag_gated_scenario_test_naming(
|
|
111
|
+
source, SCENARIO_TEST_FILE_PATH
|
|
112
|
+
)
|
|
113
|
+
advisory_text = capsys.readouterr().err
|
|
114
|
+
assert issues == []
|
|
115
|
+
assert advisory_text == "", (
|
|
116
|
+
f"Expected silence when the scenario test patches the flag, got: {advisory_text!r}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def test_should_stay_silent_when_only_one_sibling_patches_the_flag(
|
|
121
|
+
capsys: pytest.CaptureFixture[str],
|
|
122
|
+
) -> None:
|
|
123
|
+
source = (
|
|
124
|
+
"def test_should_submit_when_gate_passes(monkeypatch) -> None:\n"
|
|
125
|
+
" assert run() == 'submitted'\n"
|
|
126
|
+
"\n"
|
|
127
|
+
"def test_should_fail_when_reader_raises(monkeypatch) -> None:\n"
|
|
128
|
+
" monkeypatch.setattr('pkg.pipeline.IS_STAGED_VERIFICATION_ENABLED', True)\n"
|
|
129
|
+
" assert run() == 'failed'\n"
|
|
130
|
+
)
|
|
131
|
+
issues = code_rules_enforcer.check_flag_gated_scenario_test_naming(
|
|
132
|
+
source, SCENARIO_TEST_FILE_PATH
|
|
133
|
+
)
|
|
134
|
+
advisory_text = capsys.readouterr().err
|
|
135
|
+
assert issues == []
|
|
136
|
+
assert advisory_text == "", (
|
|
137
|
+
f"One sibling patch is not an established flag; expected silence, got: {advisory_text!r}"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_should_not_advise_for_production_file() -> None:
|
|
142
|
+
issues = code_rules_enforcer.check_flag_gated_scenario_test_naming(
|
|
143
|
+
_THREE_SIBLINGS_PATCH_THE_FLAG_ONE_SCENARIO_TEST_DOES_NOT,
|
|
144
|
+
"packages/app/services/submission_pipeline.py",
|
|
145
|
+
)
|
|
146
|
+
assert issues == []
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Tests for open_questions_in_plans_blocker hook."""
|
|
2
2
|
|
|
3
|
+
import ast
|
|
3
4
|
import json
|
|
4
5
|
import os
|
|
5
6
|
import subprocess
|
|
@@ -10,6 +11,13 @@ HOOK_SCRIPT_PATH = os.path.join(
|
|
|
10
11
|
os.path.dirname(__file__), "open_questions_in_plans_blocker.py"
|
|
11
12
|
)
|
|
12
13
|
|
|
14
|
+
|
|
15
|
+
def _read_hook_module_docstring() -> str:
|
|
16
|
+
source_text = open(HOOK_SCRIPT_PATH, encoding="utf-8").read()
|
|
17
|
+
module_docstring = ast.get_docstring(ast.parse(source_text))
|
|
18
|
+
assert module_docstring is not None
|
|
19
|
+
return module_docstring
|
|
20
|
+
|
|
13
21
|
_plan_with_open_questions = (
|
|
14
22
|
"## Context\nA plan.\n\n## Open Questions\n- Which auth provider?\n"
|
|
15
23
|
)
|
|
@@ -75,6 +83,41 @@ def test_blocks_project_local_plans_directory():
|
|
|
75
83
|
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
76
84
|
|
|
77
85
|
|
|
86
|
+
def test_module_docstring_names_docs_plans_directory_family():
|
|
87
|
+
"""The docstring enumerates every directory family the detector fires on,
|
|
88
|
+
including the repo-local `docs/plans/` family it now blocks."""
|
|
89
|
+
module_docstring = _read_hook_module_docstring()
|
|
90
|
+
|
|
91
|
+
assert "docs/plans/" in module_docstring
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_blocks_repo_docs_plan_packet_directory():
|
|
95
|
+
"""Repo-local `docs/plans/<slug>/` packet docs are plan files too."""
|
|
96
|
+
result = _run_hook(
|
|
97
|
+
"Write",
|
|
98
|
+
{
|
|
99
|
+
"file_path": "docs/plans/add-login/spec/scope.md",
|
|
100
|
+
"content": _plan_with_open_questions,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
assert result.returncode == 0
|
|
104
|
+
output = json.loads(result.stdout)
|
|
105
|
+
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def test_blocks_windows_style_repo_docs_plan_packet_directory():
|
|
109
|
+
result = _run_hook(
|
|
110
|
+
"Write",
|
|
111
|
+
{
|
|
112
|
+
"file_path": "docs\\plans\\add-login\\spec\\scope.md",
|
|
113
|
+
"content": _plan_with_open_questions,
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
assert result.returncode == 0
|
|
117
|
+
output = json.loads(result.stdout)
|
|
118
|
+
assert output["hookSpecificOutput"]["permissionDecision"] == "deny"
|
|
119
|
+
|
|
120
|
+
|
|
78
121
|
def test_blocks_case_insensitive_heading():
|
|
79
122
|
result = _run_hook(
|
|
80
123
|
"Write",
|
|
@@ -10,6 +10,7 @@ DUNDER_INIT_FILENAME: str = "__init__.py"
|
|
|
10
10
|
CONSTANTS_MODULE_SUFFIX: str = "_constants.py"
|
|
11
11
|
CONFIG_DIRECTORY_SEGMENT: str = "config"
|
|
12
12
|
DUNDER_ALL_NAME: str = "__all__"
|
|
13
|
+
GIT_DIRECTORY_NAME: str = ".git"
|
|
13
14
|
MINIMUM_UPPER_SNAKE_LENGTH: int = 2
|
|
14
15
|
MAX_DEAD_MODULE_CONSTANT_ISSUES: int = 25
|
|
15
16
|
MAX_SCAN_ROOT_FILE_COUNT: int = 2000
|
|
@@ -9,6 +9,8 @@ MARKDOWN_EXTENSION: str = ".md"
|
|
|
9
9
|
|
|
10
10
|
PLANS_PATH_SEGMENT: str = "/.claude/plans/"
|
|
11
11
|
PLANS_PATH_PREFIX: str = ".claude/plans/"
|
|
12
|
+
DOCS_PLANS_PATH_SEGMENT: str = "/docs/plans/"
|
|
13
|
+
DOCS_PLANS_PATH_PREFIX: str = "docs/plans/"
|
|
12
14
|
|
|
13
15
|
PLAN_FILE_ENCODING: str = "utf-8"
|
|
14
16
|
|
|
@@ -25,6 +27,8 @@ INLINE_CODE_PATTERN: Pattern[str] = compile(r"``[^`\n]+``|`[^`\n]+`")
|
|
|
25
27
|
|
|
26
28
|
__all__ = [
|
|
27
29
|
"CODE_FENCE_PATTERN",
|
|
30
|
+
"DOCS_PLANS_PATH_PREFIX",
|
|
31
|
+
"DOCS_PLANS_PATH_SEGMENT",
|
|
28
32
|
"INLINE_CODE_PATTERN",
|
|
29
33
|
"MARKDOWN_EXTENSION",
|
|
30
34
|
"OPEN_QUESTIONS_HEADING_PATTERN",
|
|
@@ -27,6 +27,16 @@ def test_plans_path_prefix_matches_project_local_plans_directory() -> None:
|
|
|
27
27
|
assert "PLANS_PATH_PREFIX" in constants_module.__all__
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
def test_docs_plans_path_segment_matches_repo_packet_directory() -> None:
|
|
31
|
+
assert constants_module.DOCS_PLANS_PATH_SEGMENT == "/docs/plans/"
|
|
32
|
+
assert "DOCS_PLANS_PATH_SEGMENT" in constants_module.__all__
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_docs_plans_path_prefix_matches_repo_packet_directory() -> None:
|
|
36
|
+
assert constants_module.DOCS_PLANS_PATH_PREFIX == "docs/plans/"
|
|
37
|
+
assert "DOCS_PLANS_PATH_PREFIX" in constants_module.__all__
|
|
38
|
+
|
|
39
|
+
|
|
30
40
|
def test_open_questions_heading_pattern_matches_atx_heading() -> None:
|
|
31
41
|
assert constants_module.OPEN_QUESTIONS_HEADING_PATTERN.search("## Open Questions\n")
|
|
32
42
|
|
|
@@ -111,9 +121,11 @@ def test_unreadable_file_synthetic_content_triggers_heading_pattern() -> None:
|
|
|
111
121
|
assert "UNREADABLE_FILE_SYNTHETIC_CONTENT" in constants_module.__all__
|
|
112
122
|
|
|
113
123
|
|
|
114
|
-
def
|
|
124
|
+
def test_all_exports_enumerates_ten_public_constants_in_sorted_order() -> None:
|
|
115
125
|
expected_exports = [
|
|
116
126
|
"CODE_FENCE_PATTERN",
|
|
127
|
+
"DOCS_PLANS_PATH_PREFIX",
|
|
128
|
+
"DOCS_PLANS_PATH_SEGMENT",
|
|
117
129
|
"INLINE_CODE_PATTERN",
|
|
118
130
|
"MARKDOWN_EXTENSION",
|
|
119
131
|
"OPEN_QUESTIONS_HEADING_PATTERN",
|
package/package.json
CHANGED
|
@@ -1,107 +1,68 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: anthropic-plan
|
|
3
|
-
description:
|
|
3
|
+
description: Workflow-backed implementation planning that creates a deep repo-local packet under docs/plans/<slug>/ before any code changes. Use for /anthropic-plan, /plan, "plan this first", "think before coding", "make a plan", "scope this out", "don't code yet", and non-trivial implementation requests that need source-grounded design, TDD steps, and validator approval before build work.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Anthropic Plan
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Create a source-grounded plan packet through the Claude Code Workflow runtime. The output is a repo-local `docs/plans/<slug>/` folder with context, spec, implementation, validation, and handoff docs. Stop before implementation.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Launch
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Call the workflow with the user request and current working directory:
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Plan File
|
|
25
|
-
|
|
26
|
-
Write to `~/.claude/plans/<slug>.md`.
|
|
27
|
-
|
|
28
|
-
Generate the slug from the task -- descriptive, kebab-case, 2-4 words. Examples: `add-user-auth.md`, `fix-payment-retry.md`, `refactor-config-loading.md`. Avoid the random-word convention used by built-in plan mode.
|
|
29
|
-
|
|
30
|
-
**Announce at start:** "Planning: `<slug>` -- exploring before writing code."
|
|
31
|
-
|
|
32
|
-
## Workflow
|
|
33
|
-
|
|
34
|
-
### Phase 1: Explore
|
|
35
|
-
|
|
36
|
-
Understand the problem space before proposing solutions. Launch Explore agents in parallel -- up to 3, but use the minimum needed. Quality over quantity.
|
|
37
|
-
|
|
38
|
-
What to look for:
|
|
39
|
-
- Files and modules the task will touch
|
|
40
|
-
- Existing patterns for similar functionality
|
|
41
|
-
- Utilities, helpers, constants, and shared code to reuse
|
|
42
|
-
- Test patterns already in place
|
|
43
|
-
|
|
44
|
-
Skip this phase only if the task is trivial and full context already exists in the conversation.
|
|
45
|
-
|
|
46
|
-
### Phase 2: Design
|
|
47
|
-
|
|
48
|
-
Launch Plan agent(s) to design the implementation -- up to 3 for complex or multi-area tasks, skip entirely for trivial tasks. Feed them comprehensive context from Phase 1; they cannot explore on their own, so everything they need must come from you.
|
|
49
|
-
|
|
50
|
-
### Phase 3: Review
|
|
51
|
-
|
|
52
|
-
Before committing to the plan:
|
|
53
|
-
- Read the critical files yourself to verify the agents got it right
|
|
54
|
-
- Check alignment with what the user actually asked for
|
|
55
|
-
- If requirements are ambiguous, use AskUserQuestion now -- not after writing the plan
|
|
56
|
-
|
|
57
|
-
### Phase 4: Write the Plan
|
|
14
|
+
```js
|
|
15
|
+
Workflow({
|
|
16
|
+
scriptPath: "$HOME/.claude/skills/anthropic-plan/workflow/plan-packet.mjs",
|
|
17
|
+
input: {
|
|
18
|
+
task: "$ARGUMENTS",
|
|
19
|
+
cwd: "<current working directory>"
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
```
|
|
58
23
|
|
|
59
|
-
|
|
24
|
+
If the Workflow tool is unavailable, say `anthropic-plan requires the Workflow tool; aborting` and stop.
|
|
60
25
|
|
|
61
|
-
|
|
62
|
-
## Context
|
|
63
|
-
Why this change is needed, what problem it solves, what the outcome looks like.
|
|
26
|
+
## Workflow Contract
|
|
64
27
|
|
|
65
|
-
|
|
66
|
-
The recommended implementation. One approach, not a menu of alternatives.
|
|
67
|
-
Concise but detailed enough to execute without re-exploring.
|
|
28
|
+
The workflow handles the full planning loop:
|
|
68
29
|
|
|
69
|
-
|
|
70
|
-
|
|
30
|
+
1. Resolve repo root and packet path.
|
|
31
|
+
2. Read project instructions, rules, relevant skills, manifests, docs, tests, hooks, agents, commands, configs, and workflows.
|
|
32
|
+
3. Build a source inventory and extract source facts into `context/source-map.md`.
|
|
33
|
+
4. Write the packet under `docs/plans/<slug>/`.
|
|
34
|
+
5. Run `scripts/validate_packet.py`.
|
|
35
|
+
6. Spawn `plan-packet-validator` in fresh context.
|
|
36
|
+
7. Repair packet findings up to the workflow cap.
|
|
37
|
+
8. Return packet path, validation state, and findings.
|
|
38
|
+
9. Stop before implementation.
|
|
71
39
|
|
|
72
|
-
##
|
|
73
|
-
Existing functions, utilities, constants, or patterns to leverage.
|
|
74
|
-
Include file:line references so the implementer can find them instantly.
|
|
40
|
+
## Packet Shape
|
|
75
41
|
|
|
76
|
-
|
|
77
|
-
Ordered implementation steps. Each step is a discrete, testable unit of work.
|
|
42
|
+
Required root: `docs/plans/<slug>/`
|
|
78
43
|
|
|
79
|
-
|
|
80
|
-
How to confirm end-to-end that the implementation works.
|
|
81
|
-
Specific commands, test files, or manual verification steps.
|
|
44
|
+
Required top-level files and folders:
|
|
82
45
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
88
|
-
|
|
89
|
-
|
|
46
|
+
- `README.md`
|
|
47
|
+
- `packet.json`
|
|
48
|
+
- `context/`
|
|
49
|
+
- `spec/`
|
|
50
|
+
- `implementation/`
|
|
51
|
+
- `validation/`
|
|
52
|
+
- `handoff/`
|
|
90
53
|
|
|
91
|
-
|
|
54
|
+
The packet depth rule is strict: `README.md` is a thin hub, first-level folders group purpose, and second-level files carry detail. Add `context/subsystems/<name>.md` only when the planner finds more than twelve source files or more than three subsystems.
|
|
92
55
|
|
|
93
|
-
|
|
56
|
+
## Validation
|
|
94
57
|
|
|
95
|
-
|
|
96
|
-
- **Approve** -- proceed with implementation
|
|
97
|
-
- **Revise** -- user has feedback to incorporate
|
|
98
|
-
- **Cancel** -- abandon the plan
|
|
58
|
+
The deterministic validator checks required files, placeholders, `Open Questions`, source-map strength, TDD coverage, standalone handoff prompts, and `packet.json` consistency.
|
|
99
59
|
|
|
100
|
-
|
|
60
|
+
The `plan-packet-validator` agent checks source accuracy, scope, enough implementation detail for a blind build agent, real TDD order, invented APIs or commands, and end-to-end acceptance criteria.
|
|
101
61
|
|
|
102
|
-
|
|
62
|
+
## Rules
|
|
103
63
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
-
|
|
64
|
+
- Write docs only.
|
|
65
|
+
- Do not edit production code.
|
|
66
|
+
- Do not run implementation commands.
|
|
67
|
+
- Ask the user only for product choices that cannot be derived from local context.
|
|
68
|
+
- Fold resolved answers into the packet. Never leave an `Open Questions` section.
|
|
File without changes
|
package/skills/anthropic-plan/scripts/anthropic_plan_scripts_constants/validate_packet_constants.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Constants for the plan packet validator."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
ALL_REQUIRED_RELATIVE_PATHS: tuple[str, ...] = (
|
|
6
|
+
"README.md",
|
|
7
|
+
"packet.json",
|
|
8
|
+
"context/user-request.md",
|
|
9
|
+
"context/source-map.md",
|
|
10
|
+
"context/current-state.md",
|
|
11
|
+
"context/existing-patterns.md",
|
|
12
|
+
"context/constraints.md",
|
|
13
|
+
"context/glossary.md",
|
|
14
|
+
"spec/scope.md",
|
|
15
|
+
"spec/behavior.md",
|
|
16
|
+
"spec/interfaces.md",
|
|
17
|
+
"spec/data-flow.md",
|
|
18
|
+
"spec/failure-modes.md",
|
|
19
|
+
"spec/acceptance.md",
|
|
20
|
+
"implementation/strategy.md",
|
|
21
|
+
"implementation/steps.md",
|
|
22
|
+
"implementation/tdd-plan.md",
|
|
23
|
+
"implementation/file-plan.md",
|
|
24
|
+
"implementation/refactor-checkpoints.md",
|
|
25
|
+
"validation/validator-report.md",
|
|
26
|
+
"validation/deterministic-checks.md",
|
|
27
|
+
"validation/unresolved-risks.md",
|
|
28
|
+
"handoff/build-prompt.md",
|
|
29
|
+
"handoff/review-prompt.md",
|
|
30
|
+
"handoff/verification-commands.md",
|
|
31
|
+
)
|
|
32
|
+
MARKDOWN_FILE_SUFFIX: str = ".md"
|
|
33
|
+
EXIT_CODE_VALIDATION_FAILED: int = 2
|