Compare commits

...

2 Commits

Author SHA1 Message Date
Joakim Persson c2c42c34a2 docs(v1.10.1): cut v1.10.1; v1.10.0 stays tagged-but-never-published
Lint / skill-floor (push) Successful in 11s
Lint / doc-drift (push) Successful in 12s
Lint / hadolint (push) Successful in 14s
Lint / actionlint (push) Successful in 19s
Publish Docker Image / resolve-versions (push) Successful in 12s
Publish Docker Image / base-decide (push) Successful in 13s
Publish Docker Image / build-base (push) Has been skipped
Publish Docker Image / lint-gate (push) Successful in 25s
Publish Docker Image / smoke-studio (push) Failing after 5m43s
Publish Docker Image / build-variant-studio (push) Has been skipped
Publish Docker Image / smoke (push) Failing after 8m21s
Publish Docker Image / build-variant (push) Has been skipped
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
v1.10.0's build failed one assertion of 104 and published nothing. Rather than
re-point a tag CI had already consumed, the number moves: a version that failed
its build should stay failed and readable, not be quietly overwritten with
different bytes.

CHANGELOG gains a v1.10.1 section carrying the smoke fix (moved out of
v1.10.0's Fixed list), and states plainly that everything under v1.10.0 ships
here so the big section stays the content record. v1.10.0's heading is marked
"tagged, never published — superseded by v1.10.1" with a blockquote naming the
commit (12f99c4), the run (704), the four jobs that skipped, and the fact that
no image carries the tag.

Pre-tag doc sweep, because CI reads docs from the TAG and POSTs DOCKER_HUB.md
to the Hub as full_description:

  - README "Terminal UI mode: fullscreen is the default (since v1.10.0)"
    -> v1.10.1. A "since" marker pointing at an image nobody can pull is a
    worse lie than no marker.
  - Dockerfile.variant decision comments for the pi and pi-atelier bumps
    -> v1.10.1 (these describe which release carries the change).
  - scripts/smoke-test.sh deliberately KEEPS "the v1.10.0 tag build" — that
    one is a historical event and v1.10.0 is its correct name.
  - DOCKER_HUB.md needed no change: its fullscreen note is version-free.

No code changes. RELEASE_TAG is derived from github.ref_name, so nothing in the
build hardcodes the version.

Base layer does NOT rebuild: no base input (Dockerfile.base, rootfs/**,
entrypoint.sh, entrypoint-user.sh) has changed since 12f99c4, so base-decide
will cache-hit base-dad0f365ff24, which run 704's build-base already pushed at
07:52:38Z. This retry skips the expensive half.

Gates: doc-drift 23 OK / 0 DRIFT / 0 SKIP; base-hash, workflow-shell,
skill-floor, lint-shell all rc=0.
2026-10-02 10:36:21 +02:00
Joakim Persson f3b3748223 fix(smoke): derive the clipboard assertion from what pi declares
Lint / skill-floor (push) Successful in 7s
Lint / actionlint (push) Successful in 17s
Lint / hadolint (push) Successful in 14s
Lint / doc-drift (push) Successful in 14s
v1.10.0's first tag build (run 704) failed on ONE assertion out of 104, and
published nothing. The assertion was wrong, not the image.

scripts/smoke-test.sh required @mariozechner/clipboard to be installed and
require()-able at every install site, failing hard when the family was absent.
pi 0.86.0 (#9163) "Replaced the external native clipboard dependency with
bundled asynchronous macOS, Windows, and X11 helpers while preserving platform
command and OSC 52 fallbacks". Measured in the published tarballs rather than
inferred from the changelog:

  pi 0.85.1 -> dependencies include @mariozechner/clipboard@0.3.9
  pi 0.87.1 -> no @mariozechner/* at all
  pi 1.0.0  -> no @mariozechner/* at all

So on a correct v1.10.0 image the package is legitimately gone, `if [ -z
"$sites" ]; then exit 1` fired, and both smoke jobs went red on the same line:
smoke 100 passed/1 failed, smoke-studio 103 passed/1 failed with every
studio-specific assertion green. build-variant, build-variant-studio,
promote-base-latest and update-description all skipped -> nothing published.
The gate worked; it was enforcing pi 0.85.1's dependency graph.

The guard is NOT deleted, because its "fail when absent" shape is the thing
that stops prune_foreign_natives() from deleting the binding instead of the
surplus platform copies. It now derives the expectation from what the image's
pi actually DECLARES:

  declares + install loads     -> pass
  declares + no install        -> FAIL (prune removed function)
  does not declare + no install-> pass (pi bundles it since 0.86.0)
  does not declare + install   -> FAIL (orphan nothing depends on)

That re-arms automatically if a future pi re-adds the dependency, which a
skip-if-absent would not.

Verified as that four-quadrant truth table on EXIT CODES, not messages, since
run() keys on status: rc=0/1/0/1 as listed. The final check extracted the
command string verbatim from the committed file and ran it through `sh -c` the
way run() does, so the escaping was tested as shipped rather than as drafted.

Gates: doc-drift 23 OK / 0 DRIFT; base-hash, workflow-shell, skill-floor,
lint-shell all rc=0. smoke-test.sh is not a base-hash input, so the base layer
does not rebuild.
2026-10-02 10:27:25 +02:00
4 changed files with 82 additions and 11 deletions
+56 -1
View File
@@ -11,7 +11,62 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
---
## v1.10.0 — 2026-10-02
## v1.10.1 — 2026-10-02
**v1.10.0 was tagged and never published.** Its tag build (run 704) failed one
assertion out of 104 — a smoke check that required a pi dependency upstream had
deliberately deleted — so every publish job skipped and no image, no `latest`,
no Hub description was ever written. v1.10.1 is that same release plus the fix
to the assertion: **everything described under v1.10.0 below ships here**, and
that section remains the content record for this release. Nothing in it changed.
The tag number moves rather than being re-pointed because CI had already
consumed v1.10.0; a version that failed its build should stay failed and
readable, not be quietly overwritten with different bytes.
### Fixed
- **The smoke suite asserted a pi dependency that upstream deleted, and it cost
this release its first tag build** — `scripts/smoke-test.sh` required
`@mariozechner/clipboard` to be installed and `require()`-able at every install
site. pi **0.86.0** (`#9163`) *"Replaced the external native clipboard
dependency with bundled asynchronous macOS, Windows, and X11 helpers while
preserving platform command and OSC 52 fallbacks"*. Measured in the published
tarballs: pi `0.85.1` declares `@mariozechner/clipboard@0.3.9`; `0.87.1` and
`1.0.0` declare no `@mariozechner/*` at all. So on a correct v1.10.0 image the
package is legitimately absent, the assertion's `if [ -z "$sites" ]; then exit
1` fired, and run 704 ended **100 passed / 1 failed** on `smoke` and **103
passed / 1 failed** on `smoke-studio` — same single assertion, every
studio-specific check green. `build-variant`, `build-variant-studio`,
`promote-base-latest` and `update-description` were all skipped, so **nothing
was published**: the gate behaved exactly as designed, against a stale
expectation rather than a real defect.
The fix does not delete the guard, because the guard was right: "fail when the
family is absent" is what stops `prune_foreign_natives()` from silently
deleting the binding instead of the surplus platform copies. It now **derives
its expectation from what the image's pi actually declares** — if pi declares
the dependency an install must exist and load; if pi does not, no install may
linger. That re-arms by itself should a future pi re-add it, and it still
catches an orphaned install. Verified as a four-quadrant truth table with the
command string extracted verbatim from the file and run through `sh -c` the way
`run()` invokes it: declared+present → rc=0, declared+absent → rc=1,
undeclared+absent → rc=0, undeclared+present → rc=1.
Worth stating plainly, since it is the whole value of the round: pi 1.0.0,
pi-atelier v0.13.0 and pi-studio v0.9.61 passed **103 of 104** assertions on a
pi MAJOR bump. The one red was the suite describing pi 0.85.1's dependency
graph, not the image.
---
## v1.10.0 — 2026-10-02 (tagged, never published — superseded by v1.10.1)
> Tagged 2026-10-02 at commit `12f99c4`. Its build (run 704) went red on the
> stale clipboard assertion described under v1.10.1, so `build-variant`,
> `build-variant-studio`, `promote-base-latest` and `update-description` all
> skipped and nothing reached the Hub. No image carries this tag. The content
> below is accurate and shipped as **v1.10.1**.
Three small fixes found by the v1.9.4 first-boot acceptance and the CI base
hash prediction, plus one boot-time wiring fix that stops a recurring `git push`
+3 -3
View File
@@ -154,11 +154,11 @@ ARG USER_NAME=developer
# (e7d77dc -> 1529e14 -> 731c3d4 in the nine days to 2026-10-01), so waiting for
# a tag means holding pi indefinitely. A full SHA keeps the one property
# `master` does not have: rebuilding this tag later produces the SAME image.
# v1.9.5 SKIPPED 0.99.x and 1.0.0 for lack of evidence. v1.10.0 went and got the
# v1.9.5 SKIPPED 0.99.x and 1.0.0 for lack of evidence. v1.10.1 went and got the
# evidence instead of waiting for obsmem to mention a version, because "no issue
# names 1.0" is an absence of a statement, not a measurement.
#
# v1.10.0: 0.87.1 -> 1.0.0. MEASURED 2026-10-02 against the published npm
# v1.10.1: 0.87.1 -> 1.0.0. MEASURED 2026-10-02 against the published npm
# tarballs for 0.87.1 and 1.0.0, unpacked side by side:
# 1. NO `### Breaking Changes` SECTION IN 1.0.0 AT ALL. The changelog's
# breaking sections belong to 0.87.0, 0.86.0, 0.84.3, 0.84.0, 0.83.0,
@@ -273,7 +273,7 @@ ARG PI_ATELIER_REPO=https://github.com/michaelmjhhhh/pi-atelier.git
# pi >=0.84.0, so it still spans the pinned 0.85.1. 13 commits v0.10.1..v0.10.3,
# all under src/ tests/ docs/ scripts/ plus metadata; no entry-point move.
#
# v1.10.0: v0.10.3 -> v0.13.0, closing the two-minor gap v1.9.5 flagged as the
# v1.10.1: v0.10.3 -> v0.13.0, closing the two-minor gap v1.9.5 flagged as the
# residual risk of the pi bump. peerDependencies are UNCHANGED at pi >=0.84.0
# across v0.10.3, v0.12.1 and v0.13.0 — still a FLOOR, so still not evidence of
# anything; the floor is satisfied by 1.0.0 either way. What was actually
+1 -1
View File
@@ -358,7 +358,7 @@ DOT syntax errors instead of crashing. Then in Studio: open the PNG (or a
`.md` that embeds it) and hit **refresh-from-disk** after each edit.
Note: SVG is **not** in Studio's local-image-link allowlist — use PNG.
## Terminal UI mode: fullscreen is the default (since v1.10.0)
## Terminal UI mode: fullscreen is the default (since v1.10.1)
pi **1.0.0** changed the default terminal UI mode to **fullscreen**, and this
image adopts upstream's default rather than overriding it. Fullscreen draws into
+22 -6
View File
@@ -30,7 +30,7 @@
# client bundle present + registered via `pi install`
# - no foreign npm-11 platform packages (@esbuild, clipboard) beyond the host
# - no build-time npm cache (/root/.npm) shipped in the image
# - esbuild compiles + clipboard native loads at every install site
# - esbuild compiles everywhere; clipboard present iff pi declares it
# - image size within threshold
set -euo pipefail
@@ -986,11 +986,27 @@ run "no build-time npm cache shipped (/root/.npm)" \
run "esbuild works at every install site (prune removed weight, not function)" \
'sites=$(find /usr/lib/node_modules /opt -type d -path "*/node_modules/esbuild" -prune 2>/dev/null); if [ -z "$sites" ]; then echo "no esbuild install found at all" >&2; exit 1; fi; for d in $sites; do node -e "require(\"$d\").transformSync(\"const x:number=1\",{loader:\"ts\"})" || { echo "esbuild broken at $d" >&2; exit 1; }; done; echo ok'
# Clipboard is the family pruned second, and its napi-rs loader picks its native
# binding at require() time — so a successful load IS the proof that the kept
# platform package is the one this image needs.
run "clipboard native loads at every install site" \
'sites=$(find /usr/lib/node_modules /opt -type d -path "*/node_modules/@mariozechner/clipboard" -prune 2>/dev/null); if [ -z "$sites" ]; then echo "no @mariozechner/clipboard install found at all" >&2; exit 1; fi; for d in $sites; do node -e "var c=require(\"$d\"); if (typeof c.setText !== \"function\") { throw new Error(\"native binding missing\"); }" || { echo "clipboard native broken at $d" >&2; exit 1; }; done; echo ok'
# Clipboard is the family pruned second. Upstream pi 0.86.0 (#9163) REPLACED the
# external `@mariozechner/clipboard` dependency with bundled macOS/Windows/X11
# helpers plus the OSC 52 fallback, so from 0.86.0 on there is nothing external to
# prune and nothing to require(). pi 0.85.1 declared it; 0.87.1 and 1.0.0 do not.
# This assertion therefore derives its expectation from what the image's pi
# actually DECLARES rather than hardcoding either state: it re-arms by itself if a
# future pi re-adds the dependency, and it still fails if an install lingers that
# nothing depends on. Hardcoding "must exist" is what failed the v1.10.0 tag build
# (100 passed, 1 failed, nothing published) against a perfectly correct image.
run "clipboard native: present iff pi declares it (prune removed weight, not function)" \
'PKG=/usr/lib/node_modules/@earendil-works/pi-coding-agent/package.json;
if grep -q "\"@mariozechner/clipboard\"" "$PKG" 2>/dev/null; then declared=yes; else declared=no; fi;
sites=$(find /usr/lib/node_modules /opt -type d -path "*/node_modules/@mariozechner/clipboard" -prune 2>/dev/null);
if [ "$declared" = yes ]; then
[ -n "$sites" ] || { echo "pi declares @mariozechner/clipboard but NO install found - prune removed function" >&2; exit 1; };
for d in $sites; do node -e "var c=require(\"$d\"); if (typeof c.setText !== \"function\") { throw new Error(\"native binding missing\"); }" || { echo "clipboard native broken at $d" >&2; exit 1; }; done;
echo "ok: pi declares it and the native binding loads at every site";
else
[ -z "$sites" ] || { echo "pi no longer declares @mariozechner/clipboard yet installs remain: $sites" >&2; exit 1; };
echo "ok: pi bundles clipboard since upstream 0.86.0 (#9163); no external install expected";
fi'
# ── Image size ────────────────────────────────────────────────────────
echo ""