agentready 2.46.2__tar.gz → 2.47.0__tar.gz

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 (122) hide show
  1. {agentready-2.46.2/src/agentready.egg-info → agentready-2.47.0}/PKG-INFO +1 -1
  2. {agentready-2.46.2 → agentready-2.47.0}/pyproject.toml +1 -1
  3. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/code_quality.py +107 -7
  4. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/structure.py +101 -1
  5. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/testing.py +9 -2
  6. {agentready-2.46.2 → agentready-2.47.0/src/agentready.egg-info}/PKG-INFO +1 -1
  7. {agentready-2.46.2 → agentready-2.47.0}/LICENSE +0 -0
  8. {agentready-2.46.2 → agentready-2.47.0}/README.md +0 -0
  9. {agentready-2.46.2 → agentready-2.47.0}/setup.cfg +0 -0
  10. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/__init__.py +0 -0
  11. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/__main__.py +0 -0
  12. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/__init__.py +0 -0
  13. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/base.py +0 -0
  14. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/containers.py +0 -0
  15. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/dbt.py +0 -0
  16. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/documentation.py +0 -0
  17. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/patterns.py +0 -0
  18. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/security.py +0 -0
  19. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/stub_assessors.py +0 -0
  20. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/assessors/verification.py +0 -0
  21. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/__init__.py +0 -0
  22. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/align.py +0 -0
  23. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/assess_batch.py +0 -0
  24. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/bootstrap.py +0 -0
  25. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/demo.py +0 -0
  26. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/experiment.py +0 -0
  27. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/main.py +0 -0
  28. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/main_simplified.py +0 -0
  29. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/repomix.py +0 -0
  30. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/research.py +0 -0
  31. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/schema.py +0 -0
  32. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/cli/submit.py +0 -0
  33. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/data/.agentready-config.example.yaml +0 -0
  34. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/data/Python.arsrc +0 -0
  35. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/data/RESEARCH_REPORT.md +0 -0
  36. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/data/default-weights.yaml +0 -0
  37. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/fixers/__init__.py +0 -0
  38. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/fixers/base.py +0 -0
  39. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/fixers/documentation.py +0 -0
  40. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/fixers/testing.py +0 -0
  41. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/github/__init__.py +0 -0
  42. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/github/review_formatter.py +0 -0
  43. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/__init__.py +0 -0
  44. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/assessment.py +0 -0
  45. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/attribute.py +0 -0
  46. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/batch_assessment.py +0 -0
  47. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/citation.py +0 -0
  48. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/config.py +0 -0
  49. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/discovered_skill.py +0 -0
  50. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/eval_harness.py +0 -0
  51. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/finding.py +0 -0
  52. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/fix.py +0 -0
  53. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/metadata.py +0 -0
  54. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/repository.py +0 -0
  55. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/models/theme.py +0 -0
  56. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/prompts/__init__.py +0 -0
  57. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/prompts/claude_md_generator.md +0 -0
  58. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/prompts/loader.py +0 -0
  59. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/__init__.py +0 -0
  60. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/aggregated_json.py +0 -0
  61. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/base.py +0 -0
  62. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/csv_reporter.py +0 -0
  63. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/html.py +0 -0
  64. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/json_reporter.py +0 -0
  65. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/markdown.py +0 -0
  66. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/reporters/multi_html.py +0 -0
  67. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/__init__.py +0 -0
  68. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/assessment_cache.py +0 -0
  69. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/attribute_analyzer.py +0 -0
  70. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/batch_scanner.py +0 -0
  71. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/bootstrap.py +0 -0
  72. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/claudecode_runner.py +0 -0
  73. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/experiment_comparer.py +0 -0
  74. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/fixer_service.py +0 -0
  75. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/github_scanner.py +0 -0
  76. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/language_detector.py +0 -0
  77. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/llm_cache.py +0 -0
  78. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/repomix.py +0 -0
  79. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/repository_manager.py +0 -0
  80. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/research_formatter.py +0 -0
  81. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/research_loader.py +0 -0
  82. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/scanner.py +0 -0
  83. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/schema_migrator.py +0 -0
  84. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/schema_validator.py +0 -0
  85. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/scorer.py +0 -0
  86. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/sweagent_runner.py +0 -0
  87. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/services/swebench_evaluator.py +0 -0
  88. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/align/CLAUDE.md.j2 +0 -0
  89. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/CODEOWNERS.j2 +0 -0
  90. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/CODE_OF_CONDUCT.md.j2 +0 -0
  91. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/CONTRIBUTING.md.j2 +0 -0
  92. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/PULL_REQUEST_TEMPLATE.md.j2 +0 -0
  93. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/_base/precommit.yaml.j2 +0 -0
  94. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/_base/workflows/security.yml.j2 +0 -0
  95. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/_base/workflows/tests.yml.j2 +0 -0
  96. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/dependabot.yml.j2 +0 -0
  97. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/go/precommit.yaml.j2 +0 -0
  98. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/go/workflows/security.yml.j2 +0 -0
  99. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/go/workflows/tests.yml.j2 +0 -0
  100. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/issue_templates/bug_report.md.j2 +0 -0
  101. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/issue_templates/feature_request.md.j2 +0 -0
  102. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/javascript/precommit.yaml.j2 +0 -0
  103. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/javascript/workflows/security.yml.j2 +0 -0
  104. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/javascript/workflows/tests.yml.j2 +0 -0
  105. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/python/precommit.yaml.j2 +0 -0
  106. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/python/workflows/security.yml.j2 +0 -0
  107. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/python/workflows/tests.yml.j2 +0 -0
  108. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/workflows/agentready-assessment.yml.j2 +0 -0
  109. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/bootstrap/workflows/repomix-update.yml.j2 +0 -0
  110. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/multi_report.html.j2 +0 -0
  111. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/report.html.j2 +0 -0
  112. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/templates/slides.html.j2 +0 -0
  113. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/utils/__init__.py +0 -0
  114. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/utils/privacy.py +0 -0
  115. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/utils/security.py +0 -0
  116. {agentready-2.46.2 → agentready-2.47.0}/src/agentready/utils/subprocess_utils.py +0 -0
  117. {agentready-2.46.2 → agentready-2.47.0}/src/agentready.egg-info/SOURCES.txt +0 -0
  118. {agentready-2.46.2 → agentready-2.47.0}/src/agentready.egg-info/dependency_links.txt +0 -0
  119. {agentready-2.46.2 → agentready-2.47.0}/src/agentready.egg-info/entry_points.txt +0 -0
  120. {agentready-2.46.2 → agentready-2.47.0}/src/agentready.egg-info/requires.txt +0 -0
  121. {agentready-2.46.2 → agentready-2.47.0}/src/agentready.egg-info/top_level.txt +0 -0
  122. {agentready-2.46.2 → agentready-2.47.0}/tests/test_demo_generation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentready
