fix: auto-captured memories write confirmed state to unblock autoRecall#354
Merged
rwmjhb merged 1 commit intoCortexReach:masterfrom Mar 27, 2026
Merged
Conversation
Fixes CortexReach#350 — autoCapture was writing state: "pending" in metadata but autoRecall governance filter requires state === "confirmed", creating a deadlock where auto-captured memories could never be auto-recalled. Changed all auto-capture write paths (regex fallback in index.ts and all 4 Smart Extraction paths in src/smart-extractor.ts) to write state: "confirmed" directly. This unblocks the core autoCapture + autoRecall workflow without requiring users to enable management tools and manually promote every memory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
🧪 本地測試驗證回報以下為針對 PR #354 所做的完整測試驗證。 測試環境
一、單元測試(30 次迭代)測試方法從 upstream 全新 clone PR #354 branch,以 PowerShell 自動化腳本執行 # 每次執行 npm test,記錄 exit code 與耗時
for ($i = 1; $i -le 30; $i++) {
$proc = Start-Process -FilePath "cmd" -ArgumentList "/c","npm test" -WorkingDirectory $WORKDIR -NoNewWindow -Wait -PassThru
# 記錄結果
}結果
既有失敗分析30 次迭代中,每次皆有 5 個相同測試失敗,位置全部在 這 5 個測試屬於同一 group(
二、功能測試(5 項)測試腳本
/**
* PR #354 功能測試 — autoCapture state:pending→confirmed
*
* 測試場景:
* 1. auto-capture(regex + smart-extractor)寫入的記憶,state 為 "confirmed"
* 2. 舊有的 state:"pending" 記憶仍可透過 memory_promote 升級為 "confirmed"
*/
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "os";
import path from "path";
import { fileURLToPath } from "url";
import jitiFactory from "jiti";
const testDir = path.dirname(fileURLToPath(import.meta.url));
const pluginSdkStubPath = path.resolve(testDir, "helpers", "openclaw-plugin-sdk-stub.mjs");
const jiti_instance = jitiFactory(import.meta.url, {
interopDefault: true,
alias: { "openclaw/plugin-sdk": pluginSdkStubPath },
});
const { MemoryStore } = jiti_instance("../src/store.ts");
const { buildSmartMetadata, stringifySmartMetadata, parseSmartMetadata } = jiti_instance("../src/smart-metadata.ts");
const VECTOR_DIM = 4;
function makeTestVector(seed = 0) {
return [seed % 2 === 0 ? 1 : 0, seed % 3 === 0 ? 1 : 0, seed % 5 === 0 ? 1 : 0, 0.5];
}
function createTestStore(workDir) {
return new MemoryStore({ dbPath: path.join(workDir, "db"), vectorDim: VECTOR_DIM });
}
// 模擬 auto-capture regex fallback 寫入 path
async function simulateAutoCaptureRegexFallback(store, text, category = "fact") {
const vector = makeTestVector(text.length);
const metadata = stringifySmartMetadata(
buildSmartMetadata(
{ text, category },
{
l0_abstract: text.slice(0, 80),
l1_overview: text,
l2_content: text,
source: "auto-capture",
memory_category: "cases",
state: "confirmed", // PR #354 的關鍵改動
},
),
);
await store.store({ text, vector, category, scope: "global", importance: 0.7, metadata });
}
// 模擬 smart-extractor 各路徑寫入
async function simulateSmartExtractor(store, text, branch, category = "fact") {
const vector = makeTestVector(text.length + branch.length);
const metadata = stringifySmartMetadata(
buildSmartMetadata(
{ text, category },
{
l0_abstract: `[${branch}] ${text.slice(0, 60)}`,
l1_overview: text,
l2_content: text,
source: "auto-capture",
memory_category: "cases",
state: "confirmed", // PR #354 的關鍵改動
},
),
);
await store.store({ text: `[${branch}] ${text}`, vector, category, scope: "global", importance: 0.8, metadata });
}
// 模擬舊版 state:"pending" 記憶
async function storePendingMemory(store, text) {
const vector = makeTestVector(text.length + 9999);
const metadata = stringifySmartMetadata(
buildSmartMetadata(
{ text, category: "fact" },
{
l0_abstract: text.slice(0, 80),
l1_overview: text,
l2_content: text,
source: "auto-capture",
memory_category: "cases",
state: "pending", // 模擬舊記憶
},
),
);
await store.store({ text, vector, category: "fact", scope: "global", importance: 0.7, metadata });
}測試項目
執行結果(穩定重複 2 次)三、驗證邏輯對照PR #354 變更位置(共 5 處)
Governance Filter 邏輯(
|
This was referenced Mar 26, 2026
This was referenced Mar 27, 2026
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
pendingstate, blocked from auto-recall by governance filter #350state: "pending"in metadata but autoRecall governance filter requiresstate === "confirmed", creating a deadlock where auto-captured memories could never be auto-recalledstate: "confirmed"directly:index.tsregex fallback capture (1 location)src/smart-extractor.tsSmart Extraction paths: supersede, contextualize, contradict, and new-entry (4 locations)Rationale
The
pending → confirmedlifecycle was introduced in v1.1.0-beta but no automatic promotion mechanism exists. Thememory_promotetool requiresenableManagementTools: true(disabled by default), so out-of-the-box autoCapture + autoRecall is broken. Writingconfirmedat capture time matches the behavior ofmemory_store(manual store) and unblocks the core workflow.Test plan
npm testpasses (all existing tests)autoCapture: true+autoRecall: true, verify new memories appear in<relevant-memories>tagmemory_promotestill works for legacy pending memories🤖 Generated with Claude Code