v1.27.19
[1.27.19] — 2026-08-16
Release notes
Security fixes
- A failed logout/revoke no longer says 204 "done".
POST /auth/logout
andPOST /auth/revokewrote the token to the revocation denylist
best-effort and returned success regardless — an operator logging out
believed the token was dead when a failed INSERT left it live for its full
15-minute shelf life (and a revoked token could be refreshed). Both now
surface a denylist write failure as500 revoke_failed; success still
means the token is really dead. - Purge residue deletes propagate (were
let _ =). A chunk purge deleted
the tombstoned row's relationships / vec0 embedding / evidence links /
traces in silence — one failing DELETE while the rest succeeded left a
partial erasure that the purge then certified complete. Every residue
delete now participates in the purge transaction: a failure rolls the whole
purge back instead of certifying a lie. - The prompt-injection blocklist screen runs once per hit, not per
consumer. Recall constructed eachSearchResultwith raw bytes, then the
PRF query-expansion extractors re-normalized each hit's content against the
blocklist per query. The screen now runs once at construction and rides as
an internalblocklist_hitflag (never serialized); both extractors read
the flag. Behavior-identical, one scan saved per hit per query. - Erasure hygiene warns instead of certifying silence. The DSAR/shared
purge previously swallowed a failedPRAGMA secure_delete=ONor a failed
wal_checkpoint(TRUNCATE)— the two operations that ensure erased page
images don't survive in the WAL or freelist. Failures are now logged loudly
instead of whispering "erased".
Improvements
- Audit-settle failures are visible. The best-effort audit-chain settle
(COMMIT/ROLLBACK of the chained row) could fail under a busy writer — the
caller still got a row id, and nothing said the chain might have missed it.
/health'shardeningblock now carries a monotonicaudit_commit_failures
counter (0 = green; >0 = rows possibly off the durable chain). - Every other write-path
let _ =residue propagated (23 further sites):
chunk stored without its evidence links, stale vec0 rows surviving reindex,
webhook seen-writes, retention prunes, refresh failures, orphaned PII
residues, secure_delete/TRUNCATE on purge — each now either fails the
operation or warns with context. - Client decisions announce their outcome. A failed approve/reject in the
Operations queue, a failed quartine release/delete in Security, and failed
decayed/tombstone loads in the Data panel were silently dropped — each now
renders anaria-livestatus line (waslet _ =on the result, orif let Okon the load). - A single-record ingest lost its last panic. The singleton UMP path
lowered a one-element batch with.next().unwrap()behind a length guard;
it is now apop()+?— no panic fallback left on the write path.
Bug fixes
- Dead "reserved" trace vocabulary removed.
trace.rsshipped an
#[allow(dead_code)]update:/supersedes:/contradicts:/causes:
prefix vocabulary "reserved for v1.6 Reconcile"; v1.6 shipped and closed
without consuming it. The dead constants and their tests are gone — the
used surface (MAX_HOPS/MAX_VISITEDtraversal caps) is unchanged.
Full Changelog: v1.27.18...v1.27.19