3
- Version: 2.46.2
3
+ Version: 2.47.0
4
4
  Summary: Assess and bootstrap git repositories for AI-assisted development with automated remediation
5
5
  Author-email: Jeremy Eder <jeder@redhat.com>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agentready"
3
- version = "2.46.2"
3
+ version = "2.47.0"
4
4
  description = "Assess and bootstrap git repositories for AI-assisted development with automated remediation"
5
5
  authors = [{name = "Jeremy Eder", email = "jeder@redhat.com"}]
6
6
  readme = "README.md"
@@ -3,6 +3,7 @@
3
3
  import ast
4
4
  import logging
5
5
  import re
6
+ import tomllib
6
7
 
7
8
  from ..models.attribute import Attribute
8
9
  from ..models.finding import Citation, Finding, Remediation
@@ -73,7 +74,13 @@ class TypeAnnotationsAssessor(BaseAssessor):
73
74
  )
74
75
 
75
76
  def _assess_python_types(self, repository: Repository) -> Finding:
76
- """Assess Python type annotations using AST parsing."""
77
+ """Assess Python type annotations using AST parsing.
78
+
79
+ Checks both annotation coverage (current state) and strict mode
80
+ configuration (prevents new violations). Both matter — strict mode
81
+ stops new untyped code from entering; coverage measures what's already
82
+ typed.
83
+ """
77
84
  # Use AST parsing to accurately detect type annotations
78
85
  try:
79
86
  # Security: Use safe_subprocess_run for validation and limits
