service.py
python
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22
Add fixture provenance retention deletion
Human
minor
⚠ breaking
43 days ago
| 1 | """Application service for Scooling Lab training API operations.""" |
| 2 | |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from datetime import datetime |
| 6 | from typing import Iterable |
| 7 | |
| 8 | from scooling_lab.contracts import ( |
| 9 | TrainingJobRequest, |
| 10 | TrainingJobStatus, |
| 11 | require_artifact_id, |
| 12 | require_job_id, |
| 13 | ) |
| 14 | from scooling_lab.fake_worker import FakeTrainingWorker |
| 15 | from scooling_lab.store import TrainingJobStore |
| 16 | |
| 17 | |
| 18 | class TrainingApiService: |
| 19 | """Implements the T2 API contract over a store and fake worker.""" |
| 20 | |
| 21 | def __init__(self, store: TrainingJobStore, auto_run_worker: bool = True) -> None: |
| 22 | """Create a service with optional synchronous fake-worker completion.""" |
| 23 | |
| 24 | self._store = store |
| 25 | self._worker = FakeTrainingWorker(store) |
| 26 | self._auto_run_worker = auto_run_worker |
| 27 | |
| 28 | def create_training_job(self, payload: dict[str, object]) -> dict[str, object]: |
| 29 | """Validate, create, and optionally complete a fixture training job.""" |
| 30 | |
| 31 | request = TrainingJobRequest.from_mapping(payload) |
| 32 | job = self._store.create(request) |
| 33 | if self._auto_run_worker and job.status in { |
| 34 | TrainingJobStatus.QUEUED, |
| 35 | TrainingJobStatus.RUNNING, |
| 36 | }: |
| 37 | job = self._worker.run_job(job.id) |
| 38 | return job.to_public_dict() |
| 39 | |
| 40 | def get_training_job(self, job_id: str) -> dict[str, object]: |
| 41 | """Return the public status for one training job.""" |
| 42 | |
| 43 | require_job_id(job_id) |
| 44 | return self._store.evaluate_expiry(job_id).to_public_dict() |
| 45 | |
| 46 | def cancel_training_job(self, job_id: str) -> dict[str, object]: |
| 47 | """Cancel a queued or running training job.""" |
| 48 | |
| 49 | require_job_id(job_id) |
| 50 | return self._store.update_status( |
| 51 | job_id, TrainingJobStatus.CANCELLED |
| 52 | ).to_public_dict() |
| 53 | |
| 54 | def list_artifacts(self, job_id: str) -> dict[str, object]: |
| 55 | """Return placeholder artifacts registered for one job.""" |
| 56 | |
| 57 | require_job_id(job_id) |
| 58 | self._store.evaluate_expiry(job_id) |
| 59 | artifacts = [artifact.to_dict() for artifact in self._store.list_artifacts(job_id)] |
| 60 | return {"jobId": job_id, "artifacts": artifacts} |
| 61 | |
| 62 | def get_provenance(self, job_id: str) -> dict[str, object]: |
| 63 | """Return the validated provenance record for one completed fixture job.""" |
| 64 | |
| 65 | require_job_id(job_id) |
| 66 | self._store.evaluate_expiry(job_id) |
| 67 | return self._store.get_provenance(job_id).to_dict() |
| 68 | |
| 69 | def delete_artifact(self, job_id: str, artifact_id: str) -> dict[str, object]: |
| 70 | """Delete an artifact and all derived content-bearing metadata.""" |
| 71 | |
| 72 | require_job_id(job_id) |
| 73 | require_artifact_id(artifact_id) |
| 74 | return self._store.delete_artifact(job_id, artifact_id).to_dict() |
| 75 | |
| 76 | def sweep_expired_artifacts(self, now: datetime | None = None) -> dict[str, object]: |
| 77 | """Evaluate all retention policies and delete expired artifacts.""" |
| 78 | |
| 79 | return self._store.sweep_expired(now) |
| 80 | |
| 81 | def verify_deleted_artifact_absence(self, hash_values: Iterable[str]) -> bool: |
| 82 | """Verify deleted artifact hashes are absent from all store outputs.""" |
| 83 | |
| 84 | return self._store.verify_hash_absence(hash_values) |
File History
1 commit
sha256:91e875d4a97bb1e35f37992f803988d5713931f1782d870c371c50054574af22
Add fixture provenance retention deletion
Human
minor
⚠
43 days ago