v0.16.0 — a fact remembers who was there #251
mmeyerlein
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
0.16.0 — a fact remembers who was there
A memory that cannot say who was in the room when it learned something will
eventually say it to the wrong person.
memory-hive@2.1.0closes that.affinityhas decided disclosures by a participant set since #154: a factsurfaced in a conversation is released to exactly the people who were there,
and a later round may hear it only if that round is a subset of the
recorded one. The memory half of that ruling was never built — thirteen tables
and not one column for it. So the two halves of one rule disagreed: one refused,
the other had nothing to refuse with.
What a row carries now. An episode records
speaker(an identity, not therole
user/assistant),channel(the room), andaudience_set(who waspresent). Facts and entity edges inherit both from their episode. Beliefs and
skills are derived rather than said, so they carry the intersection of
their sources' sets — otherwise two private facts could be laundered into one
shareable claim.
The rule, in the order it is evaluated. An untagged row is invisible. A
universal set is visible. A round that is a subset of the recorded set is
visible. And a row from the same channel is visible when that channel shows
its history to people who join — because an agent should not be leakier than
the room it speaks in, nor more secretive than it. That last clause never
crosses a channel boundary: material from a private conversation stays out of a
group one regardless of the group's history policy.
The order matters and is normative. Written the other way round, an untagged row
in an open channel comes out visible — the one row whose provenance we do not
have would be the one that gets through, and the weakest data path would be the
most permissive.
Fail-closed on both sides. A write lane without an audience or a channel
writes nothing and refuses on the
rejectlane;in_episodegained arequired_drainsentry so a colony cannot wire the lane and let the refusalfall on the floor. A read lane without them is refused rather than answered with
an empty bundle — a refusal and an empty answer are different sentences.
And one thing the gate gave back. The temporal leg filters before it builds
a version chain, because the other order would let the existence of an invisible
version show through a validity span: ask often enough and you map out when
something was said in a room you were never in. But filtering first means a
claim superseded by an invisible version would look current — the agent would
answer wrongly rather than narrowly. So such a candidate now carries
supersession_unknown, and neither tier 0 nor tier 2 asserts currency for it.It is a boolean and nothing more: no count, no instant, no channel of what was
removed. What the asker learns is not something about the other room, but
something about the memory's own certainty.
Breaking, with the migration named. The write lanes
in_episodeandin_rememberand the read lanein_querynow require their context keys. Theedge that carries a turn into the hive promotes them, the way it already
promotes
session_id. An existing store can be backfilled only while it hasprovably seen a single participant set — after that an untagged row can be
guessed at, but not filled honestly. That is why this lands before the next
fact rather than before the next feature.
Full detail in the CHANGELOG
and in #244.
Release: https://github.com/mmeyerlein/meclaw/releases/tag/v0.16.0
All reactions