feat(harbor): pick the runtime image per run; tag builds by commit - #588
Merged
ShuxinLin merged 3 commits intoSep 30, 2026
Merged
Conversation
Every task image builds FROM the runtime image, and the only way to choose it was the Dockerfile's ARG default, so using a published image meant retagging it as the local assetopsbench/runtime:dev. The template's docker-compose.yaml now passes AOB_RUNTIME_IMAGE to that ARG as a build arg. Harbor runs `docker compose build` with the shell's environment and every compose file, so `AOB_RUNTIME_IMAGE=<image> harbor run ...` builds FROM that image, with no task regeneration; unset, it keeps the local tag. run.sh takes it as -r (or AOB_RUNTIME_IMAGE). A registry reference is pulled first, because a local copy satisfies FROM and the build would otherwise run on a stale one; a bare name must already exist locally, as before. It exports the variable so `harbor jobs resume` sees it too, and prints the image id it uses. The image changes only the base. Each task still adds its own manifest.json, and shared/ still comes from overlays/private-data.yaml. The template change alters every generated task, so Harbor will not resume a job started before it; run.sh already says so and suggests moving it aside. Verified with Harbor's oracle agent, AOB_RUNTIME_IMAGE set to a labelled copy of runtime:dev: the 3 open tasks, and tsfm-1019 and fmsr-913 from the private suite with the private-data overlay. All 5 trials scored 1.000 with no errors. A nonexistent AOB_RUNTIME_IMAGE failed the build pulling exactly that name. The tsfm-1019 task image built on the labelled base carries the label. With the overlay's mount it sees scenario_1019/manifest.json, and a read-only shared/ where all five manifest paths resolve. run.sh's image step pulls a quay.io reference and rejects a missing local tag. 22 assetops_harbor tests pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
build-runtime-image.sh tagged only assetopsbench/runtime:dev, which every build overwrites, so a run could not name the build it used after a rebuild. With no -t given it now also tags assetopsbench/runtime:<short commit>. That tag does not move, so `run.sh -r assetopsbench/runtime:<commit>` (or AOB_RUNTIME_IMAGE) pins a run to one build while :dev stays the default the tasks build FROM. publish-images.sh adds <namespace>/runtime:<commit> beside :TAG and :latest. The commit is HEAD's, which is exactly what the image holds, because the build comes from `git archive HEAD` whatever the working tree contains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
Review fixes for the runtime-image selection. run.sh: - Resolves the image as -r, then the shell's AOB_RUNTIME_IMAGE, then ENV_FILE's, then the local default. It used to take only the shell's value and export a default over it, so an AOB_RUNTIME_IMAGE in .env was ignored; `uv run --env-file` never overrides a variable the shell already has. - Pulls whenever the image is not local, or its local copy came from that same repository. The old rule pulled only references naming a registry host, so a Docker Hub image such as publish-images.sh's own <ns>/runtime:latest was never refreshed. A local build (no RepoDigest for its name) is never pulled over. - Pins the resolved image for the whole run under a tag private to the process (aob-runtime-pin:<id>-<pid>, removed on exit) and exports that. Every trial resolves FROM when it builds, so exporting the movable :dev let a rebuild or another run's pull switch later trials' base mid-run. FROM cannot name a bare image id, which is why this uses a tag. - Records the image beside each job (<job>.runtime-image) and refuses to resume a job on a different one. Harbor's resume lock hashes the task files, not the base they build FROM, so a resume with another -r mixed two images in one job. - Exits non-zero when a model's job could not start or resume. - Runs the image step after the cheap input checks, and strips a sha256: prefix only if present when printing the id. build-runtime-image.sh: treats -tNAME and -t=NAME as naming a tag, so they no longer also get the default :dev and :<commit> tags. Its comment no longer claims the commit tag never moves (rebuilding the same commit moves it), and it says how to remove old commit tags, which now keep their images alive. publish-images.sh: the NOTE points users at the commit tag it just pushed, with :latest as the moving option. Docs: QUICKSTART says tasks generated before the build arg existed ignore the variable and need regenerating once, that the variable must be set per shell or in .env, and its pull-error entry now covers an unset AOB_RUNTIME_IMAGE. README describes the resolution order, pin, per-job record and exit status. Verified end to end with run.sh, a one-scenario profile and a fake model id, so trials fail fast without calling a provider: - The first run printed the resolved id. The pin tag existed during the run and was gone after it, the job's .runtime-image record was written, and the trial built, ran and was scored (reward 0). - A second run on the same image resumed the job, dropped the crashed trial and reran it, and exited 0. - A third run with -r set to a different image refused to resume, named the job's original image, and exited 1. - Helper checks: image_repo strips tags and digests; runtime:dev and :3bb4f12 count as local builds; quay.io/... and couchdb:3.5 count as registry images. -r and the shell beat .env, which beats the default. - `uv run pytest src/ -k "not integration"`: 714 passed, 19 failed. The base branch has the same 19 failures, in the scorer and trace-exporter tests and in the iot invalid-site tests, which need a CouchDB or no .env. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Shuxin Lin <linshuhsin@gmail.com>
7 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
You can now choose, for each run, which runtime image the Harbor tasks build FROM, and every runtime build gets a tag that pins it.
Before this PR, the base was fixed by the task Dockerfile's
ARGdefault,assetopsbench/runtime:dev, and every rebuild overwrote that tag. Using a published image meant retagging it locally, and a finished run couldn't name the build it ran on.1. Choosing the image per run (
e91aa07)template/environment/docker-compose.yamlpassesAOB_RUNTIME_IMAGEto the task Dockerfile'sARGas a build arg.docker compose buildwith the shell's environment and every compose file, soAOB_RUNTIME_IMAGE=<image> harbor run …builds FROM that image.assetopsbench/runtime:devis used, as before.run.sh -r IMAGE(the default comes fromAOB_RUNTIME_IMAGE):quay.io/…orlocalhost:5000/…is pulled first. Otherwise a stale local copy would satisfyFROM.harbor jobs resumeuses it too, and it prints the image id it runs on.2. Tagging builds by commit (
3bb4f12)build-runtime-image.sh: when no-tis given, it tags bothassetopsbench/runtime:devandassetopsbench/runtime:<short commit>.:devmoves with every build. The commit tag never does, so-r assetopsbench/runtime:<commit>pins a run to one build.git archive HEADwhatever the working tree holds.publish-images.shpushes<namespace>/runtime:<commit>next to:TAGand:latest.3. Review fixes (
1ad4eea)run.shnow takes-r, then the shell'sAOB_RUNTIME_IMAGE, then.env's, then the local default. Before, a value in.envwas ignored.:devmid-run no longer switches later trials' base. (FROMcan't take a bare image id, which is why this uses a tag.)<job>.runtime-image) and refuses to resume a job on a different image. Harbor's resume lock doesn't cover the base image.build-runtime-image.sh:-tNAMEand-t=NAMEnow count as naming a tag. The comments are corrected: rebuilding the same commit moves its tag, and old commit tags keep their images until you remove them.publish-images.sh's note now points at the commit tag.Docs
README, QUICKSTART and the note printed by
publish-images.shnow say to exportAOB_RUNTIME_IMAGE(or set it in.env) instead of retagging, and describe the commit tag. Tasks generated before this PR ignore the variable, so the docs say to regenerate them once.What doesn't change
The image changes only the base. Each task still adds its own
scenario_<id>/manifest.json, andshared/still comes fromoverlays/private-data.yaml. For the open profile,shared/is the repo copy inside the chosen image, so an image built from another commit brings that commit's open data.Usage
Caveats
run.shalready reports that and suggests moving the job aside.quay.io/assetopsbench/runtime:devis linux/arm64, so an amd64 host can't pull it.publish-images.shbuilds both architectures.Type of Change
Industry Relevance
A published result can name the exact runtime build it ran on, and third parties can run a published image without retagging it.
Related Issues
Testing & Validation
AOB_RUNTIME_IMAGEset to a labelled copy ofruntime:dev: the 3 open tasks, plustsfm-1019andfmsr-913from the private suite with the private-data overlay. All 5 trials scored 1.000 with no errors.AOB_RUNTIME_IMAGE=aob-test/does-not-exist:nope, the trial's build failed trying to pull exactly that name.tsfm-1019task image built on the labelled base carries the label. With the overlay's mount it seesscenario_1019/manifest.jsonand a read-onlyshared/, and all fiveshared/…paths in its manifest resolve.run.shimage step: it pulls aquay.ioreference and rejects a missing local tag. Registry detection gave the expected result forquay.io/…,icr.io/…,localhost:5000/…,localhost/…,assetopsbench/runtime:*andubuntu:24.04.bbb99529) tagged bothassetopsbench/runtime:devandassetopsbench/runtime:3bb4f12, and its/opt/aob/.aob-commitreads3bb4f12409ee….run.shend to end, with a one-scenario profile and a fake model id, so trials fail fast without calling a provider:.runtime-imagerecord was written, and the trial built, ran and was scored.-rset to a different image refused to resume, named the original image, and exited 1.image_repostrips tags and digests.runtime:devand:3bb4f12count as local builds, whilequay.io/…andcouchdb:3.5count as registry images.-rand the shell beat.env, which beats the default.bash -npasses on all three scripts.uv run pytest src/ -k "not integration": 714 passed, 19 failed. The base branch has the same 19 failures: the scorer and trace-exporter tests, and theiotinvalid-site tests, which need a running CouchDB or no.env.Checklist