fix: seat the build stamp in #120's redesigned bar, and stop it faking a ticket id

Three things the merge with #120 (ui/shell-polish) actually required, none of
which a clean auto-merge could have told us.

MOVED, not preserved. #120 left <header>'s markup alone but gave every child
explicit styling and a stated reading order -- "what this is, which document,
which view, which mode, what keys, what the peer is doing". A build identifier
is "what this is", so the span moves from after #status to beside <h1>. Keeping
it at the tail was loyalty to my own first draft: it read as metadata trailing
#status, and with #hint's `flex: 1 1 auto` fighting for the slack a 40-char
commit SHA there is the thing that crowds the bar.

STYLED, because unstyled is illegible-by-default in a design system. It takes
`var(--dim)` -- the same token #hint and #status use, so it tracks both themes
by construction rather than by a hand-picked colour -- at 0.72rem, and clamps
to 14ch. Measured under Chromium on the merged tree: a tag renders whole
(scrollWidth == clientWidth, 69px), a 40-char SHA truncates to a 13-character
prefix with an ellipsis, and `header` does not overflow in either case
(scrollWidth == clientWidth == 1280). Contrast of rgb(107,103,95) on
rgb(244,241,234) is ~5.0:1, above AA for small text. Selecting the text still
copies the whole SHA -- text-overflow is a rendering clamp, not a truncation.

NOT AN ID. `improvise-web.tar.gz` puts the token `improvise-web` in the tree,
and AGENTS.md's audit matches `improvise-[a-z0-9]{3,8}` -- so the artifact name
resolved to no ticket and read exactly like a dead id, which AGENTS.md calls
worse than one. `improvise-installer.sh` escapes only by being ten characters,
which is luck rather than a rule, so the exclusion list gains `web` and the
paragraph gains the general case.

RELEASING.md (which arrived in this same merge, from improvise-gx5d) listed
what a tag publishes and was made wrong by omission; it now names the web
capture and says plainly that it is not what Pages is serving.

