Conversation
|
Claude finished @uipreliga's task in 1m 37s —— View job Code Review
|
|
One thin I'm unsure about it it's behavior on custom docker images. Skills repo uses a custom docker image based on the coder-eval docker image. In this scenario, do we force consumers to set the env var? If not this PR LGTM. |
af5e07c to
4941681
Compare
|
Good question — no, consumers don't need to set anything. A custom image built A consumer only hits the refusal when their base is pinned to an older coder-eval than the host wheel (or a stale Two things
One nit for anyone wiring it up: the value must be All of this is in |
akshaylive
left a comment
There was a problem hiding this comment.
Clean PR. At some point we need to change the documentation structure. Ship it!
Replace the json.loads + dict.get + isinstance ladder at the host→container boundary with a Pydantic model: every field required, extra="forbid", StrictBool for grade/regrade, StrictInt for replicate_index. The host builds the model in _stage_inputs and keeps it on DockerRunner._staged_context. BREAKING CHANGE: a container image and host that disagree about the context.json keys now fail at parse time (exit 2, naming the field) instead of falling back to defaults (grade=True, host_task_file=None, the staged source_yaml). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…oed its contract The image version preflight now refuses instead of warning, for dockerfile_path images too, and is the single reader of the org.coder-eval.version label. The container echoes the ContainerContext it parsed into environment_info["container_contract"], written after the regrade seed so the prior row cannot overwrite it. One host guard, _assert_contract_echoed, replaces _assert_grade_honored, _assert_regrade_honored and _warn_on_version_mismatch, and quarantines a refused record to task.json.unhonored. A host grade drops a prior row's stale echo, and the echo is kept out of the rendered Environment table. BREAKING CHANGE: a driver: docker run is refused before the container starts when the image's org.coder-eval.version label is missing or differs from the host's installed coder-eval. Set ALLOW_IMAGE_SKEW=1 (not an empty string) to run a deliberately different image; a missing label is never excused. An image that predates the host→container contract is refused after the run, and its record is moved to task.json.unhonored instead of task.json.graded / task.json.rerun. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t-side DockerRunner._stage_inputs now stages task.yaml as the execution copy with driver: tempdir and sends the authored sandbox block in the contract as ContainerContext.authored_sandbox. The in-container entry point no longer rewrites the driver; it records authored_task from ctx.authored_sandbox, so a docker run's task.json still says driver: docker. The CE051 exemption moves with the rewrite: the two sites are now host staging and opt-in host grading. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Extract the run-summary rebuild into a printer-free orchestration/run_summary_rebuild.py (rebuild_run_summary, find_run_root) and expose it as `coder-eval report <run_dir> --rebuild`, which prints the same counts line and note. --rebuild refuses --format, --output, a task directory and a directory inside another run. The rebuilt run id now comes from the resolved directory, so `runs/latest --rebuild` records the real run id. BREAKING CHANGE: `coder-eval aggregate` is removed; use `coder-eval report <run_dir> --rebuild`. Its `-o/--output <dir>` option has no replacement: --rebuild writes in place, so gather task directories into the target directory first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… grade `coder-eval evaluate <task_run_dir>` now rebuilds the owning run's run.json and run.md itself after writing the verdict back, instead of telling the user to run a second command. The refresh is best-effort: any failure only warns, and the exit code is always the verdict's. find_run_root accepts only a run.json that is a coder-eval run summary (a JSON object with run_id and task_results), so a row copied into another tool's tree never overwrites that tool's run.json. rebuild_run_summary refuses to write through a symlinked run.json or run.md; both evaluate and report --rebuild inherit that, since it is their one shared write path. The refresh is skipped when the grading --run-dir sits inside the owning run, where its own task.json would count as a second row. write_run_summary now writes atomically, and the new console lines escape Rich markup in paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mmand exemption list Two review findings from the container-contract work, closed as tests: - the host compares the container's echo with its own dump, so a validator under authored_sandbox that is not idempotent across a JSON round trip would refuse every docker run; the round trip now runs over a maximal SandboxConfig; - prose_budget's _TYPER_COMMANDS kept a dead entry for the deleted aggregate command; it must now equal the commands the CLI registers. Two more candidates that need type information or are conventions are recorded in .claude/harness-candidates.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…cally Phase 6 planned to declare the flags `run` and `execute` share once, through option factories. The factory module was built and produced byte-identical --help output, but review found it saved no lines and turned each new shared flag into a five-place edit, so it was dropped and cli/ is unchanged. What remains is the drift guard: a test that compares every click attribute a shared flag can show or validate between the two commands, and asserts that --resume and --format stay command-specific. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Strip the prior row's container_contract from the staged prior.json. An image that honors regrade but predates the echo keeps the prior environment_info, so a matching echo from an earlier identical dispatch passed as its own. - A result refused by the contract echo now leaves a synthetic ERROR task.json in place of the quarantined record, like every other container failure, so the row no longer vanishes from the next run.json rebuild. - On a detached grade, the refused task.json.unhonored is folded back from the scratch directory beside the graded row, and the error no longer suggests --allow-host-grading when the image itself was refused. - Docstrings, the stale "version checks only warn" wording, the dead None branch in _quarantine_record, the run.json environment note, and a cwd-independent task path for the evaluate refresh tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rebased onto a249877, which turned the prose gate on for tests/ (#180) and hoisted function-local imports out of src/ (#176). Brings this branch's own additions in line: - Three test docstrings stated history ("Previously ...", "used to hide behind", "Accepting it recorded"); they now state the contract. - `report_command` and `evaluate_command` import `run_summary_rebuild` at module level. `evaluate_command` keeps the module import because its tests patch functions on that module. - `tests/test_container_context.py` (new in this branch) imports at module level. - Reflowed one note paragraph to the notes' 88-column width and rejoined a split docstring line in `regrade._should_grade_in_container`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4d79e93 to
ce5d761
Compare

Gives the host→container boundary of
driver: dockera typed contract that both sides must echo, and foldscoder-eval aggregateintocoder-eval report --rebuild. Rebased ontoa2498770(#177, #176 and #180 merged), so it follows the prose rules those PRs put in force onsrc/andtests/.Breaking changes
driver: dockerimage is refused before the container starts. The host reads the image'sorg.coder-eval.versionlabel. If the label is missing, or differs from the installed coder-eval, the run fails. This applies todockerfile_pathimages too. SetALLOW_IMAGE_SKEW=1(not an empty string) to run a deliberately different image; a missing label is never excused.task.json.unhonored, and a synthetic ERRORtask.jsontakes its place. This replacestask.json.gradedandtask.json.rerun.coder-eval aggregateis removed. Usecoder-eval report <run_dir> --rebuild.aggregate -o/--output <dir>has no replacement.--rebuildwrites in place; gather task directories into the target directory first.Downstream: UiPath/skills#3318 sets
ALLOW_IMAGE_SKEWon the one workflow that tests an ad-hoc image tag against the pinned wheel. It is safe to merge before this release.What changes
ContainerContextcontract.context.jsonis a strict Pydantic model: every field is required, unknown keys are refused, andgrade,regradeandreplicate_indexare strictly typed. A host/image mismatch fails with exit 2 and names the field, instead of falling back to a default.environment_info["container_contract"], after the regrade seed so a prior row cannot overwrite it. One host check,_assert_contract_echoed, replaces_assert_grade_honored,_assert_regrade_honoredand_warn_on_version_mismatch. The image-version preflight is now the single reader of the label and refuses instead of warning.driver: tempdirand sends the authored sandbox in the contract, sotask.jsonstill recordsdriver: dockerand the container needs no CE051 exemption.report --rebuild. A printer-freeorchestration/run_summary_rebuild.pybacks it. It refuses--format,--output, a task directory, a directory inside another run, and a symlinkedrun.json/run.md.evaluaterefreshesrun.json.coder-eval evaluate <task_run_dir>rebuilds the owning run'srun.jsonitself. It is best-effort (never changes the exit code), accepts only a coder-eval run summary on the walk up, and skips when--run-dirsits inside the run.write_run_summarynow writes atomically.run/executeoption sharing: dropped. A factory module was built and gave byte-identical--help, but review found it saved no lines, socli/is unchanged. A test now pins every shared flag as identical on both commands.Rationale lives in
.claude/notes/isolation.md(§ The container contract, § The image version preflight, § The contract echo) and.claude/notes/orchestration.md(§ The host-side driver rewrite). Code carries the contract and aRationale:pointer.Rebase onto main
14 conflicts across 7 of the 8 commits, all resolved to main's shape plus this branch's facts:
.claude/notes/*.mdto 88 columns. Both sides were reflowed with the same wrap (checked: it reproduces main's file byte for byte from the old one), then merged, so the resulting diff is content only.DockerRunner._stage_inputs, and the image preflight refuses), the fact is updated in the docstring and in.claude/notes/lint-rules.md.reports_stats.pywas split by refactor(reports): generate the pricing mirror and split the reports layer #176. Thecontainer_contractexclusion moved toreports/helpers.py::ENV_TABLE_EXCLUDE.prose_budget._TYPER_COMMANDSkeys are repo-relative since feat(lint): gate tests/ on the prose rules, and cap the comment run as well as the file total #180. Theaggregateentry is removed from the new form, and the exemption-list test compares repo-relative paths.One follow-up commit applies main's prose rules to this branch's own additions: no history wording in docstrings, and module-level imports in the new CLI helpers and
tests/test_container_context.py.Worth a human's eye
ALLOW_IMAGE_SKEWis aSettingsfield, not a task field. Image freshness is a property of the operator's machine, not of the evaluation.container_contractas easily as the verdict beside it. It proves the harness code honored the contract.--type codexand no--model, the task's defaultclaude-sonnet-4-6went to the Azure Codex endpoint. The turn ended with 0 messages, 0 tokens anderror: null, and the row was recorded as FAILURE. The Codex adapter should record this as an error.--run-dir,evaluatewritesgrade.logandgrade.docker.logto its own newruns/<timestamp>/, not beside the graded row.Verification
After the rebase (
ce5d761e):make verify— ruff format, ruff check, pyright 0 errors, 671 custom lint, prose gate 0 essays, 5,899 passed, 2 skipped, 92.74% coverage.Before the rebase (
4d79e933), not repeated after it:prior.json, a refused row vanishing fromrun.json, the refused record lost on the grading path).run --helpandexecute --helpbyte-identical to the pre-change baseline.driver: dockertask against a freshly builtmake docker-imageimage (0.12.1, label matches the host).tasks/agents/claude_hello_world_docker.yamlwith--type codex --model gpt-5.4: SUCCESS, 1.0, 3/3. The echo holds all 10 contract keys withgrade: true,regrade: false, andtask.jsonrecordsdriver: docker.coder-eval evaluate <row> --allow-recorded-commandsgraded in a container of the task's image, SUCCESS → SUCCESS, 3/3, exit 0. The echo showsregrade: true,started_atis unchanged (the agent did not run again),task.execute.jsonwas kept,run.jsonwas refreshed, and nograded_on_hoststamp was set.🤖 Generated with Claude Code