33from datetime import UTC , datetime , timedelta
44from pathlib import Path
55
6- from codealmanac .core .errors import ConflictError , NotFoundError
6+ from codealmanac .core .errors import NotFoundError
77from codealmanac .core .paths import normalize_path
88from codealmanac .database .local import connect_local_database
99from codealmanac .services .harnesses .models import HarnessEvent , HarnessTranscriptRef
2323 RunStatus ,
2424)
2525from codealmanac .services .runs .tables import RUN_TABLES
26+ from codealmanac .services .runs .transitions import (
27+ attach_harness_transcript ,
28+ cancel_run ,
29+ finish_run ,
30+ queued_message ,
31+ start_run ,
32+ )
2633from codealmanac .services .runs .worker_locks import RunWorkerLockStore
2734
2835
@@ -188,20 +195,10 @@ def record_event(
188195
189196 def mark_running (self , run_id : str ) -> RunRecord :
190197 record = self .read (run_id )
191- if record .status == RunStatus .RUNNING :
192- return record
193- if record .status != RunStatus .QUEUED :
194- raise ConflictError (
195- f"run { run_id } cannot start from { record .status .value } "
196- )
197198 now = datetime .now (UTC )
198- running = record .model_copy (
199- update = {
200- "status" : RunStatus .RUNNING ,
201- "updated_at" : now ,
202- "started_at" : now ,
203- }
204- )
199+ running = start_run (record , now )
200+ if running is record :
201+ return record
205202 self .update_record_preserving_spec (running )
206203 self .event_store .append_status (run_id , now , RunStatus .RUNNING .value )
207204 return running
@@ -212,12 +209,7 @@ def record_harness_transcript(
212209 transcript : HarnessTranscriptRef ,
213210 ) -> RunRecord :
214211 record = self .read (run_id )
215- updated = record .model_copy (
216- update = {
217- "harness_transcript" : transcript ,
218- "updated_at" : datetime .now (UTC ),
219- }
220- )
212+ updated = attach_harness_transcript (record , transcript , datetime .now (UTC ))
221213 self .update_record_preserving_spec (updated )
222214 return updated
223215
@@ -229,36 +221,21 @@ def finish(
229221 error : str | None ,
230222 ) -> RunRecord :
231223 record = self .read (run_id )
232- if record .status == RunStatus .CANCELLED :
233- return record
234224 now = datetime .now (UTC )
235- finished = record .model_copy (
236- update = {
237- "status" : status ,
238- "summary" : summary ,
239- "error" : error ,
240- "updated_at" : now ,
241- "finished_at" : now ,
242- }
243- )
225+ finished = finish_run (record , status , summary , error , now )
226+ if finished is record :
227+ return record
244228 self .update_record_preserving_spec (finished )
245229 self .event_store .append_status (run_id , now , status .value )
246230 return finished
247231
248232 def cancel (self , run_id : str ) -> RunCancelResult :
249233 record = self .read (run_id )
250- if record .status in TERMINAL_RUN_STATUSES :
251- return RunCancelResult (record = record , changed = False )
252234 now = datetime .now (UTC )
253- cancelled = record .model_copy (
254- update = {
255- "status" : RunStatus .CANCELLED ,
256- "updated_at" : now ,
257- "finished_at" : now ,
258- "summary" : record .summary ,
259- "error" : record .error ,
260- }
261- )
235+ result = cancel_run (record , now )
236+ if not result .changed :
237+ return result
238+ cancelled = result .record
262239 self .update_record_preserving_spec (cancelled )
263240 self .event_store .append_status (run_id , now , RunStatus .CANCELLED .value )
264241 return RunCancelResult (record = cancelled , changed = True )
@@ -307,7 +284,3 @@ def connect(self):
307284
308285def run_record_from_json (value : str ) -> RunRecord :
309286 return RunRecord .model_validate_json (value )
310-
311-
312- def queued_message (kind : RunKind ) -> str :
313- return f"queued { kind .value } "
0 commit comments