From fc4397f845260501d727d117ef6032e979ffad95 Mon Sep 17 00:00:00 2001 From: "Brent E. Edwards" Date: Sun, 22 Mar 2026 23:52:38 +0000 Subject: [PATCH] =?UTF-8?q?test:=20add=20TDD=20bug-capture=20test=20for=20?= =?UTF-8?q?#986=20=E2=80=94=20CorrectionService=20checkpoint=5Fservice=20w?= =?UTF-8?q?iring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../tdd_correction_checkpoint_wiring_steps.py | 73 +++++++++++++++++++ .../tdd_correction_checkpoint_wiring.feature | 30 ++++++++ 2 files changed, 103 insertions(+) create mode 100644 features/steps/tdd_correction_checkpoint_wiring_steps.py create mode 100644 features/tdd_correction_checkpoint_wiring.feature diff --git a/features/steps/tdd_correction_checkpoint_wiring_steps.py b/features/steps/tdd_correction_checkpoint_wiring_steps.py new file mode 100644 index 00000000..c4a8e922 --- /dev/null +++ b/features/steps/tdd_correction_checkpoint_wiring_steps.py @@ -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." + ) diff --git a/features/tdd_correction_checkpoint_wiring.feature b/features/tdd_correction_checkpoint_wiring.feature new file mode 100644 index 00000000..dabf2c71 --- /dev/null +++ b/features/tdd_correction_checkpoint_wiring.feature @@ -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