changelog: v1.8.7 — device provenance reaches the fleet
Lint / hadolint (push) Successful in 9s
Lint / actionlint (push) Successful in 17s
Publish Docker Image / resolve-versions (push) Successful in 10s
Publish Docker Image / base-decide (push) Successful in 12s
Publish Docker Image / build-base (push) Successful in 42m4s
Publish Docker Image / smoke (push) Failing after 4m44s
Publish Docker Image / build-variant (push) Has been skipped
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
Publish Docker Image / smoke-studio (push) Failing after 7m46s
Publish Docker Image / build-variant-studio (push) Has been skipped
Lint / hadolint (push) Successful in 9s
Lint / actionlint (push) Successful in 17s
Publish Docker Image / resolve-versions (push) Successful in 10s
Publish Docker Image / base-decide (push) Successful in 12s
Publish Docker Image / build-base (push) Successful in 42m4s
Publish Docker Image / smoke (push) Failing after 4m44s
Publish Docker Image / build-variant (push) Has been skipped
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
Publish Docker Image / smoke-studio (push) Failing after 7m46s
Publish Docker Image / build-variant-studio (push) Has been skipped
The provenance fix's client half lives in mempalace-toolkit, which the image clones at build time, so it only reaches the fleet through a tag. Records both routes (extension via MEMPALACE_TOOLKIT_REF folded into base_tag; vendored skill via rootfs), the three design points (stamp in the client not the agent; diary marker in TEXT because metadata is invisible to readers; solitary devbox stamps nothing), and why the allowlist is per tool (3.8.0 hard-fails -32602 on undeclared args). Carries the CI-hardening work already sitting in Unreleased, and a Still open block for the three known bounds.
This commit is contained in:
+86
-1
@@ -11,10 +11,72 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
||||
|
||||
---
|
||||
|
||||
## Unreleased
|
||||
## v1.8.7 — 2026-08-25
|
||||
|
||||
Patch release, and the fastest turnaround in the series (~9 h after v1.8.6) for
|
||||
one reason: **v1.8.6 shipped a container that cannot tell you which machine it
|
||||
is running on**, and that anonymity produced a real misattribution the same
|
||||
evening — a session on tor-ms22 read *another host's* diary out of the shared
|
||||
palace, reported its verification as its own, and built a causal inference on
|
||||
top of the coincidence. The client-side half of the fix lives in
|
||||
`mempalace-toolkit`, which the image clones **at build time**, so it can only
|
||||
reach the fleet through a tag. The CI-hardening work that had accumulated since
|
||||
v1.8.6 rides along.
|
||||
|
||||
Gitea-hosted refs re-resolved immediately before tagging (2026-08-25T22:35Z):
|
||||
pi-toolkit `0e1369e6` and pi-extensions `20228878` **unchanged** since v1.8.6;
|
||||
mempalace-toolkit `0fe64c48` → `553d8657` (the provenance change below). CI
|
||||
re-resolves pi-fork / pi-observational-memory / pi-atelier / pi-studio at build
|
||||
time as usual. **Base rebuild is forced twice over** — `Dockerfile.base` changed
|
||||
(the `MEMPALACE_VERSION` audit) *and* `base_tag` deliberately folds in the
|
||||
mempalace-toolkit SHA ("otherwise a toolkit-only fix never lands") — so expect
|
||||
~67 min, and note that either cause alone would have sufficed.
|
||||
|
||||
### Added
|
||||
|
||||
- **Palace writes now carry the device that made them, and diary entries say so
|
||||
in text.** The container is host-anonymous by construction — `hostname` is a
|
||||
Docker hash, `$DEVBOX_HOST_ALIAS` is generic, the virtiofs source tag is
|
||||
generic, and two hosts in this fleet are both `aarch64` — so nothing inside it
|
||||
distinguished tor-ms22 from EMB-7KJ4VR4G. In a *local* palace that costs
|
||||
nothing (one origin, so origin is a property of the whole store). In the
|
||||
**shared** palace it means every drawer and all 621 diary entries read as
|
||||
though written here, which is exactly how a v1.8.6 verification performed on
|
||||
EMB was reported as tor-ms22's own.
|
||||
|
||||
Two halves, arriving by different routes:
|
||||
|
||||
| Half | Where it lives | How it gets into this image |
|
||||
|---|---|---|
|
||||
| the writer — stamps `<harness>@<device>` on `add_drawer`/`checkpoint`/`mine`/`event_append`/`artifact_put`, and prefixes diary entries with `HOST:<device>\|` | `mempalace-toolkit` `extensions/pi/mempalace.ts` (553d8657) | cloned in `Dockerfile.base` at `MEMPALACE_TOOLKIT_REF`, whose SHA is folded into `base_tag` |
|
||||
| the consumer skill — stops telling the agent to do it by hand, adds the read-side warning | vendored `rootfs/…/skills/mempalace/SKILL.md`, refreshed from skillset `73c7c8e6` | `rootfs/*` is hashed into `base_tag` too |
|
||||
|
||||
Three design points worth recording, because each was arrived at the hard way:
|
||||
|
||||
- **The stamp goes in the *client*, not the agent.** RFC 001 §7.3.2 ranks
|
||||
"agent stamps it via a skill instruction" as the ❌ *worst possible* place,
|
||||
and the skill had carried exactly that instruction since 2026-08-23. It
|
||||
failed as predicted: the agent that wrote the instruction then filed its own
|
||||
provenance drawer without it. 199 rows reached the palace unresolvable.
|
||||
One `execute()` wrapper cannot forget.
|
||||
- **The diary marker is in the entry TEXT on purpose.** `diary_write` has no
|
||||
metadata parameter, but the deeper reason is that mempalace's `search`
|
||||
projects a fixed key set and `diary_read` returns content — **metadata is
|
||||
invisible to the agent who will later read the entry**, so no metadata-only
|
||||
fix, not even a server-authoritative one, would have prevented the
|
||||
misattribution. The marker is an AAAK field, so it is machine-parseable
|
||||
*and* the first thing a reader sees. The wake-up preamble now also names the
|
||||
device and warns that `diary_read` interleaves every machine's diary.
|
||||
- **A solitary devbox stamps nothing.** Gated on `MEMPALACE_PI_DEVICE` **and**
|
||||
`MEMPALACE_REMOTE_URL` — both set only when the palace is actually shared
|
||||
(RFC 001 R1). Unset either and behaviour is byte-identical to v1.8.6.
|
||||
|
||||
Never injected into `diary_write` or `kg_add`: mempalace 3.8.0 hard-rejects
|
||||
undeclared arguments with JSON-RPC `-32602` rather than dropping them (the
|
||||
behaviour changed since the RFC's 2026-08-09 note, now corrected), so a
|
||||
blanket injection would **break** those two calls instead of being ignored.
|
||||
The allowlist is per tool for that reason.
|
||||
|
||||
- **CI now shellchecks the repo's own shell scripts, not just workflow `run:` steps.** `.gitea/workflows/lint.yml`'s `actionlint` job already shellchecks every workflow step, but nothing had ever pointed shellcheck at `entrypoint.sh`, `scripts/*.sh`, or the extensionless tools under `rootfs/usr/local/bin/` (`pi-devbox-version`, `devbox-skill-reconcile`, `dot-watch`, `studio-expose`). The gap is not hypothetical: a sibling repo (skillset's `ci-release-watcher` templates) shipped `echo "$json" | python3 <<'EOF' ... json.load(sys.stdin)` for two months without anyone noticing it silently returned nothing — with no script argument python reads its *script* from stdin, so the heredoc is stdin and the JSON load hits EOF. shellcheck flags exactly this at severity **error** (`SC2259`, "This redirection overrides piped input"); it had been available to catch it the whole time, just never run.
|
||||
|
||||
New step in the `actionlint` job, `Shellcheck + syntax-check repository scripts`, runs `shellcheck -S error` plus `bash -n` over every shell file in the repo, **discovered by `*.sh` union a shebang scan** (neither alone suffices) so the extensionless `rootfs/usr/local/bin/*` tools are covered too. Measured before adding it: `-S error` is 0 findings across all 11 shell files today, so the gate is green on arrival with no cleanup. `-S warning` is *not* free (19× `SC2088` tilde-in-quotes in `scripts/recreate-sanity-check.sh`, plus assorted `SC2016`, both intentional here) — a warning-level gate would train people to ignore it, so it stays error-only, same reasoning as the existing `SHELLCHECK_OPTS` exclusions on the actionlint step. File-count guard included: the step fails loudly if the shebang scan matches zero files, since a green check over an empty set is not a check.
|
||||
@@ -137,6 +199,29 @@ Pre-v1.0.0 tags followed the pi npm version (`v{pi_version}[letter]`).
|
||||
|
||||
---
|
||||
|
||||
### Still open
|
||||
|
||||
- **Provenance stops at Chroma's metadata.** The hourly reconciler on the palace
|
||||
host stamps `device`/`agent_kind` in `chroma.sqlite3`, but knowledge-graph
|
||||
triples and coordination events live in *separate* SQLite files
|
||||
(`knowledge_graph.sqlite3`, `logstream.sqlite3`) it cannot reach. 156 triples
|
||||
carry no origin field at all; `logstream`'s `from_agent` is free-form and
|
||||
already inconsistent (`pi@tor-ms22`, `pi@emb-7kj4vr4g`, and bare `pi` in the
|
||||
same table). Tracked in RFC 001 §7.3.1.
|
||||
- **The stamp is self-asserted, and cannot be otherwise yet.** mempalace 3.8.0
|
||||
authenticates with a *single scalar* bearer token and has zero device concept,
|
||||
so a verified stamp needs per-device credentials plus an origin field in six
|
||||
write paths across three databases. Deferred to RFC 001 Phase 4, where it is
|
||||
now motivated primarily by **revocation** (one shared token covers every
|
||||
device, so cutting off one laptop means rotating the fleet) rather than by
|
||||
provenance. Forward-compatible by design: every stamp records *how* it was
|
||||
determined, so an authoritative pass overwrites with `device_source='token'`
|
||||
and nothing has to be undone.
|
||||
- **`tor-ms22` and `tor-ms22-native` are one machine with two device values**
|
||||
(4,680 and 3,826 rows). That is the hostname-as-identity cost RFC 001 §7.3.4
|
||||
warned about, now visible in data: a rename splits one device's history
|
||||
silently. Repairing it means a device-identity mapping, not a relabel.
|
||||
|
||||
## v1.8.6 — 2026-08-25
|
||||
|
||||
Patch release. Adopts the drift that accumulated in the ~2 days since v1.8.5
|
||||
|
||||
Reference in New Issue
Block a user