Closed
[缺陷] 同一工单重复评价会重复累加工人订单数,修改评分也会污染平均分 #26
jamesjulyAdd on  12 days agoClosed at  2 days ago
jamesjuly
12 days ago Create

问题

同一个已完成工单重复提交相同评价,ORDERS_TB 中仍只有一条订单,但工人的 ORDERS_NUMBER 每次都会加 1。若再次修改评分,旧评分也不会被替换,而是作为另一张订单加入平均值。

这会让重复点击、请求重试或修改评价污染工人订单数与平均评分。

代码位置与原因

检查版本:master 中 mock_backend.py 的最后修改提交 7c574faddd6776465666d4dcf967318ba0238574。

文件:https://gitcode.com/agent-best-practices/fix-system-agent/blob/master/mock_backend.py

PATCH /student/order-end 对应 student_order_end(1675–1714 行):

  • 先按 fix_table_id 更新订单的 grade、massage。
  • 随后使用 AVG_GRADE * ORDERS_NUMBER + grade 累加评分,并无条件执行 ORDERS_NUMBER + 1(1704–1708 行)。
  • 没有区分首次评价、相同评价重试和已有评价修改。

隔离复现

没有启动 HTTP 服务、WorkSwarm 或连接任何线上/真实数据。使用 Python 标准库 AST 仅抽取原文件的 student_order_end 函数,配合临时 SQLite 数据库和一个合法学生身份的测试替身调用原函数;数据库连接和请求对象为隔离测试替身。

初始合成数据:

CREATE TABLE WORKER_TB (WORK_ID TEXT PRIMARY KEY, AVG_GRADE REAL, ORDERS_NUMBER INTEGER);
CREATE TABLE ORDERS_TB (fix_table_id INTEGER PRIMARY KEY, student_id TEXT,
    work_id TEXT, grade INTEGER, massage TEXT, state INTEGER);
INSERT INTO WORKER_TB VALUES ('demo-worker', 10.0, 0);
INSERT INTO ORDERS_TB VALUES (1, 'demo-student', 'demo-worker', 10, '', 2);

让测试请求对象依次返回以下表单,调用原处理函数三次:

{"fixTableId": "1", "grade": "8", "message": "synthetic test"}
{"fixTableId": "1", "grade": "8", "message": "synthetic test"}
{"fixTableId": "1", "grade": "4", "message": "synthetic test"}

实际结果(每次均返回“评价成功”):

第一次评 8 分:实际订单行数=1,ORDERS_NUMBER=1,AVG_GRADE=8.0
原样再提交一次:实际订单行数=1,ORDERS_NUMBER=2,AVG_GRADE=8.0
将同一单改为 4 分:实际订单行数=1,ORDERS_NUMBER=3,AVG_GRADE=6.7

期望与建议验收

  • 相同工单相同评价重试,不增加工人订单计数,不改变平均分。
  • 如果允许修改评价,应替换该订单的既有评分贡献,订单数保持不变;如果不允许,则明确拒绝再次评价。
  • 显式区分“未评价”与“已评价”,因为订单初始 grade=10,不能仅凭该默认值判断是否已经评价。
  • 更新订单评价与工人统计应在同一事务中;补充首次评价、重复请求、修改评价的回归用例。

已检索全部 25 条公开 Issue,并阅读相近的 #8、#9:#8 是状态流转与进度追踪,#9 是日报统计与推送,均未描述此处重复评价导致计数、均分失真的问题。

本反馈由 AI 辅助代码检查及隔离复现,未在生产环境或真实校园数据上操作。

likedislike
grape_bot
grape_botCollaborators
12 days ago Comments:

[VOD Agent] 任务已完成。

likedislike
grape_bot
grape_botCollaborators
12 days ago Comments:

[VOD Agent] 已结构化收敛需求:

目标

修复同一工单重复评价导致工人 ORDERS_NUMBER 重复累加、修改评分污染 AVG_GRADE 的缺陷。

现状

mock_backend.py 的 student_order_end 函数(1675–1714 行,PATCH /student/order-end)在每次评价时无条件执行 ORDERS_NUMBER + 1 和 AVG_GRADE * ORDERS_NUMBER + grade 累加,未区分首次评价、相同评价重试和已有评价修改三种场景。开发者已提供隔离复现验证:同一订单三次提交后 ORDERS_NUMBER 从 0 累加到 3,AVG_GRADE 从 10.0 变为 6.7(实际订单行数仍为 1)。

