From 425008f855d5face136aacae18072a4b77259a2c Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 07:53:58 +0000 Subject: [PATCH] feat(brain): expose supersession metadata Co-Authored-By: Virgil --- php/Models/BrainMemory.php | 8 +- php/tests/Feature/BrainMemoryTest.php | 113 ++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 php/tests/Feature/BrainMemoryTest.php diff --git a/php/Models/BrainMemory.php b/php/Models/BrainMemory.php index acf1a58..3f23b38 100644 --- a/php/Models/BrainMemory.php +++ b/php/Models/BrainMemory.php @@ -1,5 +1,7 @@ supersedes_id !== null && $depth < $maxDepth) { - $current = $current->supersedes; + $current = self::withTrashed()->find($current->supersedes_id); if ($current === null) { break; @@ -185,13 +187,15 @@ class BrainMemory extends Model 'agent_id' => $this->agent_id, 'type' => $this->type, 'content' => $this->content, - 'tags' => $this->tags, + 'tags' => $this->tags ?? [], 'project' => $this->project, 'confidence' => $this->confidence, 'score' => round($score, 4), 'source' => $this->source ?? 'manual', 'supersedes_id' => $this->supersedes_id, + 'supersedes_count' => $this->getSupersessionDepth(), 'expires_at' => $this->expires_at?->toIso8601String(), + 'deleted_at' => $this->deleted_at?->toIso8601String(), 'created_at' => $this->created_at?->toIso8601String(), 'updated_at' => $this->updated_at?->toIso8601String(), ]; diff --git a/php/tests/Feature/BrainMemoryTest.php b/php/tests/Feature/BrainMemoryTest.php new file mode 100644 index 0000000..09cf2eb --- /dev/null +++ b/php/tests/Feature/BrainMemoryTest.php @@ -0,0 +1,113 @@ +workspace = Workspace::factory()->create(); + } + + public function test_BrainMemory_toMcpContext_Good_IncludesSupersessionDepthAndEmptyTags(): void + { + $root = BrainMemory::create([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'decision', + 'content' => 'Prefer named actions for all agent capabilities.', + 'confidence' => 0.9, + ]); + + $child = BrainMemory::create([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'decision', + 'content' => 'Keep the action registry namespaced.', + 'tags' => ['actions', 'registry'], + 'confidence' => 0.95, + 'supersedes_id' => $root->id, + ]); + + $context = $child->toMcpContext(); + + $this->assertSame(1, $context['supersedes_count']); + $this->assertSame(['actions', 'registry'], $context['tags']); + $this->assertNull($context['deleted_at']); + } + + public function test_BrainMemory_toMcpContext_Bad_HandlesMissingSupersededMemory(): void + { + $memory = new BrainMemory([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'research', + 'content' => 'Missing ancestors should not break MCP output.', + 'confidence' => 0.8, + ]); + + $memory->supersedes_id = Str::uuid()->toString(); + + $context = $memory->toMcpContext(); + + $this->assertSame(0, $context['supersedes_count']); + $this->assertSame([], $context['tags']); + } + + public function test_BrainMemory_toMcpContext_Ugly_WalksSoftDeletedAncestors(): void + { + $root = BrainMemory::create([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'decision', + 'content' => 'Start with the root memory.', + 'confidence' => 0.9, + ]); + + $middle = BrainMemory::create([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'decision', + 'content' => 'Replace the root memory.', + 'confidence' => 0.9, + 'supersedes_id' => $root->id, + ]); + + $middle->delete(); + + $leaf = BrainMemory::create([ + 'workspace_id' => $this->workspace->id, + 'agent_id' => 'virgil', + 'type' => 'decision', + 'content' => 'Replace the deleted middle memory.', + 'confidence' => 0.9, + 'supersedes_id' => $middle->id, + ]); + + $context = $leaf->toMcpContext(); + + $this->assertSame(2, $context['supersedes_count']); + $this->assertNull($context['deleted_at']); + + $deletedContext = BrainMemory::withTrashed()->findOrFail($middle->id)->toMcpContext(); + + $this->assertNotNull($deletedContext['deleted_at']); + $this->assertSame(1, $deletedContext['supersedes_count']); + } +}