generated from coulomb/repo-seed
Add reconciliation file write-through
This commit is contained in:
@@ -5,14 +5,23 @@ from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from api.database import get_session
|
||||
from api.models.managed_repo import ManagedRepo
|
||||
from api.models.task import Task
|
||||
from api.models.task import TaskStatus
|
||||
from api.models.workstream import Workstream
|
||||
from api.schemas.reconciliation import StateChangeRequest, StateChangeResponse
|
||||
from api.services.lifecycle import status_value
|
||||
from api.services.reconciliation import (
|
||||
ReconciliationClass,
|
||||
classify_task_status_change,
|
||||
classify_workstream_status_change,
|
||||
)
|
||||
from api.services.workplan_files import (
|
||||
find_workplan_for_workstream,
|
||||
patch_task_status,
|
||||
patch_workplan_status,
|
||||
task_block_linked,
|
||||
)
|
||||
from api.workplan_status import normalize_workstream_status
|
||||
|
||||
router = APIRouter(prefix="/reconciliation", tags=["reconciliation"])
|
||||
@@ -38,33 +47,58 @@ async def classify_state_change(
|
||||
if ws is None:
|
||||
raise HTTPException(status_code=404, detail="Workstream not found")
|
||||
|
||||
file_backed = _bool_or_default(body.file_backed, ws.repo_id is not None)
|
||||
archived_file = _bool_or_default(body.archived_file, False)
|
||||
repo = await session.get(ManagedRepo, ws.repo_id) if ws.repo_id else None
|
||||
workplan_ref = find_workplan_for_workstream(repo, ws.id)
|
||||
actual_file_backed = workplan_ref is not None
|
||||
actual_archived_file = bool(workplan_ref and workplan_ref.archived)
|
||||
file_backed = (
|
||||
actual_file_backed
|
||||
if body.apply
|
||||
else _bool_or_default(body.file_backed, actual_file_backed)
|
||||
)
|
||||
archived_file = (
|
||||
actual_archived_file
|
||||
if body.apply
|
||||
else _bool_or_default(body.archived_file, actual_archived_file)
|
||||
)
|
||||
tasks_terminal = (
|
||||
body.tasks_terminal
|
||||
if body.tasks_terminal is not None
|
||||
else await _workstream_tasks_terminal(session, ws.id)
|
||||
)
|
||||
current_status = normalize_workstream_status(ws.status)
|
||||
target_status = normalize_workstream_status(body.target_status)
|
||||
classification = classify_workstream_status_change(
|
||||
current_status=ws.status,
|
||||
target_status=body.target_status,
|
||||
current_status=current_status,
|
||||
target_status=target_status,
|
||||
file_backed=file_backed,
|
||||
archived_file=archived_file,
|
||||
tasks_terminal=tasks_terminal,
|
||||
)
|
||||
write_result = "not_attempted"
|
||||
if body.apply:
|
||||
if classification.reconciliation_class == ReconciliationClass.WRITE_THROUGH and workplan_ref:
|
||||
patch_workplan_status(workplan_ref.path, target_status)
|
||||
ws.status = target_status
|
||||
await session.commit()
|
||||
write_result = "applied"
|
||||
else:
|
||||
write_result = "not_applicable"
|
||||
return StateChangeResponse(
|
||||
target_type=body.target_type,
|
||||
target_id=body.target_id,
|
||||
actor=body.actor,
|
||||
intent=body.intent,
|
||||
current_status=normalize_workstream_status(ws.status),
|
||||
target_status=normalize_workstream_status(body.target_status),
|
||||
current_status=current_status,
|
||||
target_status=target_status,
|
||||
file_backed=file_backed,
|
||||
archived_file=archived_file,
|
||||
tasks_terminal=tasks_terminal,
|
||||
reconciliation_class=classification.reconciliation_class,
|
||||
reason=classification.reason,
|
||||
follow_up=classification.follow_up,
|
||||
write_through_result=write_result,
|
||||
workplan_path=workplan_ref.relative_path if workplan_ref else None,
|
||||
)
|
||||
|
||||
task = await session.get(Task, body.target_id)
|
||||
@@ -72,28 +106,64 @@ async def classify_state_change(
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
|
||||
ws = await session.get(Workstream, task.workstream_id)
|
||||
file_backed = _bool_or_default(body.file_backed, bool(ws and ws.repo_id))
|
||||
archived_file = _bool_or_default(body.archived_file, False)
|
||||
task_linked = _bool_or_default(body.task_linked, True)
|
||||
repo = await session.get(ManagedRepo, ws.repo_id) if ws and ws.repo_id else None
|
||||
workplan_ref = find_workplan_for_workstream(repo, ws.id) if ws else None
|
||||
actual_file_backed = workplan_ref is not None
|
||||
actual_archived_file = bool(workplan_ref and workplan_ref.archived)
|
||||
file_backed = (
|
||||
actual_file_backed
|
||||
if body.apply
|
||||
else _bool_or_default(body.file_backed, actual_file_backed)
|
||||
)
|
||||
archived_file = (
|
||||
actual_archived_file
|
||||
if body.apply
|
||||
else _bool_or_default(body.archived_file, actual_archived_file)
|
||||
)
|
||||
actual_task_linked = bool(workplan_ref and task_block_linked(workplan_ref.path, task.id))
|
||||
task_linked = (
|
||||
actual_task_linked
|
||||
if body.apply
|
||||
else _bool_or_default(body.task_linked, actual_task_linked)
|
||||
)
|
||||
current_status = status_value(task.status)
|
||||
target_status = status_value(body.target_status)
|
||||
classification = classify_task_status_change(
|
||||
current_status=task.status,
|
||||
target_status=body.target_status,
|
||||
current_status=current_status,
|
||||
target_status=target_status,
|
||||
file_backed=file_backed,
|
||||
archived_file=archived_file,
|
||||
task_linked=task_linked,
|
||||
blocking_reason=body.blocking_reason,
|
||||
)
|
||||
write_result = "not_attempted"
|
||||
if body.apply:
|
||||
if (
|
||||
classification.reconciliation_class == ReconciliationClass.WRITE_THROUGH
|
||||
and workplan_ref
|
||||
and actual_task_linked
|
||||
):
|
||||
patch_task_status(workplan_ref.path, task.id, target_status)
|
||||
task.status = TaskStatus(target_status)
|
||||
if body.blocking_reason is not None:
|
||||
task.blocking_reason = body.blocking_reason
|
||||
await session.commit()
|
||||
write_result = "applied"
|
||||
else:
|
||||
write_result = "not_applicable"
|
||||
return StateChangeResponse(
|
||||
target_type=body.target_type,
|
||||
target_id=body.target_id,
|
||||
actor=body.actor,
|
||||
intent=body.intent,
|
||||
current_status=status_value(task.status),
|
||||
target_status=status_value(body.target_status),
|
||||
current_status=current_status,
|
||||
target_status=target_status,
|
||||
file_backed=file_backed,
|
||||
archived_file=archived_file,
|
||||
task_linked=task_linked,
|
||||
reconciliation_class=classification.reconciliation_class,
|
||||
reason=classification.reason,
|
||||
follow_up=classification.follow_up,
|
||||
write_through_result=write_result,
|
||||
workplan_path=workplan_ref.relative_path if workplan_ref else None,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user