feat: 任务书 06,workspace 模块与 task.json 的"不存"清单

workspace 用一个裸仓库存代码版本,版本号是目录树编号,不造提交,每个版本挂 refs/versions/ 引用防清理。
存版本自己遍历目录、hash-object --no-filters 存,不用 git add;符号链接等特殊文件交回"存不了"。
取出用 ls-tree 加 cat-file 原样写出:实测 git archive 会按树里的 .gitattributes 丢文件、改换行符。
git 子进程不读系统和用户的配置,另关掉系统和用户的 attributes 文件:实测只关配置时 ~/.config/git/attributes 仍会被读。
比较交回文件级改动、新旧两边行号范围的块,以及带上下文的 diff 原文。
tasks:task.json 加必填的 unversionedNames,protectedFiles 删掉 solution.json。
全新上下文审阅一轮,采纳一条:注明块可以为空(空文件增删、只改可执行位)。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 23:43:01 -04:00
parent a1a2feb135
commit 6850c0a1d4
8 changed files with 500 additions and 5 deletions
+14 -2
View File
@@ -461,10 +461,10 @@ Jev 是一个判别器,和程序检查地位相同,不单独成一种记录
**任务事实**
- `TASK_KINDS`、`TaskKind`:任务种类名单,现在只有 `circle_packing`。
- `TaskFacts`(字段定义):task.json 的字段:任务种类、最终指标的编号和方向、ε、已知最好(没有写 null)、单次时限、核数、Docker 运行时、不许改的文件名单。全部必填,不认识的字段报错。
- `TaskFacts`(字段定义):task.json 的字段:任务种类、最终指标的编号和方向、ε、已知最好(没有写 null)、单次时限、核数、Docker 运行时、不许改的文件名单、存代码版本时跳过的名字(`unversionedNames`,只写名字不带 `/`,在任何一层都跳过;填圆是 `__pycache__`、`.git`、`solution.json`、`metrics.json`)。全部必填,不认识的字段报错。
- `checkTaskFacts(value)`:严格检查一份已解析的 task.json,一次列出全部错误,每条写成"字段路径:原因"。
- `Task`(类型):读进来的一个任务:task.json 的内容、任务目录(Dockerfile 所在,给 runner 建镜像)、基线目录、TASK.md 全文。
- `loadTask(taskDir)`:读任务目录,检查 task.json,交回 `Task`。
- `loadTask(taskDir)`:读任务目录,检查 task.json,交回 `Task`;"不存"清单在 `task.facts.unversionedNames` 里,flow 存版本时把它交给 workspace。
- `metricDefinitions(task)`:最终指标和常规辅助指标的定义(墙钟、CPU 秒、峰值内存、最小间隙、原分数、原违反量、扣掉的分);辅助指标的定义写在填圆的代码里。
- `protectedChanges(task, changedFiles)`:改动过的文件里属于"不许改"名单的那些。
@@ -481,3 +481,15 @@ Jev 是一个判别器,和程序检查地位相同,不单独成一种记录
- `prepareJudging(task, runDir, judgeDir, imageDigest, formal, hypothesisMetrics)`:判分第一步。正式运行超时、从外面被杀、退出码非 0,或者没有产物,直接交回不算数的判分结果;否则把产物和宿主保管的校验器复制进判分目录,交回校验器的运行定义。
- `judge(task, runDir, judgeDir, formal, validator, hypothesisMetrics)`:判分第二步。读校验器写的判定和候选写的指标文件,加上正式运行的结果,交回 `JudgedResult`:校验器判合法(含合法化后合法)算数;判不合法、或"缺了整次作废"的假设专用指标测不到,不算数。合法化的三个数既进 `extra`,也是常规辅助指标的取值;测不到的指标记测不到并附原因。校验器自己没正常跑完、判定文件认不出、修后分数高于原分数时报错停下,不当成候选的失败。
- `JudgingStep`(类型):判分第一步的结果,已判定或要跑校验器。
### workspace
下面是 `src/workspace/index.ts` 导出的全部内容。一份研究一个裸仓库,位置由调用方给;版本号是目录树编号(tree id),不造提交,每个版本挂一个 `refs/versions/<版本号>` 引用防 `git gc` 清理。"上一版是谁""现在的基线是哪个版本"都由 flow 记进账本,git 里不记。只用 git 的底层命令,每个 git 子进程都不读系统和用户的配置与 attributes 文件,`GIT_DIR` 只放进子进程的环境。git 命令失败直接报错,写明命令和 git 的报错原文,不重试。
- `createRepository(repo)`:在给定位置建一个空的裸仓库。
- `saveVersion(repo, dir, excludedNames)`:把目录现在的内容存成一个版本,交回版本号;自己遍历目录列文件(不用 `git add`,`.gitignore` 不起作用),名字在清单里的文件或目录在任何一层都跳过,空目录不进版本,可执行位记成 100755、其余 100644。遇到符号链接、设备文件这类既不是普通文件也不是目录的东西,交回"存不了"和那个路径。同样的内容永远得到同一个版本号。
- `checkoutVersion(repo, version, dir)`:把一个版本的文件原样写进调用方建好的空目录,还原可执行位;目录里没有 `.git`。
- `compareVersions(repo, from, to)`:比较两个版本,交回改动过的文件(路径;新增、删除还是修改;是否只改了可执行位;是否二进制;非二进制文件每一块改动在新旧两边的行号范围),以及给模型看的带 3 行上下文的 `git diff` 原文,不加颜色。
- `SaveOutcome`(类型):存好了和版本号,或者存不了、路径和原因。
- `LineRange`、`Hunk`(类型):一块改动在一侧是"第几行到第几行";这一侧没有行时写成"在第几行之后"(0 表示文件开头),同 `git diff -U0` 的写法。
- `FileChange`、`Comparison`(类型):一个改动过的文件,二进制文件不拆块;比较的全部结果。块可以为空:空文件的新增、删除和只改可执行位都没有块,按整个文件改了算。