chore(build-label): drop three-word slug — use full timestamp + short SHA for alpha/beta cuts

The on-page label for `--release alpha|beta` cuts used to read
`vX.Y.Z-channel · YYYY-MM-DD · word-word-word`. The three-word slug
(derived deterministically from the source SHA via shared/build-words.txt)
was meant to make "is this the same build you emailed about?" a glance
check, but the cute-words layer turned out to be more confusing than
clarifying — testers prefer a real timestamp + short SHA.

New label shape, identical to plain dev builds:

  vX.Y.Z-channel · YYYY-MM-DD HH:MM:SS · <short-source-sha>[-dirty]

Helper renamed from _source_commit_slug to _source_commit_short_sha,
returning the short SHA of the source commit (walking past any
`chore(embedded): cut …` commit at HEAD so a re-cut on unchanged
source produces the same SHA). The wordlist file is no longer
referenced and is removed; tests/build-label.spec.js's regex
simplified to require the full timestamp + SHA form.
This commit is contained in:
ZDDC 2026-05-13 11:14:35 -05:00
parent fb27e47866
commit 6dca32b282
3 changed files with 25 additions and 345 deletions

View file

@ -163,40 +163,12 @@ _source_commit_ref() {
echo "$_ref" echo "$_ref"
} }
# Three-word slug derived deterministically from the source commit's # Short SHA of the underlying source commit (skipping past embedded
# full SHA. Same source state → same slug; survives embedded auto- # auto-commits — see _source_commit_ref). Same source state → same SHA
# commits by deferring to _source_commit_ref. # even after a `chore(embedded): cut …` commit has landed on top.
# _source_commit_short_sha() {
# Three 4-hex-char chunks of the SHA are taken modulo the wordlist
# length (shared/build-words.txt). 283 words × 3 = 22M combinations,
# enough that a tester eyeballing two beta builds can tell at a glance
# whether they're running the same source.
#
# Format: "word-word-word" (lowercase, hyphen-separated).
_source_commit_slug() {
_ref=$(_source_commit_ref) _ref=$(_source_commit_ref)
_full_sha=$(git -C "$root_dir" rev-parse "$_ref" 2>/dev/null || echo "0000000000000000") git -C "$root_dir" rev-parse --short=7 "$_ref" 2>/dev/null || echo "unknown"
# build-lib.sh is sourced from each tool's build.sh as
# "$root_dir/../shared/build-lib.sh"; the wordlist lives next to
# this file in the same shared/ directory.
_words_file="$root_dir/../shared/build-words.txt"
if [ ! -f "$_words_file" ]; then
# Fall back to plain short SHA if the wordlist is missing
# (e.g. running from a checkout that predates this feature).
git -C "$root_dir" rev-parse --short=7 "$_ref" 2>/dev/null || echo "unknown"
return
fi
_wc=$(awk 'END{print NR}' "$_words_file")
_h1=$(echo "$_full_sha" | cut -c 1-4)
_h2=$(echo "$_full_sha" | cut -c 5-8)
_h3=$(echo "$_full_sha" | cut -c 9-12)
_n1=$(( (0x$_h1 % _wc) + 1 ))
_n2=$(( (0x$_h2 % _wc) + 1 ))
_n3=$(( (0x$_h3 % _wc) + 1 ))
_w1=$(awk -v n="$_n1" 'NR==n{print; exit}' "$_words_file")
_w2=$(awk -v n="$_n2" 'NR==n{print; exit}' "$_words_file")
_w3=$(awk -v n="$_n3" 'NR==n{print; exit}' "$_words_file")
echo "${_w1}-${_w2}-${_w3}"
} }
# Compute build label and channel. Reads positional args: # Compute build label and channel. Reads positional args:
@ -217,9 +189,11 @@ _source_commit_slug() {
# #
# HTML tools do NOT tag alpha/beta cuts (consistent with current # HTML tools do NOT tag alpha/beta cuts (consistent with current
# behavior — alpha and beta artifacts are mutable files, not immutable # behavior — alpha and beta artifacts are mutable files, not immutable
# per-build snapshots). The label distinguishes plain dev builds from # per-build snapshots). Plain dev builds and `--release alpha|beta`
# explicit channel cuts via the timestamp granularity (full ts + dirty # cuts share the same on-page label format — full UTC timestamp + short
# marker for plain builds vs. date-only for `--release alpha|beta`). # source SHA — so testers see one rendering shape regardless of how the
# build was produced. A plain dev build may carry a "-dirty" SHA suffix
# when the working tree has uncommitted changes; release cuts don't.
compute_build_label() { compute_build_label() {
_tool="$1" _tool="$1"
_flag="${2:-}" _flag="${2:-}"
@ -254,20 +228,12 @@ compute_build_label() {
case "$_arg" in case "$_arg" in
alpha | beta) alpha | beta)
channel="$_arg" channel="$_arg"
_date=$(date -u +"%Y-%m-%d") # Full UTC timestamp + short source SHA — same format as
# Three-word slug derived from the *source* SHA — see # plain dev builds. _source_commit_short_sha walks past
# _source_commit_slug. Two builds carrying the same slug # any `chore(embedded): cut …` auto-commit at HEAD so a
# were cut from the same source state, so a tester can # re-cut on unchanged source produces the same SHA.
# glance at the on-page label and confirm "yes, this is _sha=$(_source_commit_short_sha)
# the cobalt-otter-meadow build I was emailed about" without build_label="v${_next_stable}-${channel} · ${build_timestamp} · ${_sha}"
# having to look up a SHA. The slug is invariant across
# the embedded auto-commit step (build:971-995) so a re-cut
# on unchanged source produces the same slug, no spurious
# commit. Full source SHA is available via the binary's
# `--version` output and the chart appVersion for any case
# where exact provenance matters.
_slug=$(_source_commit_slug)
build_label="v${_next_stable}-${channel} · ${_date} · ${_slug}"
_emit_build_label_sidecar "$_tool" _emit_build_label_sidecar "$_tool"
return 0 return 0
;; ;;

View file

@ -1,283 +0,0 @@
acorn
agate
alder
almond
amber
anchor
angle
antler
apple
apricot
arbor
arch
arrow
ashen
aspen
atlas
attic
auburn
aurora
azure
badge
bagel
ballad
balm
banner
barn
basil
basin
basket
beacon
beam
bear
beech
beetle
berry
biscuit
blanket
blossom
boat
bonnet
book
boulder
brass
bread
breeze
brick
bridge
brook
broom
bubble
bucket
buckle
button
cabin
cable
cactus
cake
candle
canvas
canyon
carpet
cart
cedar
chair
chalk
chamber
chapel
charm
cherry
chime
cinder
citrus
clay
cliff
cloud
clover
cluster
coal
coast
cobble
cocoa
coin
comet
compass
copper
cottage
cove
cradle
crane
crater
creek
crescent
cricket
crystal
daisy
dawn
deer
denim
diamond
ditch
dock
dolphin
dome
drift
drum
dune
dusk
eagle
ember
emerald
fable
falcon
feather
fence
fern
fiddle
finch
flag
flame
flask
flax
fleece
flint
flute
foam
forest
fork
fort
fountain
fox
garden
garnet
gear
ginger
glacier
glade
glass
globe
gold
granite
grass
grove
hammer
harbor
harp
harvest
hazel
hearth
heron
hill
hinge
hive
holly
hook
horizon
horn
hut
indigo
iris
iron
island
ivory
ivy
jade
jasper
juniper
kayak
kelp
kettle
key
kiln
kite
lake
lamp
lantern
lark
laurel
leaf
ledge
lemon
lens
lilac
lily
linen
locust
log
loom
lotus
maple
marble
marigold
marsh
mast
meadow
melon
mesa
meteor
mint
mirror
mist
mitten
moon
moor
moss
mug
nectar
nest
niche
nickel
nimbus
oak
oasis
ocean
onyx
opal
orbit
orchard
otter
owl
oyster
paddle
palm
panel
parrot
patio
pearl
pebble
pelican
pepper
perch
pier
pillow
pine
pipe
plank
plaza
pocket
pond
poplar
port
prairie
prism
puddle
quarry
quartz
quill
quilt
rabbit
raft
rain
ranch
raven
reed
reef
ribbon
ridge
river
robin
rock
rope
saddle
sage
sail
salt
sand
sapphire
sash
satin
scarf
sea
seal
seed
shawl
shield
shore
shrub
silver
silo
slope
smoke
snail
snow
spire

View file

@ -45,18 +45,15 @@ for (const tool of tools) {
const match = html.match(/class="build-timestamp">(?:<span[^>]*>)?([^<]+?)(?:<\/span>)?</); const match = html.match(/class="build-timestamp">(?:<span[^>]*>)?([^<]+?)(?:<\/span>)?</);
expect(match, 'build-timestamp element must have text content').toBeTruthy(); expect(match, 'build-timestamp element must have text content').toBeTruthy();
const label = match[1]; const label = match[1];
// Plain dev builds and --release alpha|beta carry the next-stable // Plain dev builds and --release alpha|beta share one label
// target as a pre-release suffix; the trailing field differs: // shape — full UTC timestamp + short source SHA (with
// plain dev → full timestamp + short SHA (+ "-dirty"): // optional -dirty marker on plain dev when the tree is
// "v0.0.17-alpha · 2026-04-29 00:50:17 · 714faf6-dirty" // uncommitted):
// --release alpha|beta → date-only + a three-word source-SHA slug: // "v0.0.17-alpha · 2026-04-29 00:50:17 · 714faf6"
// "v0.0.17-beta · 2026-04-29 · candle-mast-pearl" // "v0.0.17-alpha · 2026-04-29 00:50:17 · 714faf6-dirty"
// stable cut → bare version: "v0.0.17" // "v0.0.17-beta · 2026-05-13 15:29:05 · e7f6334"
const sha = '[0-9a-f]+(?:-dirty)?'; // plain dev build // Stable cuts emit a bare version: "v0.0.17"
const slug = '[a-z]+-[a-z]+-[a-z]+'; // --release alpha|beta const isChannel = /^v\d+\.\d+\.\d+-(?:alpha|beta) · 20\d\d-\d\d-\d\d \d\d:\d\d:\d\d · [0-9a-f]+(?:-dirty)?$/.test(label);
const isChannel = new RegExp(
`^v\\d+\\.\\d+\\.\\d+-(?:alpha|beta) · 20\\d\\d-\\d\\d-\\d\\d(?: \\d\\d:\\d\\d:\\d\\d)? · (?:${sha}|${slug})$`
).test(label);
const isVersion = /^v\d+\.\d+\.\d+$/.test(label); const isVersion = /^v\d+\.\d+\.\d+$/.test(label);
expect(isChannel || isVersion, expect(isChannel || isVersion,
`Expected channel or version label, got: "${label}"` `Expected channel or version label, got: "${label}"`