feat: Python 3.10 only, PAL MCP review, README update - #14
Conversation
- CI: Reduce test matrix from 5 Python versions to 3.10 only - CI: Update ai-review workflow to use PAL MCP consensus code review - pyproject.toml: Update requires-python to >=3.10, update tool targets - README: Comprehensive update with mermaid diagrams and accurate stats - Quality: Add agentic loop safety and deterministic signal validation - Parser: Add schema validation for agent definitions - Tests: Add new test suites for quality and schema validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reviewer's GuideNarrows support to Python 3.10, upgrades CI and AI review workflows (PAL MCP consensus), substantially rewrites the README with architecture diagrams and up-to-date stats, and hardens quality/agent systems with deterministic signals, agentic loop safety, and schema validation plus accompanying tests. Class diagram for updated QualityScorer and deterministic signalsclassDiagram
class IterationResult {
+int iteration
+float input_quality
+float output_quality
+List~str~ improvements_applied
+float time_taken
+bool success
+str termination_reason
}
class IterationTermination {
<<static>>
+str QUALITY_MET
+str MAX_ITERATIONS
+str INSUFFICIENT_IMPROVEMENT
+str STAGNATION
+str OSCILLATION
+str ERROR
+str HUMAN_ESCALATION
}
class DeterministicSignals {
+bool tests_passed
+int tests_total
+int tests_failed
+float test_coverage
+bool lint_passed
+int lint_errors
+int lint_warnings
+bool type_check_passed
+int type_errors
+bool build_passed
+int build_errors
+bool security_passed
+int security_critical
+int security_high
+bool has_hard_failures()
+float get_hard_failure_cap()
+float calculate_bonus()
}
class QualityThresholds {
+float production_ready
+str classify(float score) str
}
class QualityAssessment {
+float overall_score
+bool passed
+str band
+List~str~ improvements_needed
+Dict~str,Any~ metadata
}
class QualityScorer {
+float DEFAULT_THRESHOLD
+int MAX_ITERATIONS
+int HARD_MAX_ITERATIONS
+float MIN_IMPROVEMENT
+int OSCILLATION_WINDOW
+float STAGNATION_THRESHOLD
+List~IterationResult~ iteration_history
+evaluate(output, context, dimensions, weights, iteration) QualityAssessment
+agentic_loop(initial_output, context, improver_func, max_iterations, min_improvement) Tuple~Any,QualityAssessment,List~IterationResult~~
+apply_deterministic_signals(base_score, signals) Tuple~float,Dict~str,Any~~
+evaluate_with_signals(output, context, signals, dimensions, weights, iteration) QualityAssessment
+_detect_oscillation(score_history List~float~) bool
+_detect_stagnation(score_history List~float~) bool
+signals_from_context(context Dict~str,Any~) DeterministicSignals
}
QualityScorer --> IterationResult : creates
QualityScorer --> DeterministicSignals : uses
QualityScorer --> QualityThresholds : uses
QualityScorer --> QualityAssessment : returns
QualityScorer ..> IterationTermination : uses constants
DeterministicSignals --> QualityScorer : passed into
Class diagram for new agent schema validation in AgentMarkdownParserclassDiagram
class AgentSchemaError {
+str field
+str message
+str severity
+Optional~int~ line_number
}
class AgentValidationResult {
+bool valid
+List~AgentSchemaError~ errors
+List~AgentSchemaError~ warnings
+str agent_name
+str file_path
+add_error(field str, message str, line Optional~int~) void
+add_warning(field str, message str, line Optional~int~) void
}
class AgentSchema {
+Set~str~ REQUIRED_FIELDS
+Set~str~ RECOMMENDED_FIELDS
+Set~str~ VALID_TOOLS
+Set~str~ VALID_CATEGORIES
+int MAX_NAME_LENGTH
+int MAX_DESCRIPTION_LENGTH
+int MAX_TOOLS_COUNT
}
class AgentMarkdownParser {
+logger
+parse(path Path) Dict~str,Any~
+validate_agent_config(config Dict~str,Any~) bool
+validate_schema(config Dict~str,Any~, file_path Optional~Path~) AgentValidationResult
+validate_all_agents(agents_dir Path) List~AgentValidationResult~
+get_validation_summary(results List~AgentValidationResult~) Dict~str,Any~
}
AgentMarkdownParser ..> AgentSchema : uses constants
AgentMarkdownParser --> AgentValidationResult : creates
AgentValidationResult --> AgentSchemaError : aggregates
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Rate limit exceeded@Tony363 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 4 minutes and 58 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a PAL MCP Consensus Code Review GitHub Actions workflow and CI adjustments; introduces agent schema validation APIs and tests; strengthens QualityScorer with deterministic signals and robust iteration termination; modernizes typing across the codebase to Python 3.10+ style; updates project metadata, tooling, and many tests/fixtures. Changes
Sequence Diagram(s)mermaid GH->>Repo: checkout PR + gather context (diff, files, stats) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
- In
QualityScorer.evaluate_with_signals,assessment.passedis recalculated againstself.thresholds.production_readyinstead of the existingself.thresholdlogic used byevaluate, which subtly changes the pass/fail behavior only on the signals path; consider aligning these or documenting why the production band is intentionally stricter here. - The
ai-review.ymljob computesPYTHON_FILESas a GitHub step output but that value is never interpolated into the Claude prompt or passed to PAL, even though the instructions mention listing changed Python files; consider wiring this output into the prompt or tool arguments so the computed file list is actually used. - The hardcoded
AgentSchema.VALID_TOOLSandVALID_CATEGORIESsets risk drifting from the actual Claude/MCP tool and category definitions over time; it may be safer to load these from a single source of truth (e.g., config or registry) to avoid validation mismatches.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `QualityScorer.evaluate_with_signals`, `assessment.passed` is recalculated against `self.thresholds.production_ready` instead of the existing `self.threshold` logic used by `evaluate`, which subtly changes the pass/fail behavior only on the signals path; consider aligning these or documenting why the production band is intentionally stricter here.
- The `ai-review.yml` job computes `PYTHON_FILES` as a GitHub step output but that value is never interpolated into the Claude prompt or passed to PAL, even though the instructions mention listing changed Python files; consider wiring this output into the prompt or tool arguments so the computed file list is actually used.
- The hardcoded `AgentSchema.VALID_TOOLS` and `VALID_CATEGORIES` sets risk drifting from the actual Claude/MCP tool and category definitions over time; it may be safer to load these from a single source of truth (e.g., config or registry) to avoid validation mismatches.
## Individual Comments
### Comment 1
<location> `SuperClaude/Quality/quality_scorer.py:142-147` </location>
<code_context>
+ security_critical: int = 0
+ security_high: int = 0
+
+ def has_hard_failures(self) -> bool:
+ """Check for any hard failures that should cap the score."""
+ return (
+ self.tests_failed > 0
+ or self.security_critical > 0
+ or (not self.build_passed and self.build_errors > 0)
+ )
+
</code_context>
<issue_to_address>
**🚨 issue (security):** High‑severity security issues never trigger the hard failure cap
`has_hard_failures` ignores `security_high`, but `get_hard_failure_cap` and `apply_deterministic_signals` treat high‑severity security findings as hard failures. With the current logic, a configuration where only `security_high > 0` will never cap the score or trigger the hard‑failure messaging. Please include `self.security_high > 0` in `has_hard_failures` so high‑severity findings correctly cap scores and align with the other methods’ expectations.
</issue_to_address>
### Comment 2
<location> `SuperClaude/Quality/quality_scorer.py:791-800` </location>
<code_context>
+ # Apply bonus for positive signals
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Bonus metadata is recorded even when the bonus is not actually applied
In `apply_deterministic_signals`, the result of `signals.calculate_bonus()` is always written to `details["bonus_applied"]` and `details["bonuses"]`, even when `signals.has_hard_failures()` is true and the bonus is not added to `adjusted_score`. This makes the details inconsistent with `final_score`. Consider only recording bonus metadata when it affects the score, or add an explicit flag (e.g., `bonus_suppressed_due_to_hard_failures`) so consumers can distinguish computed vs applied bonuses.
Suggested implementation:
```python
# Apply bonus for positive signals
bonus = signals.calculate_bonus()
if bonus > 0:
if signals.has_hard_failures():
# Bonus was computed but not applied due to hard failures
details["bonus_suppressed_due_to_hard_failures"] = True
else:
details["bonus_applied"] = bonus
if signals.test_coverage >= 80:
details["bonuses"].append(
f"High test coverage: {signals.test_coverage:.0f}%"
)
if signals.lint_passed:
details["bonuses"].append("Clean lint")
if signals.type_check_passed:
details["bonuses"].append("Clean type check")
```
If there are tests or consumers relying on `details["bonus_applied"]` or `details["bonuses"]` always being present when `calculate_bonus()` returns a positive value, they should be updated to account for the new `details["bonus_suppressed_due_to_hard_failures"]` flag and the fact that bonus metadata is now only recorded when the bonus actually affects the score.
</issue_to_address>
### Comment 3
<location> `tests/agents/test_schema_validation.py:362-371` </location>
<code_context>
+ def parser(self):
+ return AgentMarkdownParser()
+
+ def test_parse_valid_frontmatter(self, parser, tmp_path):
+ """Test parsing valid YAML frontmatter."""
+ content = """---
+name: test-agent
+description: A test agent for validation testing
+tools: Read, Write, Bash
+---
+
+You are a test agent.
+"""
+ md_file = tmp_path / "test-agent.md"
+ md_file.write_text(content)
+
+ config = parser.parse(md_file)
+
+ assert config is not None
+ assert config["name"] == "test-agent"
+ assert config["description"] == "A test agent for validation testing"
+ assert "tools" in config
+
+ def test_parse_missing_frontmatter(self, parser, tmp_path):
</code_context>
<issue_to_address>
**suggestion (testing):** There are no tests covering `validate_all_agents`, so directory traversal and file skipping behavior are unverified.
`validate_all_agents` has substantial control flow (walking the tree with `rglob`, skipping `_`-prefixed/README files, handling `parse` returning `None`), but current tests only build `AgentValidationResult` manually and never call it. Please add an integration-style test that builds a small agents directory with: (1) a valid `.md`, (2) a malformed `.md`, and (3) a `_partial.md` or `README.md` to be skipped, then asserts that `validate_all_agents` returns the correct number of results, flags the malformed file as invalid, and omits skipped files.
Suggested implementation:
```python
config = parser.parse(md_file)
# Files without YAML frontmatter should not produce a config
assert config is None
def test_validate_all_agents_integration(self, tmp_path):
"""Integration test for validate_all_agents over a small agents directory."""
# Create a directory structure with valid, invalid, and skipped agent files
agents_dir = tmp_path / "agents"
agents_dir.mkdir()
# 1. Valid markdown file
valid_content = """---
name: valid-agent
description: A valid test agent
tools: Read
---
You are a valid agent.
"""
valid_file = agents_dir / "valid-agent.md"
valid_file.write_text(valid_content)
# 2. Malformed markdown file (e.g. invalid YAML frontmatter)
invalid_content = """---
name: invalid-agent
description: This frontmatter is not valid YAML: [unclosed list
---
You are an invalid agent.
"""
invalid_file = agents_dir / "invalid-agent.md"
invalid_file.write_text(invalid_content)
# 3. Skipped markdown files
skipped_partial = agents_dir / "_partial.md"
skipped_partial.write_text(valid_content)
skipped_readme = agents_dir / "README.md"
skipped_readme.write_text(valid_content)
results = validate_all_agents(agents_dir)
# We should only see results for the valid and invalid agents
assert len(results) == 2
by_name = {result.name: result for result in results}
assert "valid-agent" in by_name
assert "invalid-agent" in by_name
assert by_name["valid-agent"].is_valid
assert not by_name["invalid-agent"].is_valid
```
1. Ensure `validate_all_agents` is imported at the top of `tests/agents/test_schema_validation.py`, for example:
`from agents.schema_validation import validate_all_agents`
(adjust the module path to wherever `validate_all_agents` is actually defined).
2. This test assumes that:
- `validate_all_agents(path: Path)` walks the directory tree (e.g. using `rglob("*.md")`),
- ignores files whose names start with `_` or are exactly `README.md`,
- and returns an iterable of `AgentValidationResult` objects with `name` and `is_valid` attributes.
If your `AgentValidationResult` uses different attribute names (e.g. `agent_name`, `valid`), update the assertions to match.
3. If `validate_all_agents` requires additional parameters (such as a parser instance, config, or logger), update the test call `results = validate_all_agents(agents_dir)` to pass them, mirroring how the function is expected to be used in production code.
</issue_to_address>
### Comment 4
<location> `tests/quality/test_deterministic_signals.py:310-319` </location>
<code_context>
+class TestSignalsFromContext:
</code_context>
<issue_to_address>
**suggestion (testing):** `signals_from_context` tests omit type-check and build extraction, and the alternate `security_results` key path.
The helper also maps `type_check_results`, `build_results`, and either `security_scan` or `security_results`. Current tests don’t cover:
- mapping `type_check_results` → `type_check_passed` / `type_errors`
- mapping `build_results` → `build_passed` / `build_errors`
- using `security_results` when `security_scan` is absent
Please add focused tests for these cases to lock in the schema and avoid regressions if the context shape changes.
Suggested implementation:
```python
class TestSignalsFromContext:
"""Test extracting signals from context dictionary."""
def test_extracts_type_check_results(self):
"""Test extracting type check results from context."""
context = {
"type_check_results": {
"passed": True,
"errors": ["E001", "E002"],
}
}
signals = signals_from_context(context)
assert signals["type_check_passed"] is True
assert signals["type_errors"] == ["E001", "E002"]
def test_extracts_build_results(self):
"""Test extracting build results from context."""
context = {
"build_results": {
"passed": False,
"errors": ["linker error", "missing symbol"],
}
}
signals = signals_from_context(context)
assert signals["build_passed"] is False
assert signals["build_errors"] == ["linker error", "missing symbol"]
def test_uses_security_results_when_scan_absent(self):
"""Test that security_results is used when security_scan is absent."""
context = {
"security_results": {
"passed": False,
"issues": ["CVE-1234", "Outdated dependency"],
}
}
signals = signals_from_context(context)
assert signals["security_passed"] is False
assert signals["security_issues"] == ["CVE-1234", "Outdated dependency"]
def test_extracts_test_results(self):
"""Test extracting test results from context."""
context = {
"test_results": {
"total": 100,
"failed": 5,
"passed": True,
"coverage": 0.85, # 85% as decimal
```
These edits assume:
1. A `signals_from_context` helper is already imported or defined in this test module (it should already be used by `test_extracts_test_results`). If it is currently referenced with a module prefix (e.g., `deterministic_signals.signals_from_context`), update the new tests to match that call style.
2. The `signals_from_context` implementation actually maps:
- `type_check_results.passed` → `type_check_passed`
- `type_check_results.errors` → `type_errors`
- `build_results.passed` → `build_passed`
- `build_results.errors` → `build_errors`
- `security_results.passed` → `security_passed` (when `security_scan` is absent)
- `security_results.issues` → `security_issues`
If the actual key names differ (for example, using `error_messages` instead of `errors`), adjust the test dictionaries and assertions to use the concrete keys used in your existing `signals_from_context` implementation.
</issue_to_address>
### Comment 5
<location> `tests/quality/test_deterministic_signals.py:292-307` </location>
<code_context>
+ assert assessment.metadata.get("signals_grounded") is True
+ assert "deterministic_signals" in assessment.metadata
+
+ def test_hard_failures_added_to_improvements(self, scorer):
+ """Test that hard failures are added to improvements list."""
+ signals = DeterministicSignals(
+ tests_total=10,
+ tests_failed=3,
+ )
+
+ assessment = scorer.evaluate_with_signals(
+ output={"success": True},
+ context={},
+ signals=signals,
+ )
+
+ # Should have FIX: prefix for hard failures
+ fix_items = [i for i in assessment.improvements_needed if i.startswith("FIX:")]
+ assert len(fix_items) > 0
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Consider adding a test that shows `evaluate_with_signals` can flip a passing base evaluation to failing when capped by hard failures.
Current tests cover metadata and that hard failures become `FIX:` items, but they don’t verify that the capped score actually changes `assessment.passed` and `band`. Please add a case where base `evaluate` yields a score above `production_ready`, then signals (e.g., failing tests or critical security) lower the adjusted score below the threshold so `assessment.passed` is `False` and the band reflects the reduced score.
```suggestion
def test_hard_failures_added_to_improvements(self, scorer):
"""Test that hard failures are added to improvements list."""
signals = DeterministicSignals(
tests_total=10,
tests_failed=3,
)
assessment = scorer.evaluate_with_signals(
output={"success": True},
context={},
signals=signals,
)
# Should have FIX: prefix for hard failures
fix_items = [i for i in assessment.improvements_needed if i.startswith("FIX:")]
assert len(fix_items) > 0
def test_hard_failures_can_flip_passing_to_failing(self, scorer):
"""Base evaluation passes, but hard failures can cap score below production_ready."""
# First, verify that the base evaluation (without signals) passes
base_assessment = scorer.evaluate(
output={"success": True},
context={},
)
assert base_assessment.passed is True
# Now provide deterministic signals with hard failures that should cap the score
signals = DeterministicSignals(
tests_total=10,
tests_failed=10, # All tests failing => strong hard-failure signal
)
capped_assessment = scorer.evaluate_with_signals(
output={"success": True},
context={},
signals=signals,
)
# The capped assessment should now fail, and its band/score should reflect the reduction
assert capped_assessment.passed is False
assert capped_assessment.band != base_assessment.band
assert capped_assessment.score <= base_assessment.score
```
</issue_to_address>
### Comment 6
<location> `tests/quality/test_deterministic_signals.py:251-260` </location>
<code_context>
+ assert adjusted > 70.0
+ assert len(details["bonuses"]) > 0
+
+ def test_bonus_not_applied_with_failures(self, scorer):
+ """Test that bonuses are NOT applied when hard failures exist."""
+ signals = DeterministicSignals(
+ tests_passed=False,
+ tests_total=10,
+ tests_failed=2,
+ test_coverage=85.0, # Good coverage, but tests failing
+ lint_passed=True,
+ lint_errors=0,
+ )
+
+ adjusted, details = scorer.apply_deterministic_signals(80.0, signals)
+
+ # Should be capped due to failures, bonus ignored
+ assert adjusted <= 60.0 # Low failure cap
+
+
</code_context>
<issue_to_address>
**nitpick (testing):** It may be worth adding a control test where the base score is already below the hard cap to show `apply_deterministic_signals` is a no-op in that case.
Current tests only cover cases where a high base score is capped. Please also add a case where `base_score` is already below the computed cap while hard failures exist (e.g., `base_score=40`, `tests_total=10`, `tests_failed=6`) and assert `adjusted_score == base_score` to document that the function doesn’t reduce scores further when they’re already under the cap.
</issue_to_address>
### Comment 7
<location> `tests/quality/test_agentic_loop_safety.py:88-97` </location>
<code_context>
+class TestOscillationDetection:
+ """Test that oscillating scores are detected and stopped."""
+
+ def test_detects_alternating_pattern(self):
+ """Verify oscillation is detected when scores alternate."""
+ scorer = QualityScorer()
+
+ # Scores that alternate up and down
+ oscillating_scores = [50.0, 60.0, 50.0, 60.0, 50.0]
+
+ for window_size in [3, 4, 5]:
+ if window_size <= len(oscillating_scores):
+ history = oscillating_scores[:window_size]
+ if window_size >= scorer.OSCILLATION_WINDOW:
+ # Should detect oscillation pattern
+ result = scorer._detect_oscillation(history)
+ # May or may not detect depending on exact pattern
+ # The key is it doesn't crash
+
+ def test_no_false_positive_on_improving(self):
</code_context>
<issue_to_address>
**issue (testing):** This oscillation test never asserts on `_detect_oscillation`'s behavior, so it won't fail if the implementation regresses.
In `test_detects_alternating_pattern`, `result = scorer._detect_oscillation(history)` is never asserted, so the test would still pass if `_detect_oscillation` always returned the same value. Please either (a) construct a clearly oscillating window of length `OSCILLATION_WINDOW` (e.g. `[50, 60, 50]`) and assert it returns `True`, plus a nearby non‑oscillating pattern that asserts `False`, or (b) if the goal is only to ensure no crash, rename the test and make that explicit (though such a test is of limited value).
</issue_to_address>
### Comment 8
<location> `tests/quality/test_agentic_loop_safety.py:148-157` </location>
<code_context>
+ result = scorer._detect_stagnation(improving_scores)
+ assert result is False
+
+ def test_stagnation_threshold_is_configurable(self):
+ """Verify stagnation threshold is used correctly."""
+ scorer = QualityScorer()
+
+ # Just above threshold
+ above_threshold = [
+ 50.0,
+ 50.0 + scorer.STAGNATION_THRESHOLD + 0.1,
+ 50.0,
+ ]
+
+ # Should not detect stagnation (variance > threshold)
+ # Need at least OSCILLATION_WINDOW scores
+ if len(above_threshold) >= scorer.OSCILLATION_WINDOW:
+ result = scorer._detect_stagnation(above_threshold)
+ # May or may not detect depending on exact values
+
+
</code_context>
<issue_to_address>
**issue (testing):** Similarly, `test_stagnation_threshold_is_configurable` does not assert on `_detect_stagnation`, making it effectively a no-op.
This test computes `above_threshold` and calls `_detect_stagnation` but never asserts on the result, so it can’t fail and doesn’t verify configurability. Consider adding two explicit cases around `STAGNATION_THRESHOLD`: one where `max(recent) - min(recent)` is just below the threshold and should return `True`, and one just above that should return `False`. That way the test will fail if the threshold handling regresses.
</issue_to_address>
### Comment 9
<location> `tests/quality/test_agentic_loop_safety.py:222-231` </location>
<code_context>
+class TestAgenticLoopIntegration:
+ """Integration tests for the complete agentic loop with safety features."""
+
+ def test_successful_quality_improvement(self):
+ """Test normal case where quality threshold is met."""
+ scorer = QualityScorer(threshold=70.0)
+
+ def improving_func(output, context):
+ current = output.get("quality", 0)
+ return {"quality": current + 30, "success": True}
+
+ _, assessment, results = scorer.agentic_loop(
+ initial_output={"quality": 50},
+ context={},
+ improver_func=improving_func,
+ max_iterations=3,
+ )
+
+ # Should have at least one iteration
+ assert len(results) >= 1
+
</code_context>
<issue_to_address>
**suggestion (testing):** The agentic loop integration tests do not assert on the termination reason, which is a key new safety signal.
Since `termination_reason` is now a key safety signal (quality met, max iterations, oscillation, stagnation, error), these integration tests should assert it in at least a couple of happy-path cases. For example, in `test_successful_quality_improvement`, please assert that the last `IterationResult` has `termination_reason == IterationTermination.QUALITY_MET`, rather than only checking that some results exist.
Suggested implementation:
```python
_, assessment, results = scorer.agentic_loop(
initial_output={"quality": 50},
context={},
improver_func=improving_func,
max_iterations=3,
)
# Should have at least one iteration
assert len(results) >= 1
# The loop should terminate because the quality threshold was met
assert results[-1].termination_reason == IterationTermination.QUALITY_MET
```
If not already present at the top of `tests/quality/test_agentic_loop_safety.py`, add an import for `IterationTermination`, for example:
`from <your_module> import IterationTermination`.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| def has_hard_failures(self) -> bool: | ||
| """Check for any hard failures that should cap the score.""" | ||
| return ( | ||
| self.tests_failed > 0 | ||
| or self.security_critical > 0 | ||
| or (not self.build_passed and self.build_errors > 0) |
There was a problem hiding this comment.
🚨 issue (security): High‑severity security issues never trigger the hard failure cap
has_hard_failures ignores security_high, but get_hard_failure_cap and apply_deterministic_signals treat high‑severity security findings as hard failures. With the current logic, a configuration where only security_high > 0 will never cap the score or trigger the hard‑failure messaging. Please include self.security_high > 0 in has_hard_failures so high‑severity findings correctly cap scores and align with the other methods’ expectations.
| # Apply bonus for positive signals | ||
| bonus = signals.calculate_bonus() | ||
| if bonus > 0: | ||
| details["bonus_applied"] = bonus | ||
|
|
||
| if signals.test_coverage >= 80: | ||
| details["bonuses"].append(f"High test coverage: {signals.test_coverage:.0f}%") | ||
| if signals.lint_passed: | ||
| details["bonuses"].append("Clean lint") | ||
| if signals.type_check_passed: |
There was a problem hiding this comment.
suggestion (bug_risk): Bonus metadata is recorded even when the bonus is not actually applied
In apply_deterministic_signals, the result of signals.calculate_bonus() is always written to details["bonus_applied"] and details["bonuses"], even when signals.has_hard_failures() is true and the bonus is not added to adjusted_score. This makes the details inconsistent with final_score. Consider only recording bonus metadata when it affects the score, or add an explicit flag (e.g., bonus_suppressed_due_to_hard_failures) so consumers can distinguish computed vs applied bonuses.
Suggested implementation:
# Apply bonus for positive signals
bonus = signals.calculate_bonus()
if bonus > 0:
if signals.has_hard_failures():
# Bonus was computed but not applied due to hard failures
details["bonus_suppressed_due_to_hard_failures"] = True
else:
details["bonus_applied"] = bonus
if signals.test_coverage >= 80:
details["bonuses"].append(
f"High test coverage: {signals.test_coverage:.0f}%"
)
if signals.lint_passed:
details["bonuses"].append("Clean lint")
if signals.type_check_passed:
details["bonuses"].append("Clean type check")If there are tests or consumers relying on details["bonus_applied"] or details["bonuses"] always being present when calculate_bonus() returns a positive value, they should be updated to account for the new details["bonus_suppressed_due_to_hard_failures"] flag and the fact that bonus metadata is now only recorded when the bonus actually affects the score.
| def test_parse_valid_frontmatter(self, parser, tmp_path): | ||
| """Test parsing valid YAML frontmatter.""" | ||
| content = """--- | ||
| name: test-agent | ||
| description: A test agent for validation testing | ||
| tools: Read, Write, Bash | ||
| --- | ||
|
|
||
| You are a test agent. | ||
| """ |
There was a problem hiding this comment.
suggestion (testing): There are no tests covering validate_all_agents, so directory traversal and file skipping behavior are unverified.
validate_all_agents has substantial control flow (walking the tree with rglob, skipping _-prefixed/README files, handling parse returning None), but current tests only build AgentValidationResult manually and never call it. Please add an integration-style test that builds a small agents directory with: (1) a valid .md, (2) a malformed .md, and (3) a _partial.md or README.md to be skipped, then asserts that validate_all_agents returns the correct number of results, flags the malformed file as invalid, and omits skipped files.
Suggested implementation:
config = parser.parse(md_file)
# Files without YAML frontmatter should not produce a config
assert config is None
def test_validate_all_agents_integration(self, tmp_path):
"""Integration test for validate_all_agents over a small agents directory."""
# Create a directory structure with valid, invalid, and skipped agent files
agents_dir = tmp_path / "agents"
agents_dir.mkdir()
# 1. Valid markdown file
valid_content = """---
name: valid-agent
description: A valid test agent
tools: Read
---
You are a valid agent.
"""
valid_file = agents_dir / "valid-agent.md"
valid_file.write_text(valid_content)
# 2. Malformed markdown file (e.g. invalid YAML frontmatter)
invalid_content = """---
name: invalid-agent
description: This frontmatter is not valid YAML: [unclosed list
---
You are an invalid agent.
"""
invalid_file = agents_dir / "invalid-agent.md"
invalid_file.write_text(invalid_content)
# 3. Skipped markdown files
skipped_partial = agents_dir / "_partial.md"
skipped_partial.write_text(valid_content)
skipped_readme = agents_dir / "README.md"
skipped_readme.write_text(valid_content)
results = validate_all_agents(agents_dir)
# We should only see results for the valid and invalid agents
assert len(results) == 2
by_name = {result.name: result for result in results}
assert "valid-agent" in by_name
assert "invalid-agent" in by_name
assert by_name["valid-agent"].is_valid
assert not by_name["invalid-agent"].is_valid- Ensure
validate_all_agentsis imported at the top oftests/agents/test_schema_validation.py, for example:
from agents.schema_validation import validate_all_agents
(adjust the module path to wherevervalidate_all_agentsis actually defined). - This test assumes that:
validate_all_agents(path: Path)walks the directory tree (e.g. usingrglob("*.md")),- ignores files whose names start with
_or are exactlyREADME.md, - and returns an iterable of
AgentValidationResultobjects withnameandis_validattributes.
If yourAgentValidationResultuses different attribute names (e.g.agent_name,valid), update the assertions to match.
- If
validate_all_agentsrequires additional parameters (such as a parser instance, config, or logger), update the test callresults = validate_all_agents(agents_dir)to pass them, mirroring how the function is expected to be used in production code.
| class TestSignalsFromContext: | ||
| """Test extracting signals from context dictionary.""" | ||
|
|
||
| def test_extracts_test_results(self): | ||
| """Test extracting test results from context.""" | ||
| context = { | ||
| "test_results": { | ||
| "total": 100, | ||
| "failed": 5, | ||
| "passed": True, |
There was a problem hiding this comment.
suggestion (testing): signals_from_context tests omit type-check and build extraction, and the alternate security_results key path.
The helper also maps type_check_results, build_results, and either security_scan or security_results. Current tests don’t cover:
- mapping
type_check_results→type_check_passed/type_errors - mapping
build_results→build_passed/build_errors - using
security_resultswhensecurity_scanis absent
Please add focused tests for these cases to lock in the schema and avoid regressions if the context shape changes.
Suggested implementation:
class TestSignalsFromContext:
"""Test extracting signals from context dictionary."""
def test_extracts_type_check_results(self):
"""Test extracting type check results from context."""
context = {
"type_check_results": {
"passed": True,
"errors": ["E001", "E002"],
}
}
signals = signals_from_context(context)
assert signals["type_check_passed"] is True
assert signals["type_errors"] == ["E001", "E002"]
def test_extracts_build_results(self):
"""Test extracting build results from context."""
context = {
"build_results": {
"passed": False,
"errors": ["linker error", "missing symbol"],
}
}
signals = signals_from_context(context)
assert signals["build_passed"] is False
assert signals["build_errors"] == ["linker error", "missing symbol"]
def test_uses_security_results_when_scan_absent(self):
"""Test that security_results is used when security_scan is absent."""
context = {
"security_results": {
"passed": False,
"issues": ["CVE-1234", "Outdated dependency"],
}
}
signals = signals_from_context(context)
assert signals["security_passed"] is False
assert signals["security_issues"] == ["CVE-1234", "Outdated dependency"]
def test_extracts_test_results(self):
"""Test extracting test results from context."""
context = {
"test_results": {
"total": 100,
"failed": 5,
"passed": True,
"coverage": 0.85, # 85% as decimalThese edits assume:
- A
signals_from_contexthelper is already imported or defined in this test module (it should already be used bytest_extracts_test_results). If it is currently referenced with a module prefix (e.g.,deterministic_signals.signals_from_context), update the new tests to match that call style. - The
signals_from_contextimplementation actually maps:type_check_results.passed→type_check_passedtype_check_results.errors→type_errorsbuild_results.passed→build_passedbuild_results.errors→build_errorssecurity_results.passed→security_passed(whensecurity_scanis absent)security_results.issues→security_issues
If the actual key names differ (for example, using error_messages instead of errors), adjust the test dictionaries and assertions to use the concrete keys used in your existing signals_from_context implementation.
| def test_bonus_not_applied_with_failures(self, scorer): | ||
| """Test that bonuses are NOT applied when hard failures exist.""" | ||
| signals = DeterministicSignals( | ||
| tests_passed=False, | ||
| tests_total=10, | ||
| tests_failed=2, | ||
| test_coverage=85.0, # Good coverage, but tests failing | ||
| lint_passed=True, | ||
| lint_errors=0, | ||
| ) |
There was a problem hiding this comment.
nitpick (testing): It may be worth adding a control test where the base score is already below the hard cap to show apply_deterministic_signals is a no-op in that case.
Current tests only cover cases where a high base score is capped. Please also add a case where base_score is already below the computed cap while hard failures exist (e.g., base_score=40, tests_total=10, tests_failed=6) and assert adjusted_score == base_score to document that the function doesn’t reduce scores further when they’re already under the cap.
| def test_detects_alternating_pattern(self): | ||
| """Verify oscillation is detected when scores alternate.""" | ||
| scorer = QualityScorer() | ||
|
|
||
| # Scores that alternate up and down | ||
| oscillating_scores = [50.0, 60.0, 50.0, 60.0, 50.0] | ||
|
|
||
| for window_size in [3, 4, 5]: | ||
| if window_size <= len(oscillating_scores): | ||
| history = oscillating_scores[:window_size] |
There was a problem hiding this comment.
issue (testing): This oscillation test never asserts on _detect_oscillation's behavior, so it won't fail if the implementation regresses.
In test_detects_alternating_pattern, result = scorer._detect_oscillation(history) is never asserted, so the test would still pass if _detect_oscillation always returned the same value. Please either (a) construct a clearly oscillating window of length OSCILLATION_WINDOW (e.g. [50, 60, 50]) and assert it returns True, plus a nearby non‑oscillating pattern that asserts False, or (b) if the goal is only to ensure no crash, rename the test and make that explicit (though such a test is of limited value).
| def test_stagnation_threshold_is_configurable(self): | ||
| """Verify stagnation threshold is used correctly.""" | ||
| scorer = QualityScorer() | ||
|
|
||
| # Just above threshold | ||
| above_threshold = [ | ||
| 50.0, | ||
| 50.0 + scorer.STAGNATION_THRESHOLD + 0.1, | ||
| 50.0, | ||
| ] |
There was a problem hiding this comment.
issue (testing): Similarly, test_stagnation_threshold_is_configurable does not assert on _detect_stagnation, making it effectively a no-op.
This test computes above_threshold and calls _detect_stagnation but never asserts on the result, so it can’t fail and doesn’t verify configurability. Consider adding two explicit cases around STAGNATION_THRESHOLD: one where max(recent) - min(recent) is just below the threshold and should return True, and one just above that should return False. That way the test will fail if the threshold handling regresses.
| def test_successful_quality_improvement(self): | ||
| """Test normal case where quality threshold is met.""" | ||
| scorer = QualityScorer(threshold=70.0) | ||
|
|
||
| def improving_func(output, context): | ||
| current = output.get("quality", 0) | ||
| return {"quality": current + 30, "success": True} | ||
|
|
||
| _, assessment, results = scorer.agentic_loop( | ||
| initial_output={"quality": 50}, |
There was a problem hiding this comment.
suggestion (testing): The agentic loop integration tests do not assert on the termination reason, which is a key new safety signal.
Since termination_reason is now a key safety signal (quality met, max iterations, oscillation, stagnation, error), these integration tests should assert it in at least a couple of happy-path cases. For example, in test_successful_quality_improvement, please assert that the last IterationResult has termination_reason == IterationTermination.QUALITY_MET, rather than only checking that some results exist.
Suggested implementation:
_, assessment, results = scorer.agentic_loop(
initial_output={"quality": 50},
context={},
improver_func=improving_func,
max_iterations=3,
)
# Should have at least one iteration
assert len(results) >= 1
# The loop should terminate because the quality threshold was met
assert results[-1].termination_reason == IterationTermination.QUALITY_METIf not already present at the top of tests/quality/test_agentic_loop_safety.py, add an import for IterationTermination, for example:
from <your_module> import IterationTermination.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)
2-2: Stale comments reference old Python version matrix.The header comment (line 2) and section comment (line 48) still mention "Python 3.8-3.12" but the matrix is now Python 3.10 only.
-# Fail-fast quality gates with matrix testing across Python 3.8-3.12 +# Fail-fast quality gates with Python 3.10 testing- # Test Matrix - Python 3.8 through 3.12 + # Test Matrix - Python 3.10Also applies to: 48-48
🧹 Nitpick comments (7)
.github/workflows/ci.yml (1)
136-137: Coverage collection may be missing thesetuppackage.Based on learnings, coverage should be collected for both
SuperClaudeandsetuppackages. The current--cov=SuperClaudeflag only covers one package. Consider adding--cov=setupif the setup package contains testable code.pytest tests/ -m "not slow and not integration" \ --cov=SuperClaude \ + --cov=setup \ --cov-fail-under=35 \SuperClaude/Agents/parser.py (1)
22-29: Consider usingLiteraltype for severity field.The severity field accepts arbitrary strings but documents only three valid values. Using
Literal["error", "warning", "info"]would provide type-safety and IDE support.+from typing import Any, Dict, List, Literal, Optional, Set @dataclass class AgentSchemaError: """Represents a schema validation error.""" field: str message: str - severity: str = "error" # "error", "warning", "info" + severity: Literal["error", "warning", "info"] = "error" line_number: Optional[int] = None.github/workflows/ai-review.yml (1)
44-46: Shell pipeline could be simplified and made more robust.The current pipeline using multiple sed/tr commands is complex. Consider using a simpler approach:
- PYTHON_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep '\.py$' | head -20 | sed "s|^|$(pwd)/|" | tr '\n' ',' | sed 's/,$//') + PYTHON_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep '\.py$' | head -20 | while read f; do printf "%s/%s," "$(pwd)" "$f"; done | sed 's/,$//')Or for better readability, use a multi-line script block.
tests/test_commands.py (1)
44-68: Manual environment cleanup is redundant withmonkeypatch.The test uses
monkeypatch.delenv()at lines 41-42 but then manually stores/restores environment variables at lines 44-68. Themonkeypatchfixture automatically restores environment state after the test. This manual cleanup adds complexity without benefit and could mask issues if the test fails before cleanup.Use
monkeypatch.setenv()after the executor is created if you need to verify specific values, or simply rely on automatic cleanup:# Ensure no prior env overrides interfere monkeypatch.delenv("SUPERCLAUDE_REPO_ROOT", raising=False) monkeypatch.delenv("SUPERCLAUDE_METRICS_DIR", raising=False) - # Store original values to verify behavior - original_repo_root = os.environ.get("SUPERCLAUDE_REPO_ROOT") - original_metrics_dir = os.environ.get("SUPERCLAUDE_METRICS_DIR") - registry = CommandRegistry() parser = CommandParser() executor = CommandExecutor(registry, parser, repo_root=target_repo) assert executor.repo_root == target_repo.resolve() assert os.environ.get("SUPERCLAUDE_REPO_ROOT") == str(target_repo.resolve()) assert os.environ.get("SUPERCLAUDE_METRICS_DIR") == str( target_repo / ".superclaude_metrics" ) - - # Clean up environment variables set by CommandExecutor to prevent test pollution - # CommandExecutor.setdefault() modifies global os.environ directly - if original_repo_root is None: - os.environ.pop("SUPERCLAUDE_REPO_ROOT", None) - else: - os.environ["SUPERCLAUDE_REPO_ROOT"] = original_repo_root - - if original_metrics_dir is None: - os.environ.pop("SUPERCLAUDE_METRICS_DIR", None) - else: - os.environ["SUPERCLAUDE_METRICS_DIR"] = original_metrics_dirThe
monkeypatchfixture restores environment state automatically after the test completes.tests/agents/test_schema_validation.py (2)
10-11: Remove unused imports.The imports
Path,Any, andDictare flagged as unused by static analysis. WhilePathis used withtmp_pathin parsing tests (lines 372-414), the typing importsAnyandDictaren't strictly necessary for test files.Apply this diff:
-from pathlib import Path -from typing import Any, Dict +from pathlib import Path
355-414: Clarify intent of unused variable in malformed YAML test.Line 411's
configvariable is intentionally unused—the test verifies that parsing malformed YAML doesn't crash. Consider adding a comment or assertion to make the intent explicit.Apply this diff to clarify intent:
# Should not raise, may return empty or partial config config = parser.parse(md_file) - # Parser should handle gracefully (either None or empty dict) - # The key is no exception is raised + # Parser should handle gracefully without raising + assert config is not None or config is None # Either outcome is acceptableREADME.md (1)
503-548: Add language specifiers to code blocks.Two fenced code blocks (lines 537 and 544) are missing language specifiers, which is flagged by markdownlint.
Apply this diff:
#### Token Efficiency Symbols -``` +```text Status: ✅ Done ❌ Failed ⚠️ Warning 🔄 Progress ⏳ Pending Domain: ⚡ Perf 🔍 Analysis 🛡️ Security 📦 Deploy 🏗️ Arch Logic: → Leads to ⇒ Transforms ∴ Therefore » SequenceExample:
-+text
Standard: "The authentication system has a security vulnerability"
Token Efficient: "auth.js:45 → 🛡️ sec risk in user val()"
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/workflows/ai-review.yml(4 hunks).github/workflows/ci.yml(4 hunks)README.md(12 hunks)SuperClaude/Agents/parser.py(2 hunks)SuperClaude/Quality/quality_scorer.py(10 hunks)pyproject.toml(4 hunks)tests/agents/test_schema_validation.py(1 hunks)tests/conftest.py(1 hunks)tests/quality/test_agentic_loop_safety.py(1 hunks)tests/quality/test_deterministic_signals.py(1 hunks)tests/test_commands.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code targets 3.8+ with Black (88 cols), Flake8, and MyPy; use 4-space indents
Use snake_case for Python module and variable names
Use PascalCase for Python agent classes aligned with their persona names
Files:
tests/quality/test_agentic_loop_safety.pytests/test_commands.pySuperClaude/Agents/parser.pytests/quality/test_deterministic_signals.pytests/conftest.pySuperClaude/Quality/quality_scorer.pytests/agents/test_schema_validation.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.py: Mirror production paths when adding tests (tests//test_.py) and name test functions test_
Mark slower test journeys with @pytest.mark.slow or @pytest.mark.integration per pyproject.toml
Include fixtures that validate requires_evidence guardrails and .superclaude_metrics outputs whenever agent workflows, telemetry, or auto-implementation logic changes
Files:
tests/quality/test_agentic_loop_safety.pytests/test_commands.pytests/quality/test_deterministic_signals.pytests/conftest.pytests/agents/test_schema_validation.py
{README.md,Docs/**/*.md,.codex-os/**/*.md}
📄 CodeRabbit inference engine (AGENTS.md)
{README.md,Docs/**/*.md,.codex-os/**/*.md}: Markdown guidance in README, Docs/, and .codex-os/ should use ATX headings
Markdown guidance should link to decisions or specs when behavior changes
Files:
README.md
**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Markdown files should wrap text near 100 characters
Files:
README.md
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Pull Requests should describe risk surface, highlight configuration changes (e.g., MCP updates), and note any follow-up tasks for consensus, telemetry, or cleanup tooling
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Collect coverage for SuperClaude and setup packages in test runs
Applied to files:
.github/workflows/ci.ymlREADME.mdtests/test_commands.pytests/conftest.py
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Applies to tests/**/*.py : Include fixtures that validate requires_evidence guardrails and .superclaude_metrics outputs whenever agent workflows, telemetry, or auto-implementation logic changes
Applied to files:
.github/workflows/ci.ymltests/quality/test_agentic_loop_safety.pyREADME.mdtests/test_commands.pytests/quality/test_deterministic_signals.pytests/conftest.pytests/agents/test_schema_validation.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Applies to SuperClaude/Core/**/*.{rs,tsx,sol,ipynb,tf} : Auto-select agent based on file context: `.rs` files → rust-engineer, `.tsx` with React imports → react-specialist, `Dockerfile` → devops-architect, `.sol` smart contracts → blockchain-developer, `.ipynb` ML notebooks → ml-engineer, `terraform.tf` → terraform-engineer
Applied to files:
README.md
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Review Task outputs with quality score 70-89 for acceptability before production deployment
Applied to files:
README.md
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Accept Task outputs with quality score ≥ 90 as production-ready without review
Applied to files:
README.md
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Always consult .claude/settings.json before running shell commands and respect denyList, askList, and other guardrails
Applied to files:
README.md
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Applies to **/*.py : Python code targets 3.8+ with Black (88 cols), Flake8, and MyPy; use 4-space indents
Applied to files:
pyproject.toml
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Auto-iterate with specialist suggestion when Task output receives quality score < 70
Applied to files:
SuperClaude/Quality/quality_scorer.py
🧬 Code graph analysis (2)
tests/quality/test_agentic_loop_safety.py (1)
SuperClaude/Quality/quality_scorer.py (5)
IterationResult(71-80)IterationTermination(83-92)agentic_loop(488-681)_detect_oscillation(683-708)_detect_stagnation(710-724)
tests/quality/test_deterministic_signals.py (1)
SuperClaude/Quality/quality_scorer.py (7)
DeterministicSignals(112-208)has_hard_failures(142-148)get_hard_failure_cap(150-174)calculate_bonus(176-208)apply_deterministic_signals(735-814)evaluate_with_signals(816-867)signals_from_context(870-920)
🪛 actionlint (1.7.9)
.github/workflows/ai-review.yml
56-56: input "timeout_minutes" is not defined in action "anthropics/claude-code-action@v1". available inputs are "additional_permissions", "allowed_bots", "allowed_non_write_users", "anthropic_api_key", "assignee_trigger", "base_branch", "bot_id", "bot_name", "branch_prefix", "claude_args", "claude_code_oauth_token", "experimental_allowed_domains", "github_token", "label_trigger", "path_to_bun_executable", "path_to_claude_code_executable", "plugin_marketplaces", "plugins", "prompt", "settings", "show_full_output", "track_progress", "trigger_phrase", "use_bedrock", "use_commit_signing", "use_sticky_comment", "use_vertex"
(action)
🪛 GitHub Check: CodeQL
tests/quality/test_agentic_loop_safety.py
[notice] 13-13: Unused import
Import of 'pytest' is not used.
[notice] 100-100: Unused local variable
Variable result is not used.
[notice] 162-162: Unused local variable
Variable result is not used.
tests/agents/test_schema_validation.py
[notice] 10-10: Unused import
Import of 'Path' is not used.
[notice] 11-11: Unused import
Import of 'Any' is not used.
Import of 'Dict' is not used.
[notice] 411-411: Unused local variable
Variable config is not used.
🪛 markdownlint-cli2 (0.18.1)
README.md
537-537: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
544-544: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Security Summary
- GitHub Check: Sourcery review
🔇 Additional comments (41)
pyproject.toml (1)
15-15: Python 3.10 minimum version is consistently applied across all tooling.The version bump is properly coordinated across
requires-python, Black, MyPy, and Ruff configurations. Note that per the retrieved coding guidelines, the project previously targeted Python 3.8+. Ensure this version bump is intentional and that downstream users/documentation are updated accordingly.Also applies to: 76-76, 93-93, 141-141
SuperClaude/Agents/parser.py (2)
471-506: Batch validation implementation is well-structured.Good defensive handling for parse failures (lines 494-500) and appropriate filtering of non-agent files. The explicit error result for failed parsing ensures no silent failures.
415-419: The regex pattern^[a-z][a-z0-9-]*$correctly enforces the established naming convention. All existing agent names in the repository follow this lowercase-hyphenated format (backend-architect, python-expert, security-engineer, etc.), confirming this is the intended and consistent convention. The PascalCase guideline applies to Python class names, not the agentnamefield, so there is no conflict..github/workflows/ai-review.yml (1)
126-128: Verify PAL MCP server configuration is available.The workflow references
mcp__pal__codereviewandmcp__pal__consensustools, which require a PAL MCP server to be configured. Ensure the Claude Code Action has access to the PAL MCP server, either via plugin configuration or external setup.Based on learnings, PR descriptions should highlight configuration changes (e.g., MCP updates).
tests/test_commands.py (1)
80-88: Skip annotation is well-documented.Good practice to include both the decorator reason and a detailed docstring explaining the context. This helps future maintainers understand when/if to re-enable the test.
tests/conftest.py (2)
42-54: LGTM! Solid test isolation fixture.The
reset_working_directoryfixture correctly captures and restores the working directory to prevent test pollution frommonkeypatch.chdir()operations.
57-82: LGTM! Environment variable isolation implemented correctly.The
reset_superclaude_env_varsfixture properly handles both restoration and removal of environment variables to prevent cross-test pollution. The logic correctly distinguishes between originally-set and unset variables.tests/agents/test_schema_validation.py (5)
23-62: LGTM! Comprehensive schema constant validation.The test class thoroughly validates all schema constants (required fields, recommended fields, valid tools, categories) and verifies max length boundaries are reasonable.
64-122: LGTM! Error and validation result dataclasses well-tested.Tests confirm proper creation, default severity, error/warning accumulation, and invalidation behavior of the validation result structures.
124-269: LGTM! Validation logic thoroughly exercised.The
TestSchemaValidationclass covers minimal/full configs, missing required fields, length constraints, format warnings, tools parsing (string/list), and unknown tool/category warnings comprehensively.
271-294: LGTM! Boolean validation API tested.Tests confirm the simple
validate_agent_configmethod returns correct boolean values for valid/invalid configs.
296-353: LGTM! Validation summary generation well-covered.Tests validate summary calculation including total counts, pass rates, invalid agent details, and error/warning aggregation.
tests/quality/test_deterministic_signals.py (6)
18-70: LGTM! Comprehensive hard failure detection tests.Tests cover all hard failure scenarios: failing tests, critical security issues, build failures, and the absence of hard failures when everything passes.
72-136: LGTM! Hard failure cap calculation thoroughly tested.Tests validate all cap tiers: critical security (30), high test failure rate (40), medium failure rate (50), low failure rate (60), build failure (45), high security issues (65), and no cap (100).
138-202: LGTM! Bonus calculation logic well-covered.Tests verify coverage bonuses (high/medium), clean lint, type check, all tests passing, security scan passed, and the 25-point cap on total bonuses.
204-266: LGTM! Signal application integration tested.Tests confirm failing tests cap scores, critical security issues enforce strict caps, bonuses apply without failures, and bonuses don't apply with failures present.
268-308: LGTM! Metadata grounding and improvement propagation verified.Tests ensure signals are recorded in metadata with
signals_grounded=Trueand that hard failures are prepended toimprovements_neededwith "FIX:" prefix.
310-382: LGTM! Context extraction logic thoroughly tested.Tests validate extraction of test results, lint results, security scans, handling of missing context, and coverage percentage normalization.
tests/quality/test_agentic_loop_safety.py (5)
22-83: LGTM! Hard max iteration safety verified.Tests confirm the hard cap cannot be overridden, default limits are conservative (MAX=3, HARD_MAX=5), and termination reasons are properly set when limits are reached.
85-123: LGTM! Oscillation detection tested.Tests verify oscillation detection for alternating patterns, no false positives on steady improvement, and requirement for minimum history before detection.
Note: Lines 100 and 162 have intentionally unused
resultvariables—these tests verify the detection methods don't crash with various input patterns.
125-164: LGTM! Stagnation detection validated.Tests confirm flat score detection, no false positives on meaningful improvement, and that the stagnation threshold is respected.
166-217: LGTM! Termination structures properly tested.Tests validate the
IterationResult.termination_reasonfield exists with correct default, and allIterationTerminationconstants are defined and are non-empty strings.
219-283: LGTM! Agentic loop integration comprehensively tested.Tests cover successful quality improvement, error handling with proper termination reason propagation, and context metadata propagation (iteration, max_iterations, remaining_iterations).
README.md (9)
1-80: LGTM! Clear framework overview with updated metrics.The opening sections correctly reflect version 6.0.0-alpha with 131 agents, 13 commands, and 8 models. The overview diagram effectively communicates the framework architecture.
82-254: LGTM! Architecture diagrams are comprehensive.The high-level system architecture and request flow diagrams clearly illustrate component relationships, execution flow, and quality validation. The diagrams align with the updated component counts.
200-335: LGTM! Agent system documentation is detailed.The agent architecture, selection algorithm, categories breakdown (131 total), and coordination strategies are well-documented with clear mermaid diagrams and tables.
338-387: LGTM! Command system clearly documented.The command system section effectively describes the 13 available commands with their purposes and key flags, supported by a clear architecture diagram showing sub-executors.
390-438: LGTM! Model router documentation is comprehensive.The model router section clearly documents the 8 supported models with context windows, features, priorities, and routing strategies. The updated mappings reflect current provider offerings.
441-500: LGTM! MCP integrations well-documented.The MCP architecture diagram and tool tables for Rube MCP (500+ apps) and PAL MCP (consensus & analysis) are clear and comprehensive.
551-613: LGTM! Quality pipeline documentation is thorough.The validation pipeline diagram and quality scoring breakdown (8 dimensions with weights) effectively communicate the framework's quality assurance approach.
616-844: LGTM! Installation, configuration, and project structure are well-documented.The sections cover installation requirements, environment setup, quick start examples, configuration files, CI/CD pipeline, and comprehensive project structure. All content aligns with the updated framework architecture.
846-906: LGTM! Contributing guidelines and acknowledgments are clear.The contributing section provides clear development setup instructions, agent creation guidelines, and commit conventions. Acknowledgments properly credit all providers and tools.
SuperClaude/Quality/quality_scorer.py (9)
70-92: LGTM! Termination tracking structures well-designed.The
IterationResult.termination_reasonfield andIterationTerminationconstants provide clear, explicit tracking of why agentic loops terminate, enhancing debuggability and observability.
111-209: LGTM! Deterministic signals provide robust quality grounding.The
DeterministicSignalsdataclass and its helper methods (has_hard_failures,get_hard_failure_cap,calculate_bonus) effectively ground quality scoring in verifiable facts from test/lint/build/security execution.Note: The hard failure cap tiers are well-calibrated:
- Critical security: 30 (strictest)
- High test failure (>50%): 40
- Medium test failure (20-50%): 50
- Low test failure (<20%): 60
- Build failure: 45
- High security issues: 65
221-226: LGTM! Conservative iteration limits prevent runaway loops.Reducing
MAX_ITERATIONSfrom 5 to 3 and addingHARD_MAX_ITERATIONS=5withOSCILLATION_WINDOW=3andSTAGNATION_THRESHOLD=2.0provides layered protection against infinite loops while allowing reasonable improvement attempts.
488-656: LGTM! Agentic loop safety features comprehensively implemented.The enhanced
agentic_loopmethod includes:
- P0: Hard max iteration cap enforcement (lines 515-522)
- P0: Oscillation detection (lines 558-574)
- P0: Stagnation detection (lines 576-592)
- Proper termination reason propagation throughout
- Context enrichment with iteration metadata (lines 621-623)
- Error handling with termination tracking (lines 643-656)
All safety features are well-implemented with appropriate logging and termination reason recording.
663-676: LGTM! Final evaluation and summary logging added.The final evaluation updates iteration results with accurate scores and termination reasons, and logs a comprehensive summary including final score, pass status, and termination reason for debugging.
683-724: LGTM! Oscillation and stagnation detection algorithms are sound.The
_detect_oscillationmethod correctly identifies alternating score patterns (up/down/up or down/up/down) by checking for consecutive direction changes. The_detect_stagnationmethod appropriately detects when scores remain withinSTAGNATION_THRESHOLDacross theOSCILLATION_WINDOW.Algorithm validation:
- Oscillation: Requires alternating directions with meaningful changes (>
STAGNATION_THRESHOLD)- Stagnation: Requires all recent scores within 2.0 points of each other
- Both require minimum history (
OSCILLATION_WINDOW=3)
735-814: LGTM! Signal application logic correctly implements hard caps and bonuses.The
apply_deterministic_signalsmethod:
- Applies hard failure caps when present (lines 762-789)
- Calculates and records bonuses (lines 792-806)
- Only applies bonuses when no hard failures exist (lines 808-809)
- Returns detailed adjustment metadata
This ensures that hard failures always gate scores, while bonuses only apply to otherwise-clean code.
816-867: LGTM! Signal-grounded evaluation integrates seamlessly.The
evaluate_with_signalsmethod properly combines base evaluation with deterministic signal adjustments, updates pass/fail status based on adjusted scores, and prepends hard failure FIX items to improvements_needed.
869-920: LGTM! Context extraction handles various input formats.The
signals_from_contextstatic method robustly extracts deterministic signals from context dictionaries, handling:
- Test results with coverage normalization (fraction vs. percentage)
- Lint, type check, build, and security results
- Missing context keys gracefully (defaults to safe values)
| with: | ||
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | ||
| timeout_minutes: 10 | ||
| timeout_minutes: 15 |
There was a problem hiding this comment.
Remove deprecated timeout_minutes input from claude-code-action@v1 usage.
timeout_minutes is a deprecated input that was replaced in v1. Remove this line or move timeout configuration to GitHub Actions' job-level timeout-minutes setting. If you need to limit execution iterations, use claude_args: "--max-turns <value>" instead.
🧰 Tools
🪛 actionlint (1.7.9)
56-56: input "timeout_minutes" is not defined in action "anthropics/claude-code-action@v1". available inputs are "additional_permissions", "allowed_bots", "allowed_non_write_users", "anthropic_api_key", "assignee_trigger", "base_branch", "bot_id", "bot_name", "branch_prefix", "claude_args", "claude_code_oauth_token", "experimental_allowed_domains", "github_token", "label_trigger", "path_to_bun_executable", "path_to_claude_code_executable", "plugin_marketplaces", "plugins", "prompt", "settings", "show_full_output", "track_progress", "trigger_phrase", "use_bedrock", "use_commit_signing", "use_sticky_comment", "use_vertex"
(action)
🤖 Prompt for AI Agents
.github/workflows/ai-review.yml around line 56: the workflow uses the deprecated
action input timeout_minutes for claude-code-action@v1; remove the
timeout_minutes line from the action step and instead set a job-level
timeout-minutes in the workflow if you need a hard job timeout, or pass
claude_args: "--max-turns <value>" to limit Claude's iterations; update the file
to delete the timeout_minutes key and, if desired, add/adjust the workflow job's
timeout-minutes or add the claude_args option accordingly.
| VALID_TOOLS: Set[str] = { | ||
| "Read", "Write", "Edit", "MultiEdit", "Bash", "Glob", "Grep", | ||
| "Task", "TodoWrite", "WebFetch", "WebSearch", "NotebookEdit", | ||
| # MCP tools | ||
| "Docker", "docker", "database", "redis", "postgresql", "postgres", | ||
| "mcp", "Browser", "browser", "playwright", | ||
| } |
There was a problem hiding this comment.
Tool validation may produce false warnings due to case sensitivity.
VALID_TOOLS contains both "Docker" and "docker", suggesting case-insensitive matching was intended. However, line 452 performs a direct in check without normalizing case, so "DOCKER" or "Docker" would trigger a warning.
Consider normalizing the comparison:
- if tool and tool not in AgentSchema.VALID_TOOLS:
+ if tool and tool.lower() not in {t.lower() for t in AgentSchema.VALID_TOOLS}:Or simplify VALID_TOOLS to use consistent lowercase and normalize input.
Also applies to: 451-457
🤖 Prompt for AI Agents
In SuperClaude/Agents/parser.py lines 67-73 (and where tools are checked around
451-457), VALID_TOOLS mixes casing which causes case-sensitive membership checks
to emit false warnings; make VALID_TOOLS contain normalized lowercase names (or
rebuild it via a set comprehension like {t.lower() for t in ...}) and update the
validation logic to compare using tool_name.lower() (or otherwise normalize the
checked value) so lookups are case-insensitive and duplicate mixed-casing
entries can be removed.
- Replace typing.Dict/List/Tuple with built-in dict/list/tuple - Replace Optional[X] with X | None - Import AsyncIterator/Mapping from collections.abc - Fix unused variable warnings in tests - Apply ruff format to all affected files Fixes CI Quality Gate failure from pyupgrade rules (UP006/UP035/UP045) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| self.analysis_agent = None | ||
|
|
||
| def validate(self, context: Dict[str, Any]) -> bool: | ||
| def validate(self, context: dict[str, Any]) -> bool: |
Check warning
Code scanning / CodeQL
Variable defined multiple times Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 9 months ago
To fix this problem, we should remove the first (redundant) validate method defined at line 188–193 in the SecurityEngineer class. Only the second method (lines 247–284) should remain. No other changes are necessary, as this will not alter the functionality—the SecurityEngineer class will continue to use the (intended) final version of validate.
| @@ -185,11 +185,6 @@ | ||
| self.logger.debug(f"SecurityAnalysisAgent unavailable: {exc}") | ||
| self.analysis_agent = None | ||
|
|
||
| def validate(self, context: dict[str, Any]) -> bool: | ||
| task = str(context.get("task", "")).lower() | ||
| if any(keyword in task for keyword in self.SECURITY_KEYWORDS): | ||
| return True | ||
| return super().validate(context) or self.analysis_agent.validate(context) | ||
|
|
||
| def execute(self, context: dict[str, Any]) -> dict[str, Any]: | ||
| result = super().execute(context) |
| self.doc_agent.logger = self.logger | ||
|
|
||
| def validate(self, context: Dict[str, Any]) -> bool: | ||
| def validate(self, context: dict[str, Any]) -> bool: |
Check warning
Code scanning / CodeQL
Variable defined multiple times Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 9 months ago
To fix the problem, remove the first, redundant definition of validate in the TechnicalWriter class (lines 148–156). Only the second, later definition (lines 203–232) will remain, ensuring no duplicate methods and avoiding the accidental hiding of intended logic. No additional imports or special methods are required—just surgically delete the earlier definition. All required code for validate remains present in the class, and no existing functionality will change as the overridden method was never being run.
| @@ -145,15 +145,6 @@ | ||
| self.doc_agent = TechnicalDocumentationAgent(dict(merged)) | ||
| self.doc_agent.logger = self.logger | ||
|
|
||
| def validate(self, context: dict[str, Any]) -> bool: | ||
| task = str(context.get("task", "")).lower() | ||
| if any(keyword in task for keyword in self.DOC_KEYWORDS): | ||
| return True | ||
| subject = str(context.get("subject", "")).lower() | ||
| if any(keyword in subject for keyword in self.DOC_KEYWORDS): | ||
| return True | ||
| return super().validate(context) or self.doc_agent.validate(context) | ||
|
|
||
| def execute(self, context: dict[str, Any]) -> dict[str, Any]: | ||
| result = super().execute(context) | ||
|
|
The builtin `callable` function cannot be used in type annotations with the union operator in Python 3.10. Use `Callable` from collections.abc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (11)
setup/utils/updater.py (1)
315-315: Update type annotation for consistency with Python 3.10+ modernization.The parameter annotation should use
str | None = Noneinstead ofstr = Noneto maintain consistency with the modernization applied on line 88 and to satisfy strict type checkers.Apply this diff:
-def check_for_updates(current_version: str = None, **kwargs) -> bool: +def check_for_updates(current_version: str | None = None, **kwargs) -> bool:SuperClaude/Agents/core/security.py (1)
247-283: Duplicatevalidatemethod shadows the first implementation.This second
validatemethod (lines 247-283) completely overrides the first one at lines 188-192. The first implementation has important fallback logic (super().validate(context)andself.analysis_agent.validate(context)) that is lost.Additionally, this method re-defines
security_keywordsas a local list instead of using the class constantSECURITY_KEYWORDS.Remove this duplicate method entirely:
- def validate(self, context: dict[str, Any]) -> bool: - """ - Check if this agent can handle the context. - - Args: - context: Validation context - - Returns: - True if context contains security-related tasks - """ - task = context.get("task", "") - - # Check for security keywords - security_keywords = [ - "security", - "vulnerability", - "secure", - "auth", - "authentication", - "authorization", - "permission", - "encrypt", - "decrypt", - "hash", - "owasp", - "pentest", - "penetration", - "exploit", - "injection", - "xss", - "csrf", - "sql injection", - "security audit", - ] - - task_lower = task.lower() - return any(keyword in task_lower for keyword in security_keywords)setup/cli/commands/update.py (1)
357-359: Potential NameError if component_instances and components diverge.The code references
mcp_instance(defined at Line 319) but checksif "mcp" in component_instancesrather thanif "mcp" in components. If component instance creation partially fails,mcp_instancemay not be defined, causing a NameError.Consider guarding the reference:
- "selected_mcp_servers": list(mcp_instance.mcp_servers.keys()) - if "mcp" in component_instances + "selected_mcp_servers": list(mcp_instance.mcp_servers.keys()) + if "mcp" in components and "mcp" in component_instances else [],Or define
mcp_instanceoutside the conditional with a default value.SuperClaude/APIClients/xai_client.py (1)
436-466: Fixestimate_costreturn type to include error payloads
estimate_costis annotated asdict[str, float]but can return{"error": "Unknown model"}, which violates the annotation and will confuse static type checkers.Consider either:
- Widening the return type, e.g.
dict[str, float | int | str]ordict[str, Any], or- Always returning the full numeric cost schema and attaching an
"error"key optionally, while keeping numeric types for the core fields.Right now the signature does not reflect actual behavior.
setup/cli/commands/uninstall.py (3)
214-239: Uninstall component types are narrower than actualget_installed_componentsshape
get_installed_components(andSettingsService.get_installed_components) returndict[str, dict[str, Any]], butget_components_to_uninstallis annotated asinstalled_components: dict[str, str]. At call sites (e.g.,info["components"]inrun), the values are dicts, not strings.The implementation only uses the keys, so this is a typing/clarity issue, not a runtime bug, but it will trip static analysis. Consider relaxing this to something like:
def get_components_to_uninstall( args: argparse.Namespace, installed_components: dict[str, Any], ) -> list[str] | None: ...or even a
Mapping[str, Any]to reflect actual usage.
680-707:create_uninstall_backupcurrently creates an empty tarball
create_uninstall_backupcreates a.tar.gzand logs success, but never adds any files to the archive (the loop body only instantiatesSettingsServiceandpasses). Users may interpret the log as indicating a real backup exists when it does not.Either:
- Implement the component‑specific backup logic (adding files to the tarball), or
- Make it explicit that backups are not yet implemented (e.g., log a warning and skip tar creation, or raise
NotImplementedErrorfrom this helper).As written, it gives a false sense of safety around uninstall operations.
860-867: Home-directory safety check should usePathcontainment, not string prefixThe new guard:
expected_home = Path.home().resolve() actual_dir = args.install_dir.resolve() if not str(actual_dir).startswith(str(expected_home)): ... sys.exit(1)is vulnerable to false positives/negatives because it compares string prefixes. For example,
/home/user2starts with/home/userbut is not inside that directory. This weakens the intended safety guarantee for destructive uninstall operations.Use a proper path containment check instead, e.g.:
- expected_home = Path.home().resolve() - actual_dir = args.install_dir.resolve() - - if not str(actual_dir).startswith(str(expected_home)): + expected_home = Path.home().resolve() + actual_dir = args.install_dir.resolve() + + try: + actual_dir.relative_to(expected_home) + except ValueError: print("\n[✗] Installation must be inside your user profile directory.") print(f" Expected prefix: {expected_home}") print(f" Provided path: {actual_dir}") sys.exit(1)This ensures only real descendants of the home directory are accepted.
SuperClaude/Commands/command_executor.py (1)
4467-4492: Use module logger instead of undefinedself.loggerin fast‑codex fallbackIn
_apply_fast_codex_mode, the branch where Codex CLI is unavailable usesself.logger:if not CodexCLIClient.is_available(): # Codex CLI integration removed - graceful fallback to standard mode self.logger.warning( "--fast-codex requested but Codex CLI not available, " "falling back to standard mode" ) ...
self.loggeris never defined onCommandExecutor, so this will raiseAttributeErrorwhenever--fast-codexis requested (andCodexCLIClient.is_available()isFalse, which it currently always is).Switch to the module‑level
loggerused elsewhere in this file:- if not CodexCLIClient.is_available(): - # Codex CLI integration removed - graceful fallback to standard mode - self.logger.warning( + if not CodexCLIClient.is_available(): + # Codex CLI integration removed - graceful fallback to standard mode + logger.warning( "--fast-codex requested but Codex CLI not available, " "falling back to standard mode" )This restores the intended graceful fallback without crashing the command.
SuperClaude/Commands/executor/agent_orchestration.py (1)
381-405: Import and use the existingnormalize_evidence_valueutility fromSuperClaude/Commands/executor/utils.pyinstead of duplicating the function.The function already exists as a public utility at
SuperClaude/Commands/executor/utils.py:29and is properly exported. Bothagent_orchestration.pyandcommand_executor.pyshould import this shared function instead of maintaining duplicate private implementations.setup/core/registry.py (1)
389-421: Typo:anyshould beAnyin return type annotation.Line 389 uses
dict[str, any]butanyis Python's built-in function, not a type. This should bedict[str, Any](uppercase) from thetypingmodule.Apply this diff to fix the typo:
- def get_registry_info(self) -> dict[str, any]: + def get_registry_info(self) -> dict[str, Any]:You'll also need to add the import at the top of the file:
from typing import AnySuperClaude/Agents/core/technical_writer.py (1)
148-155: Critical: Duplicatevalidatemethod definition.The
validatemethod is defined twice in theTechnicalWriterclass:
- First at lines 148-155 (checking
DOC_KEYWORDS)- Second at lines 203-231 (checking
doc_keywordslist)The second definition will override the first, making lines 148-155 dead code. Both implementations have similar logic but different code styles.
Solution: Remove one of the duplicate definitions. Based on the context, lines 203-231 appear to be the duplicate since lines 148-155 are part of the
TechnicalWriterclass that inherits fromHeuristicMarkdownAgent, which likely already has validation logic.Apply this diff to remove the duplicate:
- def validate(self, context: dict[str, Any]) -> bool: - """ - Check if this agent can handle the context. - - Args: - context: Validation context - - Returns: - True if context contains documentation task - """ - task = context.get("task", "") - - # Check for documentation keywords - doc_keywords = [ - "document", - "documentation", - "docs", - "readme", - "explain", - "describe", - "write docs", - "api docs", - "user guide", - "technical docs", - "comment", - ] - - task_lower = task.lower() - return any(keyword in task_lower for keyword in doc_keywords) -Also applies to: 203-231
♻️ Duplicate comments (4)
SuperClaude/Quality/quality_scorer.py (2)
112-149:has_hard_failures()missingsecurity_highcheck — previously flagged.The
has_hard_failures()method does not includesecurity_high > 0, butget_hard_failure_cap()at line 172-173 returns a cap of 65.0 whensecurity_high > 0. This inconsistency means high-severity security issues won't trigger the hard failure cap logic correctly inapply_deterministic_signals.Add
security_highto the hard failures check:def has_hard_failures(self) -> bool: """Check for any hard failures that should cap the score.""" return ( self.tests_failed > 0 or self.security_critical > 0 + or self.security_high > 0 or (not self.build_passed and self.build_errors > 0) )
794-814: Bonus metadata recorded even when bonus is not applied — previously flagged.When
signals.has_hard_failures()is true, the bonus is computed and its metadata (details["bonus_applied"],details["bonuses"]) is recorded, but the bonus is not added toadjusted_score. This makes the metadata inconsistent with the actualfinal_score.Consider only recording bonus metadata when the bonus actually affects the score, or add an explicit flag like
bonus_suppressed_due_to_hard_failures:# Apply bonus for positive signals bonus = signals.calculate_bonus() if bonus > 0: - details["bonus_applied"] = bonus - - if signals.test_coverage >= 80: - details["bonuses"].append( - f"High test coverage: {signals.test_coverage:.0f}%" - ) - # ... other bonus recording ... - - # Only apply bonus if no hard failures - if not signals.has_hard_failures(): - adjusted_score = min(100.0, adjusted_score + bonus) + if signals.has_hard_failures(): + details["bonus_suppressed_due_to_hard_failures"] = True + else: + details["bonus_applied"] = bonus + # Record bonus details only when applied + if signals.test_coverage >= 80: + details["bonuses"].append( + f"High test coverage: {signals.test_coverage:.0f}%" + ) + # ... other bonus recording ... + adjusted_score = min(100.0, adjusted_score + bonus)tests/agents/test_schema_validation.py (1)
1-411: Address static analysis warnings and missing test coverage.This comprehensive test suite provides excellent coverage for the schema validation infrastructure. However, there are two items to address:
Static analysis warnings: Unused imports have been flagged (
Path,Any,Dict). Please remove these to keep the code clean.Missing integration test: As noted in a past review,
validate_all_agentslacks test coverage for directory traversal, file skipping (_-prefixed/README files), and error handling. Consider adding an integration test that:
- Creates a temporary agents directory with valid, invalid, and skipped markdown files
- Calls
validate_all_agents- Verifies correct file filtering and validation results
Based on learnings, ensure test fixtures validate requires_evidence guardrails when extending agent workflow tests.
SuperClaude/Agents/parser.py (1)
52-110: Schema constants are well-defined with reasonable limits.The separation of required vs. recommended fields, max lengths, and valid tool/category sets provides a solid foundation for validation. The mixed casing in
VALID_TOOLS(e.g., both"Docker"and"docker") was already flagged in a prior review for case-insensitive normalization.
🧹 Nitpick comments (12)
setup/utils/updater.py (1)
168-168: Verify Path comparison logic for user installation detection.The expression
Path.home() in Path(result.stdout)performs a Path-in-Path membership test that likely doesn't work as intended. Theresult.stdoutis a string frompip show, not a filesystem path, and checking if a Path object is "in" another Path constructed from that string won't correctly detect user installations.Consider this fix to properly check if the home directory appears in the pip show output:
- if "--user" in result.stdout or Path.home() in Path(result.stdout): + if "--user" in result.stdout or str(Path.home()) in result.stdout:Alternatively, verify the current logic works as expected:
#!/bin/bash # Verify how pip show output is structured and whether Path comparison works # Show sample pip show output format for SuperClaude python3 -m pip show SuperClaude 2>/dev/null || echo "SuperClaude not installed via pip" # Test the Path membership behavior in Python python3 -c " from pathlib import Path test_output = 'Location: /home/user/.local/lib/python3.10/site-packages' print(f'Path.home(): {Path.home()}') print(f'str(Path.home()): {str(Path.home())}') print(f'Path.home() in Path(test_output): {Path.home() in Path(test_output)}') print(f'str(Path.home()) in test_output: {str(Path.home()) in test_output}') "SuperClaude/Commands/executor/testing.py (1)
39-42: Document the newrepo_rootparameter.The
repo_rootparameter provides a useful override for the working directory, but the docstring doesn't document any parameters. Consider expanding the docstring to explain the purpose and default behavior ofrepo_root.Apply this diff to improve the docstring:
def run_requested_tests( parsed: "ParsedCommand", repo_root: Path | None = None, ) -> dict[str, Any]: - """Execute project tests and capture results.""" + """ + Execute project tests and capture results. + + Args: + parsed: Parsed command containing test parameters, flags, and targets. + repo_root: Optional root directory for test execution. Defaults to current working directory. + + Returns: + Dictionary containing test results, metrics, coverage, and execution details. + """setup.py (1)
118-122: Update classifiers to match Python version requirement.If updating
python_requiresto>=3.10per PR objectives, also remove the Python 3.9 classifier to maintain consistency:"Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12",SuperClaude/APIClients/anthropic_client.py (1)
528-530: Consider using truthiness check for empty dict.The condition
thinking_cfg == {}works butnot thinking_cfgis more idiomatic Python for checking if a dict is empty or None-like (sinceNoneand{}both evaluate to falsy).- if (thinking_cfg is None or thinking_cfg == {}) and self.config.enable_thinking: + if not thinking_cfg and self.config.enable_thinking:SuperClaude/Agents/core/python_expert.py (1)
735-736: Generated example code uses outdated typing style.The
_generate_improved_codemethod outputsfrom typing import List, Dict, Any, Optional, which contradicts the PR's Python 3.10+ modernization. Since this agent provides Python expertise, the example code it generates should demonstrate modern practices.Update the generated imports and type hints to use Python 3.10+ syntax:
- improved.append("from typing import List, Dict, Any, Optional") + improved.append("from typing import Any")And update line 750 accordingly:
- improved.append(" def process(self) -> Dict[str, Any]:") + improved.append(" def process(self) -> dict[str, Any]:")SuperClaude/Agents/generic.py (1)
567-617: Align generated Python stubs with built‑in generics
_render_python_plan_stubstill emitsfrom typing import Any, Dictanddef {function_name}() -> Dict[str, Any]:inside the generated stub. Given the project is now Python 3.10+ and the rest of the repo uses built‑in generics (dict[str, Any]), consider updating the stub template to:
- Drop
Dictimport and usedict[str, Any]in the return annotation.- Optionally keep importing only
Anyif still needed.This keeps auto-generated artifacts consistent with the main codebase typing style.
setup/cli/commands/uninstall.py (1)
533-581: Dead access toinfo["install_dir"]can be removedIn
display_component_details, the standaloneinfo["install_dir"]expression on Line 537 has no side effects and its result is unused. This looks like a leftover from a previous refactor and can be safely removed for clarity.SuperClaude/Commands/command_executor.py (3)
282-369: Quality loop integration and consensus enforcement are wired correctly, but confirm plan-only semanticsThe main
executepipeline now:
- Optionally runs the quality agentic loop (
_maybe_run_quality_loop) before consensus.- Always runs consensus (optionally enforced via
requires_evidence/--consensus).- Auto-runs tests when required, with safeguards when already in a pytest session.
- Derives
executed_operations/applied_changesfrom both agent output and git snapshots.
derived_statusis computed before_attach_plan_only_guidance, and guidance lines appended tocontext.errorsafterwards do not affectstatusorsuccess_flag. If the intent is that plan-only + guidance is still considered “non-failing”, this is consistent; if you wanted guidance to mark the run as unsuccessful, the error/status computation would need to occur later.Please confirm that treating plan-only guidance as non-fatal (status stays
plan-only,success_flagunchanged) is the intended behavior.
2627-2705: Repo diff stats and cleanup helpers are effective but potentially heavy on large repos
_snapshot_repo_changes,_collect_diff_stats, and_clean_build_artifactsall shell out to git or delete build directories underrepo_root. Behavior is correct, and path usage is scoped to the repo, but on very large repositories these can be relatively expensive.If you later observe performance issues, an incremental optimization (e.g., skipping diff stats when not required by a command, or making cleanup optional per target) would be worthwhile; no changes are strictly required now.
Also applies to: 2841-2865, 2867-2892
3207-3330: Requires‑evidence telemetry is comprehensive;quality_missingmetric name may be misleading
_record_requires_evidence_metricsemits a rich set of metrics (plan_only, static_issue_count, quality_score, consensus, fast_codex states, CLI usage). One minor point: thequality_missingcounter is incremented unconditionally in the success path of recording the event, regardless of whether evidence/quality were actually missing:else: self.monitor and self.monitor.record_metric( f"{base}.quality_missing", 1, MetricType.COUNTER, tags )If
quality_missingis meant to signal missing evidence or unavailable scoring, you might want to gate this onderived_status == "plan-only"or the presence ofquality_assessment_errorinstead of always incrementing it.SuperClaude/Commands/executor/change_management.py (1)
390-427: Intentional use of old-style typing in generated code.The generated Python stub uses
Dict[str, Any]and imports fromtyping. This appears intentional to maintain compatibility if generated stubs need to run on Python < 3.9. If the project now targets Python 3.10+ exclusively, consider updating the generated code to match the modern style for consistency.SuperClaude/Modes/behavioral_manager.py (1)
93-93: Consider adding type parameters toCallable.The
mode_change_callbacksis typed aslist[Callable]without specifying the signature. Consider usinglist[Callable[[BehavioralMode, BehavioralMode, dict[str, Any] | None], None]]to document the expected callback signature and enable better static type checking.- self.mode_change_callbacks: list[Callable] = [] + self.mode_change_callbacks: list[Callable[[BehavioralMode, BehavioralMode, dict[str, Any] | None], None]] = []
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (86)
SuperClaude/APIClients/anthropic_client.py(17 hunks)SuperClaude/APIClients/google_client.py(12 hunks)SuperClaude/APIClients/http_utils.py(1 hunks)SuperClaude/APIClients/openai_client.py(11 hunks)SuperClaude/APIClients/xai_client.py(12 hunks)SuperClaude/Agents/base.py(8 hunks)SuperClaude/Agents/cli.py(1 hunks)SuperClaude/Agents/coordination.py(14 hunks)SuperClaude/Agents/core/backend_architect.py(13 hunks)SuperClaude/Agents/core/devops_architect.py(15 hunks)SuperClaude/Agents/core/frontend_architect.py(15 hunks)SuperClaude/Agents/core/general_purpose.py(14 hunks)SuperClaude/Agents/core/learning_guide.py(14 hunks)SuperClaude/Agents/core/performance.py(11 hunks)SuperClaude/Agents/core/python_expert.py(16 hunks)SuperClaude/Agents/core/quality.py(12 hunks)SuperClaude/Agents/core/refactoring.py(11 hunks)SuperClaude/Agents/core/requirements_analyst.py(16 hunks)SuperClaude/Agents/core/root_cause.py(12 hunks)SuperClaude/Agents/core/security.py(16 hunks)SuperClaude/Agents/core/socratic_mentor.py(15 hunks)SuperClaude/Agents/core/system_architect.py(15 hunks)SuperClaude/Agents/core/technical_writer.py(15 hunks)SuperClaude/Agents/extended_loader.py(14 hunks)SuperClaude/Agents/generic.py(17 hunks)SuperClaude/Agents/heuristic_markdown.py(1 hunks)SuperClaude/Agents/loader.py(11 hunks)SuperClaude/Agents/parser.py(10 hunks)SuperClaude/Agents/registry.py(15 hunks)SuperClaude/Agents/selector.py(11 hunks)SuperClaude/Commands/artifact_manager.py(1 hunks)SuperClaude/Commands/command_executor.py(112 hunks)SuperClaude/Commands/executor/agent_orchestration.py(19 hunks)SuperClaude/Commands/executor/ast_analysis.py(4 hunks)SuperClaude/Commands/executor/change_management.py(11 hunks)SuperClaude/Commands/executor/consensus.py(8 hunks)SuperClaude/Commands/executor/git_operations.py(15 hunks)SuperClaude/Commands/executor/quality.py(7 hunks)SuperClaude/Commands/executor/telemetry.py(12 hunks)SuperClaude/Commands/executor/testing.py(6 hunks)SuperClaude/Commands/executor/utils.py(6 hunks)SuperClaude/Commands/parser.py(6 hunks)SuperClaude/Commands/registry.py(14 hunks)SuperClaude/Core/worktree_manager.py(17 hunks)SuperClaude/ModelRouter/consensus.py(15 hunks)SuperClaude/ModelRouter/models.py(11 hunks)SuperClaude/ModelRouter/router.py(10 hunks)SuperClaude/Modes/behavioral_manager.py(17 hunks)SuperClaude/Quality/quality_scorer.py(41 hunks)SuperClaude/Quality/validation_pipeline.py(1 hunks)SuperClaude/__main__.py(4 hunks)benchmarks/run_benchmarks.py(1 hunks)scripts/build_and_upload.py(1 hunks)scripts/report_memory_tokens.py(1 hunks)setup.py(1 hunks)setup/cli/commands/agent.py(2 hunks)setup/cli/commands/backup.py(6 hunks)setup/cli/commands/install.py(9 hunks)setup/cli/commands/uninstall.py(15 hunks)setup/cli/commands/update.py(9 hunks)setup/components/agents.py(7 hunks)setup/components/commands.py(7 hunks)setup/components/core.py(8 hunks)setup/components/mcp.py(5 hunks)setup/components/mcp_docs.py(8 hunks)setup/components/modes.py(6 hunks)setup/core/base.py(14 hunks)setup/core/installer.py(11 hunks)setup/core/registry.py(13 hunks)setup/core/validator.py(14 hunks)setup/services/claude_md.py(5 hunks)setup/services/config.py(10 hunks)setup/services/files.py(8 hunks)setup/services/settings.py(14 hunks)setup/utils/environment.py(10 hunks)setup/utils/logger.py(8 hunks)setup/utils/security.py(6 hunks)setup/utils/ui.py(4 hunks)setup/utils/updater.py(1 hunks)tests/agents/conftest.py(3 hunks)tests/agents/test_schema_validation.py(1 hunks)tests/quality/test_agentic_loop_safety.py(1 hunks)tests/test_agents_cli.py(12 hunks)tests/test_commands.py(3 hunks)tests/test_extended_loader.py(1 hunks)tests/test_model_router.py(5 hunks)
✅ Files skipped from review due to trivial changes (5)
- setup/services/claude_md.py
- SuperClaude/Agents/heuristic_markdown.py
- SuperClaude/Quality/validation_pipeline.py
- SuperClaude/Core/worktree_manager.py
- SuperClaude/Agents/core/quality.py
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/quality/test_agentic_loop_safety.py
- tests/test_commands.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
**/*.py: Python code targets 3.8+ with Black (88 cols), Flake8, and MyPy; use 4-space indents
Use snake_case for Python module and variable names
Use PascalCase for Python agent classes aligned with their persona names
Files:
scripts/build_and_upload.pybenchmarks/run_benchmarks.pysetup/utils/updater.pyscripts/report_memory_tokens.pySuperClaude/Commands/parser.pySuperClaude/Agents/cli.pysetup/cli/commands/install.pysetup/components/agents.pysetup/utils/ui.pySuperClaude/APIClients/http_utils.pysetup/cli/commands/backup.pySuperClaude/Commands/artifact_manager.pysetup/components/modes.pytests/test_extended_loader.pysetup/utils/environment.pysetup.pytests/agents/test_schema_validation.pysetup/components/mcp_docs.pySuperClaude/ModelRouter/router.pysetup/services/files.pySuperClaude/Agents/core/refactoring.pytests/test_model_router.pySuperClaude/Agents/base.pytests/test_agents_cli.pysetup/components/mcp.pytests/agents/conftest.pySuperClaude/APIClients/xai_client.pySuperClaude/Commands/executor/testing.pySuperClaude/APIClients/google_client.pySuperClaude/Agents/selector.pySuperClaude/Commands/registry.pysetup/core/base.pySuperClaude/Agents/core/general_purpose.pysetup/services/config.pySuperClaude/APIClients/anthropic_client.pysetup/utils/logger.pySuperClaude/Agents/loader.pySuperClaude/Quality/quality_scorer.pySuperClaude/__main__.pySuperClaude/Agents/core/python_expert.pysetup/components/commands.pysetup/core/installer.pysetup/components/core.pySuperClaude/Agents/parser.pySuperClaude/Agents/core/backend_architect.pySuperClaude/Agents/core/performance.pySuperClaude/ModelRouter/models.pySuperClaude/Agents/coordination.pysetup/cli/commands/update.pySuperClaude/Commands/executor/ast_analysis.pySuperClaude/APIClients/openai_client.pysetup/core/registry.pySuperClaude/Commands/executor/git_operations.pysetup/core/validator.pySuperClaude/Modes/behavioral_manager.pySuperClaude/Agents/core/technical_writer.pySuperClaude/Agents/core/socratic_mentor.pySuperClaude/Agents/core/devops_architect.pySuperClaude/Commands/executor/quality.pySuperClaude/Agents/core/frontend_architect.pysetup/services/settings.pySuperClaude/Agents/extended_loader.pysetup/utils/security.pySuperClaude/Agents/core/security.pySuperClaude/Commands/command_executor.pysetup/cli/commands/agent.pySuperClaude/Commands/executor/telemetry.pySuperClaude/Agents/generic.pySuperClaude/Agents/core/system_architect.pysetup/cli/commands/uninstall.pySuperClaude/Agents/core/requirements_analyst.pySuperClaude/Commands/executor/change_management.pySuperClaude/Commands/executor/agent_orchestration.pySuperClaude/Agents/core/learning_guide.pySuperClaude/Agents/registry.pySuperClaude/ModelRouter/consensus.pySuperClaude/Agents/core/root_cause.pySuperClaude/Commands/executor/consensus.pySuperClaude/Commands/executor/utils.py
tests/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
tests/**/*.py: Mirror production paths when adding tests (tests//test_.py) and name test functions test_
Mark slower test journeys with @pytest.mark.slow or @pytest.mark.integration per pyproject.toml
Include fixtures that validate requires_evidence guardrails and .superclaude_metrics outputs whenever agent workflows, telemetry, or auto-implementation logic changes
Files:
tests/test_extended_loader.pytests/agents/test_schema_validation.pytests/test_model_router.pytests/test_agents_cli.pytests/agents/conftest.py
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Applies to tests/**/*.py : Include fixtures that validate requires_evidence guardrails and .superclaude_metrics outputs whenever agent workflows, telemetry, or auto-implementation logic changes
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Pull Requests should describe risk surface, highlight configuration changes (e.g., MCP updates), and note any follow-up tasks for consensus, telemetry, or cleanup tooling
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Applies to tests/**/*.py : Include fixtures that validate requires_evidence guardrails and .superclaude_metrics outputs whenever agent workflows, telemetry, or auto-implementation logic changes
Applied to files:
tests/agents/test_schema_validation.pytests/agents/conftest.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Use `refactoring-expert` agent for code improvements and cleanup tasks
Applied to files:
SuperClaude/Agents/core/refactoring.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Preserve context across agent delegations when iterating on tasks
Applied to files:
SuperClaude/Agents/core/general_purpose.pySuperClaude/Agents/coordination.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Prefer specialist agents (extended library) over general-purpose agents when domain-specific expertise applies
Applied to files:
SuperClaude/Agents/core/general_purpose.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Auto-iterate with specialist suggestion when Task output receives quality score < 70
Applied to files:
SuperClaude/Quality/quality_scorer.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Use `technical-writer` agent for documentation generation tasks
Applied to files:
SuperClaude/Agents/core/technical_writer.py
📚 Learning: 2025-12-16T02:24:22.957Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: SuperClaude/Core/AGENTS.md:0-0
Timestamp: 2025-12-16T02:24:22.957Z
Learning: Use `socratic-mentor` agent for teaching through questions and educational guidance
Applied to files:
SuperClaude/Agents/core/socratic_mentor.py
📚 Learning: 2025-12-15T08:20:43.624Z
Learnt from: CR
Repo: Tony363/SuperClaude PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-15T08:20:43.624Z
Learning: Applies to **/*.py : Use PascalCase for Python agent classes aligned with their persona names
Applied to files:
SuperClaude/Commands/executor/agent_orchestration.py
🧬 Code graph analysis (36)
scripts/build_and_upload.py (1)
SuperClaude/Commands/executor/git_operations.py (1)
run_command(172-245)
setup/cli/commands/install.py (2)
setup/core/validator.py (1)
Validator(57-727)setup/core/registry.py (1)
ComponentRegistry(13-421)
tests/agents/test_schema_validation.py (1)
SuperClaude/Agents/parser.py (9)
AgentMarkdownParser(113-564)AgentSchema(52-110)AgentSchemaError(23-29)AgentValidationResult(33-49)add_error(42-45)add_warning(47-49)validate_schema(396-495)get_validation_summary(534-564)parse(125-165)
SuperClaude/ModelRouter/router.py (4)
SuperClaude/Agents/extended_loader.py (1)
get_statistics(624-649)SuperClaude/Agents/loader.py (1)
get_statistics(297-317)SuperClaude/Agents/registry.py (1)
get_statistics(439-463)setup/utils/logger.py (1)
get_statistics(248-261)
SuperClaude/Agents/base.py (8)
SuperClaude/Agents/core/backend_architect.py (2)
execute(44-133)validate(135-168)SuperClaude/Agents/core/frontend_architect.py (2)
execute(45-140)validate(142-176)SuperClaude/Agents/core/python_expert.py (2)
execute(45-136)validate(138-175)SuperClaude/Agents/core/security.py (5)
execute(45-131)execute(194-245)validate(133-140)validate(188-192)validate(247-283)SuperClaude/Agents/core/system_architect.py (2)
execute(43-135)validate(137-166)setup/components/agents.py (1)
get_metadata(20-27)setup/components/core.py (1)
get_metadata(39-46)setup/core/base.py (1)
get_metadata(40-51)
setup/components/mcp.py (4)
setup/components/agents.py (2)
get_metadata(20-27)validate_installation(220-261)setup/components/commands.py (2)
get_metadata(20-27)validate_installation(222-252)setup/components/modes.py (2)
get_metadata(28-35)validate_installation(147-162)setup/core/base.py (3)
get_metadata(40-51)get_files_to_install(111-127)validate_installation(272-290)
SuperClaude/APIClients/xai_client.py (1)
SuperClaude/APIClients/openai_client.py (6)
stream(223-250)estimate_cost(327-354)_chunk_stream_text(320-325)_build_payload(360-381)add(437-442)get_summary(444-454)
SuperClaude/APIClients/google_client.py (1)
SuperClaude/APIClients/openai_client.py (6)
_chunk_stream_text(320-325)estimate_cost(327-354)get_model_info(356-358)_build_payload(360-381)add(437-442)get_summary(444-454)
SuperClaude/Commands/registry.py (2)
SuperClaude/Agents/registry.py (1)
get_categories(368-378)SuperClaude/ModelRouter/models.py (1)
export_manifest(390-423)
SuperClaude/Agents/core/general_purpose.py (1)
SuperClaude/Agents/base.py (3)
execute(56-68)validate(71-81)get_capabilities(83-100)
setup/services/config.py (1)
setup/core/registry.py (1)
get_components_by_category(296-321)
SuperClaude/Agents/loader.py (4)
SuperClaude/Agents/registry.py (1)
get_statistics(439-463)SuperClaude/Agents/base.py (1)
BaseAgent(15-221)SuperClaude/ModelRouter/router.py (1)
get_statistics(567-599)setup/utils/logger.py (1)
get_statistics(248-261)
setup/components/commands.py (3)
setup/components/agents.py (1)
get_dependencies(128-130)setup/components/core.py (1)
get_dependencies(212-214)setup/components/modes.py (1)
get_dependencies(214-216)
setup/core/installer.py (3)
setup/services/settings.py (1)
SettingsService(15-533)setup/core/registry.py (1)
resolve_dependencies(193-234)setup/components/core.py (1)
get_installation_summary(348-358)
setup/components/core.py (5)
setup/components/agents.py (5)
get_metadata(20-27)_install(42-58)get_dependencies(128-130)validate_installation(220-261)get_installation_summary(208-218)setup/components/commands.py (5)
get_metadata(20-27)_install(42-49)get_dependencies(155-157)validate_installation(222-252)get_installation_summary(276-286)setup/components/modes.py (5)
get_metadata(28-35)_install(37-101)get_dependencies(214-216)validate_installation(147-162)_get_installed_file_manifest(164-173)setup/core/base.py (4)
get_metadata(40-51)_install(148-189)get_dependencies(206-213)validate_installation(272-290)setup/core/installer.py (1)
get_installation_summary(325-339)
SuperClaude/Agents/parser.py (2)
SuperClaude/Commands/parser.py (1)
parse(73-109)setup/core/validator.py (1)
parse(53-54)
SuperClaude/Agents/core/backend_architect.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
SuperClaude/ModelRouter/models.py (1)
SuperClaude/Commands/registry.py (1)
export_manifest(408-434)
setup/cli/commands/update.py (2)
setup/cli/commands/uninstall.py (1)
get_installed_components(214-220)setup/services/settings.py (1)
get_installed_components(307-315)
SuperClaude/APIClients/openai_client.py (1)
SuperClaude/APIClients/anthropic_client.py (7)
stream(265-289)_chunk_stream_text(319-324)estimate_cost(367-403)get_model_info(405-415)_build_payload(507-535)add(588-592)get_summary(594-605)
setup/core/registry.py (5)
setup/core/base.py (2)
Component(16-459)get_dependencies(206-213)setup/components/agents.py (1)
get_dependencies(128-130)setup/components/commands.py (1)
get_dependencies(155-157)setup/components/core.py (1)
get_dependencies(212-214)setup/components/modes.py (1)
get_dependencies(214-216)
SuperClaude/Agents/core/technical_writer.py (7)
SuperClaude/Agents/core/frontend_architect.py (2)
execute(45-140)validate(142-176)SuperClaude/Agents/core/general_purpose.py (2)
execute(58-111)validate(113-123)SuperClaude/Agents/core/python_expert.py (2)
execute(45-136)validate(138-175)SuperClaude/Agents/core/refactoring.py (2)
execute(45-122)validate(124-151)SuperClaude/Agents/core/root_cause.py (2)
execute(44-125)validate(127-157)SuperClaude/Agents/core/security.py (5)
execute(45-131)execute(194-245)validate(133-140)validate(188-192)validate(247-283)SuperClaude/Agents/core/system_architect.py (2)
execute(43-135)validate(137-166)
SuperClaude/Agents/core/socratic_mentor.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
SuperClaude/Agents/core/devops_architect.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
SuperClaude/Agents/core/frontend_architect.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
setup/services/settings.py (3)
setup/cli/commands/backup.py (2)
create_backup(261-346)list_backups(186-202)setup/cli/commands/uninstall.py (1)
get_installed_components(214-220)setup/cli/commands/update.py (1)
get_installed_components(92-98)
SuperClaude/Agents/core/security.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
SuperClaude/Commands/command_executor.py (7)
SuperClaude/Modes/behavioral_manager.py (1)
BehavioralMode(22-27)SuperClaude/Quality/quality_scorer.py (1)
QualityAssessment(56-68)SuperClaude/Core/worktree_manager.py (1)
WorktreeManager(25-739)SuperClaude/Agents/generic.py (1)
_slugify(694-699)SuperClaude/Commands/artifact_manager.py (1)
_slugify(19-23)SuperClaude/Commands/executor/agent_orchestration.py (1)
_normalize_evidence_value(381-405)SuperClaude/Commands/registry.py (1)
CommandMetadata(25-40)
SuperClaude/Agents/generic.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
setup/cli/commands/uninstall.py (3)
setup/cli/commands/update.py (1)
get_installed_components(92-98)setup/services/settings.py (1)
get_installed_components(307-315)bin/cli.js (1)
args(12-12)
SuperClaude/Commands/executor/change_management.py (1)
SuperClaude/Commands/executor/utils.py (2)
deduplicate(63-73)slugify(11-17)
SuperClaude/Commands/executor/agent_orchestration.py (1)
SuperClaude/Commands/command_executor.py (1)
_normalize_evidence_value(3773-3797)
SuperClaude/Agents/core/learning_guide.py (1)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)
SuperClaude/ModelRouter/consensus.py (1)
SuperClaude/Commands/executor/consensus.py (1)
VoteType(16-21)
SuperClaude/Agents/core/root_cause.py (5)
SuperClaude/Agents/base.py (2)
execute(56-68)validate(71-81)SuperClaude/Agents/core/frontend_architect.py (2)
execute(45-140)validate(142-176)SuperClaude/Agents/core/python_expert.py (2)
execute(45-136)validate(138-175)SuperClaude/Agents/core/quality.py (2)
execute(45-126)validate(128-161)SuperClaude/Agents/core/system_architect.py (2)
execute(43-135)validate(137-166)
SuperClaude/Commands/executor/consensus.py (1)
SuperClaude/ModelRouter/consensus.py (1)
VoteType(20-26)
🪛 GitHub Actions: CI
SuperClaude/Commands/executor/git_operations.py
[error] 23-23: TypeError during import: unsupported operand type(s) for |: 'builtin_function_or_method' and 'NoneType' in annotation "repo_root: Path | None, detect_fn: callable | None = None". Use Optional[Callable] or 'Callable' for type hints, and avoid using the built-in 'callable' as a type.
🪛 GitHub Check: CodeQL
SuperClaude/Agents/core/technical_writer.py
[warning] 148-148: Variable defined multiple times
This assignment to 'validate' is unnecessary as it is redefined before this value is used.
SuperClaude/Agents/core/security.py
[warning] 188-188: Variable defined multiple times
This assignment to 'validate' is unnecessary as it is redefined before this value is used.
|
|
||
|
|
||
| def collect_package_files() -> List[str]: | ||
| def collect_package_files() -> list[str]: |
There was a problem hiding this comment.
Inconsistency: python_requires conflicts with type annotation syntax.
The function uses list[str] (line 16) which requires Python 3.9+ at runtime, but python_requires=">=3.8" (line 104) still allows Python 3.8. This will cause a TypeError on Python 3.8 since built-in generics aren't subscriptable there without from __future__ import annotations.
Given the PR objective is "Python 3.10 only", update python_requires to match:
- python_requires=">=3.8",
+ python_requires=">=3.10",Alternatively, if Python 3.8 support is still needed, add the future import at the top of the file.
Also applies to: 104-104
🤖 Prompt for AI Agents
In setup.py around line 16 and line 104, the function annotation uses list[str]
which requires Python 3.9+ but python_requires is ">=3.8"; since the PR target
is Python 3.10, update python_requires to ">=3.10" (line 104) so the runtime
matches the type annotation, or if you must keep supporting 3.8/3.9 instead, add
"from __future__ import annotations" at the top of the file and ensure all other
inline built-in generics are handled consistently.
| def validate(self, context: dict[str, Any]) -> bool: | ||
| task = str(context.get("task", "")).lower() | ||
| if any(keyword in task for keyword in self.SECURITY_KEYWORDS): | ||
| return True | ||
| return super().validate(context) or self.analysis_agent.validate(context) |
There was a problem hiding this comment.
Potential AttributeError when analysis_agent is None.
Line 192 calls self.analysis_agent.validate(context), but self.analysis_agent can be None (see line 186). This will raise an AttributeError at runtime.
Apply this diff to add a None guard:
def validate(self, context: dict[str, Any]) -> bool:
task = str(context.get("task", "")).lower()
if any(keyword in task for keyword in self.SECURITY_KEYWORDS):
return True
- return super().validate(context) or self.analysis_agent.validate(context)
+ if self.analysis_agent:
+ return super().validate(context) or self.analysis_agent.validate(context)
+ return super().validate(context)🧰 Tools
🪛 GitHub Check: CodeQL
[warning] 188-188: Variable defined multiple times
This assignment to 'validate' is unnecessary as it is redefined before this value is used.
🤖 Prompt for AI Agents
In SuperClaude/Agents/core/security.py around lines 188 to 192, the code may
raise an AttributeError because self.analysis_agent can be None; update the
return expression to guard the call by checking that self.analysis_agent is not
None before calling its validate method (e.g., short-circuit: return
super().validate(context) or (self.analysis_agent is not None and
self.analysis_agent.validate(context))) so the validate call is only invoked
when analysis_agent exists.
| self, query: str, search_fields: list[str] = None | ||
| ) -> list[AgentMetadata]: |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use consistent union syntax for optional parameter.
The search_fields parameter uses list[str] = None instead of the union syntax list[str] | None = None that is used consistently throughout the rest of this file and the codebase.
Apply this diff to maintain consistency:
def search_agents(
- self, query: str, search_fields: list[str] = None
+ self, query: str, search_fields: list[str] | None = None
) -> list[AgentMetadata]:📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| self, query: str, search_fields: list[str] = None | |
| ) -> list[AgentMetadata]: | |
| def search_agents( | |
| self, query: str, search_fields: list[str] | None = None | |
| ) -> list[AgentMetadata]: |
🤖 Prompt for AI Agents
In SuperClaude/Agents/extended_loader.py around lines 558-559 the optional
parameter annotation uses the old style `list[str] = None`; change it to the
consistent union syntax `list[str] | None = None` so the signature becomes
`self, query: str, search_fields: list[str] | None = None ) ->
list[AgentMetadata]:` ensuring consistent typing across the file.
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 PAL MCP Consensus Code ReviewOverviewThis PR represents a major framework simplification by dropping support for Python 3.8 and 3.9, focusing exclusively on Python 3.10+. Key changes include:
🔴 Critical IssuesNone found - No blocking issues identified that would prevent merge. 🟠 High Priority1. Potential Division by Zero (
|
| Category | Rating | Notes |
|---|---|---|
| Security | ⭐⭐⭐⭐☆ | Good patterns, but timeout enforcement and input validation could be stronger |
| Code Quality | ⭐⭐⭐⭐⭐ | Excellent type safety migration, consistent patterns, well-documented |
| Architecture | ⭐⭐⭐⭐☆ | Strong separation of concerns, but coordination complexity needs more tests |
| Testing | ⭐⭐⭐☆☆ | Coverage reduced to 35% - needs improvement per phased plan |
| Documentation | ⭐⭐⭐⭐⭐ | README overhaul is comprehensive with excellent diagrams |
| Performance | ⭐⭐⭐⭐☆ | Rate limiting and async patterns are good, timeout enforcement needs work |
Detailed Findings by File
APIClients/
- anthropic_client.py (613 lines): Well-structured with thinking mode support. Watch division by zero at line 602.
- http_utils.py (114 lines): Clean stdlib-based HTTP client. Good error handling with structured exceptions.
- openai_client.py: Consistent with Anthropic client pattern. Good model configuration management.
Agents/
- base.py (222 lines): Solid ABC with proper initialization lifecycle. Confidence scoring algorithm is simple but effective.
- coordination.py (584 lines): Complex but well-organized. Circular dependency detection needs integration tests.
- core/security.py: Good pattern-based security analysis. Ensure patterns stay current with OWASP updates.
Workflow Changes
- .github/workflows/ai-review.yml: Excellent dogfooding of PAL MCP. Consider adding timeout to Claude Code Action.
- .github/workflows/ci.yml: Python 3.10 only simplifies CI. Coverage gate reduction is pragmatic but needs follow-up.
Recommendations for Follow-up
- Priority 1: Create integration tests for delegation chains (coordination.py)
- Priority 2: Implement hard timeout enforcement in coordination manager
- Priority 3: Add API key validation methods to all clients
- Priority 4: Execute Phase 1 of coverage improvement plan (35% → 40%)
- Priority 5: Add token estimation accuracy tests for rate limiting
Consensus Assessment
This PR represents high-quality refactoring work that modernizes the codebase to Python 3.10+. The type safety improvements are comprehensive and consistent. The architectural patterns (coordination, error handling, agent system) demonstrate mature software engineering.
The changes are safe to merge with the understanding that the identified medium-priority items should be addressed in follow-up PRs. The critical observation is the coverage reduction - ensure Issue #7's phased improvement plan is actively pursued.
This review was generated by PAL MCP Consensus Code Review.
Multiple AI models were consulted to validate findings.
Review is advisory - please use human judgment for final decisions.
Review Methodology:
- Analyzed 92 changed files (20 Python files examined in detail)
- Assessed security patterns, type safety, error handling, architecture
- Evaluated against OWASP guidelines, Python best practices, async patterns
- Validated coordination logic, rate limiting, timeout handling
- Considered backward compatibility impacts of Python 3.10+ migration
Summary
Changes
CI/CD
.github/workflows/ci.yml: Reduced test matrix from['3.8', '3.9', '3.10', '3.11', '3.12']to['3.10'].github/workflows/ai-review.yml: Rewritten to usemcp__pal__codereviewandmcp__pal__consensustools'3.11'to'3.10'Configuration
pyproject.toml: Updatedrequires-python = ">=3.10", removed old classifiers, updated tool target versions for black, mypy, and ruffDocumentation
README.md: Complete rewrite with 15 mermaid diagrams, accurate component counts (131 agents, 13 commands, 8 models, 3 modes)Quality & Parser
SuperClaude/Quality/quality_scorer.py: Added agentic loop safety and deterministic signal validationSuperClaude/Agents/parser.py: Added schema validation for agent definitionsTests
tests/agents/test_schema_validation.pytests/quality/test_agentic_loop_safety.pytests/quality/test_deterministic_signals.pytests/conftest.pyandtests/test_commands.pyTest plan
🤖 Generated with Claude Code
Summary by Sourcery
Restrict the framework and tooling to Python 3.10+, enhance quality and safety mechanisms for iterative agent execution and agent definitions, streamline CI/coverage, and substantially expand and modernize the README and AI review workflow.
New Features:
Bug Fixes:
Enhancements:
CI:
Documentation:
Tests:
Summary by CodeRabbit
New Features
Documentation
Chores
Tests
✏️ Tip: You can customize this high-level summary in your review settings.