fix: preserve stale task identity history
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a053ff-1d6f-7fe2-ac1c-a6eb40a42a0c
This commit is contained in:
parent
ddce470944
commit
a32112e5ab
4 changed files with 65 additions and 44 deletions
|
|
@ -884,7 +884,7 @@ async def reset_repository_projection(
|
|||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy import select
|
||||
|
||||
from api.models.managed_repo import ManagedRepo
|
||||
from api.models.task import Task
|
||||
|
|
@ -1200,10 +1200,13 @@ async def reset_repository_projection(
|
|||
row = matched.get(key)
|
||||
if row is None:
|
||||
continue
|
||||
desired_record_ids = {
|
||||
task.record_id.strip().lower() for task in workplan.tasks
|
||||
}
|
||||
groups: dict[str, list[Any]] = {}
|
||||
for task_row in tasks_by_wp.get(row.id, []):
|
||||
record_id = (task_row.record_id or "").strip().lower()
|
||||
if record_id:
|
||||
if record_id and record_id in desired_record_ids:
|
||||
groups.setdefault(record_id, []).append(task_row)
|
||||
for task_rows in groups.values():
|
||||
if len(task_rows) > 1:
|
||||
|
|
@ -1226,9 +1229,11 @@ async def reset_repository_projection(
|
|||
return outcome
|
||||
|
||||
# Check every task the reset would create in one query. A derived UUID held
|
||||
# by another workplan is a global identity collision, even when the two
|
||||
# human-readable rows happen to have different titles. Letting the INSERT
|
||||
# discover this would turn a deterministic refusal into an IntegrityError.
|
||||
# by another workplan is a global identity collision. A repeated record_id
|
||||
# on a different workplan is not sufficient by itself: terminal rows from
|
||||
# older, wrong projections retain that label as history and tasks have no
|
||||
# projection-retirement marker. Letting the INSERT discover a UUID collision
|
||||
# would turn a deterministic refusal into an IntegrityError.
|
||||
creating_tasks: dict[str, tuple[DerivedWorkplan, DerivedTask]] = {}
|
||||
for key, workplan in want.items():
|
||||
row = matched.get(key)
|
||||
|
|
@ -1247,10 +1252,6 @@ async def reset_repository_projection(
|
|||
creating_tasks[task.uuid] = (workplan, task)
|
||||
|
||||
if creating_tasks:
|
||||
creating_tasks_by_record_id = {
|
||||
task.record_id.strip().lower(): (workplan, task)
|
||||
for workplan, task in creating_tasks.values()
|
||||
}
|
||||
current_holder_filters = [Workplan.projection_retired_at.is_(None)]
|
||||
if stale:
|
||||
# The caller has already acknowledged these retirements (the
|
||||
|
|
@ -1267,11 +1268,8 @@ async def reset_repository_projection(
|
|||
.join(Workplan, Workplan.id == Task.workplan_id)
|
||||
.where(
|
||||
*current_holder_filters,
|
||||
or_(
|
||||
Task.id.in_(
|
||||
[uuid.UUID(task_id) for task_id in creating_tasks]
|
||||
),
|
||||
func.lower(Task.record_id).in_(creating_tasks_by_record_id),
|
||||
Task.id.in_(
|
||||
[uuid.UUID(task_id) for task_id in creating_tasks]
|
||||
),
|
||||
)
|
||||
)
|
||||
|
|
@ -1280,15 +1278,10 @@ async def reset_repository_projection(
|
|||
if task_holders:
|
||||
outcome.status = "refused"
|
||||
for holder in task_holders:
|
||||
candidate = creating_tasks.get(str(holder.id))
|
||||
if candidate is None:
|
||||
candidate = creating_tasks_by_record_id[
|
||||
(holder.record_id or "").strip().lower()
|
||||
]
|
||||
workplan, task = candidate
|
||||
workplan, task = creating_tasks[str(holder.id)]
|
||||
outcome.refused.append(
|
||||
{
|
||||
"reason": "task identity already belongs to another current workplan",
|
||||
"reason": "derived task identifier already belongs to another current workplan",
|
||||
"kind": "task",
|
||||
"record_id": task.record_id,
|
||||
"uuid": task.uuid,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue