fix both criterion 6 failures at the cause - #52
Merged
Conversation
The scope check added in #44 would not have caught the incident it cites. Both guessed ids belonged to the author, in a different project, so ownership held and three facts about Indian tax compliance still attached themselves to an embedding table's lesson. Owning a node is not the same as it being the right node. The test the server can justify is whether it would ever have offered this node as a candidate for this mention: candidates are drawn above low_threshold, so an id pointing below it cannot be an answer to a question this server asked. Measured on the real embedder before picking the bar rather than assumed. The incident's own pairs score 0.030 and 0.041; the hardest legitimate confirmation on record, "AGE" against "Apache AGE", scores 0.497. An exact name or alias match skips the check, since there the id is redundant rather than doubtful. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0191FunuahgEA734jXUrxzJm
Migration 0011 backfilled absent agent_ids to 'unknown' rather than to 'claude-code', and that refusal to guess was right. It was also total, which left the store permanently unable to say anything about authorship - and the criterion 6 gate reads that as a bar that can never be met. One case is not a guess. A session is one tool's conversation, so a session holding both attributed and unattributed facts has already said who wrote the rest. Three of the thirty in the author's own store are recoverable that way; twenty-seven sit in sessions with no attributed fact at all and stay unattributed, which the command says plainly instead of picking something. A session claimed by two agent ids is refused too. Taking the more frequent one would be a guess wearing a majority vote. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0191FunuahgEA734jXUrxzJm
The gate required every fact in the store to have a recorded author before any cross-tool save could count. The danger it was guarding against is real - 'unknown' is unequal to every real agent id, so a save citing an authorless fact satisfies `written_by != recalled_by` because one side is missing rather than because two tools were involved - but the scope was wrong. Applied globally, it refused two saves that name real tools at both ends because of twenty-seven unrelated facts in sessions holding nothing attributable. The check's own message called those unrecoverable, so the bar could never be cleared by any action available to anyone. That is not a gate, it is a wall, and it is why criterion 6 has sat undecidable for three weeks. The exclusion now happens per save, in observations.counts, against that save's own two agent ids. The store-wide count is still reported - a store losing authorship is worth seeing - and now points at `reattribute --agent` instead of saying nothing can be done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0191FunuahgEA734jXUrxzJm
A confirmed resolved_to does two things and the cleanup on 2026-09-02 undid one. It points the episode's facts at the named node, and it appends the mention to that node's aliases - which is what makes a misdirected resolution a merge rather than a misfiled fact, and is criterion 6's third bar word for word: two distinct entities in one node. The misdirected edges were deleted. The aliases were not, so for eight days 'node_embedding table' has answered to 'Eigon billing profile' and 'AGE graphid column type' to 'Eigon GST tax rule'. _exact_match checks aliases, so this was not historical damage: the next mention of either name was one retired node away from landing on an embedding table's lesson. Doing the first half by hand is why the second half was missed, so this is a command rather than a Cypher statement in someone's scrollback. It lists candidates and refuses to act on its own, because a genuine duplicate pair on its way to being merged properly looks identical from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0191FunuahgEA734jXUrxzJm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The saves bar and the bad-merge bar were both failing for reasons in the code
rather than in the trial.
The bad merges were still live
A confirmed
resolved_todoes two things, and the second is easy to miss: itpoints the episode's facts at the named node and appends the mention to that
node's aliases. That alias is what makes a misdirected resolution a merge
rather than a misfiled fact, and it is criterion 6's third bar word for word -
two distinct entities in one node.
The 2026-09-02 cleanup deleted the misdirected edges and left the aliases. For
eight days
node_embedding tableanswered toEigon billing profileandAGE graphid column typetoEigon GST tax rule._exact_matchchecks aliases, sothis was not historical damage: the next mention of either name was one retired
node away from landing on an embedding table's lesson.
echo-memory unmergeis the missing half of that cleanup - it lists every nodecarrying another node's name and refuses to act on its own, because a genuine
duplicate pair on its way to being merged properly looks identical from here.
Both scopes of the author's store are now clean.
Running it found a third merge nobody had seen, made the same day by
session
c87a143c-billing-hardening:Eigon warm-base ALB sharingabsorbedinto
Eigon API tokens page. Recorded as an observation rather than quietlyrepaired, so the trial count is now 3, not 2.
The scope check from #44 would not have caught any of them
Every guessed id belonged to the caller, in a different project, so ownership
held. Owning a node is not the same as it being the right node.
resolve_entitiesnow also asks whether it would ever have offered this nodeas a candidate for this mention - candidates are drawn above
low_threshold,so an id pointing below it cannot be an answer to a question this server asked.
Measured before picking the bar rather than assumed:
Eigon billing profile/node_embedding tableEigon GST tax rule/AGE graphid column typeEigon warm-base ALB sharing/Eigon API tokens page(today's)AGE/Apache AGE- hardest legitimate confirmation on recordAll three incidents fall below 0.45; the legitimate confirmation clears it. An
exact name or alias match skips the check, since there the id is redundant
rather than doubtful.
The saves bar could never have been met
It required the entire store to have attributed facts before any cross-tool
save could count. The danger is real - 'unknown' is unequal to every real agent
id, so a save citing an authorless fact satisfies
written_by != recalled_bybecause one side is missing, not because two tools were involved - but the
scope was wrong. It refused two saves naming real tools at both ends because of
twenty-seven unrelated facts in sessions holding nothing attributable, which
the check's own message called unrecoverable. An unclearable bar is not a gate.
The exclusion is now per save, against that save's own two agent ids.
reattribute --agentrecovers the authors that are recoverable, and onlythose: a session is one tool's conversation, so a session with both attributed
and unattributed facts has already said who wrote the rest. Three of the thirty
came back that way. The other twenty-seven sit in sessions with no attributed
fact at all and stay unattributed - a session claimed by two agent ids is
refused too, because taking the more frequent one is a guess wearing a majority
vote.
Where the trial actually stands
Nothing here manufactures evidence. After the fixes: 2/3 cross-tool saves
(a third has to be earned by a real one), 1 duplicate (within budget),
3 bad merges (one more than before, because the repair tool found one).
515 tests pass. Every new test was checked against the unfixed code first.
🤖 Generated with Claude Code
https://claude.ai/code/session_0191FunuahgEA734jXUrxzJm