From 099d37f566afde1b4e83d97d55671326cd62aaef Mon Sep 17 00:00:00 2001 From: Tristan Simas Date: Sun, 1 Nov 2026 09:53:11 -0500 Subject: [PATCH] Fix generation-owned Retry refusal diagnostics --- src/agent_comms/goal_generation.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/agent_comms/goal_generation.py b/src/agent_comms/goal_generation.py index 348e32e609..f4b20e8d75 100644 --- a/src/agent_comms/goal_generation.py +++ b/src/agent_comms/goal_generation.py @@ -4,6 +4,7 @@ from sqlite3 import Connection +from abc import abstractmethod from dataclasses import dataclass from typing import TYPE_CHECKING, ClassVar @@ -87,10 +88,11 @@ def allows_resume(self, active_turn: bool) -> bool: def stopped_permit(self, store: GoalAttemptStore, generation: Generation) -> GoalTurnPermit: return NoLaunchPermit() + @abstractmethod def authorize_retry( self, store: GoalAttemptStore, generation: Generation, decision: WorkDecision ) -> None: - raise ValueError("The goal attempt is unresolved; inspect it before retrying.") + """Authorize new work or refuse according to this generation's lifecycle.""" @dataclass(frozen=True) @@ -139,6 +141,14 @@ def authorize_retry( @dataclass(frozen=True) class ReservedGeneration(GenerationState): + def authorize_retry( + self, store: GoalAttemptStore, generation: Generation, decision: WorkDecision + ) -> None: + raise ValueError( + f"The goal generation is reserved for attempt {generation.attempt_identity.attempt_id}; " + "Retry cannot replace it. Inspect that attempt before deciding on new work." + ) + def stopped_permit(self, store: GoalAttemptStore, generation: Generation) -> GoalTurnPermit: return store.read_attempt(generation.attempt_identity.attempt_id).stopped_permit() @@ -196,11 +206,21 @@ def authorize_retry( @dataclass(frozen=True) class CompletedGeneration(Complete, Terminal, GenerationState): + def authorize_retry( + self, store: GoalAttemptStore, generation: Generation, decision: WorkDecision + ) -> None: + raise ValueError("The goal generation is completed; Retry cannot restart completed work.") + def execution(self, source: GoalExecutionSource) -> GoalExecution: return CompletedExecution(source.goal.id) @dataclass(frozen=True) class CancelledGeneration(Terminal, GenerationState): + def authorize_retry( + self, store: GoalAttemptStore, generation: Generation, decision: WorkDecision + ) -> None: + raise ValueError("The goal generation is cancelled; Retry cannot restart cancelled work.") + def validate_attempt(self, attempt_id: AttemptId | NoAttemptId) -> None: """Retirement preserves either the recorded attempt or its declared absence."""