chore(semantic): remediate backend core contracts

This commit is contained in:
2026-03-15 21:23:44 +03:00
parent 84a2cd5429
commit 0bf55885a8
7 changed files with 166 additions and 49 deletions

View File

@@ -29,6 +29,10 @@ from ..logger import logger, belief_scope
# @TIER: CRITICAL
# @SEMANTICS: persistence, service, database, sqlalchemy
# @PURPOSE: Provides methods to save and load tasks from the tasks.db database using SQLAlchemy.
# @RELATION: [DEPENDS_ON] ->[backend.src.core.database.TasksSessionLocal]
# @RELATION: [DEPENDS_ON] ->[backend.src.models.task.TaskRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.models.mapping.Environment]
# @RELATION: [USED_BY] ->[backend.src.core.task_manager.manager.TaskManager]
# @INVARIANT: Persistence must handle potentially missing task fields natively.
#
# @TEST_CONTRACT: TaskPersistenceService ->
@@ -46,6 +50,7 @@ from ..logger import logger, belief_scope
# @TEST_INVARIANT: accurate_round_trip -> verifies: [valid_task_persistence, load_corrupt_json_params]
class TaskPersistenceService:
# [DEF:_json_load_if_needed:Function]
# @TIER: TRIVIAL
# @PURPOSE: Safely load JSON strings from DB if necessary
# @PRE: value is an arbitrary database value
# @POST: Returns parsed JSON object, list, string, or primitive
@@ -68,6 +73,7 @@ class TaskPersistenceService:
# [/DEF:_json_load_if_needed:Function]
# [DEF:_parse_datetime:Function]
# @TIER: TRIVIAL
# @PURPOSE: Safely parse a datetime string from the database
# @PRE: value is an ISO string or datetime object
# @POST: Returns datetime object or None
@@ -89,6 +95,7 @@ class TaskPersistenceService:
# @PURPOSE: Resolve environment id into existing environments.id value to satisfy FK constraints.
# @PRE: Session is active
# @POST: Returns existing environments.id or None when unresolved.
# @DATA_CONTRACT: Input[env_id: Optional[str]] -> Output[Optional[str]]
@staticmethod
def _resolve_environment_id(session: Session, env_id: Optional[str]) -> Optional[str]:
with belief_scope("_resolve_environment_id"):
@@ -140,6 +147,8 @@ class TaskPersistenceService:
# @POST: Task record created or updated in database.
# @PARAM: task (Task) - The task object to persist.
# @SIDE_EFFECT: Writes to task_records table in tasks.db
# @DATA_CONTRACT: Input[Task] -> Model[TaskRecord]
# @RELATION: [CALLS] ->[self._resolve_environment_id]
def persist_task(self, task: Task) -> None:
with belief_scope("TaskPersistenceService.persist_task", f"task_id={task.id}"):
session: Session = TasksSessionLocal()
@@ -202,6 +211,7 @@ class TaskPersistenceService:
# @PRE: isinstance(tasks, list)
# @POST: All tasks in list are persisted.
# @PARAM: tasks (List[Task]) - The list of tasks to persist.
# @RELATION: [CALLS] ->[self.persist_task]
def persist_tasks(self, tasks: List[Task]) -> None:
with belief_scope("TaskPersistenceService.persist_tasks"):
for task in tasks:
@@ -216,6 +226,9 @@ class TaskPersistenceService:
# @PARAM: limit (int) - Max tasks to load.
# @PARAM: status (Optional[TaskStatus]) - Filter by status.
# @RETURN: List[Task] - The loaded tasks.
# @DATA_CONTRACT: Model[TaskRecord] -> Output[List[Task]]
# @RELATION: [CALLS] ->[self._json_load_if_needed]
# @RELATION: [CALLS] ->[self._parse_datetime]
def load_tasks(self, limit: int = 100, status: Optional[TaskStatus] = None) -> List[Task]:
with belief_scope("TaskPersistenceService.load_tasks"):
session: Session = TasksSessionLocal()
@@ -269,6 +282,7 @@ class TaskPersistenceService:
# @PRE: task_ids is a list of strings.
# @POST: Specified task records deleted from database.
# @PARAM: task_ids (List[str]) - List of task IDs to delete.
# @SIDE_EFFECT: Deletes rows from task_records table.
def delete_tasks(self, task_ids: List[str]) -> None:
if not task_ids:
return
@@ -290,7 +304,9 @@ class TaskPersistenceService:
# @TIER: CRITICAL
# @SEMANTICS: persistence, service, database, log, sqlalchemy
# @PURPOSE: Provides methods to save and query task logs from the task_logs table.
# @RELATION: DEPENDS_ON -> TaskLogRecord
# @RELATION: [DEPENDS_ON] ->[backend.src.models.task.TaskLogRecord]
# @RELATION: [DEPENDS_ON] ->[backend.src.core.database.TasksSessionLocal]
# @RELATION: [USED_BY] ->[backend.src.core.task_manager.manager.TaskManager]
# @INVARIANT: Log entries are batch-inserted for performance.
#
# @TEST_CONTRACT: TaskLogPersistenceService ->
@@ -328,6 +344,7 @@ class TaskLogPersistenceService:
# @PARAM: task_id (str) - The task ID.
# @PARAM: logs (List[LogEntry]) - Log entries to insert.
# @SIDE_EFFECT: Writes to task_logs table.
# @DATA_CONTRACT: Input[List[LogEntry]] -> Model[TaskLogRecord]
def add_logs(self, task_id: str, logs: List[LogEntry]) -> None:
if not logs:
return
@@ -360,6 +377,7 @@ class TaskLogPersistenceService:
# @PARAM: task_id (str) - The task ID.
# @PARAM: log_filter (LogFilter) - Filter parameters.
# @RETURN: List[TaskLog] - Filtered log entries.
# @DATA_CONTRACT: Model[TaskLogRecord] -> Output[List[TaskLog]]
def get_logs(self, task_id: str, log_filter: LogFilter) -> List[TaskLog]:
with belief_scope("TaskLogPersistenceService.get_logs", f"task_id={task_id}"):
session: Session = TasksSessionLocal()
@@ -412,6 +430,7 @@ class TaskLogPersistenceService:
# @POST: Returns LogStats with counts by level and source.
# @PARAM: task_id (str) - The task ID.
# @RETURN: LogStats - Statistics about task logs.
# @DATA_CONTRACT: Model[TaskLogRecord] -> Output[LogStats]
def get_log_stats(self, task_id: str) -> LogStats:
with belief_scope("TaskLogPersistenceService.get_log_stats", f"task_id={task_id}"):
session: Session = TasksSessionLocal()
@@ -458,6 +477,7 @@ class TaskLogPersistenceService:
# @POST: Returns list of unique source strings.
# @PARAM: task_id (str) - The task ID.
# @RETURN: List[str] - Unique source names.
# @DATA_CONTRACT: Model[TaskLogRecord] -> Output[List[str]]
def get_sources(self, task_id: str) -> List[str]:
with belief_scope("TaskLogPersistenceService.get_sources", f"task_id={task_id}"):
session: Session = TasksSessionLocal()
@@ -499,6 +519,7 @@ class TaskLogPersistenceService:
# @PRE: task_ids is a list of task IDs.
# @POST: All logs for the tasks are deleted.
# @PARAM: task_ids (List[str]) - List of task IDs.
# @SIDE_EFFECT: Deletes rows from task_logs table.
def delete_logs_for_tasks(self, task_ids: List[str]) -> None:
if not task_ids:
return