Skip to content

Commit c945654

Browse files
web-flowclaude
andcommitted
chore(consideratecoder): ruff/mypy を配線し診断を 0 にする、ruff format を適用
方法論を配る側が自分の検証コードを検めていないのは筋が通らない。本プラグインの 実体は skills/ と commands/ の Markdown で、Python は tests/ の 4 本だけだが、 それらは「方法論どおりに書いた実装例が実際に通るか」を検める検証コードである。 pyproject.toml を新設(`[project]` / `[build-system]` は置かない——配布物ではなく 設定を読む場所として要るだけ)。規約は和集合: select 10 集合 + mypy strict。 - lint 2 件: E741(`l` → `line`) - mypy strict 57 → 0: 35 件は `-> None` の付与(AST 判定で機械的に)、 `_split_frontmatter` / `_outsource_phase{4,5}_region` の 4 本を型付けすると no-untyped-call 17 件が連鎖で消えた - **`union-attr` 1 件は実バグ手前だった** —— `re.search(...).group(1)` は search が None を返すと AttributeError になる。match を束ねて assert を挟み、 「tools: 行が在ること」というテストの意図をコードに書いた - ruff format 4 files 検証: ruff All checks passed / mypy Success (4 source files) / pytest 35 passed Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 35ed241 commit c945654

5 files changed

Lines changed: 81 additions & 66 deletions

File tree

ConsiderateCoder/pyproject.toml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# ConsiderateCoder の開発ツール設定。
2+
#
3+
# `[project]` / `[build-system]` は意図的に置かない —— 本プラグインの実体は
4+
# skills/ と commands/ の Markdown(開発方法論)で、Python は tests/ の 4 本だけ。
5+
# それらは「方法論どおりに書いた実装例が実際に通るか」を検める検証コードであり、
6+
# 配布物ではない。ここが要るのは ruff / mypy / pytest が設定を読む場所としてだけ。
7+
#
8+
# 規約はワークスペースの和集合(2026-08-25 確定): ruff の select は広く取り、
9+
# mypy は strict。方法論を配る側が自分の検証コードを検めていないのは筋が通らない。
10+
11+
[tool.ruff]
12+
src = ["tests"]
13+
14+
[tool.ruff.lint]
15+
# ruff の default 選択は版が上がるたび広がるので明示固定する。集合は
16+
# BlueberrySprite / NewsCaster / GeneralConstructor / ContextPreloader と同一の 10 個。
17+
select = ["E4", "E7", "E9", "F", "I", "UP", "N", "B", "SIM", "PTH"]
18+
19+
[tool.mypy]
20+
strict = true
21+
22+
[tool.pytest.ini_options]
23+
testpaths = ["tests"]