期望行为

  1. 相同工单相同评价重试:不增加订单计数,不改变平均分。
  2. 修改评价:替换该订单既有评分贡献,订单数保持不变(或明确拒绝再次评价)。
  3. 显式区分"未评价"与"已评价"(订单初始 grade=10 不能作为判断依据)。
  4. 订单评价更新与工人统计更新在同一事务中执行。
  5. 补充首次评价、重复请求、修改评价三种场景的回归测试用例。

验收标准

优先级

P1(重要 — 影响数据准确性,但不阻塞核心流程)

代码位置

  • mock_backend.py → student_order_end 函数(1675–1714 行)
  • 涉及表:ORDERS_TB(订单)、WORKER_TB(工人统计)

来源:Issue #26
auto-submitted by VOD Agent

likedislike
grape_botgrape_botCollaborators
12 days ago Added label: bug
grape_botgrape_botCollaborators
12 days ago Added label: P1spec-ready
grape_botgrape_botCollaborators
12 days ago Assign grape_bot as responsible person
grape_botgrape_botCollaborators
12 days ago Added label: triaged
grape_bot
grape_botCollaborators
12 days ago Comments:

[issue agent] 📋 Spec Document

Spec: Issue #26 — 重复评价导致工人订单数与平均分统计污染修复

Generated by Issue Agent | Developability: ready | 2026-10-30

Objective

  • 构建什么:修复 mock_backend.py 中 PATCH /student/order-end(student_order_end,1675–1714 行)对同一工单重复评价/修改评分时无差别累加 ORDERS_NUMBER 与 AVG_GRADE 的缺陷,并补充三类场景的回归测试。
  • 为什么:重复点击、请求重试、修改评价都会污染工人统计数据——开发者隔离复现显示同一订单三次提交后 ORDERS_NUMBER 从 0 涨到 3、AVG_GRADE 从 10.0 变为 6.7,而实际订单行数仍为 1。工人考核数据失真直接影响派单与绩效展示。
  • 用户是谁:校园报修系统的学生(评价方)、维修工人(被统计方)与管理员(查看统计)。
  • 成功标准:五条验收标准全部通过且现有测试套件(python3 -m unittest discover tests -v)不回归。

Scope

In Scope

  • mock_backend.py → student_order_end:评价去重与评分贡献替换逻辑、显式「已评价」标记、单事务原子提交。
  • mock_backend.py → init_db/migrate:为 ORDERS_TB 增加 evaluated(或等价 end_time/massage 判定)列的建表与旧库迁移语句。
  • 新增 tests/test_issue26_order_end.py:首次评价 / 相同评价重复提交 / 修改评价三类回归用例(参照 tests/test_issue12_security.py 的 BackendTestBase + TestClient 模式)。

Out of Scope

  • worker_order_end(工人确认完工,1825–1837 行):其 state=2 幂等更新不涉及统计累加,无需改动。
  • 前端 web/static/app.js 评价交互与 CDN 依赖(#16 已另行跟踪)。
  • AVG_GRADE 历史脏数据修复脚本:存量数据清洗不在本单范围,如需要另行立项。

Technical Approach

方案概述

为订单引入显式「是否已评价」状态位,student_order_end 按三分支处理:首次评价(累加)、重复相同评价(幂等返回)、修改评价(替换旧评分贡献),订单更新与工人统计更新收敛于同一事务。

实现路径

  1. init_db 的 ORDERS_TB 建表语句增加 evaluated INTEGER DEFAULT 0;同步增加旧库迁移(ALTER TABLE ORDERS_TB ADD COLUMN evaluated INTEGER DEFAULT 0,需捕获 duplicate column name 保证幂等,参照现有 migrate_passwords 的防御式写法)。
  2. student_order_end 改造(伪代码):
    读取订单 → 不存在则 404(保持现状)
    evaluated=0(首次评价):
      UPDATE ORDERS_TB SET grade, massage, evaluated=1
      工人统计:total = AVG_GRADE*ORDERS_NUMBER + grade;new_count = ORDERS_NUMBER + 1
    evaluated=1 且 grade 与库中相同(幂等重试):
      仅更新 massage(可选),不触碰工人统计,直接返回“评价成功”
    evaluated=1 且 grade 变化(修改评价):
      UPDATE ORDERS_TB SET grade, massage
      工人统计:total = AVG_GRADE*ORDERS_NUMBER - 旧grade + 新grade;new_count 不变
    两个 UPDATE(ORDERS_TB + WORKER_TB)在同一个 conn 事务内 commit
    
  3. 「未评价/已评价」判定依赖新列 evaluated,禁止用 grade=10 默认值判断(Issue 明确指出该默认值不可作为依据)。
  4. 保持现有响应契约:json_response(None, message="评价成功") 与错误码(401 未登录 / 404 订单不存在)不变,避免影响 web/server.py 代理与前端。
  5. 新增 tests/test_issue26_order_end.py:
    • 用例 A 首次评价:ORDERS_NUMBER 0→1,AVG_GRADE = 评分。
    • 用例 B 重复相同评价:计数与均分不变(对应复现脚本第 2 次提交)。
    • 用例 C 修改评分:计数不变、均分按「去旧加新」重算(对应第 3 次提交:8→4 后 AVG_GRADE 应为 4 而非 6.7)。
    • 补充边界:grade 缺省、订单不存在 404、未登录 401。

关键设计决策

决策 选项 选择 理由
已评价判定 复用 grade=10 默认值 / massage 非空 / 显式 evaluated 列 显式 evaluated 列 Issue 验收明确要求显式区分;默认值 10 与合法评分冲突
重复相同评价 静默幂等 / 返回错误 幂等返回成功 兼容请求重试与重复点击,不破坏前端交互
修改评价语义 拒绝修改 / 替换贡献 替换贡献 VOD 收敛结论与 Issue 期望一致:AVG 反映最新评分,计数不变
统计重算方式 增量替换(-旧+新)/ 全量重算 增量替换 保持现有增量算法风格,改动最小;全量重算留作可选增强
事务边界 两次独立 commit / 单事务 单事务 验收标准明确要求原子性,防止订单已更新而统计未更新的中间态

Affected Modules

模块 改动类型 说明
mock_backend.py student_order_end 重构 三分支评价逻辑 + 单事务提交
mock_backend.py init_db/迁移 修改 ORDERS_TB 增加 evaluated 列(建表 + 幂等 ALTER)
tests/test_issue26_order_end.py 新增 三类场景回归测试 + 边界用例

依赖关系

student_order_end 被 create_app 注册为 PATCH /student/order-end 路由(1891 行起);worker_order_pass/student_order_pass 等读路径不读 evaluated,无下游破坏。web/server.py 白名单代理 student/* 原样转发,契约不变。

Acceptance Criteria

Risks & Mitigations

Risk Impact Mitigation
旧库无 evaluated 列导致启动失败 High 迁移语句幂等(捕获 duplicate column),参照 migrate_passwords 既有模式
增量替换在历史脏数据(计数已虚高)上计算偏差 Low 本单不清洗存量;如上线后发现历史污染,另行立项重算
前端存在连点/重放路径触发并发写 Low SQLite 单写者天然串行化;如需更强保证可后续加 BEGIN IMMEDIATE(可选增强)
修改 grade 缺省回退逻辑(data.get("grade", order["grade"]))被误动 Med 保持缺省回退语义,仅在其外层加分支,测试覆盖 grade 缺省分支

Open Questions

  • 无(VOD 已完成需求收敛,三场景与验收标准明确;evaluated 列方案为唯一开放设计点,已在上表定案)。

可开发性评级:ready(需求完整性 complete / 技术可行性 feasible / 依赖就绪性 ready / 范围确定性 clear)。标签:bug / P1 / spec-ready / triaged;负责人:grape_bot。里程碑:仓库当前无里程碑,按仓库惯例不设。接下来 A2A 移交 coding agent 开发。

likedislike
grape_botgrape_botCollaborators
12 days ago Associated pull request
grape_bot
grape_botCollaborators
12 days ago Comments:

[Coding Agent] ✅ 已按 Spec 完成实现,请审查 PR #11(feat/issue-26 → master)。

改动要点:

  • ORDERS_TB 新增 evaluated 显式已评价列(init_db 建表 + 幂等 ALTER 迁移,旧库二次执行不报错)
  • student_order_end 三分支:首次评价累加;相同评价幂等(仅刷新留言、不触碰统计);修改评价替换旧评分贡献(total=AVG*n-旧grade+新grade,计数不变);订单与工人统计同一事务提交
  • 响应契约不变(评价成功/401/404),敏感字段零暴露

验证:新增 tests/test_issue26_order_end.py 7 用例(首次/重复/修改/404/401/grade 缺省/旧库迁移);python3 -m unittest discover tests -v 53 用例全绿;复现脚本三步后 ORDERS_NUMBER=1、AVG_GRADE=4.0(8 改 4)。pre-pr-check:增量敏感扫描 0 命中、拦截无关文件 0 个。

likedislike
grape_bot
grape_botCollaborators
12 days ago Comments:

[QA Agent] 任务已完成。

likedislike
程曙程曙Collaborators
2 days ago Close issue