feat(prompts): implement Phase 1 - Foundation (FR-1)
Implement addressable artifacts with content-based identity and change detection. Core Features: - Artifact model with SHA-256 content digests - ArtifactReference for cross-space addressing - IArtifactRepository interface for pluggable storage - SQLiteArtifactRepository implementation - ArtifactService for high-level operations - Content digest calculation utilities Database: - prompt_artifacts table with indexes - Support for artifact metadata and types - UNIQUE constraint on space_id+name Tests (41 passing): - 26 model tests (metadata, artifacts, references, digests) - 15 repository tests (CRUD, queries, constraints) Implements: - FR-1.1: Unique addressability by name and ID - FR-1.2: Content digest computation and storage - FR-1.3: Cross-space artifact references Files Created: - markitect/prompts/models.py - markitect/prompts/repositories/interfaces.py - markitect/prompts/repositories/sqlite.py - markitect/prompts/services/artifact_service.py - migrations/prompts/001_create_artifacts_table.sql - tests/unit/prompts/test_artifact_models.py - tests/unit/prompts/test_artifact_repository.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
159
markitect/prompts/repositories/interfaces.py
Normal file
159
markitect/prompts/repositories/interfaces.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
Repository interfaces for artifact persistence.
|
||||
|
||||
Defines abstract interfaces for artifact storage, enabling
|
||||
pluggable storage backends.
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Optional
|
||||
from markitect.prompts.models import Artifact, ArtifactType
|
||||
|
||||
|
||||
class RepositoryError(Exception):
|
||||
"""Base exception for repository errors."""
|
||||
pass
|
||||
|
||||
|
||||
class ArtifactNotFoundError(RepositoryError):
|
||||
"""Raised when an artifact cannot be found."""
|
||||
pass
|
||||
|
||||
|
||||
class DuplicateArtifactError(RepositoryError):
|
||||
"""Raised when attempting to create an artifact with duplicate name."""
|
||||
pass
|
||||
|
||||
|
||||
class IArtifactRepository(ABC):
|
||||
"""
|
||||
Abstract interface for artifact persistence.
|
||||
|
||||
Implements FR-1: InformationSpace Addressability
|
||||
Provides CRUD operations for artifacts with content digest tracking.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def create(self, artifact: Artifact) -> Artifact:
|
||||
"""
|
||||
Persist a new artifact.
|
||||
|
||||
Args:
|
||||
artifact: Artifact to create
|
||||
|
||||
Returns:
|
||||
Created artifact
|
||||
|
||||
Raises:
|
||||
DuplicateArtifactError: If artifact with same space_id+name exists
|
||||
RepositoryError: On other persistence errors
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_by_id(self, artifact_id: str) -> Optional[Artifact]:
|
||||
"""
|
||||
Retrieve artifact by ID.
|
||||
|
||||
Args:
|
||||
artifact_id: Artifact identifier
|
||||
|
||||
Returns:
|
||||
Artifact if found, None otherwise
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_by_name(self, space_id: str, name: str) -> Optional[Artifact]:
|
||||
"""
|
||||
Retrieve artifact by space and name.
|
||||
|
||||
Implements FR-1.3: Cross-space artifact lookup
|
||||
|
||||
Args:
|
||||
space_id: Space identifier
|
||||
name: Artifact name
|
||||
|
||||
Returns:
|
||||
Artifact if found, None otherwise
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_by_digest(self, content_digest: str) -> List[Artifact]:
|
||||
"""
|
||||
Find artifacts with matching content digest.
|
||||
|
||||
Implements FR-1.2: Content digest queries
|
||||
|
||||
Args:
|
||||
content_digest: SHA-256 digest to match
|
||||
|
||||
Returns:
|
||||
List of artifacts with matching digest
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def list_by_space(
|
||||
self,
|
||||
space_id: str,
|
||||
artifact_type: Optional[ArtifactType] = None,
|
||||
) -> List[Artifact]:
|
||||
"""
|
||||
List all artifacts in a space.
|
||||
|
||||
Args:
|
||||
space_id: Space identifier
|
||||
artifact_type: Optional type filter
|
||||
|
||||
Returns:
|
||||
List of artifacts in space
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def update(self, artifact: Artifact) -> Artifact:
|
||||
"""
|
||||
Update an existing artifact.
|
||||
|
||||
Updates content digest and modified timestamp.
|
||||
|
||||
Args:
|
||||
artifact: Artifact with updated data
|
||||
|
||||
Returns:
|
||||
Updated artifact
|
||||
|
||||
Raises:
|
||||
ArtifactNotFoundError: If artifact doesn't exist
|
||||
RepositoryError: On other persistence errors
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def delete(self, artifact_id: str) -> bool:
|
||||
"""
|
||||
Delete an artifact.
|
||||
|
||||
Args:
|
||||
artifact_id: Artifact identifier
|
||||
|
||||
Returns:
|
||||
True if deleted, False if not found
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def exists(self, space_id: str, name: str) -> bool:
|
||||
"""
|
||||
Check if artifact exists.
|
||||
|
||||
Args:
|
||||
space_id: Space identifier
|
||||
name: Artifact name
|
||||
|
||||
Returns:
|
||||
True if artifact exists
|
||||
"""
|
||||
pass
|
||||
Reference in New Issue
Block a user