Skip to content

题目版本管理(草稿、发布与有效成绩) ​

Neuro OJ 的每道题都有不可变的版本:用户作答、评测与历史查看都绑定在某个具体版本上。 本文面向出题人、管理员与选手,说明草稿与发布、提交时版本、有效版本策略、批量升级与 重测,以及历史数据的读法。

术语速查:草稿是共享的可编辑内容;版本是发布后不可修改的完整作答与评测内容; 提交时版本是某条提交创建时实际使用的版本;评测尝试是用某个版本评测某条提交的 一次执行;有效版本策略决定当前统计接受哪些版本的成绩。


1. 草稿与发布(出题人) ​

编辑页面有两个独立动作:

动作作用影响谁
保存草稿写入每题唯一的共享草稿,携带 revision 乐观锁只有编辑者看得到
发布版本把当前草稿固定为新的不可变版本(V1、V2…)之后的新作答使用该版本

规则:

  • 草稿允许暂时不完整(缺支持包、缺完整运行配置、客观题缺小题都可以先存);发布前会做完整预检, 未通过会给出具体原因(缺文件、引用路径不存在、客观题没有小题等)。
  • 多人同时编辑同一题:草稿写入必须携带当前 revision,缺失返回 428、过时返回 409, 重新加载后再保存即可,不会互相覆盖。
  • 相同内容重复发布不会制造空版本:服务端按内容哈希去重,返回 unchanged: true 与既有版本号。
  • 每题只能有一个共享草稿;「保存草稿」不会改变正在作答的题目内容——只有发布才生效。
  • 发布后题型(OI / AI / 客观题)与 AI 题的提交模式(代码 / 产物)固定,跨类型转换请新建题目。
  • 未发布题目对普通访问者等同于不存在(详情 404、不进题库列表与搜索);编辑者通过草稿接口读取。

题包导入(CLI problems import 或管理端导入)是「写草稿 → 显式发布」:不发布时题目只有草稿, 生产演练与开发初始化会显式发布(--publish)。


2. 提交时版本与评测版本(选手) ​

  • 题库默认作答版本:策略为 any 时用最新版,为 exact(X) 时用要求版本 X。
  • 竞赛默认作答版本:该竞赛固定的题目版本(加入竞赛时钉住,之后题库发布新版不影响本场比赛)。
  • 提交时客户端携带 version_id:
    • 题库允许显式提交其他已发布版本(用于复现历史问题);
    • 竞赛只接受固定版本,客户端覆盖会被拒绝;
    • 竞赛固定版本已变化时返回 409 CONTEST_PROBLEM_VERSION_CHANGED,请刷新页面后重新提交 (编辑器会保留你已经写的代码或答案)。
  • 老客户端缺少 version_id 时会收到明确的升级提示,服务端不会静默绑定最新版。

3. 有效版本策略:历史均有效 vs 精确版本(管理员) ​

ts
type EffectiveVersionPolicy =
  | { mode: "any" } // 默认:历史版本均可产生有效成绩
  | { mode: "exact"; version_id: string };
  • 题库策略与**每个「竞赛 × 题目」**的策略相互独立。
  • 发布新版本、重测指定版本、切换有效版本策略是三个独立动作:发布不会自动改策略, 改策略不会自动重测。
  • 策略切换在事务提交后立即生效,不依赖缓存过期或榜单刷新。
  • 竞赛采用 exact(X) 时,固定作答版本必须同时为 X;单独升级固定版本时可同时提交新策略, 冲突会返回 409。

管理端入口:「题目版本」页可逐题切换题库策略与竞赛固定版本(带 revision 乐观锁,冲突后自动重载)。

跨版本成绩如何保留 ​

一条提交可以同时拥有多个版本的当前判定;每个版本只采用最近一次完成的正式判定。 举例(选手先后用 V1、V2 评测):

操作V1 当前成绩V2 当前成绩any 下通过exact(V2) 下通过
初次提交 V1,通过AC无是否
发布 V2AC无是否
用 V2 重测,失败ACWA是否
再次用 V1 重测,失败WAWA否否
用 V2 重测,通过WAAC是是

要点:

  • 基础设施错误不替换已有正式判定(平台失败与「评测完成但不通过」严格区分)。
  • 正在重测时,已有判定继续有效,直到新结果落库。
  • 是否通过由「通过候选」单独计算,不看最高分——因此存在「最高分版本不通过、其他版本通过」的情况。
  • 一条提交即使在多个版本上评测,统计里只算一次提交;用户升级会产生新提交,因此会增加提交数。

