mempalace: drop the stage ENV pin, fix the shared-server compose
Lint / actionlint (push) Successful in 21s
Lint / hadolint (push) Successful in 29s

The feeder now defaults to <palace-root>/pi-stage upstream, so pinning
MEMPALACE_PI_STAGE into ~/.pi here is unnecessary -- and was actively wrong. It
created a second convention that could still diverge from the palace: keep the
devbox-palace volume, drop devbox-pi-config, and a scoped `mempalace sync`
prunes every conversation drawer, because dedup keys on the staged path. Both
the ENV and the entrypoint export are gone; a comment explains why adding one
back re-introduces the split it was meant to fix.

docker-compose.mempalace.yml was broken on mempalace 3.6.0 in both directions:
  - `--host 0.0.0.0` with no token in the environment makes the server refuse
    to start, crash-looping under `restart: unless-stopped`.
  - Supply a token and the healthcheck's unauthenticated `tools/list` POST 401s,
    marking a perfectly healthy server unhealthy forever.
Now the token is required via ${MEMPALACE_REMOTE_TOKEN:?...} so it fails fast at
`docker compose up` with a readable message, and the healthcheck probes the
deliberately token-free /healthz. The "no authentication of its own" security
note has been stale since 3.6.0 and is replaced with the actual posture
(bearer token + Host pin + Origin allowlist), including why browser-shaped auth
must not be put in front of it.

Dockerfile.base: mempalace-pi-session symlinked onto PATH, with a build-time
`--help` check so a broken feeder fails the image build rather than the first
session.

smoke-test: assert the stage resolves beside the palace (default, and following
$MEMPALACE_PALACE_PATH) instead of asserting the removed ENV pin. The two
behavioural guards -- a synthetic session that must be captured, an abandoned
one that must not be -- are unchanged.

.env.example: recommend `mempalace serve` on the docker0 gateway rather than
`mempalace-mcp --transport http --host 0.0.0.0`, with the two binds to avoid.
This commit is contained in:
Joakim Persson
2026-08-12 17:04:14 +02:00
parent 7649d53f3b
commit 7c00dd6001
6 changed files with 265 additions and 13 deletions
+53
View File
@@ -91,6 +91,59 @@ run "terminfo: modern emulators (ncurses-term)" 'for t in wezterm alacritty foot
run "terminfo: xterm-ghostty alias (tic)" "infocmp -x xterm-ghostty >/dev/null 2>&1"
run "nvim true-colour default (sysinit.vim)" "nvim --headless -c 'lua os.exit(vim.o.termguicolors and 0 or 1)'"
run "mempalace-mcp" "mempalace-mcp --help"
run "mempalace-pi-session on PATH" "mempalace-pi-session --help"
# The staging dir must sit next to the palace, not in a disposable cache: the
# palace keys per-source dedup on the STAGED path, so a stage that can be wiped
# while the palace survives lets `mempalace sync` prune every drawer mined from
# it. Assert the resolved default, not an env var — the guarantee is "stage
# shares the palace's lifetime", which an ENV pin would quietly break.
# NOTE: --sessions-dir gets an EMPTY temp dir, never /tmp. The stage banner is
# printed before any export, so nothing needs to be found — and pointing a
# default-staged run at a populated dir would export whatever transcripts it
# finds into the real stage, which is how a synthetic test session ends up
# staged for mining as if it were a real conversation.
run "pi stage defaults next to the palace (not a cache dir)" '
out=$(mempalace-pi-session --dry-run --reason smoke --sessions-dir "$(mktemp -d)" 2>&1) || true
echo "$out" | grep -q "stage=/home/developer/.mempalace/pi-stage/"
'
run "pi stage follows MEMPALACE_PALACE_PATH" '
out=$(MEMPALACE_PALACE_PATH=/tmp/alt/.mempalace/palace \
mempalace-pi-session --dry-run --reason smoke --sessions-dir "$(mktemp -d)" 2>&1) || true
echo "$out" | grep -q "stage=/tmp/alt/.mempalace/pi-stage/"
'
# 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
# synthetic session and assert it is actually exported. Uses --dry-run so no
# palace is touched, and a temp stage so nothing real is written.
run "pi transcript exporter recognises a pi session" '
set -e
d=$(mktemp -d); s="$d/sessions/--workspace--"; mkdir -p "$s"
{
printf "%s\n" "{\"type\":\"session\",\"version\":1,\"id\":\"smoke\",\"cwd\":\"/workspace\",\"timestamp\":\"2026-01-01T00:00:00Z\"}"
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"user\",\"content\":\"question one\"}}"
a=$(printf "a%.0s" $(seq 1 1200))
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"$a\"}]}}"
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"user\",\"content\":\"question two\"}}"
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"short reply\"}]}}"
} > "$s/2026-01-01T00-00-00-000Z_smoke.jsonl"
out=$(mempalace-pi-session --dry-run --sessions-dir "$d/sessions" --stage "$d/stage" 2>&1)
echo "$out" | grep -q "Exported 1 session"
'
# The same guard from the other side: a session with no real assistant output
# (an abandoned prompt, whose bulk is injected skill text) must NOT be filed.
run "pi transcript exporter rejects an abandoned session" '
set -e
d=$(mktemp -d); s="$d/sessions/--workspace--"; mkdir -p "$s"
{
printf "%s\n" "{\"type\":\"session\",\"version\":1,\"id\":\"smoke2\",\"cwd\":\"/workspace\",\"timestamp\":\"2026-01-01T00:00:00Z\"}"
u=$(printf "u%.0s" $(seq 1 13000))
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"user\",\"content\":\"$u\"}}"
printf "%s\n" "{\"type\":\"message\",\"message\":{\"role\":\"assistant\",\"content\":[{\"type\":\"text\",\"text\":\"Ready. What would you like to work on?\"}]}}"
} > "$s/2026-01-01T00-00-00-000Z_smoke2.jsonl"
out=$(mempalace-pi-session --dry-run --sessions-dir "$d/sessions" --stage "$d/stage" 2>&1)
echo "$out" | grep -q "no sessions qualified"
'
# v1.0.0 base additions — verify presence and basic functionality.
run "pandoc" "pandoc --version"
run "typst" "typst --version"