diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cbd9ff..354d46d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,139 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`). --- -## Unreleased +## v1.9.4 — 2026-09-22 + +### Dependency audit (2026-09-22) + +Every component checked against upstream by direct command, not assumed. "Baked" +is v1.9.3's published labels or, for the floating `*_VERSION=latest` tools, the +binaries in a running v1.9.3 container. The 13 GitHub-`latest` tools were +resolved through the same `/releases/latest` redirect the Dockerfile follows. + +| Component | Baked in v1.9.3 | Upstream now | Action | +|---|---|---|---| +| **pi** | `0.85.1` (pinned) | **`0.87.0`** (0.86.0, 0.86.1, 0.87.0 since) | **held — blocked by pi-observational-memory, see below** | +| **pi-atelier** | `v0.10.1` (`734258b`) | **`v0.10.3`** (`ed3837b`, released 2026-09-22) | **bumped** | +| **mempalace** | `3.9.0` (pinned) | **`3.10.0`** (changelog dated 2026-09-15) | **bumped, with one adaptation** | +| **mempalace-toolkit** | `817b3a8` | **`2167a1b`** | floating `main`; the commit is this release's own (below) | +| **pi-observational-memory** | `cba0334` (3.1.3) | **`e7d77dc`** (3.1.4) | adopted implicitly via `master` (below) | +| pi-toolkit | `9c87ee8` | `9c87ee8` | none | +| pi-extensions | `25c1265` | `25c1265` | none | +| pi-fork | `e69725c` | `e69725c` | none | +| pi-studio (studio variant) | `e04fc7a` | `e04fc7a` highest semver tag | none | +| skillset (mempalace fallback snapshot) | `e9e45f7` | skillset at `1c5f960`; `check-doc-drift.sh` rc=0 (snapshot still byte-identical) | none | +| gitea-mcp, agent-browser, node | `1.7.0`, `0.38.1`, `v24.21.0` | identical | none | +| 13 floating `*_VERSION=latest` tools | — | all 13 identical to the running v1.9.3 binaries | none | + +### mempalace 3.9.0 → 3.10.0, and why one `ENV` line comes with it + +v1.9.3 deferred 3.10.0 for two "Upgrade notes" items. Both were re-measured +against the 3.10.0 wheel rather than the changelog; one needed an adaptation, the +other turned out to be the other side's problem. + +**"New installs keep config and palace under `~/.config/mempalace`."** The +resolution order (`config.py`, `_default_config_dir`) is `$MEMPALACE_CONFIG_DIR`, +then `~/.mempalace` *if* it holds `config.json`, `people_map.json` or +`palace/chroma.sqlite3`, then XDG. An **empty** `~/.mempalace` fails that test — +and an empty `~/.mempalace` is exactly what a freshly mounted `devbox-palace` +volume looks like at first boot (and what `entrypoint.sh`'s `mkdir` leaves on a +volume-less container). Measured with a fresh `$HOME` and `uvx mempalace==3.10.0`: +`mempalace init` wrote `config.json` to `~/.config/mempalace`, `~/.mempalace` +stayed empty, and `entrypoint-user.sh`'s first-run test `[ ! -d ~/.mempalace/palace ]` +would have stayed true on every start. Same run with `MEMPALACE_CONFIG_DIR` set: +everything landed in `~/.mempalace`. + +So `Dockerfile.base` now sets `ENV MEMPALACE_CONFIG_DIR=/home/${USER_NAME}/.mempalace` +(in the non-root-user section, where `USER_NAME` is in scope), and +`entrypoint-user.sh` reads `PALACE_DIR` from the same variable with the old path +as fallback — the first-run test and mempalace's own resolution can no longer +disagree. Existing volumes were safe either way (`config.json` is a legacy +marker; this container's volume holds one); the `ENV` is for first boots. +`palace_path` still defaults to `/palace` and `MEMPALACE_PALACE_PATH` +is still honoured (`config.py:927`), so `smoke-test.sh`'s stage-path test keeps +its meaning, and `recreate-sanity-check.sh`'s hard-coded `~/.mempalace/palace/chroma.sqlite3` +stays correct. + +**"MCP event listing returns the newest events first when no cursor is given."** +This is **server-side**. The pi extension talks to the fleet hub over +`MEMPALACE_REMOTE_URL`, so `mempalace_event_list`'s default flips when *synlig* +upgrades, not when this image does. `mempalace-toolkit` `2167a1b` (this release) +makes every cursor-less `event_list` call in the extension say `order: "desc"` +explicitly — three of five did not — so the mailbox's `deriveOwed` and +`deriveClosed` read the same newest-N window against either server version. Its +selection was already order-independent (`isStrictlyAfter`); what the fix changes +is *which* events are in the window: on a 3.9.0 hub the cursor-less calls were +returning the **oldest** N, the latent truncation `deriveOwed` had already fixed +for two of its calls in toolkit `e2b060a` (2026-09-09). + +Also in the upgrade notes, neither reaching this image: `mempalace rules` dropped +`--agent` (zero callers in pi-devbox, mempalace-toolkit, skillset, myconfigs); +`get_collection()` refuses unknown collection names (library callers only). MCP +tool-schema review — the regression class this pin exists for: no tool removed or +renamed; additive fields on search results (`filed_at` / `content_date` +provenance), `limit`/`offset` on `kg_timeline`, `last_modified` on drawers. + +**Server state, measured over ssh on 2026-09-22:** synlig serves mempalace +**3.9.0** as a `uv tool` under `systemd` (`mempalace-serve.service`, python +3.12.13, chromadb 1.5.9) — *not* via `docker-compose.mempalace.yml`, which the +`Dockerfile.base` sequencing comment had claimed for two releases (corrected in +this commit). Client and server are level today; this image reintroduces skew +until synlig runs `uv tool upgrade mempalace` and restarts the unit. That is the +step that lights up the server-side changes above. Skew-relevant meanwhile: 3.10.0 +CLI writes follow the daemon write-routing policy (`direct`/`prefer`/`require`), +so the feeder (`mempalace-pi-session`, 3.10.0 client) against the 3.9.0 hub is +the one path to exercise on the built image before tagging — see *Still open*. + +### pi-atelier v0.10.1 → v0.10.3 (`734258b` → `ed3837b`) + +Fixes only per the release notes for v0.10.2 and v0.10.3 (both 2026-09-22): +sidebar text/borders preserved beside inline images (#53), transcript images +hidden while capturing overlays are open, Workspace Pulse skips redundant +HEAD/diff when nothing tracked changed (#61), sidebar height from row counts +(#59), git/usage scans suspended while disabled, Display Revert + Undo ordering. +Checked before bumping: `package.json` at v0.10.3 still declares zero runtime +dependencies and no build script (the no-`npm install` reasoning in +`Dockerfile.variant` holds), `peerDependencies` still `>=0.84.0` (spans the +pinned pi 0.85.1), 13 commits all under `src/ tests/ docs/ scripts/` plus +metadata, no entry-point move. Both tags are annotated: the SHA above is the +peeled commit, which is what `resolve-versions` bakes and what check 9 compares. + +### pi held at 0.85.1 (0.86.1 and 0.87.0 exist) + +Not an oversight. pi 0.87.0 *"Removed the inherited `shouldStopAfterTurn` agent +option. Use `finishTurn` and return `{ action: "end" }` instead"*, and 0.86.0 +moved provider stream inputs to `TranscriptContext` with the system prompt read +from `context.messages`. pi-observational-memory 3.1.4 still uses both the +removed option and `AgentContext.systemPrompt` in its observer, reflector and +dropper workers — measured in `src/agents/*/agent.ts` on both the baked 3.1.3 +tree and upstream `master`: `shouldStopAfterTurn` once per worker, `finishTurn` +zero. Its `peerDependencies` are `*`, so nothing at install time would refuse; +under 0.87 the workers would lose their turn caps and their specialised prompts +at runtime. Upstream tracks it as pi-observational-memory +[#82](https://github.com/elpapi42/pi-observational-memory/issues/82) with fix PR +[#83](https://github.com/elpapi42/pi-observational-memory/pull/83) — opened +2026-09-21, mergeable, **not merged** at this writing. Bump pi and pi-obsmem +together once #83 ships in a release. + +The other extensions were checked against the 0.86.0 and 0.87.0 breaking lists +and are clean: `ssh-controlmaster`'s `user_bash` handler already returns +`undefined | { operations }` (0.86.0's fail-closed contract), and its four +`registerTool` calls spread the built-in tools so they carry parameter schemas +(#9300). 0.86.1 as an intermediate was not tested — not worth the pty matrix for +a stop that #83 makes moot. + +### Still open + +- **Feeder against the 3.9.0 hub** — run `mempalace-pi-session` from the built + v1.9.4 image against synlig (dry-run first) before tagging. The palace-path + adaptation was measured with the wheel, not the image; the recreate acceptance + on the first device should confirm `~/.mempalace/palace/chroma.sqlite3` still + passes in `recreate-sanity-check.sh` and that `~/.config/mempalace` does not + appear. +- **synlig upgrade to 3.10.0** after v1.9.4 is accepted on one device: + `uv tool upgrade mempalace`, restart `mempalace-serve.service`, verify one + search and one `event_list`. +- **pi 0.87.x + pi-observational-memory ≥ 3.1.5** together, when #83 has shipped. ### pi-observational-memory 3.1.3 → 3.1.4 (`cba0334` → `e7d77dc`) diff --git a/Dockerfile.base b/Dockerfile.base index 87f19ed..bcefed0 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -14,7 +14,7 @@ # content-addressed over this file, so any byte change invalidates the # cache. Recommended cadence: once per release for security updates. # -# BASE_REBUILD_DATE: 2026-09-19 (v1.9.3 — mempalace-version label, mempalace-toolkit 817b3a8 mine deadline, pi-extensions skill floor 25c1265; the marker had been stale since 2026-07-13 through the v1.9.0 Node 24 and v1.9.2 npm-residue rebuilds, updated now because the base is rebuilding anyway) +# BASE_REBUILD_DATE: 2026-09-22 (v1.9.4 — mempalace 3.9.0 -> 3.10.0 with ENV MEMPALACE_CONFIG_DIR pinning the layout, mempalace-toolkit 2167a1b explicit event_list order; previous marker 2026-09-19 / v1.9.3) # # ── Lineage note ───────────────────────────────────────────────────── # Adapted from opencode-devbox/Dockerfile.base (commit before v1.16.2). @@ -532,14 +532,22 @@ ARG INSTALL_MEMPALACE=true # the part that should stay manual. # # Deployment sequencing note for whoever ships this bump: synlig (the shared -# central palace host) serves mempalace 3.8.0 SERVER-SIDE via -# docker-compose.mempalace.yml, which reuses this same devbox image. (Measured -# 2026-09-06 over ssh: synlig's UV_TOOL_DIR mempalace entry last changed -# 2026-08-25 15:33 — this comment previously said 3.7.1, which was stale.) -# Bumping this ARG changes only the CLIENT version baked into pi-devbox -# images: it introduces client/server skew until synlig's compose stack is -# separately rebuilt/redeployed with the new pin. Not something to code around -# here — just sequence the redeploy. +# central palace host) serves mempalace SERVER-SIDE as a `uv tool` install run +# by the systemd unit `mempalace-serve.service` (`python -m mempalace.mcp_server +# --transport http`), NOT via docker-compose.mempalace.yml — that compose file +# exists in this repo but is not what runs there. (Measured 2026-09-22 over +# ssh: `uv tool list` -> mempalace v3.9.0, python 3.12.13, chromadb 1.5.9; +# `docker ps` matched no palace container. This comment previously said the +# compose stack served 3.8.0, which was stale on both counts.) Bumping this ARG +# changes only the CLIENT version baked into pi-devbox images: it introduces +# client/server skew until synlig's tool is upgraded (`uv tool upgrade +# mempalace` + restart the unit). Not something to code around here — just +# sequence the upgrade. And note which side OWNS what: MCP tool semantics +# (event_list ordering, kg_timeline pagination, search result fields) come +# from the SERVER the extension talks to over MEMPALACE_REMOTE_URL, so they +# change when synlig upgrades; only the local CLI (`mempalace init` at first +# run, the mempalace-pi-session feeder) and the on-disk layout under +# ~/.mempalace change when THIS pin does. # # v1.8.13: 3.8.0 -> 3.9.0. Audited: no Breaking/Removed changelog headings. # Adopted mainly for #2281 (`mempalace_mine` accepts a single conversation @@ -551,7 +559,42 @@ ARG INSTALL_MEMPALACE=true # (release awareness, `task create`/`task launch` MCP tools) are SERVER-side, # so they stay dark until synlig is redeployed — a client bump alone cannot # light them up. -ARG MEMPALACE_VERSION=3.9.0 +# +# v1.9.4: 3.9.0 -> 3.10.0 (PyPI 2026-09-15). Deferred at v1.9.3 for two +# "Upgrade notes" items; both re-measured against the 3.10.0 wheel, one needed +# an adaptation: +# - "New installs keep config and palace under ~/.config/mempalace". The +# resolution order is $MEMPALACE_CONFIG_DIR, then ~/.mempalace IF it holds +# config.json / people_map.json / palace/chroma.sqlite3, then XDG. An +# EMPTY ~/.mempalace does not count — and an empty ~/.mempalace is exactly +# what a freshly mounted devbox-palace volume (or entrypoint.sh's mkdir on +# a volume-less container) looks like at first boot. Measured with a fresh +# $HOME: `mempalace init` wrote to ~/.config/mempalace, outside the +# persisted path, and entrypoint-user.sh's first-run test +# `[ ! -d ~/.mempalace/palace ]` would stay true on every start. With +# MEMPALACE_CONFIG_DIR set, everything landed in ~/.mempalace. Hence the +# ENV MEMPALACE_CONFIG_DIR below (in the non-root-user section, where +# ${USER_NAME} is in scope): first in the resolution order, so the +# heuristic never runs and the image's layout contract no longer depends +# on it. Existing volumes were safe either way (config.json is a legacy +# marker); the ENV is for first boots. palace_path still defaults to +# /palace and MEMPALACE_PALACE_PATH is still honoured (config.py +# :927), so scripts/smoke-test.sh's stage-path test keeps its meaning. +# - "MCP event listing returns the newest events first when no cursor is +# given". SERVER-side (see above), so it lands when synlig upgrades, not +# here. mempalace-toolkit 2167a1b made every cursor-less event_list call +# in the pi extension say `order: "desc"` explicitly, so the mailbox reads +# the same window against either server version. +# Also in the notes, neither reaching this image: `mempalace rules` dropped +# `--agent` (no caller in pi-devbox, mempalace-toolkit, skillset or myconfigs); +# `get_collection()` refuses unknown collection names (library callers only). +# MCP tool-schema review, as always: no tool removed or renamed; additive +# fields on search results (filed_at / content_date provenance), `limit` / +# `offset` on kg_timeline, `last_modified` on drawers. Skew-relevant while +# synlig stays on 3.9.0: CLI writes now follow the daemon write-routing policy +# (direct / prefer / require) — the feeder against a 3.9.0 hub is the one +# thing to exercise before tagging. +ARG MEMPALACE_VERSION=3.10.0 # Recorded as a label HERE, not in Dockerfile.variant, for three reasons: the # value lives next to the ARG that defines it (a second copy in the variant # would be one more pin able to drift, which is the class check-doc-drift.sh @@ -832,6 +875,18 @@ print('chromadb embedding model warmed: all-MiniLM-L6-v2')" && \ ENV NPM_CONFIG_PREFIX=/home/${USER_NAME}/.pi/npm-global ENV PATH="/home/${USER_NAME}/.pi/npm-global/bin:${PATH}" +# ── MemPalace config/palace root: pin it, do not let a heuristic pick it ── +# mempalace >= 3.10.0 resolves its config dir as $MEMPALACE_CONFIG_DIR, then +# ~/.mempalace ONLY if it already holds a config/palace, else ~/.config/mempalace +# (XDG). An empty ~/.mempalace — a fresh devbox-palace volume, or entrypoint.sh's +# mkdir on a volume-less container — fails that test, so a first boot would put +# the palace outside the persisted path and re-run first-run init forever. This +# ENV is first in the order, so the layout is what entrypoint.sh (mkdir), +# entrypoint-user.sh (first-run test), the feeder's /pi-stage and +# scripts/recreate-sanity-check.sh all already assume. Rationale and the +# measurement live with ARG MEMPALACE_VERSION above; keep the two in step. +ENV MEMPALACE_CONFIG_DIR=/home/${USER_NAME}/.mempalace + # ── Shell defaults (bash history, aliases, readline) ───────────────── RUN mkdir -p /etc/skel-devbox COPY rootfs/home/developer/.bash_aliases /etc/skel-devbox/.bash_aliases diff --git a/Dockerfile.variant b/Dockerfile.variant index 08492b1..fdc816c 100644 --- a/Dockerfile.variant +++ b/Dockerfile.variant @@ -113,6 +113,27 @@ ARG USER_NAME=developer # signature is ~5s of sustained CPU. Two-sided check: the atelier sidebar # painted ACTIVITY+WORKSPACE identically to the 0.84.4 control, so the test # could distinguish "loaded" from "silently absent". +# +# v1.9.4: HELD at 0.85.1 while 0.86.1 and 0.87.0 exist upstream. 0.87.0's +# changelog: "Removed the inherited `shouldStopAfterTurn` agent option. Use +# `finishTurn` and return `{ action: "end" }` instead" (no issue number on +# that line); 0.86.0 moved provider stream inputs to `TranscriptContext`, with +# system prompts read from `context.messages`. pi-observational-memory 3.1.4 +# (the `master` ref baked below) still uses both the old option and +# `AgentContext.systemPrompt` in its observer, reflector and dropper workers — +# measured 2026-09-22 in src/agents/*/agent.ts, both the baked 3.1.3 tree and +# upstream master 3.1.4: `shouldStopAfterTurn` 1 per worker (3), `finishTurn` +# 0, `systemPrompt` 1 per worker. Its peerDependencies are `*`, +# so nothing at install time would refuse; it would break at runtime (turn +# caps ignored, workers losing their specialised prompts). Upstream tracks it +# as pi-observational-memory #82 with fix PR #83 (opened 2026-09-21, mergeable, +# not merged at this writing). Bump pi and pi-obsmem TOGETHER once #83 has +# shipped in a release. The other extensions were checked against the 0.86.0 +# and 0.87.0 breaking lists and are clean: ssh-controlmaster's `user_bash` +# handler already returns `undefined | { operations }` (0.86.0 fail-closed +# contract) and its registerTool calls spread the built-in tools so they +# carry parameter schemas (#9300). 0.86.1 as an intermediate is untested and +# not worth the pty matrix for a stop that #83 will make moot. ARG PI_VERSION=0.85.1 ARG PI_TOOLKIT_REF=main ARG PI_EXTENSIONS_REF=main @@ -170,9 +191,20 @@ ARG PI_ATELIER_REPO=https://github.com/michaelmjhhhh/pi-atelier.git # old and new pin. Included because it was already exercised: the pty matrix # for PI_VERSION above ran atelier v0.10.1 against pi 0.85.1 and painted the # sidebar identically to v0.10.0. -ARG PI_ATELIER_REF=v0.10.1 +# +# v1.9.4: v0.10.1 -> v0.10.3 (both v0.10.2 and v0.10.3 released 2026-09-22). +# Fixes only per the release notes: sidebar text/borders preserved beside +# inline images (#53), transcript images hidden while capturing overlays are +# open, Workspace Pulse skips redundant HEAD/diff when nothing tracked changed +# (#61), sidebar height from row counts (#59), git/usage scans suspended while +# disabled, Display Revert + Undo ordering. Checked before bumping: package.json +# at v0.10.3 still declares zero runtime dependencies and no build script (so +# the no-`npm install` reasoning above holds) and peerDependencies are still +# 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. +ARG PI_ATELIER_REF=v0.10.3 # Human-readable tag PI_ATELIER_REF was resolved from; recorded as a label. -ARG PI_ATELIER_VERSION=v0.10.1 +ARG PI_ATELIER_VERSION=v0.10.3 RUN set -e && \ # git_fetch_ref: clone-equivalent helper that accepts EITHER a branch name diff --git a/README.md b/README.md index ba2b3bd..92de055 100644 --- a/README.md +++ b/README.md @@ -572,7 +572,13 @@ ChromaDB ONNX embedding model so first-time semantic search is instant. The palace data lives at `~/.mempalace/palace` on the host -(bind-mounted into the container). This means: +(bind-mounted into the container). The image pins that layout with +`ENV MEMPALACE_CONFIG_DIR=/home/developer/.mempalace` (`Dockerfile.base`): +mempalace ≥ 3.10.0 would otherwise treat an *empty* `~/.mempalace` — a freshly +mounted volume at first boot — as "no install here" and put a new palace under +`~/.config/mempalace`, outside anything the compose files persist. With the +variable set, first in mempalace's resolution order, the location is a contract +rather than a heuristic. This means: - A pi running on the host and a pi running inside this container see the same palace. @@ -1140,8 +1146,8 @@ resolved to `latest` at build time: | Component | Pin | Where | |---|---|---| | pi | `0.85.1` | `ARG PI_VERSION` — `Dockerfile.variant` | -| pi-atelier | `v0.10.1` | `ARG PI_ATELIER_REF` — `Dockerfile.variant` | -| mempalace | `3.9.0` | `ARG MEMPALACE_VERSION` — `Dockerfile.base` | +| pi-atelier | `v0.10.3` | `ARG PI_ATELIER_REF` — `Dockerfile.variant` | +| mempalace | `3.10.0` | `ARG MEMPALACE_VERSION` — `Dockerfile.base` | The objective is **not** to freeze versions. Bumping is routine — usually one line plus a changelog note. The objective is that adopting a new upstream diff --git a/entrypoint-user.sh b/entrypoint-user.sh index f7a38cf..e84c2e5 100755 --- a/entrypoint-user.sh +++ b/entrypoint-user.sh @@ -100,7 +100,14 @@ fi # existing data. `--yes` auto-accepts detected entities so the init is # non-interactive. if command -v mempalace &>/dev/null && [ -d /workspace ]; then - PALACE_DIR="${HOME}/.mempalace" + # Read the root from the same variable mempalace itself reads (set as an + # image ENV in Dockerfile.base since mempalace 3.10.0 started resolving + # ~/.config/mempalace for an EMPTY ~/.mempalace). The fallback keeps the + # historical location for anyone running this script with the ENV unset; + # the point of naming the variable here is that this test and mempalace's + # own resolution can no longer disagree about where the palace lives — a + # disagreement that would make this branch fire on every start. + PALACE_DIR="${MEMPALACE_CONFIG_DIR:-${HOME}/.mempalace}" if [ ! -d "$PALACE_DIR/palace" ]; then echo "Initializing MemPalace for workspace (non-interactive)..." #