release: audited bumps (pi 0.85.1, mempalace 3.9.0, atelier v0.10.1) + two guards
Version audit for the next release. pi 0.84.4 -> 0.85.1, deliberately skipping 0.85.0 (it published internal experimental code and broke SDK imports, upstream #9132). mempalace 3.8.0 -> 3.9.0. pi-atelier v0.10.0 -> v0.10.1. PI_STUDIO_VERSION relabelled none -> v0.9.60-rc.0 so the floating main ref's RC status is visible at docker-inspect time instead of discovered later. PI_FORK_REF stays floating and adopts e69725c. The pi bump was verified by running it under a pty in five combinations rather than by reading the changelog, because this repo has already shipped a version pair no changelog flagged (atelier < 0.7.1 hangs pi >= 0.84). CPU delta 0.00-0.01s over 5s against a ~5s sustained-CPU hang signature, two-sided via the atelier sidebar painting identically to the 0.84.4 control. NODE_VERSION stays 22 on purpose: node 24 is technically safe (pi's five prebuilt addons are all NAPI, nothing declares a ceiling, agent-browser's engines.node >=24 is vestigial for the shipped aarch64 ELF), but this release already moves two minors and bakes an RC, and a node major would leave four suspects if the image misbehaves. Own release, smoke suite as the gate. Also corrects a stale claim at the mempalace ARG: synlig serves 3.8.0 server-side, not 3.7.1 (measured over ssh 2026-09-06). agent-browser volume shadowing: the image has shipped 0.35.2, but every session on mbp-m1-2020 ran 0.27.0 from a 2026-07-17 hand-install in ~/.pi/npm-global (a VOLUME, at PATH position 2 vs /usr/bin at 8). Third package hit by this hazard after pi and pi-atelier, so the guard is now generalised: entrypoint-user.sh retires the copy by moving it aside (reversible, only when the image ships its own), recreate-sanity-check.sh asserts resolution under /usr where the volume is real, smoke-test.sh carries the build-time half and says in the source why it is weak. The real damage was the stale BUNDLED SKILL (3 skillsets/17.6 KB vs 8/31.5 KB, ten subcommands undocumented to the agent) - a stale tool errors, a stale skill quietly teaches wrong commands. pi-fork capability floor (extensions: []): forks were measured across four dispatches ignoring their brief, answering in the user's voice, fabricating self-referential measurements, and once filing a diary entry as agent_name=pi. Cause is upstream by design - the child gets getHeader()+getBranch(), the whole active session branch, with the brief as the final user message. Not a model-capability problem: the same model as the fast profile obeyed the identical brief perfectly with a fresh session and no inherited context. extensions: [] runs children with --no-extensions, so the mempalace bridge is absent and palace writes are impossible by construction (verified by asking a child to enumerate its tools: read, bash, edit, write). Removes palace writes, not filesystem writes.
This commit is contained in:
@@ -718,6 +718,34 @@ exec_test "pi-atelier registered in packages[] (TUI sidebar)" \
|
||||
exec_test "pi-atelier registered from /opt, not npm: (volume-shadowing guard)" \
|
||||
'jq -e "((.packages // []) | any((type == \"string\") and endswith(\"/pi-atelier\"))) and (((.packages // []) | any(. == \"npm:pi-atelier\")) | not)" $HOME/.pi/agent/settings.json'
|
||||
|
||||
# agent-browser: the third package hit by ~/.pi/npm-global volume shadowing
|
||||
# (after pi itself and pi-atelier). This build-time check is deliberately WEAK
|
||||
# and says so: a `docker run` container has an EMPTY config volume, so it can
|
||||
# only prove the image ships a sane copy and nothing in the image itself
|
||||
# shadows it. The check that actually bites lives in
|
||||
# recreate-sanity-check.sh, which runs where the volume is real — that is
|
||||
# where a 7-week-old 0.27.0 was caught shadowing 0.35.2 on 2026-09-06.
|
||||
exec_test "agent-browser resolves under /usr (volume-shadowing guard, build-time half)" '
|
||||
p=$(command -v agent-browser) || { echo "agent-browser not on PATH" >&2; exit 1; }
|
||||
r=$(readlink -f "$p")
|
||||
echo "resolved=[$r] version=[$(agent-browser --version 2>/dev/null | head -n1)]" >&2
|
||||
case "$r" in /usr/*) ;; *) exit 1 ;; esac
|
||||
test ! -d "$HOME/.pi/npm-global/lib/node_modules/agent-browser" || exit 1
|
||||
echo ok
|
||||
'
|
||||
|
||||
# pi-fork capability floor. `extensions: []` makes a fork child run with
|
||||
# --no-extensions, which is the only MECHANICAL guarantee that a fork cannot
|
||||
# file drawers or diary entries under the parent's identity — the mempalace
|
||||
# bridge is an extension, so removing extensions removes the write path.
|
||||
# Asserted because it is a security-shaped default that a settings merge or a
|
||||
# hand-edit could silently drop, and its absence is invisible until a fork
|
||||
# writes to the shared palace as you (measured twice: 2026-09-01, 2026-09-06).
|
||||
# Deliberately compares to [] and not "is falsy": null means "load normal
|
||||
# extensions", i.e. exactly the unguarded state this asserts against.
|
||||
exec_test "pi-fork extensions floor is [] (forks cannot write to the palace)" \
|
||||
'jq -e ".[\"pi-fork\"].extensions == []" $HOME/.pi/agent/settings.json'
|
||||
|
||||
# ── /tmp/sshcm directory created by entrypoint ────────────────────────
|
||||
exec_test "/tmp/sshcm dir mode 700 (ssh ControlMaster)" \
|
||||
'test -d /tmp/sshcm && [ "$(stat -c %a /tmp/sshcm)" = "700" ] && echo ok'
|
||||
|
||||
Reference in New Issue
Block a user