test: add TDD bug-capture test for #986 — CorrectionService checkpoint_service wiring

Add a Behave feature with two scenarios that verify the DI container
wires checkpoint_service into CorrectionService.  Both assertions
currently fail — proving bug #986 exists — and the @tdd_expected_fail
tag inverts the result so the test passes CI while the bug is unfixed.

Scenario 1 asserts _checkpoint_service is not None after resolving
CorrectionService from the container.  Scenario 2 additionally verifies
the injected object is a CheckpointService instance.  When bug #986 is
fixed (checkpoint_service=checkpoint_service added to the container
registration), both assertions will pass and the developer must remove
@tdd_expected_fail per the TDD bug workflow.

Tags: @tdd_expected_fail @tdd_bug @tdd_bug_986 @mock_only

Quality gates verified:
- lint: pass
- typecheck: pass (0 errors)
- unit_tests: 462 features, 12232 scenarios, 0 failures
- coverage: 98% (threshold 97%)
- tag_validation: 19/19 scenarios pass
- e2e_tests: 37/37 pass

ISSUES CLOSED: #1030
This commit is contained in:
2026-03-22 23:52:38 +00:00
parent a2113deace
commit fc4397f845
2 changed files with 103 additions and 0 deletions
@@ -0,0 +1,73 @@
"""Step definitions for TDD Bug #986 — CorrectionService checkpoint_service wiring.
This test captures bug #986: the DI container registers CorrectionService
without wiring checkpoint_service, so revert-mode corrections silently skip
checkpoint rollback. The test is tagged @tdd_expected_fail and will pass CI
via result inversion until the bug is fixed.
See: https://git.cleverthis.com/cleveragents/cleveragents-core/issues/986
"""
from __future__ import annotations
from typing import Any
from behave import given, then, when
from behave.runner import Context
@given("tccw a fresh DI container with an in-memory database")
def step_fresh_container(context: Context) -> None:
"""Set up a clean DI container with an in-memory SQLite database."""
import os
from cleveragents.application.container import get_container, reset_container
# Reset to ensure a fresh container for this scenario.
reset_container()
# Ensure database URL points to an in-memory database so the
# CheckpointService factory can resolve without filesystem side-effects.
os.environ["CLEVERAGENTS_DATABASE_URL"] = "sqlite:///:memory:"
os.environ["CLEVERAGENTS_TEST_DATABASE_URL"] = "sqlite:///:memory:"
container = get_container()
context.tccw_container = container # type: ignore[attr-defined]
@when("tccw I resolve the correction_service from the container")
def step_resolve_correction_service(context: Context) -> None:
"""Resolve the CorrectionService singleton from the container."""
container: Any = context.tccw_container # type: ignore[attr-defined]
context.tccw_correction_svc = container.correction_service() # type: ignore[attr-defined]
@then("tccw the correction_service should have a non-None checkpoint_service")
def step_assert_checkpoint_service_not_none(context: Context) -> None:
"""Assert that the resolved CorrectionService has checkpoint_service wired."""
svc: Any = context.tccw_correction_svc # type: ignore[attr-defined]
# Bug #986: CorrectionService._checkpoint_service is None because the
# container does not pass checkpoint_service to the constructor.
assert svc._checkpoint_service is not None, (
"CorrectionService._checkpoint_service is None — the DI container "
"does not wire checkpoint_service into CorrectionService. See bug #986."
)
@then("tccw the checkpoint_service should be a CheckpointService instance")
def step_assert_checkpoint_service_type(context: Context) -> None:
"""Assert that the injected checkpoint_service is a CheckpointService."""
from cleveragents.application.services.checkpoint_service import (
CheckpointService,
)
svc: Any = context.tccw_correction_svc # type: ignore[attr-defined]
cp_svc = svc._checkpoint_service
assert cp_svc is not None, (
"CorrectionService._checkpoint_service is None — cannot verify type. "
"See bug #986."
)
assert isinstance(cp_svc, CheckpointService), (
f"Expected CheckpointService instance, got {type(cp_svc).__name__}. "
"See bug #986."
)
@@ -0,0 +1,30 @@
@tdd_expected_fail @tdd_bug @tdd_bug_986 @mock_only
Feature: TDD Bug #986 — CorrectionService missing checkpoint_service wiring in DI container
As a developer
I want to verify that CorrectionService receives checkpoint_service
from the DI container
So that revert-mode corrections can perform checkpoint rollback
Bug #986: The DI container registers CorrectionService with only
event_bus but omits checkpoint_service, despite CheckpointService
being registered in the same container. As a result, revert-mode
corrections silently skip checkpoint rollback because the dependency
is never injected.
Additionally, the CLI creates an ad-hoc CorrectionService instance
that bypasses the container entirely, which means even if the
container wiring is fixed, the CLI path remains broken.
These tests assert the expected wiring and will FAIL until the bug
is fixed. The @tdd_expected_fail tag inverts the result so CI
passes.
Scenario: DI container wires checkpoint_service into CorrectionService
Given tccw a fresh DI container with an in-memory database
When tccw I resolve the correction_service from the container
Then tccw the correction_service should have a non-None checkpoint_service
Scenario: Container-provided CorrectionService checkpoint_service is a CheckpointService instance
Given tccw a fresh DI container with an in-memory database
When tccw I resolve the correction_service from the container
Then tccw the checkpoint_service should be a CheckpointService instance