fix(题单): 「选做」终于作数了,分母只算必做题
isRequired 一直只是卡片上的一行字:卡片写着「(选做)」,进度分母和 all_problems 奖章却照样要求做完。结果是学生按提示跳过选做题,进度条卡在 100% 以下、全通奖章也 拿不到 —— 快照里 22 个人做完了全部必做题却显示未完成(题单 5 三人、6 十人、8 两人、 11 七人)。旧栈的 update_progress 同样不区分,是一路继承下来的。 改成:分母只算必做题,选做题做了仍然计分(totalScore 把它算进去),只是不卡完成。 一道必做都没标的题单退回「全部都算必做」—— 那种题单多半是没用这个字段,而不是真的 整单选做,不兜住的话它永远完不成。 ## problem_count 奖章不能跟着改 老师当初是按题单的**总题数**设阈值的:题单 5 的「一职欧拉」要 8 题,而它的必做只有 7 道。要是 problem_count 也改用只数必做的 completedProblemsCount,这枚奖章一夜之间 不可得,76 个已经拿到的人会被 recalculateBadge 收回。所以它数的是「做出的题目总数 (含选做)」,从 progress_detail 的键数来。score 类同理不受影响。 预演证实了这道闸门有效:22 人拿到完成状态,奖章补发 56 条、**收回 0 条**。 ## 顺带:第三份手抄的达标逻辑 PUT /problem-set-progress 里还藏着一份 inline 的奖章判定,和 services 里那份、 补发脚本里那份是三份各写各的 —— 这次改 problem_count 的语义,漏掉任何一份都会让 学生提交时发的奖章和后台重算的结果对不上。三处统一到 eligibleForBadge。 ## 工具改名并扩到进度 backfill-badges → backfill-problemsets。语义变更之后,已有的进度行要跑一遍才会按新 规则重算,否则那 22 个人得等到老师下次动题单才生效。两笔账本来也是同一笔:进度一变, 奖章达标面就跟着变,所以落库走 resyncProgress(它重算进度后会顺手重算该题单全部奖章), 预演里的奖章差异也是照着订正后的进度算的,保证预演和 --apply 的结果一致。 在生产快照上实跑: 合计:进度 494 条要重算(完成 +22 / -0),奖章补发 56 条、收回 0 条 已订正 10 个题单 → 复核通过:题单数据与规则一致 user_badge 1180 → 1236,已完成 621 → 643 「未完成但有完成时间」仍是 4 条(d7a6414 那条语义保住了) 重复跑幂等:进度 0 条、奖章 0 条 抽查题单 6(9 必做 + 1 选做):只做必做的显示 9/9 100% 已完成、80 分;连选做一起做的 同样 9/9 已完成,但 90 分。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QqqZwxtXLo2GTqMi51C94D
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
* oj2-api healthcheck # 探活,给 Dockerfile 的 HEALTHCHECK 用
|
||||
* oj2-api sql-child # SQL 判题子进程,由服务自己 spawn,不该手动调
|
||||
* oj2-api migrate # 执行待办的数据库迁移,部署时由 docker/deploy.sh 调
|
||||
* oj2-api backfill-badges # 补发历史欠账的题单奖章,默认只读预演,--apply 才落库
|
||||
* oj2-api backfill-problemsets # 把题单进度与奖章订正到与规则一致,默认只读预演
|
||||
*
|
||||
* 用动态 import 而非顶层 import:这几个模块都有导入即执行的副作用
|
||||
* (Bun.serve、连 Redis 开消费者),静态导入会让 sql-child 也把整个服务拉起来。
|
||||
@@ -35,10 +35,10 @@ switch (command) {
|
||||
break
|
||||
}
|
||||
// 一次性的数据订正,跟着二进制走而不是留成源码脚本 —— 生产镜像里没有 bun 也没有源码
|
||||
case "backfill-badges": {
|
||||
const { backfillProblemSetBadges } = await import("./scripts/backfill-problemset-badges")
|
||||
case "backfill-problemsets": {
|
||||
const { backfillProblemSets } = await import("./scripts/backfill-problemsets")
|
||||
const args = process.argv.slice(3)
|
||||
process.exit(await backfillProblemSetBadges({
|
||||
process.exit(await backfillProblemSets({
|
||||
apply: args.includes("--apply"),
|
||||
allowRevoke: args.includes("--allow-revoke"),
|
||||
}))
|
||||
@@ -63,6 +63,6 @@ switch (command) {
|
||||
}
|
||||
}
|
||||
default:
|
||||
console.error(`未知子命令:${command}\n可用:serve | worker | migrate | backfill-badges | healthcheck | sql-child`)
|
||||
console.error(`未知子命令:${command}\n可用:serve | worker | migrate | backfill-problemsets | healthcheck | sql-child`)
|
||||
process.exit(2)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user