From d9a7fe101bf106c3954f03368ddea26be10a3760 Mon Sep 17 00:00:00 2001 From: Joakim Persson Date: Sun, 30 Aug 2026 00:52:36 +0200 Subject: [PATCH] changelog: an Unreleased section for a rule that was already there MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the two skill commits ahead of tomorrow's build, and states the finding that shaped them: the "a negative result is usually your own filter" rule was already baked, already symlinked in at every container start, and already survived every recreate — then was violated five times by a session that had it available. The gap was activation, not persistence, which is why the cross-cutting form went into the always-appended AGENTS block instead of into a skill that only loads when a task description matches. Also notes what the entry's own subject implies for the reader: neither change reaches a running container until the image is rebuilt AND the container recreated, since ~/.agents/skills and the global AGENTS.md both live in the image rather than in a volume or a mount. --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b1a32..4f16bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,74 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`). --- +## Unreleased + +**Two vendored skills changed, and one of the changes is a correction rather than +an addition.** Nothing about the image's behaviour moves; this is entirely about +what the next agent reads before it acts. + +**`pi-devbox-environment` §2 had a rule that was half wrong, and the wrong half +cost five findings in one session.** The section "A negative result is usually +your own filter" closed with *"a positive result needs no such scepticism — it +carries its own evidence."* That sentence is false. A positive result is evidence +about the question your command *actually posed*, which may not be the question +you meant — and the failure is invisible precisely because the command succeeded. +Three measured instances, all from 2026-08-29, all filed as fact before being +caught: an SSH handshake that succeeded and greeted the agent as `joakimp` while +it believed it was probing `gitea.egl.lan` (a `Host gitea*` block had rewritten +`HostName`, so it authenticated to the wrong Gitea instance); a `401` that was a +genuine answer from an issuer which had never minted the credential being tested; +and a "regression" produced by diffing `ssh -G` output against a `2222` that the +agent's own earlier `-p 2222` flag had supplied. The section now carries a +counterpart, *"…and a positive result only proves what you actually asked"*, plus +the three false-negative rows that session added (a palace scan that queried +`embedding_metadata` while documents live in `embedding_fulltext_search_content`; +a token declared dead on a 401 from the wrong issuer; a host declared unreachable +after trying two of its three open ports, with the port written in an environment +variable the agent already held). + +**The cross-cutting form of that rule went into `pi-global-AGENTS.append.md`, not +into the skill — deliberately, and this is the whole point of the change.** The +rule *already existed* in the baked skill, authored by an earlier session, +symlinked into `~/.agents/skills/` at every container start. It survived every +recreate, was available for the entire session that broke it, and was violated +five times anyway. So the gap was never persistence; it was **activation**. +A reasoning rule that only loads when a task description happens to match it +cannot fire on the occasions that need it, because "I am about to state something +false" is not a recognisable task type. The always-appended block is read by every +agent in every container without being asked for, which is the only property that +matters here. Writing a sixth document restating the rule would have felt like +progress and changed nothing. + +**New baked skill: `credential-incident-response`.** Authored here, so the baked +copy is canonical and it is *not* listed in `skillset-owned.txt`. It carries the +*facts* a two-day credential incident produced, on the theory that facts transfer +between sessions where exhortations do not: probe the issuing provider **first** +(11 of 13 "exposed" credentials in that sweep turned out to be already dead at the +provider — five HTTP requests would have established it, and nobody asked); +`sha256[:8]` fingerprints as leak-free credential identity; the `403`-vs-`401` +trap that scoped tokens introduce into liveness probes, where a live token looks +revoked on `/api/v1/user`; **revocation beats deletion** for anything already +replicated, because deletion is best-effort over an unbounded copy set (FTS shadow +rows, per-host feed inboxes, sqlite free pages, mesh replicas, backups) while +revocation invalidates copies nobody enumerated; the three places a secret hides +in a Chroma palace, in coverage order; deriving least-privilege scopes from +*measured* consumers; and the exposures rotation does not fix (cleartext channels, +git history, agent-authored drawers). + +**Three smoke assertions extended** so a rebuild cannot silently drop the new +skill: baked-file existence, resolves-to-the-baked-tree, and reported as `baked` +by `pi-devbox-version`. Skill directories are picked up by a glob in +`entrypoint-user.sh`, so no registration was needed — verified rather than +assumed, since an enumerated list would have left the skill inert, which would +have been a fitting way for *this* skill to fail. + +Neither change reaches a running container until the image is rebuilt **and** the +container recreated: `~/.agents/skills/` and the global `AGENTS.md` both live in +the image, not in a volume or a mount. + +--- + ## v1.8.11 — 2026-08-27 **Shell state that the writable layer eats on every recreate now gets rebuilt at