Verified on the merged tree: 1631 cargo tests over 37 binaries, node --test
47 -> 50 (so #120's three new shell tests survived the merge rather than being
silently dropped), 42 Playwright tests green under Chromium, and the stamp
gate re-proved by injecting the missed substitution again -- a header rewrite
does not carry the old fault injection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-21 23:01:08 -07:00
parent 1ac2a13b6c
commit 926396352f
4 changed files with 43 additions and 8 deletions
+9 -1
View File
@@ -263,7 +263,7 @@ filing, and before pushing docs run the audit:
grep -rohE 'improvise-[a-z0-9]{3,8}\b' \ grep -rohE 'improvise-[a-z0-9]{3,8}\b' \
context README.md AGENTS.md CLAUDE.md crates src tests examples web harness docs \ context README.md AGENTS.md CLAUDE.md crates src tests examples web harness docs \
| sort -u \ | sort -u \
| grep -vE '^improvise-(core|formula|io|protocol|command|gp|ws|worker|wasm|harness|registry|side)$' \ | grep -vE '^improvise-(core|formula|io|protocol|command|gp|ws|worker|wasm|harness|registry|side|web)$' \
> /tmp/bd-audit-ids.txt > /tmp/bd-audit-ids.txt
bd show $(cat /tmp/bd-audit-ids.txt) 2>&1 \ bd show $(cat /tmp/bd-audit-ids.txt) 2>&1 \
| grep -iE 'not found|no such issue' || echo "all resolve" | grep -iE 'not found|no such issue' || echo "all resolve"
@@ -291,6 +291,14 @@ real defect through:
exclusion list is a filter, and a filter that over-matches fails in the exclusion list is a filter, and a filter that over-matches fails in the
direction that looks like success. (Anchoring it is also what caught the direction that looks like success. (Anchoring it is also what caught the
example id this very paragraph originally spelled out — see the note below.) example id this very paragraph originally spelled out — see the note below.)
- **A release artifact's name is ID-shaped, and `improvise-installer.sh`
escaped only by being ten characters long.** `improvise-web.tar.gz`
(improvise-oujb) is three, so it matches `{3,8}` and resolves to nothing;
`web` is therefore excluded above. The general point is that the length
bound, not any rule, is what has been keeping `dist`'s artifact names out of
this audit — so **a new artifact whose name is a short lowercase word must be
added to the exclusion list in the same commit**, or it arrives as a dead id
that no amount of `bd` archaeology explains.
Note the recipe's own prose deliberately spells no live or dead id: a document Note the recipe's own prose deliberately spells no live or dead id: a document
that lists ids as examples makes itself a source of audit noise. that lists ids as examples makes itself a source of audit noise.
+13 -1
View File
@@ -48,7 +48,19 @@ moved. Every step below exists to put that check before the irreversible one.
5. **Watch the run.** A green release takes about three minutes and publishes 5. **Watch the run.** A green release takes about three minutes and publishes
tarballs for all four targets with their `.sha256` files, `sha256.sum`, tarballs for all four targets with their `.sha256` files, `sha256.sum`,
`dist-manifest.json`, `source.tar.gz` and `improvise-installer.sh`. `dist-manifest.json`, `source.tar.gz`, `improvise-installer.sh` and
`improvise-web.tar.gz` — the assembled landing page and browser app, stamped
with the tag, which the page then shows in its header (improvise-oujb).
**`improvise-web.tar.gz` is a self-hostable copy and a rollback target, not
what the published site is serving.** GitHub Pages tracks `main` and a tag
does not deploy it, so the site and the release are deliberately different
code. Two things follow when the web half goes wrong. `release.yml` is
autogenerated, so never hand-edit it: change `dist-workspace.toml` and re-run
`dist generate`, which should leave the workflow byte-identical. And a
**pull-request** run of the Release workflow skips `build-global-artifacts`,
so a green PR says nothing about the web capture — to exercise it without
cutting a tag, run `dist build --artifacts=global` locally.
The failure signature is unmistakable once you know it: **`plan` fails in The failure signature is unmistakable once you know it: **`plan` fails in
about twenty seconds and the four jobs behind it skip.** That is the tag not about twenty seconds and the four jobs behind it skip.** That is the tag not
+7 -6
View File
@@ -34,17 +34,18 @@
--> -->
<header> <header>
<h1>improvise</h1> <h1>improvise</h1>
<!--
What this page IS: web/assemble.sh rewrites the text below to the tag
or commit it assembled from (improvise-oujb). It sits with the name
because the bar's order starts at "what this is", and a tree served
straight out of web/ was never assembled and honestly says so.
-->
<span title="Build this page was assembled from" id="build-version">unstamped</span>
<span id="doc-name"></span> <span id="doc-name"></span>
<span id="view-name"></span> <span id="view-name"></span>
<span id="mode"></span> <span id="mode"></span>
<span id="hint"></span> <span id="hint"></span>
<span id="status" role="status"></span> <span id="status" role="status"></span>
<!--
What this page IS: web/assemble.sh rewrites the text below to the tag
or commit it assembled from (improvise-oujb). A page served straight
out of web/ was never assembled and honestly says so.
-->
<span title="Build this page was assembled from" id="build-version">unstamped</span>
</header> </header>
<!-- <!--
+14
View File
@@ -87,6 +87,20 @@ header h1 {
flex: none; flex: none;
} }
/* Which build this is (improvise-oujb). Quietest thing on the bar -- it is
reference, never state -- but it must stay legible enough to quote. */
#build-version {
flex: none;
/* A tag fits whole; a 40-char commit SHA truncates to a prefix long enough
to name a build, and selecting the text still copies the whole thing. */
max-width: 14ch;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--dim);
font-size: 0.72rem;
}
#doc-name { #doc-name {
flex: none; flex: none;
/* Wide enough for the shipped document's whole title, `name (stored_as)`, /* Wide enough for the shipped document's whole title, `name (stored_as)`,