Skip to content

v1.27.22 — Cascade

Choose a tag to compare

@markfietje markfietje released this 18 Aug 09:41
· 43 commits to main since this release

[1.27.22] — 2026-08-18

Server-only release (server Cargo.toml/lock 1.27.211.27.22; client +
plugin unchanged). "Cascade" — a bug-fix release closing two
documented-but-unimplemented behaviors in the graph edge layer: edge
supersession was write-once (nothing ever closed an old edge's invalid_at when
reality changed) and traversal claimed to skip superseded edges but never did.
This release makes the code true to its own documentation, reusing the
bi-temporal columns + hash-chained audit + quarantine machinery already shipped.
No new storage, no new schema columns/tables, no wire change, no telemetry; the
schema stamp advances to 1.27.22 for the added relationships.superseded_at
column + index swap.

Bug fixes

  • Edge supersession is now wired (BUG-1). The ingest path replaced its
    write-once INSERT OR IGNORE with a pure bi-temporal resolver
    (resolve_edge_insert). Re-ingesting an unchanged relation is still an
    idempotent no-op (no history churn); re-ingesting a relation with a changed
    window/interval now retires the old edge version (superseded_at = the
    transaction-time end, old row preserved verbatim) and inserts the corrected
    version as the new current belief. The handoff is exact:
    old.superseded_at == new.created_at.
  • Traversal now skips superseded edges (BUG-2), matching its own doc. The
    recursive walk filters edges to current beliefs: live (superseded_at IS NULL) and the newest live version of their (from, to, relation_type)
    triple. This is a no-op on well-formed/legacy DBs (a lone edge has no newer
    live peer), so default recall/traversal output is byte-identical; it corrects
    the case where a backdated supersession previously returned two edges claiming
    the same triple at one instant.
  • /graph/relationships/{id}/history (Admin, audited). A new read surface
    reconstructs the full version history of an edge triple — every version in
    order with its four timestamps (valid_at, invalid_at, created_at,
    superseded_at) + a current flag — given any one version id, so a
    superseded belief can always be recovered (supersession never deletes).
  • Superseded edges are hidden from graph + adjacency reads. GET /graph/relations, entity_relations, relations_for, the UMP relation
    fan-out, and the graph-PPR adjacency aggregation all filter to current
    beliefs, so a retired edge no longer surfaces as a live relation.

Improvements

  • Supersession events ride the existing hash-chained audit log
    (AuditKind::Ingest, detail created:<id> / superseded:<old_id>->:<new_id>)
    and the history-surface read is itself recorded (AuditKind::GraphRead).
  • Fail-closed: an inability to resolve an edge insert declines the ingest
    transaction (never a silent half-write); an unresolvable history id returns
    404 Relationship not found.

Security fixes

  • None (no new trust boundary; the graph-label read seam posture is unchanged
    from v1.27.21).