v1.8.6: adopt pi 0.84.3 + mempalace 3.8.0, close the v1.8.5 doc/observability gaps
Lint / hadolint (push) Successful in 9s
Publish Docker Image / resolve-versions (push) Successful in 15s
Publish Docker Image / base-decide (push) Successful in 8s
Lint / actionlint (push) Successful in 1m9s
Publish Docker Image / build-base (push) Successful in 41m23s
Publish Docker Image / smoke (push) Successful in 4m50s
Publish Docker Image / smoke-studio (push) Successful in 5m5s
Publish Docker Image / build-variant (push) Successful in 15m46s
Publish Docker Image / update-description (push) Successful in 7s
Publish Docker Image / promote-base-latest (push) Successful in 15s
Publish Docker Image / build-variant-studio (push) Successful in 19m59s

Three coupled pieces of work, all of which ride on the base rebuild that the
mempalace bump forces anyway.

DRIFT ADOPTED
- pi 0.84.2 -> 0.84.3. Its release notes carry a "Breaking Changes" line
  (GoogleThinkingLevel -> GoogleApiThinkingLevel). Audited before adopting:
  zero references across all four vendored companions (pi-fork,
  pi-observational-memory, pi-atelier, pi-studio), so it is inert for us. The
  reason to adopt is two skill-discovery fixes that land directly on v1.8.5's
  vendored-skill work: nested Markdown skills inside grouping directories were
  not discovered, and root README.md/AGENTS.md in skill dirs were reported as
  broken skills.
- mempalace core 3.7.1 -> 3.8.0. Additive/reliability only. Its sync fix
  (#2320/#2322) stops sync --apply deleting drawers whose source_file was
  unreachable *at that moment* -- which does NOT relax the standing landmine
  against sync on the shared palace, because that landmine is about paths
  permanently absent from whichever host runs the sync. Different failure
  shape; the caution stands.

DOCS -- three defects, one of them public
- DOCKER_HUB.md advertised "neovim (LazyVim defaults)". Nothing in the image
  installs LazyVim; the only nvim config is a 19-line sysinit.vim. CI PATCHes
  this file into the Docker Hub description on every release, so this was a
  false claim published to the world. Removed.
- agent-browser + Playwright + Chromium is the single largest addition in the
  image (~625 MB) and had zero mentions in README, DOCKER_HUB or THIRD_PARTY --
  it was documented only to agents, in the AGENTS.md managed block. Now
  documented to humans, including the Chromium licence dimension.
- typst and socat appeared in README prose but not in the "What's inside"
  inventory. Added.

OBSERVABILITY -- the three gaps v1.8.5 listed as still open
- build-manifest.json now records mempalace core, read from the live binary
  (ground truth, not the build ARG). Placed as a sibling of pi_version rather
  than inside components{}, because pi-devbox-version renders that map through
  [0:12] and would truncate a version string.
- smoke asserts the pi-observational-memory clone actually CONTAINS the ce9fc98
  auth fix, pinned to src/runtime.ts. Deliberately not a repo-wide grep: two of
  the three markers also live under tests/, so the repo-wide form stays green
  with the fix site reverted. That is the third false-green of this exact family
  in this repo (canary phrase in both snapshots; reconciler fixture using a
  non-owned name; now this) -- pin containment checks to the fix site.
- smoke asserts the feeder's pi@<device> agent default behaviourally. The
  earlier audit concluded this needed a --print-config added upstream; it does
  not. AGENT is assigned before arg parsing, so `bash -x mempalace-pi-session
  --help` observes the real resolution with no toolkit change. Two-sided:
  device set => pi@<device>, unset => must not be pi@*.
- pi-devbox-version now prints a palace: line with the same live-vs-baked drift
  detection pi already had. This matters more than it looks: mempalace is the
  one component that is both client (here) and server (synlig), so skew between
  them is a real failure mode. Degrades quietly on pre-v1.8.6 images.

Deferred deliberately: a native arm64 act_runner on tor-ms22 (the current
runner is on synlig, x86_64, so every arm64 layer ships QEMU-emulated).
Analysis and caveats filed to the palace rather than actioned here.
This commit is contained in:
2026-08-25 15:29:22 +02:00
parent 26f223568d
commit 93f986e90e
8 changed files with 369 additions and 6 deletions
+61
View File
@@ -151,6 +151,33 @@ run "pi stage follows MEMPALACE_PALACE_PATH" '
mempalace-pi-session --dry-run --reason smoke --sessions-dir "$(mktemp -d)" 2>&1) || true
echo "$out" | grep -q "stage=/tmp/alt/.mempalace/pi-stage/"
'
# The feeder's --agent default is WHO a drawer is attributed to. mempalace core
# records neither the machine nor the harness on a write, and one shared bearer
# token means the server cannot tell clients apart, so toolkit c64ffa1 changed
# this default from $USER to pi@$MEMPALACE_PI_DEVICE — the one string that makes
# a write attributable to both. Nothing ever PRINTED the resolved value (the
# banner shows mode= and stage= only), so an image built from a pre-c64ffa1
# toolkit ref would ship unattributed writes with every check still green.
#
# `--help` assigns AGENT (script top) before it parses args, then exits 0 with
# no side effects — so `bash -x` observes the REAL resolution, env interpolation
# and fallback included, rather than grepping the source for a literal line that
# any reformat would break. Two-sided on purpose: device set => pi@<device>;
# device UNSET => must not be pi@anything. The second half is what fails against
# the old unconditional $USER default, which ignored the device entirely.
#
# Probes the PATH entry (a symlink into the /opt clone) rather than that clone
# path directly: this is the invocation the systemd/launchd timers and
# entrypoint-user.sh actually use, so it is the default that reaches the palace.
run "feeder resolves --agent to pi@<device> (drawer attribution)" '
f=$(command -v mempalace-pi-session) || { echo "feeder not on PATH" >&2; exit 1; }
with=$(MEMPALACE_PI_DEVICE=smoke-device bash -x $f --help 2>&1 | sed -n "s/^+* *AGENT=//p" | tail -n1)
without=$(env -u MEMPALACE_PI_DEVICE bash -x $f --help 2>&1 | sed -n "s/^+* *AGENT=//p" | tail -n1)
echo "resolved with-device=[$with] without-device=[$without]" >&2
[ "$with" = "pi@smoke-device" ] || exit 1
case "$without" in pi@*) exit 1 ;; esac
echo ok
'
# Regression guard for the pi transcript exporter. If pi ever changes its
# session JSONL shape, the exporter stops recognising sessions and the palace
# silently gets nothing (or, worse, raw JSON chunked as prose). Feed it a
@@ -263,6 +290,26 @@ run "pi-fork clone + node_modules" \
"test -f /opt/pi-fork/package.json && test -d /opt/pi-fork/node_modules"
run "pi-observational-memory clone + node_modules" \
"test -f /opt/pi-observational-memory/package.json && test -d /opt/pi-observational-memory/node_modules"
# ...and that the clone carries the AUTH FIX, not merely that it exists. om's
# pre-flight hasUsableAuth() check silently disabled `recall` for ~8 weeks once
# pi moved to request-time SigV4 signing and stopped exposing a static Bedrock
# key; upstream fixed it in ce9fc98, adopted in v1.8.4. PI_OBSMEM_REF tracks
# master, so an upstream revert or force-push would ship a dead `recall` with
# the clone assertion above still green — the exact gap flagged as open in the
# v1.8.5 changelog.
#
# Pin the markers to src/runtime.ts, the fix SITE, rather than grepping the
# repo: two of these three strings also appear under tests/, so a repo-wide
# grep stays green with runtime.ts itself reverted. That is a false green of the
# same family as the old skill-snapshot canary.
run "pi-observational-memory carries the ce9fc98 auth fix (recall stays alive)" '
f=/opt/pi-observational-memory/src/runtime.ts
test -f "$f" || { echo "fix site missing: $f" >&2; exit 1; }
for m in availability_recheck providerCredentialConfigured hasConfiguredAuth; do
grep -q "$m" "$f" || { echo "marker absent from runtime.ts: $m" >&2; exit 1; }
done
echo ok
'
# pi-atelier: deliberately NO node_modules assertion, unlike its siblings —
# it declares zero runtime dependencies (only peerDeps, satisfied by the baked
# pi) and has no build step, so Dockerfile.variant skips `npm install` for it.
@@ -307,6 +354,20 @@ run_expect "manifest records pi-atelier" \
"cat /etc/pi-devbox/build-manifest.json" '"pi-atelier"'
run_expect "manifest records pi_version" \
"cat /etc/pi-devbox/build-manifest.json" '"pi_version"'
# mempalace CORE was absent from the manifest through v1.8.5: the toolkit SHA
# was recorded but the palace version behind the MCP tools was not, so a palace
# bug could not be correlated to an image version. Assert the field exists AND
# equals the installed binary — recording it from ARG MEMPALACE_VERSION instead
# would look identical here yet drift silently the first time an install
# resolved to something other than the pin, which is the whole reason this file
# is built from ground truth. `// empty` matters: jq -r prints the 4-char
# string "null" for a JSON null, which would satisfy a naive -n test.
run "manifest mempalace_version matches the installed core" '
m=$(jq -r ".mempalace_version // empty" /etc/pi-devbox/build-manifest.json)
b=$(mempalace --version 2>/dev/null | head -n1 | tr -d "\r"); b=${b##* }
echo "manifest=[$m] installed=[$b]" >&2
[ -n "$m" ] && [ "$m" = "$b" ]
'
# Every component must be a resolved commit (or null for pi-studio in the
# non-studio variant) — 'unknown' means a clone silently failed to resolve.
run "manifest has no unresolved ('unknown') components" \