changelog: an Unreleased section for a rule that was already there
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.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user