From cf460fdcf9c5eeb50837a39e3b0eacd772423b8f Mon Sep 17 00:00:00 2001 From: HAL9000 Date: Fri, 8 May 2026 07:01:18 +0000 Subject: [PATCH] fix(plan-correction): implement list_by_decision in CorrectionAttemptRepository The domain protocol (CorrectionRepositoryProtocol.list_by_decision) was added in the previous commit but the concrete SQLAlchemy-backed adapter was missing this method, causing a run-time AttributeError whenever code called the adapter. This resolves the spec-compliance blocker from PR review #7887 (issue #8531). Changes: - CorrectionAttemptRepository.list_by_decision(decision_id, *, new_only=False) queries CorrectionAttemptModel rows by original_decision_id with optional filtering on terminal states - Follows the same @database_retry + session pattern as other repository methods - Properly wraps DB errors in DatabaseError ISSUES CLOSED: #8531 --- .../infrastructure/database/repositories.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/cleveragents/infrastructure/database/repositories.py b/src/cleveragents/infrastructure/database/repositories.py index 818af488e..0cceba972 100644 --- a/src/cleveragents/infrastructure/database/repositories.py +++ b/src/cleveragents/infrastructure/database/repositories.py @@ -6056,6 +6056,50 @@ class CorrectionAttemptRepository: f"Failed to list correction attempts for plan {plan_id}: {exc}" ) from exc + # --- LIST BY DECISION -------------------------------------------------- + + @database_retry + def list_by_decision( + self, + decision_id: str, + *, + new_only: bool = False, + ) -> list[CorrectionAttemptRecord]: + """List all correction attempts targeting a given decision. + + Args: + decision_id: Decision ULID — the ``original_decision_id`` of + ``CorrectionAttemptModel`` rows to filter on. + new_only: If ``True``, only return corrections that have not yet + completed (i.e. state is neither ``"complete"`` nor + ``"failed"``). Defaults to ``False`` (returns all history). + + Returns: + List of ``CorrectionAttemptRecord`` domain objects, ordered by + creation time ascending. + + Raises: + DatabaseError: On transient or unexpected DB errors. + """ + session = self._session() + try: + query = session.query(CorrectionAttemptModel).filter_by( + original_decision_id=decision_id, + ) + if new_only: + query = query.filter( + CorrectionAttemptModel.state.notin_( + ("complete", "failed"), + ) + ) + rows = query.order_by(CorrectionAttemptModel.created_at).all() + return [row.to_domain() for row in rows] + except (OperationalError, SQLAlchemyDatabaseError) as exc: + raise DatabaseError( + f"Failed to list correction attempts for decision " + f"{decision_id}: {exc}" + ) from exc + # --- UPDATE STATE ------------------------------------------------------ @database_retry