Stop minting identifiers nothing reads: moving channel tags, :c-<sha> on main, and a label-keyed build cache #239
@@ -487,6 +487,11 @@ jobs:
|
||||
set -eu
|
||||
ID=$(sh scripts/artifacts.sh identity web "$CHANNEL")
|
||||
echo "identity=$ID" >> "$GITHUB_OUTPUT"
|
||||
# The value step 3 will key on once the label mechanism is proven.
|
||||
# Emitted now so the build below can stamp it — stamping is harmless
|
||||
# and is what gives the shadow read something to find next push.
|
||||
REV=$(sh scripts/artifacts.sh revision web)
|
||||
echo "revision=$REV" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Every build that runs now claims the identity. The carve-out here
|
||||
# existed only for tag pushes, which rebuilt an already-published
|
||||
@@ -502,6 +507,66 @@ jobs:
|
||||
echo "reuse: $IMAGE:$ID is not published — building"
|
||||
fi
|
||||
|
||||
# --- shadow: can we read a label off the channel tag? (milestone 318 step 3)
|
||||
# Informational ONLY — no `set -e`, every probe falls back to
|
||||
# UNAVAILABLE, and nothing downstream reads this. It must never fail a
|
||||
# build; that is the whole reason it runs before the mechanism does.
|
||||
#
|
||||
# The question: can the reuse check be keyed on an image LABEL read off
|
||||
# the channel tag, instead of on a separate r-<rev> tag? If yes, nothing
|
||||
# is minted per build, the -main/-dev identity split disappears, and the
|
||||
# base-refresh clobber (#3154) stops existing.
|
||||
#
|
||||
# Two questions, answered at different times — worth separating, because
|
||||
# reading "no value" as "the mechanism does not work" would abandon a
|
||||
# working design:
|
||||
#
|
||||
# 1. Do the TEMPLATE MECHANICS work here? Answered on the very first
|
||||
# run, by probes B and C: if they print a labels map (even an empty
|
||||
# one) or a config JSON, `--format` over .Image resolves on this
|
||||
# buildx and this registry. That is the actual gate for step 3.
|
||||
# 2. Does a stamped value ROUND-TRIP? Only answerable once an artifact
|
||||
# genuinely rebuilds. A push that changes no shipped file reuses,
|
||||
# the build is skipped, and nothing gets stamped — so an artifact
|
||||
# keeps reporting no label until its own source next moves.
|
||||
#
|
||||
# That second point is not a defect, it is the migration path: under the
|
||||
# real mechanism "no label" reads as a MISS, so the artifact rebuilds
|
||||
# once and is stamped from then on. One extra build per artifact, ever,
|
||||
# in the safe direction. `imagetools create` cannot add the label on the
|
||||
# reuse path — it copies a manifest and config labels are not manifest
|
||||
# annotations — so there is no way to backfill, and no need to.
|
||||
#
|
||||
# Several probes on purpose: `--format` templating over .Image varies by
|
||||
# buildx version, and one push should tell us which spelling works
|
||||
# rather than costing a round trip per guess.
|
||||
- name: Shadow — read fc.revision off the channel tag (informational)
|
||||
env:
|
||||
IMAGE: git.fabledsword.com/bvandeusen/fabledcurator
|
||||
CHANNEL: ${{ steps.tag.outputs.channel }}
|
||||
DERIVED: ${{ steps.reuse.outputs.revision }}
|
||||
run: |
|
||||
set -u
|
||||
# The moving tag this channel publishes. `main` is asked about
|
||||
# :latest, which is what step 4 keeps; :main is on its way out.
|
||||
if [ "$CHANNEL" = "main" ]; then T=latest; else T=dev; fi
|
||||
REF="$IMAGE:$T"
|
||||
echo "label-shadow: ref=$REF derived=$DERIVED"
|
||||
|
||||
A=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ index .Image.Config.Labels "fc.revision" }}' 2>&1 || echo FAILED)
|
||||
echo "label-shadow: probe-index = $A"
|
||||
|
||||
B=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ .Image.Config.Labels }}' 2>&1 | head -c 300 || echo FAILED)
|
||||
echo "label-shadow: probe-labels = $B"
|
||||
|
||||
C=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ json .Image }}' 2>&1 | head -c 400 || echo FAILED)
|
||||
echo "label-shadow: probe-json = $C"
|
||||
|
||||
echo "label-shadow: buildx = $(docker buildx version 2>&1 || echo UNAVAILABLE)"
|
||||
|
||||
- name: Download signed XPI from Forgejo release asset
|
||||
# dev and main each bundle the XPI their own sign-extension just
|
||||
# published — the point of the channel work (milestone 271 step 6): the
|
||||
@@ -586,6 +651,11 @@ jobs:
|
||||
file: Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.reuse.outputs.build_tags }}
|
||||
# Stamped now, read later. Additive and inert this step: no
|
||||
# decision depends on it until the shadow above proves the
|
||||
# label can actually be read back (milestone 318 step 3).
|
||||
labels: |
|
||||
fc.revision=${{ steps.reuse.outputs.revision }}
|
||||
# Only the web image carries a channel: it is the one that serves
|
||||
# /api/extension/manifest. The ml and agent images have nothing to
|
||||
# report it to.
|
||||
@@ -745,6 +815,11 @@ jobs:
|
||||
set -eu
|
||||
ID=$(sh scripts/artifacts.sh identity ml "$CHANNEL")
|
||||
echo "identity=$ID" >> "$GITHUB_OUTPUT"
|
||||
# The value step 3 will key on once the label mechanism is proven.
|
||||
# Emitted now so the build below can stamp it — stamping is harmless
|
||||
# and is what gives the shadow read something to find next push.
|
||||
REV=$(sh scripts/artifacts.sh revision ml)
|
||||
echo "revision=$REV" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Every build that runs now claims the identity. The carve-out here
|
||||
# existed only for tag pushes, which rebuilt an already-published
|
||||
@@ -760,6 +835,66 @@ jobs:
|
||||
echo "reuse: $IMAGE:$ID is not published — building"
|
||||
fi
|
||||
|
||||
# --- shadow: can we read a label off the channel tag? (milestone 318 step 3)
|
||||
# Informational ONLY — no `set -e`, every probe falls back to
|
||||
# UNAVAILABLE, and nothing downstream reads this. It must never fail a
|
||||
# build; that is the whole reason it runs before the mechanism does.
|
||||
#
|
||||
# The question: can the reuse check be keyed on an image LABEL read off
|
||||
# the channel tag, instead of on a separate r-<rev> tag? If yes, nothing
|
||||
# is minted per build, the -main/-dev identity split disappears, and the
|
||||
# base-refresh clobber (#3154) stops existing.
|
||||
#
|
||||
# Two questions, answered at different times — worth separating, because
|
||||
# reading "no value" as "the mechanism does not work" would abandon a
|
||||
# working design:
|
||||
#
|
||||
# 1. Do the TEMPLATE MECHANICS work here? Answered on the very first
|
||||
# run, by probes B and C: if they print a labels map (even an empty
|
||||
# one) or a config JSON, `--format` over .Image resolves on this
|
||||
# buildx and this registry. That is the actual gate for step 3.
|
||||
# 2. Does a stamped value ROUND-TRIP? Only answerable once an artifact
|
||||
# genuinely rebuilds. A push that changes no shipped file reuses,
|
||||
# the build is skipped, and nothing gets stamped — so an artifact
|
||||
# keeps reporting no label until its own source next moves.
|
||||
#
|
||||
# That second point is not a defect, it is the migration path: under the
|
||||
# real mechanism "no label" reads as a MISS, so the artifact rebuilds
|
||||
# once and is stamped from then on. One extra build per artifact, ever,
|
||||
# in the safe direction. `imagetools create` cannot add the label on the
|
||||
# reuse path — it copies a manifest and config labels are not manifest
|
||||
# annotations — so there is no way to backfill, and no need to.
|
||||
#
|
||||
# Several probes on purpose: `--format` templating over .Image varies by
|
||||
# buildx version, and one push should tell us which spelling works
|
||||
# rather than costing a round trip per guess.
|
||||
- name: Shadow — read fc.revision off the channel tag (informational)
|
||||
env:
|
||||
IMAGE: git.fabledsword.com/bvandeusen/fabledcurator-ml
|
||||
CHANNEL: ${{ steps.tag.outputs.channel }}
|
||||
DERIVED: ${{ steps.reuse.outputs.revision }}
|
||||
run: |
|
||||
set -u
|
||||
# The moving tag this channel publishes. `main` is asked about
|
||||
# :latest, which is what step 4 keeps; :main is on its way out.
|
||||
if [ "$CHANNEL" = "main" ]; then T=latest; else T=dev; fi
|
||||
REF="$IMAGE:$T"
|
||||
echo "label-shadow: ref=$REF derived=$DERIVED"
|
||||
|
||||
A=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ index .Image.Config.Labels "fc.revision" }}' 2>&1 || echo FAILED)
|
||||
echo "label-shadow: probe-index = $A"
|
||||
|
||||
B=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ .Image.Config.Labels }}' 2>&1 | head -c 300 || echo FAILED)
|
||||
echo "label-shadow: probe-labels = $B"
|
||||
|
||||
C=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ json .Image }}' 2>&1 | head -c 400 || echo FAILED)
|
||||
echo "label-shadow: probe-json = $C"
|
||||
|
||||
echo "label-shadow: buildx = $(docker buildx version 2>&1 || echo UNAVAILABLE)"
|
||||
|
||||
- name: Build and push ml image
|
||||
if: steps.reuse.outputs.hit != 'true'
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -768,6 +903,11 @@ jobs:
|
||||
file: Dockerfile.ml
|
||||
push: true
|
||||
tags: ${{ steps.reuse.outputs.build_tags }}
|
||||
# Stamped now, read later. Additive and inert this step: no
|
||||
# decision depends on it until the shadow above proves the
|
||||
# label can actually be read back (milestone 318 step 3).
|
||||
labels: |
|
||||
fc.revision=${{ steps.reuse.outputs.revision }}
|
||||
|
||||
# Registry-side manifest copy: no layer transfer, no local daemon, no
|
||||
# rebuild. Each -t becomes another reference to the SAME manifest the
|
||||
@@ -918,6 +1058,11 @@ jobs:
|
||||
set -eu
|
||||
ID=$(sh scripts/artifacts.sh identity agent "$CHANNEL")
|
||||
echo "identity=$ID" >> "$GITHUB_OUTPUT"
|
||||
# The value step 3 will key on once the label mechanism is proven.
|
||||
# Emitted now so the build below can stamp it — stamping is harmless
|
||||
# and is what gives the shadow read something to find next push.
|
||||
REV=$(sh scripts/artifacts.sh revision agent)
|
||||
echo "revision=$REV" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Every build that runs now claims the identity. The carve-out here
|
||||
# existed only for tag pushes, which rebuilt an already-published
|
||||
@@ -933,6 +1078,66 @@ jobs:
|
||||
echo "reuse: $IMAGE:$ID is not published — building"
|
||||
fi
|
||||
|
||||
# --- shadow: can we read a label off the channel tag? (milestone 318 step 3)
|
||||
# Informational ONLY — no `set -e`, every probe falls back to
|
||||
# UNAVAILABLE, and nothing downstream reads this. It must never fail a
|
||||
# build; that is the whole reason it runs before the mechanism does.
|
||||
#
|
||||
# The question: can the reuse check be keyed on an image LABEL read off
|
||||
# the channel tag, instead of on a separate r-<rev> tag? If yes, nothing
|
||||
# is minted per build, the -main/-dev identity split disappears, and the
|
||||
# base-refresh clobber (#3154) stops existing.
|
||||
#
|
||||
# Two questions, answered at different times — worth separating, because
|
||||
# reading "no value" as "the mechanism does not work" would abandon a
|
||||
# working design:
|
||||
#
|
||||
# 1. Do the TEMPLATE MECHANICS work here? Answered on the very first
|
||||
# run, by probes B and C: if they print a labels map (even an empty
|
||||
# one) or a config JSON, `--format` over .Image resolves on this
|
||||
# buildx and this registry. That is the actual gate for step 3.
|
||||
# 2. Does a stamped value ROUND-TRIP? Only answerable once an artifact
|
||||
# genuinely rebuilds. A push that changes no shipped file reuses,
|
||||
# the build is skipped, and nothing gets stamped — so an artifact
|
||||
# keeps reporting no label until its own source next moves.
|
||||
#
|
||||
# That second point is not a defect, it is the migration path: under the
|
||||
# real mechanism "no label" reads as a MISS, so the artifact rebuilds
|
||||
# once and is stamped from then on. One extra build per artifact, ever,
|
||||
# in the safe direction. `imagetools create` cannot add the label on the
|
||||
# reuse path — it copies a manifest and config labels are not manifest
|
||||
# annotations — so there is no way to backfill, and no need to.
|
||||
#
|
||||
# Several probes on purpose: `--format` templating over .Image varies by
|
||||
# buildx version, and one push should tell us which spelling works
|
||||
# rather than costing a round trip per guess.
|
||||
- name: Shadow — read fc.revision off the channel tag (informational)
|
||||
env:
|
||||
IMAGE: git.fabledsword.com/bvandeusen/fabledcurator-agent
|
||||
CHANNEL: ${{ steps.tag.outputs.channel }}
|
||||
DERIVED: ${{ steps.reuse.outputs.revision }}
|
||||
run: |
|
||||
set -u
|
||||
# The moving tag this channel publishes. `main` is asked about
|
||||
# :latest, which is what step 4 keeps; :main is on its way out.
|
||||
if [ "$CHANNEL" = "main" ]; then T=latest; else T=dev; fi
|
||||
REF="$IMAGE:$T"
|
||||
echo "label-shadow: ref=$REF derived=$DERIVED"
|
||||
|
||||
A=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ index .Image.Config.Labels "fc.revision" }}' 2>&1 || echo FAILED)
|
||||
echo "label-shadow: probe-index = $A"
|
||||
|
||||
B=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ .Image.Config.Labels }}' 2>&1 | head -c 300 || echo FAILED)
|
||||
echo "label-shadow: probe-labels = $B"
|
||||
|
||||
C=$(docker buildx imagetools inspect "$REF" \
|
||||
--format '{{ json .Image }}' 2>&1 | head -c 400 || echo FAILED)
|
||||
echo "label-shadow: probe-json = $C"
|
||||
|
||||
echo "label-shadow: buildx = $(docker buildx version 2>&1 || echo UNAVAILABLE)"
|
||||
|
||||
- name: Build and push agent image
|
||||
if: steps.reuse.outputs.hit != 'true'
|
||||
uses: docker/build-push-action@v5
|
||||
@@ -941,6 +1146,11 @@ jobs:
|
||||
file: agent/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.reuse.outputs.build_tags }}
|
||||
# Stamped now, read later. Additive and inert this step: no
|
||||
# decision depends on it until the shadow above proves the
|
||||
# label can actually be read back (milestone 318 step 3).
|
||||
labels: |
|
||||
fc.revision=${{ steps.reuse.outputs.revision }}
|
||||
|
||||
# Registry-side manifest copy: no layer transfer, no local daemon, no
|
||||
# rebuild. Each -t becomes another reference to the SAME manifest the
|
||||
|
||||
Reference in New Issue
Block a user