4. 用户升级与管理员重测(批量任务) ​

4.1 选手:升级到最新版 ​

在「我的提交」列表勾选提交 → 批量升级到最新版(单次最多 500 条)。服务端会:

  • 在受理时固定每题最新版;沿用原用户,生成新的提交并记录「由旧版本升级而来」;
  • 新提交使用当前时间(历史提交的原始时间不变);
  • 竞赛来源的升级可要求仍留在原竞赛(context = source_contest),此时新版必须恰好等于固定版本;
  • 重复提交(同一幂等键同请求)返回原任务,不会重复生成提交。

常见跳过原因:原提交已经在最新版(ALREADY_LATEST,需要重新评测请找管理员重测)、 原提交正在评测、题目未发布新版本等。用户升级失败不会影响原提交与原成绩的读取。

4.2 管理员:重测 ​

「批量重测」页支持三种范围与三种目标:

范围说明
整题某道题的全部提交(不受 500 条上限约束,后台分批执行)
整场某场竞赛某题的全部提交
手选手动勾选提交,单次上限 500 条
目标说明
提交时版本用不可变的提交时版本重测(历史提交不会换版)
最新版受理时解析并固定每题最新版
全部用 V3先把 V3 展开成逐题版本映射,任一题没有 V3 则整次受理失败(不产生任务、不改策略)

任务受理返回任务 ID 与条目进度;条目级失败会给出 reason_code(例如 LEGACY_VERSION_UNKNOWN 表示历史提交没有提交时版本、ARTIFACT_MISSING 表示旧产物已删除、 LANGUAGE_NOT_SUPPORTED、ARTIFACT_TOO_LARGE_FOR_VERSION)。失败条目可一键重试, 重试生成关联的新任务并保留目标版本映射,不会再次修改有效策略。

手动选择的提交集合在受理时固定:受理之后产生的新提交不会进入本批任务。


5. 客观题:标识与强行重判 ​

  • 客观题小题有跨版本稳定的 key:编辑保留 key,新增小题生成新 key;题包 questions.json 可显式提供 key(重复会被拒绝),未提供时由服务端生成。
  • 卷面以提交时版本的快照为准:小题增删或改答案不会改变已有提交的判定与展示。
  • 强行重判(管理员重测)按目标版本的 key 匹配原答案:
    • 目标版本新增的小题按未作答;原版本被删除的小题不计分;
    • 题型变化导致旧答案形式不兼容时按未作答;
    • 原始 answers 永不被改写,详情里会说明匹配/缺失/形式不兼容的情况。
  • 竞赛模式仍然保持「一次性提交」约束:已提交的选手不能再次提交,但可以升级为练习提交, 管理员可以重测原提交。

6. 产物、存储与历史缺失 ​

  • 支持包与 OI 数据文件都登记在对象存储引用表里;发布时复制引用(不复制字节), 因此后续替换草稿文件不会影响历史版本。
  • 新产物提交的对象保留到提交被显式删除,不设置自动过期时间。
  • 历史数据可能真的「缺失」,系统保留未知状态而不是伪造版本:
    • 迁移前的历史提交保留 submitted_version_id = NULL(legacy_unknown):在 any 策略下 历史成绩继续有效;exact(X) 下不匹配;
    • 按「提交时版本」重测这类提交会跳过(LEGACY_VERSION_UNKNOWN);
    • 旧产物已被删除时重测条目失败(ARTIFACT_MISSING),保留已有成绩;
    • 迁移前客观题小题若已被替换,旧卷面无法还原,提交详情按空卷面展示(原始答案仍可读)。
  • 物理删除统一经过引用守卫:仍被历史版本引用的对象字节不会被误删。

7. 出题与管理速查 ​

我想…去哪里
改题面/配置但不影响现在的作答编辑器「保存草稿」
让新内容生效编辑器「发布版本」
只认某一版成绩管理端「题目版本」→ 题库策略 exact(X)
换掉某场竞赛的固定版本管理端「题目版本」→ 竞赛固定版本(可同时提交新策略)
用最新版重测一批提交管理端「批量重测」→ 目标「最新版」
让选手用最新版重做选手在「我的提交」勾选 → 批量升级(管理员可在管理端代做)
查看某条提交在各版本的判定提交详情 →「各版本判定」表格

版本号只在单题内递增:P12 的 V3 与 P13 的 V3 是不同版本。数据库与 API 使用版本 UUID, 数字版本号只用于展示与批量选择。

Neuro OJ 是一个独立社区项目,与 CCF、LMCC、IOAI 及 NOAI 无官方关系。