-
Notifications
You must be signed in to change notification settings - Fork 29
Description
feat: Implement InlineDocumentationAssessor
Attribute Definition
Attribute ID: inline_documentation (Attribute #14 - Tier 2)
Definition: Function, class, and module-level documentation using language-specific conventions (Python docstrings, JSDoc/TSDoc).
Why It Matters: Type hints significantly improve LLM experience. Well-typed code directs LLMs into latent space regions corresponding to higher code quality—similar to how LaTeX-formatted math problems get better results.
Impact on Agent Behavior:
- Understanding function purpose without reading implementation
- Better parameter validation suggestions
- More accurate return type predictions
- Improved test generation
- Enhanced refactoring confidence
Measurable Criteria:
- All public functions/methods have docstrings
- Docstrings include: description, parameters, return values, exceptions, examples
- Python: PEP 257 compliant
- JavaScript/TypeScript: JSDoc or TSDoc
- Coverage: >80% of public API documented
- Tools: pydocstyle, documentation-js
Implementation Requirements
File Location: src/agentready/assessors/documentation.py
Class Name: InlineDocumentationAssessor
Tier: 2 (Critical)
Default Weight: 0.03 (3% of total score)
Assessment Logic
Scoring Approach: Language-specific AST parsing for accurate detection
Evidence to Check (Python):
- Parse Python files with AST
- Count public functions/classes (not starting with
_) - Check for docstring presence (
ast.get_docstring()) - Calculate coverage percentage
- Optionally check docstring quality (has Args, Returns, etc.)
Evidence to Check (JavaScript/TypeScript):
- Check for JSDoc comments (
/** ... */) - Parse with regex or esprima/babel parser
- Count functions with JSDoc vs. total functions
- Calculate coverage percentage
Scoring Logic:
documented_functions = count_functions_with_docstrings(files)
total_public_functions = count_public_functions(files)
coverage_percent = (documented_functions / total_public_functions) * 100
score = self.calculate_proportional_score(
measured_value=coverage_percent,
threshold=80.0,
higher_is_better=True,
)
status = "pass" if score >= 75 else "fail"Code Pattern to Follow
Reference: TypeAnnotationsAssessor in code_quality.py
Pattern:
- Check
is_applicable()for supported languages - Use AST parsing for Python (similar to TypeAnnotationsAssessor)
- Walk AST tree to find function/class definitions
- Check for docstring using
ast.get_docstring(node) - Calculate proportional score based on coverage
Example Finding Responses
Pass (Score: 88)
Finding(
attribute=self.attribute,
status="pass",
score=88.0,
measured_value="88%",
threshold="≥80%",
evidence=[
"Documented functions: 45/51",
"Coverage: 88.2%",
"All public classes have docstrings",
"6 private functions missing docstrings (acceptable)",
],
remediation=None,
error_message=None,
)Fail (Score: 42)
Finding(
attribute=self.attribute,
status="fail",
score=42.0,
measured_value="34%",
threshold="≥80%",
evidence=[
"Documented functions: 18/53",
"Coverage: 34.0%",
"Many public functions lack docstrings",
"No module-level documentation",
],
remediation=self._create_remediation(),
error_message=None,
)Not Applicable
Finding.not_applicable(
self.attribute,
reason="No Python or JavaScript code found in repository"
)Registration
Add to src/agentready/services/scanner.py in create_all_assessors():
from ..assessors.documentation import (
CLAUDEmdAssessor,
READMEAssessor,
ConciseDocumentationAssessor,
InlineDocumentationAssessor, # Add this import
)
def create_all_assessors() -> List[BaseAssessor]:
return [
# ... existing assessors ...
InlineDocumentationAssessor(), # Add this line
]Testing Guidance
Test File: tests/unit/test_assessors_documentation.py
Test Cases to Add:
test_inline_docs_pass_high_coverage: Python files with >80% docstring coveragetest_inline_docs_fail_low_coverage: Python files with <50% coveragetest_inline_docs_partial_score: 65% coverage (proportional score)test_inline_docs_ignore_private: Private functions (starting with_) not requiredtest_inline_docs_no_code: Empty repository returns not_applicable
Note: AgentReady codebase has good docstring coverage in assessors/ and models/, should score well.
Dependencies
External Tools: None (uses AST parsing)
Python Standard Library:
astfor parsing Python codeast.get_docstring()for extracting docstringspathlib.Pathfor file iteration
Optional Enhancement: Use pydocstyle for quality checking (not just presence)
Remediation Steps
def _create_remediation(self) -> Remediation:
return Remediation(
summary="Add docstrings to public functions and classes",
steps=[
"Identify functions/classes without docstrings",
"Add PEP 257 compliant docstrings for Python",
"Add JSDoc comments for JavaScript/TypeScript",
"Include: description, parameters, return values, exceptions",
"Add examples for complex functions",
"Run pydocstyle to validate docstring format",
],
tools=["pydocstyle", "jsdoc"],
commands=[
"# Install pydocstyle",
"pip install pydocstyle",
"",
"# Check docstring coverage",
"pydocstyle src/",
"",
"# Generate documentation",
"pip install sphinx",
"sphinx-apidoc -o docs/ src/",
],
examples=[
'''# Python - Good docstring
def calculate_discount(price: float, discount_percent: float) -> float:
"""
Calculate discounted price.
Args:
price: Original price in USD
discount_percent: Discount percentage (0-100)
Returns:
Discounted price
Raises:
ValueError: If discount_percent not in 0-100 range
Example:
>>> calculate_discount(100.0, 20.0)
80.0
"""
if not 0 <= discount_percent <= 100:
raise ValueError("Discount must be 0-100")
return price * (1 - discount_percent / 100)
''',
'''// JavaScript - Good JSDoc
/**
* Calculate discounted price
*
* @param {number} price - Original price in USD
* @param {number} discountPercent - Discount percentage (0-100)
* @returns {number} Discounted price
* @throws {Error} If discountPercent not in 0-100 range
* @example
* calculateDiscount(100.0, 20.0)
* // Returns: 80.0
*/
function calculateDiscount(price, discountPercent) {
if (discountPercent < 0 || discountPercent > 100) {
throw new Error("Discount must be 0-100");
}
return price * (1 - discountPercent / 100);
}
''',
],
citations=[
Citation(
source="Python.org",
title="PEP 257 - Docstring Conventions",
url="https://peps.python.org/pep-0257/",
relevance="Python docstring standards",
),
Citation(
source="TypeScript",
title="TSDoc Reference",
url="https://tsdoc.org/",
relevance="TypeScript documentation standard",
),
],
)Implementation Notes
- AST Parsing: Use
ast.parse()andast.walk()to traverse code - Docstring Extraction: Use
ast.get_docstring(node)which returns None if missing - Public vs Private: Exclude functions/classes starting with
_ - Module Docstrings: Also check module-level docstrings (
ast.get_docstring(tree)) - File Filtering: Use
git ls-files *.pyto get tracked Python files - Error Handling: Skip files with syntax errors gracefully
- Edge Cases: Handle empty functions, property decorators, async functions
Quality Checks (Optional Enhancement):
- Check if docstring has "Args:" section
- Check if docstring has "Returns:" section
- Check if docstring has example
- Use pydocstyle for PEP 257 compliance