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:
+108
@@ -13,6 +13,114 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
||||
|
||||
## Unreleased
|
||||
|
||||
**Version audit + three pins moved, one deliberately not moved.** `pi`
|
||||
0.84.4 -> 0.85.1, `mempalace` 3.8.0 -> 3.9.0, `pi-atelier` v0.10.0 -> v0.10.1,
|
||||
and `PI_STUDIO_VERSION` relabelled `none` -> `v0.9.60-rc.0` to record what the
|
||||
floating `main` ref actually resolves to. `PI_FORK_REF=master` stays floating
|
||||
and therefore adopts e69725c. Each rationale is written at the ARG itself
|
||||
rather than only here, because that is where the next person doing the audit
|
||||
will be standing.
|
||||
|
||||
0.85.0 is SKIPPED on purpose: it shipped internal experimental code and extra
|
||||
subpaths that broke SDK imports (upstream #9132), and 0.85.1 exists to undo
|
||||
exactly that. Neither release has a Breaking/Removed changelog heading, the
|
||||
engine floor is unchanged (>=22.19.0 against the container's 22.23.2), and
|
||||
runtime deps drop 20 -> 19.
|
||||
|
||||
The pi bump was verified by RUNNING it, not by reading about it, because this
|
||||
repo has already been burned by a version pair that no changelog flagged
|
||||
(pi-atelier < 0.7.1 hangs pi >= 0.84 at startup with no error). 0.85.1 was
|
||||
side-installed and driven under a pty in five combinations — each companion
|
||||
extension plus atelier v0.10.0 AND v0.10.1 — with a CPU delta of 0.00-0.01s
|
||||
over a 5s window where the known hang signature is ~5s of sustained CPU. The
|
||||
check was two-sided: the atelier sidebar painted ACTIVITY+WORKSPACE markers
|
||||
identically to the 0.84.4 control, so "alive" could be distinguished from
|
||||
"silently absent".
|
||||
|
||||
**NODE_VERSION stays 22 — audited, not overlooked.** node 24 is technically
|
||||
safe: all five prebuilt native addons in pi use NAPI (ABI-stable, no
|
||||
NODE_MODULE_VERSION lock, no binding.gyp), nothing in the image declares a node
|
||||
CEILING, and the install is one token (`setup_${NODE_VERSION}.x`). agent-browser
|
||||
0.36.0 declares `engines.node >=24`, but that field is vestigial for the
|
||||
artifact actually shipped: the image's own 0.35.2 declares the same floor and
|
||||
runs fine on 22.23.2 as a prebuilt aarch64 ELF. The reason to wait is
|
||||
attribution, not compatibility — this release already moves pi a minor,
|
||||
mempalace a minor and bakes a Studio RC, so adding a node major would leave four
|
||||
suspects if the image misbehaves. Worth doing as its own release with the smoke
|
||||
suite as the gate. (v22 is in maintenance until 2027-04-30; v24 is Active LTS
|
||||
to 2026-10-20 and maintained to 2028-04-30, so there is real headroom.)
|
||||
|
||||
mempalace's client bump carries a sequencing note that is now also CORRECT: the
|
||||
comment at the ARG claimed synlig serves 3.7.1 server-side, which was stale.
|
||||
Measured 2026-09-06 over ssh, synlig's uv tool entry last changed 2026-08-25
|
||||
and serves 3.8.0. Client 3.9.0 against server 3.8.0 is accepted skew until
|
||||
synlig's compose stack is redeployed; 3.9.0's headline additions (release
|
||||
awareness, `task create`/`task launch`) are SERVER-side and stay dark until
|
||||
then — a client bump alone cannot light them up.
|
||||
|
||||
**agent-browser was running 7 weeks stale, and the interesting part is why
|
||||
nothing noticed.** The image has shipped 0.35.2 since the last base rebuild,
|
||||
but every session on mbp-m1-2020 was executing 0.27.0 from a 2026-07-17
|
||||
hand-install: `npm i -g` writes into `~/.pi/npm-global`, which is the
|
||||
devbox-pi-config VOLUME, and PATH puts that at position 2 against /usr/bin at
|
||||
position 8. This is the third package hit by that exact hazard (pi itself and
|
||||
pi-atelier already have guards), so the guard is now generalised instead of
|
||||
re-invented a fourth time.
|
||||
|
||||
The damage was not the binary. It was the BUNDLED SKILL, which is the part an
|
||||
agent reads: 3 skillsets / 17.6 KB core in 0.27.0 versus 8 skillsets / 31.5 KB
|
||||
core in 0.35.2, with ten subcommands present in the image and entirely
|
||||
undocumented to the agent (a11y, browser, data, mcp, page, plugin, read,
|
||||
selectors, to, webmcp). A stale tool announces itself with an error; a stale
|
||||
skill just quietly teaches the wrong commands and everything looks fine.
|
||||
|
||||
Three changes, at the three places this can be caught:
|
||||
- `entrypoint-user.sh` retires a volume copy by MOVING it aside (reversible,
|
||||
same instinct as the settings backups) and only when the image ships its own
|
||||
copy, so a machine that deliberately hand-installs on an image without one
|
||||
keeps it. The `bin/` shim is removed too — a dangling symlink would be a
|
||||
worse failure than a stale version.
|
||||
- `scripts/recreate-sanity-check.sh` asserts `agent-browser` resolves under
|
||||
/usr. This is the check that matters, because it runs where the volume is
|
||||
real.
|
||||
- `scripts/smoke-test.sh` gets the build-time half, labelled WEAK in the source
|
||||
for an honest reason: a `docker run` container has an empty config volume, so
|
||||
it can never see the shadowing it is nominally testing for.
|
||||
|
||||
**pi-fork gets a capability floor: `extensions: []`.** Forks were measured
|
||||
twice (2026-09-01, 2026-09-06, 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` — which landed in `wing_pi`, where a
|
||||
wing-scoped `diary_read` never sees it.
|
||||
|
||||
The cause is upstream and by design, so there is nothing to wait for: the child
|
||||
is handed `getHeader()+getBranch()`, i.e. the WHOLE active session branch, with
|
||||
the brief appended as the final user message and the system prompt untouched
|
||||
(pi-fork `src/index.ts`). In a long session the parent narrative simply
|
||||
outweighs the task, and the child does the statistically obvious thing — it
|
||||
continues the story it finds itself inside. Config offers no context knob
|
||||
(extensions, environment, offline, costFooter, effort profiles only).
|
||||
|
||||
Falsified the tempting explanation before acting on it: the failures are NOT a
|
||||
too-small model. The same model as the `fast` profile (haiku, thinking off)
|
||||
obeyed the identical brief perfectly when run as
|
||||
`pi -p --mode json --session-id <fresh> --no-extensions` — correct values,
|
||||
exact format, no session recap, 3 seconds, $0.012. Model held constant, context
|
||||
inheritance removed, failure gone.
|
||||
|
||||
`extensions: []` is therefore a mechanical guarantee rather than an
|
||||
instruction: the mempalace bridge is a pi EXTENSION, so a fork child now runs
|
||||
with `--no-extensions` and cannot write to the shared palace under the parent's
|
||||
identity. Verified by asking a child to enumerate its own tools: `read, bash,
|
||||
edit, write` — no `mempalace_*`, no `recall`, no nested `fork`. Two honest
|
||||
limits, stated so nobody over-trusts this: it removes PALACE writes, not
|
||||
FILESYSTEM writes (`edit`/`write` remain), and it costs forks their palace
|
||||
search and recall. Set the key to `null` to restore normal loading.
|
||||
|
||||
Smoke asserts the floor is `[]` specifically, not merely falsy — `null` is the
|
||||
unguarded state, so a "truthy or not" test would pass on exactly the
|
||||
configuration being guarded against.
|
||||
|
||||
**`credential-incident-response` §5/§6 corrected — a stated mechanism was wrong,
|
||||
and this is the second time in three days this section named a wrong reason
|
||||
for a zero.** Docs only.
|
||||
|
||||
Reference in New Issue
Block a user