@@ -130,28 +137,121 @@ class TypeAnnotationsAssessor(BaseAssessor):
130
137
  )
131
138
 
132
139
  coverage_percent = (typed_functions / total_functions) * 100
133
- score = self.calculate_proportional_score(
140
+
141
+ # Check for strict mode configuration (mypy/pyright)
142
+ strict_mode = self._check_strict_mode(repository)
143
+
144
+ # Score combines coverage (up to 80 pts) + strict mode bonus (up to 20 pts)
145
+ coverage_score = self.calculate_proportional_score(
134
146
  measured_value=coverage_percent,
135
147
  threshold=80.0,
136
148
  higher_is_better=True,
137
149
  )
150
+ score = min(100.0, coverage_score + (20.0 if strict_mode else 0.0))
138
151
 
139
152
  status = "pass" if score >= 75 else "fail"
140
153
 
154
+ evidence = [
155
+ f"Typed functions: {typed_functions}/{total_functions}",
156
+ f"Coverage: {coverage_percent:.1f}%",
157
+ ]
158
+ if strict_mode:
159
+ evidence.append("Strict mode configured")
160
+ else:
161
+ evidence.append("No strict mode configuration found")
162
+
141
163
  return Finding(
142
164
  attribute=self.attribute,
143
165
  status=status,
144
166
  score=score,
145
167
  measured_value=f"{coverage_percent:.1f}%",
146
- threshold="≥80%",
147
- evidence=[
148
- f"Typed functions: {typed_functions}/{total_functions}",
149
- f"Coverage: {coverage_percent:.1f}%",
150
- ],
168
+ threshold="≥80% coverage + strict mode",
169
+ evidence=evidence,
151
170
  remediation=self._create_remediation() if status == "fail" else None,
152
171
  error_message=None,
153
172
  )
154
173
 
174
+ @staticmethod
175
+ def _check_strict_mode(repository: Repository) -> bool:
176
+ """Check whether the Python type checker is configured in strict mode.
177
+
178
+ Looks for mypy/pyright strict mode configuration in pyproject.toml,
179
+ mypy.ini, setup.cfg, or pyrightconfig.json.
180
+
181
+ ADR A.6: Strict mode prevents new violations; coverage measures
182
+ current state. Both matter.
183
+ """
184
+ # Check pyproject.toml for mypy/pyright strict config
185
+ pyproject_path = repository.path / "pyproject.toml"
186
+ if pyproject_path.exists():
187
+ try:
188
+ with open(pyproject_path, "rb") as f:
189
+ data = tomllib.load(f)
190
+
191
+ # mypy: [tool.mypy] strict = true
192
+ tool = data.get("tool", {})
193
+ mypy_cfg = tool.get("mypy", {})
194
+ if mypy_cfg.get("strict", False):
195
+ return True
196
+ if "disallow_untyped_defs" in mypy_cfg and mypy_cfg[
197
+ "disallow_untyped_defs"
198
+ ]:
199
+ return True
200
+
201
+ # pyright: [tool.pyright] strict = true
202
+ pyright_cfg = tool.get("pyright", {})
203
+ if pyright_cfg.get("strict", False):
204
+ return True
205
+
206
+ except (OSError, tomllib.TOMLDecodeError):
207
+ pass
208
+
209
+ # Check mypy.ini
210
+ mypy_ini_path = repository.path / "mypy.ini"
211
+ if mypy_ini_path.exists():
212
+ try:
213
+ content = mypy_ini_path.read_text(encoding="utf-8")
214
+ if "[mypy]" in content:
215
+ for line in content.splitlines():
216
+ stripped = line.strip().lower()
217
+ if stripped == "strict = true" or stripped == "strict=true":
218
+ return True
219
+ if stripped.startswith("disallow_untyped_defs"):
220
+ return True
221
+ except OSError:
222
+ pass
223
+
224
+ # Check setup.cfg
225
+ setup_cfg_path = repository.path / "setup.cfg"
226
+ if setup_cfg_path.exists():
227
+ try:
228
+ content = setup_cfg_path.read_text(encoding="utf-8")
229
+ if "[mypy]" in content or "[mypy]" in content.lower():
230
+ for line in content.splitlines():
231
+ stripped = line.strip().lower()
232
+ if "strict = true" in stripped or "strict=true" in stripped:
233
+ return True
234
+ if stripped.startswith("disallow_untyped_defs"):
235
+ return True
236
+ except OSError:
237
+ pass
238
+
239
+ # Check pyrightconfig.json
240
+ pyright_path = repository.path / "pyrightconfig.json"
241
+ if pyright_path.exists():
242
+ try:
243
+ import json
244
+
245
+ content = json.loads(pyright_path.read_text(encoding="utf-8"))
246
+ if content.get("typeCheckingMode", "") == "strict":
247
+ return True
248
+ if content.get("strict", False):
249
+ return True
250
+ except (json.JSONDecodeError, OSError):
251
+ pass
252
+
253
+ return False
254
+
155
255
  def _assess_typescript_types(self, repository: Repository) -> Finding:
156
256
  """Assess TypeScript type configuration across all tsconfig.json files.
157
257
 
@@ -126,6 +126,9 @@ class StandardLayoutAssessor(BaseAssessor):
126
126
  - Go: cmd/, internal/, pkg/ with go.mod, tests in *_test.go
127
127
 
128
128
  Fix for #246, #305: Support multiple valid Python layouts
129
+ ADR A.7: Adds naming consistency check for Python repos — mixed
130
+ naming conventions (camelCase vs snake_case in same directory) reduce
131
+ "glob-ability" for agents.
129
132
  """
130
133
  if self._primary_language(repository, {"Python", "Go"}) == "Go":
131
134
  return self._assess_go_layout(repository)
@@ -162,6 +165,16 @@ class StandardLayoutAssessor(BaseAssessor):
162
165
  higher_is_better=True,
163
166
  )
164
167
 
168
+ # ADR A.7: Naming consistency check for Python repos
169
+ naming_penalty = 0.0
170
+ naming_evidence = []
171
+ if repository.languages.get("Python", 0) > 0:
172
+ penalty, evidence = self._check_naming_consistency(repository)
173
+ naming_penalty = penalty
174
+ naming_evidence = evidence
175
+
176
+ score = max(0.0, score - naming_penalty)
177
+
165
178
  status = "pass" if score >= 75 else "fail"
166
179
 
167
180
  # Build evidence with detailed source directory info
@@ -180,7 +193,7 @@ class StandardLayoutAssessor(BaseAssessor):
180
193
  f"Found {found_dirs}/{required_dirs} standard directories",
181
194
  source_evidence,
182
195
  f"tests/: {'✓' if has_tests else '✗'}",
183
- ]
196
+ ] + naming_evidence
184
197
 
185
198
  return Finding(
186
199
  attribute=self.attribute,
@@ -497,6 +510,93 @@ project/
497
510
  ],
498
511
  )
499
512
 
513
+ def _check_naming_consistency(self, repository: Repository) -> tuple:
514
+ """Check for mixed naming conventions in the same directory.
515
+
516
+ ADR A.7: Inconsistent naming (camelCase vs snake_case coexisting in
517
+ the same directory) reduces "glob-ability" for agents. A consistent
518
+ naming convention makes it easier for agents to use glob patterns like
519
+ `src/**/*.py` to find all relevant files.
520
+
521
+ Returns:
522
+ (penalty_score, evidence_list)
523
+ - penalty_score: 0-20, where 20 is maximum penalty for mixed conventions
524
+ - evidence_list: human-readable evidence strings
525
+ """
526
+ # Only check source directories, not test directories
527
+ # We look at Python files (.py, .pyi) in source locations
528
+ source_path = repository.path / "src"
529
+ if not source_path.exists():
530
+ # Try project-named directory
531
+ package_name = self._get_package_name_from_pyproject(repository)
532
+ if package_name:
533
+ source_path = repository.path / package_name.replace("-", "_")
534
+ if not source_path.exists():
535
+ # Fall back to root for small repos
536
+ source_path = repository.path
537
+
538
+ file_stats: dict = {"snake_case": 0, "camelCase": 0, "mixed": set()}
539
+ total_files = 0
540
+
541
+ try:
542
+ for py_file in source_path.rglob("*.py"):
543
+ # Skip venv, node_modules, etc.
544
+ if any(
545
+ part in py_file.parts
546
+ for part in [".venv", "venv", "node_modules", ".git", ".tox"]
547
+ ):
548
+ continue
549
+ total_files += 1
550
+ dirname = py_file.parent.name
551
+ filename = py_file.name
552
+
553
+ # Group files by directory and check naming per directory
554
+ is_snake = bool(re.fullmatch(r"[a-z][a-z0-9]*(?:_[a-z0-9]+)*\.py(?:i)?$", filename))
555
+ is_camel = bool(re.fullmatch(r"[a-z][a-zA-Z0-9]*\.py(?:i)?$", filename))
556
+
557
+ if is_snake and is_camel:
558
+ pass # lowercase is snake_case
559
+ elif is_snake:
560
+ key = f"{dirname}/"
561
+ if key not in file_stats:
562
+ file_stats[key] = {"snake_case": 0, "camelCase": 0}
563
+ file_stats[key]["snake_case"] += 1
564
+ elif is_camel:
565
+ key = f"{dirname}/"
566
+ if key not in file_stats:
567
+ file_stats[key] = {"snake_case": 0, "camelCase": 0}
568
+ file_stats[key]["camelCase"] += 1
569
+
570
+ except OSError:
571
+ return 0.0, []
572
+
573
+ # Check if any directory has mixed naming
574
+ penalty = 0.0
575
+ evidence = []
576
+
577
+ for dir_key, counts in file_stats.items():
578
+ snake_count = counts.get("snake_case", 0)
579
+ camel_count = counts.get("camelCase", 0)
580
+
581
+ # Only count directories with at least 2 files (need meaningful sample)
582
+ if snake_count > 0 and camel_count > 0:
583
+ total_in_dir = snake_count + camel_count
584
+ if total_in_dir >= 2:
585
+ penalty += 10.0
586
+ evidence.append(
587
+ f"Mixed naming in {dir_key}: {snake_count} snake_case, {camel_count} camelCase"
588
+ )
589
+
590
+ # Cap the penalty at 20 points
591
+ penalty = min(20.0, penalty)
592
+
593
+ if penalty > 0:
594
+ evidence.insert(0, "Inconsistent naming conventions detected")
595
+ elif total_files > 0:
596
+ evidence.append("Naming convention consistent")
597
+
598
+ return penalty, evidence
599
+
500
600
  def _create_remediation(self, has_source: bool, has_tests: bool) -> Remediation:
501
601
  """Create context-aware remediation guidance for standard layout.
502
602
 
@@ -564,12 +564,17 @@ class TestExecutionAssessor(BaseAssessor):
564
564
 
565
565
  text_sources = self._read_go_build_files(repository)
566
566
 
567
- has_test_cmd = bool(re.search(r"(?:\bgo|\$\(GO\))\s+test\b", text_sources))
567
+ has_test_cmd = bool(
568
+ re.search(
569
+ r"(?:\bgo|\$\(GO\))\s+test\b|\bmake\s+test\b|\bginkgo\b",
570
+ text_sources,
571
+ )
572
+ )
568
573
  if has_test_cmd:
569
574
  score += 20.0
570
575
  evidence.append("Go test command found in project files")
571
576
  else:
572
- evidence.append("No 'go test' command found in Makefile/CI/README")
577
+ evidence.append("No test command found in Makefile/CI/README/AGENTS.md")
573
578
 
574
579
  has_coverage = bool(
575
580
  re.search(r"(?<!\S)-cover(?:\b|profile\b|mode\b)", text_sources)
@@ -634,6 +639,8 @@ class TestExecutionAssessor(BaseAssessor):
634
639
  repository.path / "Makefile",
635
640
  repository.path / "Taskfile.yml",
636
641
  repository.path / "README.md",
642
+ repository.path / "AGENTS.md",
643
+ repository.path / "CLAUDE.md",
637
644
  ]
638
645
 
639
646
  # Include module-local build files (Go monorepos)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentready
3
- Version: 2.46.2
3
+ Version: 2.47.0
4
4
  Summary: Assess and bootstrap git repositories for AI-assisted development with automated remediation
5
5
  Author-email: Jeremy Eder <jeder@redhat.com>
6
6
  License: MIT
File without changes
File without changes
File without changes