fix: revalidate review context and serialize index retry

This commit is contained in:
2026-09-26 19:50:57 +08:00
parent b800481902
commit fe851c5f91
4 changed files with 35 additions and 3 deletions
+11
View File
@@ -175,6 +175,17 @@ def test_fixed_batch_membership_duplicate_queue_and_review(db, monkeypatch, sess
"comment": "人工核定", "reason": "核查纸质材料"}, "给 3 分")
action_id = prepared["pending_action"]["id"]
assert score.teacher_score is None
student = db.get(Student, first.student_id)
student.name = "身份变化"
db.commit()
with pytest.raises(HTTPException):
confirm(db, conversation, action_id)
assert score.teacher_score is None
student.name = "学生4"
db.commit()
prepared = execute(db, conversation, "prepare_review", {"score_id": score.id, "score": 3,
"comment": "人工核定", "reason": "核查纸质材料"}, "给 3 分")
action_id = prepared["pending_action"]["id"]
confirm(db, conversation, action_id)
db.refresh(score)
assert score.teacher_score == 3 and score.model_score is None and score.status == "reviewed"
+18 -2
View File
@@ -101,15 +101,27 @@ def _state(db, kind, payload):
"rubric": digest({"criteria": rubric.criteria, "weights": rubric.weights}), "project_ids": projects}
if kind == "start_batch":
batch = services.found(db, ScoringBatch, payload["batch_id"])
version = services.found(db, CourseVersion, batch.course_version_id)
rubric = services.found(db, RubricVersion, batch.rubric_version_id)
if not version.published or not rubric.published or rubric.course_version_id != version.id:
raise HTTPException(409, "课程或规则发布状态已变化,请重新预览")
return {"status": batch.status, "project_ids": batch.project_ids,
"snapshot": digest(batch.rubric_snapshot)}
if kind == "review":
score = services.found(db, CriterionScore, payload["score_id"])
batch = services.found(db, ScoringBatch, score.batch_id)
project = services.found(db, Project, score.project_id)
if project.course_version_id != batch.course_version_id or batch.project_ids is not None and project.id not in batch.project_ids:
raise HTTPException(409, "评分项与批次项目关系已变化,请重新预览")
if not any(item["criterion_id"] == score.criterion_id for item in batch.rubric_snapshot["criteria"]):
raise HTTPException(409, "评分项不属于批次规则快照")
student = services.found(db, Student, project.student_id)
evidence = db.scalars(select(ScoreEvidence).where(ScoreEvidence.score_id == score.id).order_by(ScoreEvidence.id)).all()
return {"status": score.status, "model_score": score.model_score,
"teacher_score": score.teacher_score, "teacher_comment": score.teacher_comment,
"error": score.error, "batch_id": score.batch_id, "project_id": score.project_id,
"criterion_id": score.criterion_id,
"student_id": student.id, "student_no": student.student_no, "student_name": student.name,
"criterion_id": score.criterion_id, "rubric_snapshot": digest(batch.rubric_snapshot),
"evidence": digest([[item.id, item.page, item.quote] for item in evidence])}
if kind == "export":
batch = services.found(db, ScoringBatch, payload["batch_id"])
@@ -235,7 +247,11 @@ def confirm(db, conversation: Conversation, action_id: int):
if action.kind == "import" and action.preview.get("requires_edit"):
raise HTTPException(409, "导入候选存在歧义,请教师修正文件选择并更新预览")
expires = action.expires_at.replace(tzinfo=timezone.utc) if action.expires_at.tzinfo is None else action.expires_at
if expires <= now() or _state(db, action.kind, action.payload) != action.expected:
try:
current = _state(db, action.kind, action.payload) if expires > now() else None
except (HTTPException, ValueError):
current = None
if current != action.expected:
action.status = "stale"
db.commit()
raise HTTPException(409, "目标或文件已变化,请重新预览")
+5 -1
View File
@@ -137,8 +137,11 @@ def enqueue_index_task(db, task_id: int):
def retry_index_task(db, source_id: int):
source = found(db, IndexTask, source_id)
source = db.scalar(select(IndexTask).where(IndexTask.id == source_id).with_for_update())
if not source:
raise HTTPException(404, "索引任务不存在")
if source.status != "failed":
db.rollback()
raise HTTPException(409, "仅失败的索引任务可重试")
existing = db.scalar(select(IndexTask).where(IndexTask.id > source.id,
IndexTask.course_version_id == source.course_version_id,
@@ -146,6 +149,7 @@ def retry_index_task(db, source_id: int):
IndexTask.kind == source.kind, IndexTask.status.in_(["queued", "running", "completed"]))
.order_by(IndexTask.id.desc()))
if existing:
db.commit()
return existing
retry = IndexTask(course_version_id=source.course_version_id, submission_file_id=source.submission_file_id,
kind=source.kind, status="queued")