47b4c5fbfb
CI / push-validation (push) Successful in 10s
CI / helm (push) Successful in 28s
CI / build (push) Successful in 29s
CI / typecheck (push) Successful in 53s
CI / lint (push) Successful in 3m44s
CI / quality (push) Successful in 3m58s
CI / security (push) Successful in 4m12s
CI / e2e_tests (push) Successful in 4m49s
CI / integration_tests (push) Successful in 6m47s
CI / unit_tests (push) Successful in 8m3s
CI / docker (push) Successful in 1m31s
CI / coverage (push) Successful in 10m51s
CI / status-check (push) Successful in 1s
CI / benchmark-publish (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
SKILL.md (1,878 → 2,099 lines, 23 → 25 decision trees): New 'Is my work done?' tree — comprehensive Definition of Done checklist synthesising all requirements across implementation, three-level testing (unit/integration/benchmarks), coverage ≥ 97%, five CI quality checks, commit anatomy (atomic, body, footer), documentation (changelog, docstrings, CONTRIBUTORS.md), PR fields (description, dep direction, Epic scope, milestone, Type label), CI checks, and issue state transitions. New 'What design pattern should I use?' tree — all 24 patterns from CONTRIBUTING.md categorised across Creational (Factory, Abstract Factory, Builder, Prototype, Singleton, Object Pool, DI), Structural (Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy, Module), Behavioral (Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor, Null Object), and Architectural (Repository, Unit of Work, Service Layer, MVC, CQRS, Event Sourcing, Specification). Every pattern includes a when-to-use description and a CleverAgents-specific example. Expand 'Am I about to write code?' — link to new patterns tree. Expand 'Am I writing tests?' — add And/But/Outline Gherkin keywords with examples, add Scenario Outline explanation, add naming good/bad examples with anti-pattern list, expand integration test guidance with what good integration tests exercise (CLI, DB, filesystem, service layer), expand Hypothesis section with 6 specific use cases and recommended strategies to build. Expand 'Am I about to commit?' — improve commit body guidance with a worked example showing what to write (context, why this approach, risks, caveats). Expand 'Am I triaging?' — add Epic/Legendary triage rules (no point estimates, no milestone assignment, sign-off labels required for closure). Add two branches to master decision tree for new trees. Reference files: references/testing/README.md (187 → 296 lines): - Add Gherkin Quality Guidelines section: Given/When/Then semantics table, Scenario Outline explanation with example, naming rules with good/bad table, common anti-patterns (implementation details, multiple behaviors, missing Then) - Add Property-Based Testing (Hypothesis) section: when-to-use table with 6 specific CleverAgents use cases, recommended strategies to build, integration with Behave step definitions with worked example references/langchain-langgraph/README.md (307 → 375 lines): - Add RxPY Reactive Streams section: Subject vs BehaviorSubject vs ReplaySubject decision table with when-to-use and code examples, key operators table with use cases and code examples, backpressure management patterns (debounce vs throttle_first with examples), and clear list of what RxPY is NOT for references/toolchain/README.md (271 → 272 lines): - Add Hypothesis to tool table (property-based testing, nox -s unit_tests) references/ci-cd/README.md (124 → 131 lines): - Fix project-specific version number in release example (v3.6.0 → generic v<MAJOR>.<MINOR>.<PATCH>) - Add release failure recovery procedure (verify secrets → build locally → delete tag → fix → re-tag) ISSUES CLOSED: #0
Testing — CleverAgents Project
⚠️ Rules here override
cleverthis-guidelines. Apply these exactly.
Framework Decisions (non-negotiable)
| Test type | Framework | Directory | nox session |
|---|---|---|---|
| Unit / BDD | Behave (Cucumber/Gherkin) | features/ |
nox -s unit_tests |
| Integration | Robot Framework via pabot | robot/ |
nox -s integration_tests |
| End-to-end | Robot Framework (real LLM keys) | robot/ |
nox -s e2e_tests |
| Performance | ASV (Airspeed Velocity) | benchmarks/ |
nox -s benchmark |
Prohibited:
- No pytest-style unit tests — ever.
- No
tests/directory — it intentionally does not exist in this project. - No xUnit-style tests (JUnit, NUnit, etc.) at the unit level.
Behave (BDD Unit Tests)
Location rules
- Feature files:
features/orfeatures/<topic>/ - Step definitions:
features/steps/ - Mocks/fakes/stubs:
features/mocks/ONLY
Step file naming (strictly enforced)
- Before creating a new step file — check whether an existing file already covers the same behavior. Extend it rather than creating a duplicate.
- Steps used only by
foo.feature→features/steps/foo_steps.py - Steps used by multiple features → clearly named, reusable file under
features/steps/(update existing shared files before creating new ones) - Every
.featurefile must be committed with all its steps fully implemented — never placeholder step definitions
Running Behave
nox -s unit_tests # always use nox — never run behave directly
Robot Framework (Integration + E2E)
Integration tests (robot/)
- Exercise real services, real endpoints, real dependencies
- NO mocking of any kind — strictly prohibited
- Mocks acceptable ONLY for truly impractical external dependencies (document why)
- Must be updated whenever component interfaces change
nox -s integration_tests # Robot Framework via pabot (parallel)
End-to-end tests (robot/ — e2e tagged)
- Require real LLM API keys — separate from integration tests
- Test the complete system with real providers end-to-end
nox -s e2e_tests
Coverage Requirement (hard merge gate)
- Threshold: ≥ 97% — this is a hard project requirement
- Measured by: Slipcover via
nox -s coverage_report - PR is blocked automatically if coverage drops below 97%
- Exception: project owner can grant a documented exception only
- Any code excluded from coverage: requires explicit project owner approval
nox -s coverage_report # look for "COVERAGE OK" or "COVERAGE FAILED"
Mock Placement (absolute rule)
| Location | Permitted? |
|---|---|
features/mocks/ |
✅ YES — the ONLY permitted location |
src/cleveragents/ |
❌ NEVER |
scripts/ |
❌ NEVER |
| Anywhere else | ❌ NEVER |
- Production code must not contain
if testing:guards or test-only paths - Use dependency injection to substitute test doubles — not conditional logic
Performance Benchmarks
- Write ASV benchmarks for all performance-sensitive code
- Benchmarks live in
benchmarks/ - Run benchmarks:
nox -s benchmark - PR regression check:
nox -s benchmark_regression(results uploaded as artifact)
TDD Bug Fix Tag System
The three tags
| Tag | Lifecycle | Purpose |
|---|---|---|
@tdd_issue |
PERMANENT | Generic filter — on ALL TDD issue tests |
@tdd_issue_N |
PERMANENT | Issue link (N = bug number) — regression reference |
@tdd_expected_fail |
TEMPORARY | Inverts pass/fail while bug unfixed |
How @tdd_expected_fail works
- When present: test PASSES CI if the underlying assertion FAILS (bug still exists)
- When present: test FAILS CI if the underlying assertion PASSES (bug fixed but tag not removed)
- When absent: test runs normally
CI-enforced validation rules (all checked on every PR)
@tdd_issue_Npresent →@tdd_issueMUST also be present@tdd_expected_failpresent →@tdd_issueAND@tdd_issue_NMUST both be present- Bug fix PR closing #N →
@tdd_expected_failMUST be removed from all@tdd_issue_Nscenarios- PR is BLOCKED if the tag is still present
- Bug fix PR closing #N → a
@tdd_issue_Ntest MUST exist in the codebase- PR is BLOCKED if no TDD test was ever written
Assertion type rule (critical)
Expected-fail steps must use AssertionError:
# CORRECT — inverted by the TDD hook:
assert some_condition, "descriptive failure message"
raise AssertionError("bug still present: description of what should work")
# WRONG — these are NOT inverted, they break CI regardless of the tag:
raise ValueError(...)
raise RuntimeError(...)
raise OSError(...)
raise TypeError(...)
Complete example
# Before fix — all three tags:
@tdd_issue @tdd_issue_123 @tdd_expected_fail
Scenario: Bug #123 — SHACL validation rejects valid graph
Given a valid resource graph
When SHACL validation is applied
Then the validation should succeed
# After fix — dev removes @tdd_expected_fail, leaves the other two:
@tdd_issue @tdd_issue_123
Scenario: Bug #123 — SHACL validation rejects valid graph
Given a valid resource graph
When SHACL validation is applied
Then the validation should succeed
Gherkin Quality Guidelines
Good Gherkin scenarios are readable by non-developers and serve as living documentation.
Given / When / Then semantics
| Keyword | Purpose | What it tests |
|---|---|---|
Given |
Pre-conditions — establish the state of the world before the action | Inputs, setup |
When |
The action under test — what the user or system does | The triggering event |
Then |
The observable outcome — what must be true after the action | Outputs, side effects |
And |
Continuation — extends the previous Given/When/Then | More of the same type |
But |
Contrasting continuation — typically for "does NOT happen" assertions | Negative outcomes |
Scenario Outline (data-driven scenarios)
Use Scenario Outline when the same behavior must be verified for multiple data combinations:
Scenario Outline: Invalid confidence scores are rejected
Given an automation profile with <flag> set to <value>
When the profile is validated
Then a validation error is raised
Examples:
| flag | value |
| decompose_task | -0.1 |
| decompose_task | 1.1 |
| edit_code | -1.0 |
Naming rules
# GOOD — describes the behavior:
Scenario: Plan enters errored state when execution actor raises uncaught exception
Scenario: SHACL validation rejects a graph with a missing required property
# BAD — describes the test mechanics:
Scenario: Test plan execution with error
Scenario: Test case 1 for validator
Common anti-patterns to avoid
- Implementation details in steps:
When PlanService._execute_phase() is called→When the plan executes - Multiple behaviors per scenario: split into separate scenarios
- Over-specific data: use meaningful values, not arbitrary UUIDs in step text
- Missing Then: every scenario must have at least one assertion
Property-Based Testing (Hypothesis)
Use Hypothesis for verifying invariants and boundary conditions.
When to use Hypothesis
| Use case | Example |
|---|---|
| Invariants that must hold for any valid input | Decision tree structural invariants |
| Boundary conditions | Confidence score clamp to 0.0–1.0 |
| Merge correctness | No data loss for any combination of file edits |
| Ordering/sorting | ULID lexicographic monotonicity |
| Precedence rules | Invariant resolution always follows plan > action > project > global |
Recommended strategies to build
from hypothesis import given, strategies as st
from hypothesis.strategies import composite
@composite
def ulid_strategy(draw):
"""Strategy that generates valid ULID strings."""
...
@composite
def confidence_score_strategy(draw):
"""Strategy for valid confidence scores (0.0–1.0 inclusive)."""
return draw(st.floats(min_value=0.0, max_value=1.0, allow_nan=False))
@composite
def invariant_set_strategy(draw):
"""Strategy for sets of invariants at multiple scopes."""
...
Integration with Behave
Hypothesis tests run inside Behave step definitions:
from hypothesis import given, settings
import hypothesis.strategies as st
@then("the confidence score is always clamped to the valid range")
def step_confidence_clamped(context):
@given(raw=st.floats(allow_nan=True, allow_infinity=True))
@settings(max_examples=200)
def check_clamp(raw):
clamped = clamp_confidence(raw)
assert 0.0 <= clamped <= 1.0
check_clamp()
LangChain/LangGraph Testing
- Use
FakeListLLMor a custom mock provider — never real LLM API in unit tests - Test each graph node's state transformation in isolation
- Verify complete workflow execution with expected state transitions
- Streaming: test both event emission AND final results
- Memory: verify conversation history and entity tracking
Test-First Development (mandatory)
- Write the test before the implementation — no exceptions
- Tests go in the same commit as the implementation they cover
- Never commit implementation without its tests
- Test failure during development → immediately becomes a blocking task
- Exception:
@tdd_expected_failtests are tracked failures, not unaddressed ones
- Exception: