Finding (truffleruby feedstock jvm leg, local gate 2026-09-07)
An on_runtime composition (spec 33) whose owner pair is a pre-2.5.0 launcher does NOT fail closed — it fails with a confusing entry-not-found, because the pre-spec-33 driver joins --tebako-entry onto the FIRST --tebako-image mount, which in a composition is the depending runtime's env image. Spec 33 §1 amends exactly that rule ("resolves against the first mount whose manifest is NOT the depending runtime's env image"), and 2.5.0 is the first line implementing it.
Reproduced systematically (truffleruby-feedstock local jvm leg, out/work-jvm-aarch64-macos/store):
- owner = published graalvm pair
java-25.0.4.1-2.4.0 (exe b27b44f5…, the v2.4.1 release): composed smoke → entrypoint '/app/bin/hello' not found at '/__runners__/truffleruby/app/bin/hello' — the entry joined onto the dep mount (/__runners__/truffleruby) instead of the app mount (/).
- Same store, ONLY the owner exe swapped to the 2.5.0 launcher: green (
hello from truffleruby 3.4.9, JSON cext OK). The dep exe, the shim, the payload, and the manifests were all ruled out by elimination first.
Why owner_contract can't gate this
Spec 33 §4's owner_contract constraint discriminates the owner's contract_version. The 2.4.0 and 2.5.0 launchers BOTH speak contract 2 — the capability that changed is the driver's entry-routing rule, not the wire contract. So §4 today has no fail-closed arm for a pre-spec-33 owner; the composition silently-ish misroutes.
Proposal
- Spec 33 §4 gains the named failure: an
on_runtime dispatch whose owner shard's tebako_version predates 2.5.0 (the first line implementing §1's amended entry rule) fails closed at dispatch — exit-75 negotiation class — naming the owner ref AND its line.
- The shim implements the check. The discriminant already rides the owner shard:
"tebako_version": "2.4.0" (verified on the published graalvm shard, tebako-packages/openjdk v2.4.1). No new wire, no new mirror — one version compare at plan time, only on the composition path.
- Version comparison, not a flag: a
>= 2.5.0 floor on the owner's product line when the first triple's shard carries on_runtime. (A future capability word would be prettier; the line floor says the same thing with data the shard already ships.)
Mitigation already in flight
tamatebako/tebako-runtime-openjdk#32 relines BOTH java flavors (temurin + graalvm) to the 2.5.0 line so every published owner is spec-33-capable. But a store holding the cached java-25.0.4.1-2.4.0 pair keeps it, and TEBAKO_OFFLINE=1 or an explicit pin can still select it — the fail-closed check is the difference between a named error and a mystifying one for that store.
Rides the axis-polish batch (with #548, #549, spec 28 §8 any_of, EngineProvides.language_version).
Finding (truffleruby feedstock jvm leg, local gate 2026-09-07)
An
on_runtimecomposition (spec 33) whose owner pair is a pre-2.5.0 launcher does NOT fail closed — it fails with a confusing entry-not-found, because the pre-spec-33 driver joins--tebako-entryonto the FIRST--tebako-imagemount, which in a composition is the depending runtime's env image. Spec 33 §1 amends exactly that rule ("resolves against the first mount whose manifest is NOT the depending runtime's env image"), and 2.5.0 is the first line implementing it.Reproduced systematically (truffleruby-feedstock local jvm leg,
out/work-jvm-aarch64-macos/store):java-25.0.4.1-2.4.0(exeb27b44f5…, the v2.4.1 release): composed smoke →entrypoint '/app/bin/hello' not found at '/__runners__/truffleruby/app/bin/hello'— the entry joined onto the dep mount (/__runners__/truffleruby) instead of the app mount (/).hello from truffleruby 3.4.9, JSON cext OK). The dep exe, the shim, the payload, and the manifests were all ruled out by elimination first.Why
owner_contractcan't gate thisSpec 33 §4's
owner_contractconstraint discriminates the owner'scontract_version. The 2.4.0 and 2.5.0 launchers BOTH speak contract 2 — the capability that changed is the driver's entry-routing rule, not the wire contract. So §4 today has no fail-closed arm for a pre-spec-33 owner; the composition silently-ish misroutes.Proposal
on_runtimedispatch whose owner shard'stebako_versionpredates 2.5.0 (the first line implementing §1's amended entry rule) fails closed at dispatch — exit-75 negotiation class — naming the owner ref AND its line."tebako_version": "2.4.0"(verified on the published graalvm shard, tebako-packages/openjdk v2.4.1). No new wire, no new mirror — one version compare at plan time, only on the composition path.>= 2.5.0floor on the owner's product line when the first triple's shard carrieson_runtime. (A future capability word would be prettier; the line floor says the same thing with data the shard already ships.)Mitigation already in flight
tamatebako/tebako-runtime-openjdk#32 relines BOTH java flavors (temurin + graalvm) to the 2.5.0 line so every published owner is spec-33-capable. But a store holding the cached
java-25.0.4.1-2.4.0pair keeps it, andTEBAKO_OFFLINE=1or an explicit pin can still select it — the fail-closed check is the difference between a named error and a mystifying one for that store.Rides the axis-polish batch (with #548, #549, spec 28 §8
any_of, EngineProvides.language_version).