ConsiderateCoder/tests/test_stage1_domain.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
generalized (no workspace-specific tokens leaked from the source copy).
55
Stdlib only: json / re / pathlib. No external dependencies, no conftest.
66
"""
7+
78
import json
89
import re
910
from pathlib import Path
@@ -20,7 +21,7 @@
2021
]
2122

2223

23-
def test_plugin_manifest():
24+
def test_plugin_manifest() -> None:
2425
manifest_path = PLUGIN_ROOT / ".claude-plugin" / "plugin.json"
2526
assert manifest_path.exists(), f"missing {manifest_path}"
2627

@@ -43,7 +44,7 @@ def test_plugin_manifest():
4344
)
4445

4546

46-
def test_rule_skills_exist_and_generic():
47+
def test_rule_skills_exist_and_generic() -> None:
4748
"""Both rule skills exist with skill frontmatter (name/description) and
4849
carry no workspace-specific tokens."""
4950
for path in RULE_SKILLS:
@@ -58,7 +59,7 @@ def test_rule_skills_exist_and_generic():
5859
assert token not in text, f"{path.name} contains forbidden token: {token!r}"
5960

6061

61-
def test_dev_rules_latest_and_self_contained():
62+
def test_dev_rules_latest_and_self_contained() -> None:
6263
"""dev-rules carries the CI static-check line (stale-copy regression
6364
check) and must be self-contained: subagents do not receive the full
6465
Claude Code system prompt, so the rules may not defer to it."""
@@ -76,7 +77,7 @@ def test_dev_rules_latest_and_self_contained():
7677
)
7778

7879

79-
def test_dev_rules_deletion_test_and_grounded_numbers():
80+
def test_dev_rules_deletion_test_and_grounded_numbers() -> None:
8081
"""dev-rules operationalizes YAGNI at both ends: the Deletion Test
8182
inspects finished work ("does the completion proof still hold without
8283
this?") with a non-negotiable floor (validation / error handling /
@@ -89,15 +90,15 @@ def test_dev_rules_deletion_test_and_grounded_numbers():
8990
assert token in text, f"dev-rules missing rule token: {token!r}"
9091

9192

92-
def test_dev_rules_solution_ladder_in_understand():
93+
def test_dev_rules_solution_ladder_in_understand() -> None:
9394
"""The solution-search ladder (don't write → reuse → stdlib → existing
9495
dependency → minimal new code) must sit inside the Understand step in
9596
close (same or <=3 line) proximity, so search-first reads as part of
9697
the flow rather than a detached slogan (same proximity pattern as the
9798
Stage 3 policy tests)."""
9899
lines = RULE_SKILLS[0].read_text(encoding="utf-8").splitlines()
99-
ladder_idxs = [i for i, l in enumerate(lines) if "標準ライブラリ" in l]
100-
understand_idxs = [i for i, l in enumerate(lines) if "Understand" in l]
100+
ladder_idxs = [i for i, line in enumerate(lines) if "標準ライブラリ" in line]
101+
understand_idxs = [i for i, line in enumerate(lines) if "Understand" in line]
101102
assert ladder_idxs, "dev-rules missing the solution ladder (標準ライブラリ step)"
102103
assert understand_idxs, "dev-rules missing the Understand step"
103104
assert any(abs(a - b) <= 3 for a in ladder_idxs for b in understand_idxs), (

ConsiderateCoder/tests/test_stage2_usecase.py

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
evidence references (dates, proof counts, local-environment paths).
66
Stdlib only: re / pathlib. No external dependencies, no conftest.
77
"""
8+
89
import re
910
from pathlib import Path
1011

@@ -26,15 +27,15 @@
2627
DATE_PATTERN = re.compile(r"20\d\d-\d\d")
2728

2829

29-
def _split_frontmatter(path):
30+
def _split_frontmatter(path: Path) -> tuple[str, str, str]:
3031
assert path.exists(), f"missing {path}"
3132
text = path.read_text(encoding="utf-8")
3233
m = FRONTMATTER_RE.match(text)
3334
assert m, f"{path.name}: frontmatter delimiters (---) not found"
3435
return m.group(1), m.group(2), text
3536

3637

37-
def test_agent_frontmatter():
38+
def test_agent_frontmatter() -> None:
3839
"""Both agents declare name/description/model; orchestrator's tools
3940
line excludes Edit/Write (structural guarantee: the commander cannot
4041
touch files directly). Word-boundary matching avoids false positives
@@ -59,7 +60,7 @@ def test_agent_frontmatter():
5960
)
6061

6162

62-
def test_orchestrator_references_namespaced_worker():
63+
def test_orchestrator_references_namespaced_worker() -> None:
6364
"""orchestrator body must delegate via the namespaced worker
6465
(ConsiderateCoder:worker); a bare `subagent_type: worker` would not
6566
resolve once the agent is installed as a plugin.
@@ -74,31 +75,29 @@ def test_orchestrator_references_namespaced_worker():
7475
)
7576

7677

77-
def test_structural_tool_guarantees():
78+
def test_structural_tool_guarantees() -> None:
7879
"""Structural guarantees on both sides of the delegation: the
7980
orchestrator cannot send async messages (no SendMessage — its own
8081
discipline bans round-trips), and the worker cannot re-delegate
8182
(Agent is disallowed). Discipline is culture; the tool list is law."""
8283
orchestrator_fm, _, _ = _split_frontmatter(ORCHESTRATOR_PATH)
83-
tools_line = re.search(
84-
r"^tools:\s*(.+)$", orchestrator_fm, re.MULTILINE
85-
).group(1)
84+
tools_match = re.search(r"^tools:\s*(.+)$", orchestrator_fm, re.MULTILINE)
85+
assert tools_match, "orchestrator frontmatter has no tools: line"
86+
tools_line = tools_match.group(1)
8687
assert not re.search(r"\bSendMessage\b", tools_line), (
8788
f"orchestrator tools must not include SendMessage: {tools_line!r}"
8889
)
8990

9091
worker_fm, _, _ = _split_frontmatter(WORKER_PATH)
91-
disallowed_match = re.search(
92-
r"^disallowedTools:\s*(.+)$", worker_fm, re.MULTILINE
93-
)
92+
disallowed_match = re.search(r"^disallowedTools:\s*(.+)$", worker_fm, re.MULTILINE)
9493
assert disallowed_match, "worker frontmatter missing disallowedTools line"
9594
assert re.search(r"\bAgent\b", disallowed_match.group(1)), (
9695
f"worker disallowedTools must include Agent (no re-delegation): "
9796
f"{disallowed_match.group(1)!r}"
9897
)
9998

10099

101-
def test_agents_preload_dev_rules():
100+
def test_agents_preload_dev_rules() -> None:
102101
"""Both agents preload dev-rules via the skills: frontmatter field —
103102
the official wiring that injects full rule content into a subagent's
104103
context at spawn (subagents don't receive the full Claude Code system
@@ -108,15 +107,14 @@ def test_agents_preload_dev_rules():
108107
skills_match = re.search(r"^skills:\s*(.+)$", frontmatter, re.MULTILINE)
109108
assert skills_match, f"{path.name} missing skills: preload line"
110109
assert "dev-rules" in skills_match.group(1), (
111-
f"{path.name} skills: must preload dev-rules: "
112-
f"{skills_match.group(1)!r}"
110+
f"{path.name} skills: must preload dev-rules: {skills_match.group(1)!r}"
113111
)
114112

115113

116114
STATUS_VOCAB = ("COMPLETED", "PARTIAL", "BLOCKED", "RETURNED")
117115

118116

119-
def test_completion_status_vocabulary_symmetric():
117+
def test_completion_status_vocabulary_symmetric() -> None:
120118
"""The worker report opens with a one-word completion status, and a stop
121119
(3-Strike STOP / interruption / unverified work) is never written as
122120
COMPLETED; the orchestrator briefs and reviews with the same four-state
@@ -133,17 +131,15 @@ def test_completion_status_vocabulary_symmetric():
133131
)
134132

135133

136-
def test_worker_reports_discovered_issues():
134+
def test_worker_reports_discovered_issues() -> None:
137135
"""Out-of-scope problems the worker notices must reach the report:
138136
staying hands-off is required, staying silent is forbidden (discovering
139137
an issue and not reporting it reads as a clean pass to the reviewer)."""
140138
_, body, _ = _split_frontmatter(WORKER_PATH)
141-
assert "黙過" in body, (
142-
"worker.md missing the no-silent-discovery rule (黙過)"
143-
)
139+
assert "黙過" in body, "worker.md missing the no-silent-discovery rule (黙過)"
144140

145141

146-
def test_no_dev_evidence_refs():
142+
def test_no_dev_evidence_refs() -> None:
147143
"""Neither agent may carry development-session evidence: dates,
148144
proof-count callouts, local model assumptions, or local paths.
149145
"""

0 commit comments

Comments
 (0)