Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backfill-embeddings.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const require = createRequire(import.meta.url)
const __dirname = dirname(fileURLToPath(import.meta.url))

// ── Load .env.local if present ─────────────────────────────
// [2026-05-29 千夏 fix] .env.local 在 chinatsu-workspace/(memory/ 上一级),
// [2026-05-29 fix] .env.local 在 workspace/(memory/ 上一级),
// 不在 memory/。原代码 resolve(__dirname,'.env.local') 指向 memory/.env.local(不存在)→
// 除非 shell 已 export env 否则 EMBEDDING_API_KEY 取不到直接 exit 1。两个路径都试。
for (const p of [resolve(__dirname, '..', '.env.local'), resolve(__dirname, '.env.local')]) {
Expand All @@ -53,7 +53,7 @@ const CONCURRENCY = parseInt(getFlag('--concurrency') || '3', 10)
const DRY_RUN = hasFlag('--dry-run')

// ── Configuration ───────────────────────────────────────────
// [2026-05-29 千夏 fix] 与 index.mjs:35-38 同一套解析:优先 engram.db(真实库),
// [2026-05-29 fix] 与 index.mjs:35-38 同一套解析:优先 engram.db(真实库),
// 原默认 tokenmem.db 是 fresh-install 占位库(仅 10 行)→ 回填空转。
const DB_PATH = process.env.TOKENMEM_DB_PATH
|| (existsSync(resolve(__dirname, 'engram.db'))
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/longmemeval/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ reproducible result.
node benchmarks/longmemeval/run.mjs `
--dataset C:\data\longmemeval_s_cleaned.json `
--per-category 5 `
--engine baseline=E:\Project\mneme-baseline\index.mjs `
--engine candidate=E:\Project\mneme\index.mjs `
--engine baseline=C:\work\mneme-baseline\index.mjs `
--engine candidate=C:\work\mneme\index.mjs `
--output C:\tmp\mneme-longmemeval-ab.json
```

Expand Down
2 changes: 1 addition & 1 deletion encoding-damage.integration.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const check = (label, cond, detail = '') => {
check('ordinary prose with a question mark is not flagged',
detectEncodingDamage('is the daemon up? it looked fine at 04:00') === null)
check('intact CJK is not flagged',
detectEncodingDamage('daemon 重启脚本在 chinatsu-workspace/scripts 下,怎么跑?') === null)
detectEncodingDamage('daemon 重启脚本在 workspace/scripts 下,怎么跑?') === null)
check('a short string is never flagged', detectEncodingDamage('??') === null)
check('empty input is not flagged', detectEncodingDamage(null, undefined) === null)

Expand Down
4 changes: 2 additions & 2 deletions high-signal-tokens.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const SHRINK_MIN_OLD_LEN = 200
// What ends a URL or path token. Half-width ':' and ',' stay legal (ports,
// and trailing commas are stripped afterwards), but CJK text and CJK punctuation
// terminate: Chinese prose runs straight into a path with no space, so without
// this a path swallows the rest of the sentence — "E:/Project/foo/。使用文档是".
// this a path swallows the rest of the sentence — "C:/work/foo/。使用文档是".
const PATH_STOP = '\\s"\'`))((\\[\\]【】,、。;:!?…\\u4e00-\\u9fff\\u3000-\\u303f'

const HIGH_SIGNAL_PATTERNS = [
Expand Down Expand Up @@ -57,7 +57,7 @@ export function extractHighSignalTokens(text) {
* @returns {Array<{id,oldLen,newLen,ratio,dropped,droppedCount}>} one entry per suspicious pair
*/
// A token is still carried if the new text names it OR names something it is the
// tail of. Writing `memory/index.mjs` out and `E:/Project/ws/memory/index.mjs` in
// tail of. Writing `memory/index.mjs` out and `C:/work/ws/memory/index.mjs` in
// is not a loss — it is the same file, said more precisely, and set difference
// alone calls it a drop.
//
Expand Down
2 changes: 1 addition & 1 deletion index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ export function initMemory() {
// migration 003: decay_score + prior_versions (power-law decay + supersede paper trail).
// Inline so upgrading an OLD db gets them without manually applying migrations/003 —
// otherwise recall's `AND decay_score >= ?` (strict/cold-pool path) throws "no such column".
// (2026-06-10: caught during 爱芮 engram v1.1→v2.2 upgrade — 003 was the only file not inlined.)
// (2026-06-10: caught during an engram v1.1→v2.2 upgrade — 003 was the only file not inlined.)
try {
db.exec(`ALTER TABLE memories ADD COLUMN decay_score REAL NOT NULL DEFAULT 1.0`)
log('Migration: added decay_score column')
Expand Down
4 changes: 2 additions & 2 deletions memory-health.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ function check(label, cond, detail = '') {
const db = new Database(DB_PATH)

const OPS = 'ops entry: http://10.0.0.5:9000 root, /api/svc/v1 routes, SVC_TOKEN and SVC_URL env, '
+ 'code at E:/Project/svc/, handler src/http.mjs, schema src/db.mjs. '
+ 'code at C:/work/svc/, handler src/http.mjs, schema src/db.mjs. '
+ 'Padding so the row clears the 200B floor and has a real historical peak to measure against.'
const priors = (content) => JSON.stringify([{ content, summary: null, merged_at: Date.now(), source_rowid: 1, created_at: Date.now() }])
const ins = db.prepare(`INSERT INTO memories (content, summary, memory_type, category, importance, memory_level, access_count, prior_versions, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?)`)
Expand All @@ -281,7 +281,7 @@ function check(label, cond, detail = '') {
// low importance: shrank the same way but below the review bar
ins.run('svc status: now v2.', 'low-imp shrink', 'long_term', 'general', 4, 'semi_abstract', 1, priors(OPS), t, t)
// faithful rewrite: shorter prose, every identifier carried over
ins.run('http://10.0.0.5:9000 · /api/svc/v1 · SVC_TOKEN · SVC_URL · E:/Project/svc/ · src/http.mjs · src/db.mjs',
ins.run('http://10.0.0.5:9000 · /api/svc/v1 · SVC_TOKEN · SVC_URL · C:/work/svc/ · src/http.mjs · src/db.mjs',
'faithful tightening', 'long_term', 'general', 9, 'semi_abstract', 3, priors(OPS), t, t)

const sh = detectShrinkVictims(db)
Expand Down
8 changes: 4 additions & 4 deletions meta-gate.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// Configure the soft-binding vocabularies before importing the gate.
process.env.MNEME_META_GATE_PROJECT_NAMES = 'AbyssDatabase,BlueBlob'
process.env.MNEME_META_GATE_PERSON_NAMES = '小天,千夏,爱芮,小梦'
process.env.MNEME_META_GATE_PERSON_NAMES = '张三,李四,王五,赵六'

const { applyMetaGate } = await import('./meta-gate.mjs')

Expand All @@ -12,12 +12,12 @@ const cases = [
{ content: 'AbyssDatabase v0.2.0 released', expect: true, label: 'project+version' },
{ content: '2026-05-05 ship notes for the mesh refactor', expect: true, label: 'iso_date' },
{ content: 'continues from mem 6008 personality rules', expect: true, label: 'mem_ref' },
{ content: 'edit E:/Project/example/store.mjs to add the guard', expect: true, label: 'abs_path_windows' },
{ content: 'edit C:/work/example/store.mjs to add the guard', expect: true, label: 'abs_path_windows' },
{ content: 'the daemon config lives at /etc/mneme/config.json', expect: true, label: 'abs_path_posix' },
{ content: 'after commit 41171eb we must verify the committer', expect: true, label: 'commit_hash' },

// Downgrade (soft bindings — require env-configured vocabularies)
{ content: '小天 and 千夏 aligned on the approach', expect: true, label: 'multi_person (env)' },
{ content: '张三 and 李四 aligned on the approach', expect: true, label: 'multi_person (env)' },

// Pass — signal-word cue and no bindings
{ content: 'cross-project rule: verify before you cite, always', expect: false, label: 'meta_signal_head' },
Expand All @@ -29,7 +29,7 @@ const cases = [
{ content: 'listen on port 8080000 in the dev sandbox', expect: false, label: 'digit_only_not_hash' },

// Pass — single person mention below multi-person threshold
{ content: 'when writing 小天 should not inflate importance to please anyone', expect: false, label: 'single_person' },
{ content: 'when writing 张三 should not inflate importance to please anyone', expect: false, label: 'single_person' },
]

let pass = 0, fail = 0
Expand Down
18 changes: 9 additions & 9 deletions supersede-shrink.integration.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ const FAT = `${marker} Key service ops entry.
Service root http://100.87.169.100:8787 with agent API under /api/agent/v1.
Set SERVICE_MANAGER_URL and SERVICE_MANAGER_TOKEN before calling.
GET /api/agent/v1/whoami verifies identity; POST /keys/claim needs an Idempotency-Key.
Code lives at E:/Project/key-manager/, routes in src/http.mjs, schema in src/db.mjs.
Credentials under E:/Project/nas-setup/agents/. Inventory currently 300 available.`
Code lives at C:/work/key-manager/, routes in src/http.mjs, schema in src/db.mjs.
Credentials under C:/work/nas-setup/agents/. Inventory currently 300 available.`

// ── Case 1: 1:1 supersede that keeps only the delta → warn on both axes ──
{
Expand Down Expand Up @@ -70,8 +70,8 @@ Credentials under E:/Project/nas-setup/agents/. Inventory currently 300 availabl
check(missed.length === 0, 'case1 high-signal tokens reported as dropped',
missed.length ? `not reported: ${missed.join(', ')}` : `${dropped.size} tokens`)

const winPath = [...dropped].some(t => /^E:[\\/]Project/.test(t))
check(winPath, 'case1 windows drive path detected', [...dropped].filter(t => t.startsWith('E:')).join(', '))
const winPath = [...dropped].some(t => /^C:[\\/]work/.test(t))
check(winPath, 'case1 windows drive path detected', [...dropped].filter(t => t.startsWith('C:')).join(', '))
}

// ── Case 2: full restatement + new fact → no warning ──
Expand Down Expand Up @@ -239,8 +239,8 @@ dbRead.close()
const { checkSupersedeShrink, isStillCarried } = await import('./high-signal-tokens.mjs')

const carried = [
['memory/index.mjs', 'E:/Project/ws/memory/index.mjs'],
['session-summarize.mjs', 'E:/Project/ws/memory/scripts/session-summarize.mjs'],
['memory/index.mjs', 'C:/work/ws/memory/index.mjs'],
['session-summarize.mjs', 'C:/work/ws/memory/scripts/session-summarize.mjs'],
['scripts/run.sh', 'C:/tools/scripts/run.sh'],
]
for (const [short, long] of carried) {
Expand All @@ -249,18 +249,18 @@ dbRead.close()

// The boundary is a path separator. Same suffix, different file — must still warn.
check('a different file that merely ends the same way is NOT carried',
!isStillCarried('send.mjs', new Set(['E:/Project/ws/feishu-send.mjs'])))
!isStillCarried('send.mjs', new Set(['C:/work/ws/feishu-send.mjs'])))
check('a bare substring is not carried either',
!isStillCarried('index.mjs', new Set(['reindex.mjs'])))

const oldContent = 'runner lives at memory/index.mjs and the log rotates via scripts/run.sh, token in API_TOKEN, see https://ops.example.com/dash'
const newContent = 'runner lives at E:/Project/ws/memory/index.mjs and the log rotates via C:/tools/scripts/run.sh, token in API_TOKEN, see https://ops.example.com/dash — now also covers the nightly path'
const newContent = 'runner lives at C:/work/ws/memory/index.mjs and the log rotates via C:/tools/scripts/run.sh, token in API_TOKEN, see https://ops.example.com/dash — now also covers the nightly path'
const clean = checkSupersedeShrink(newContent, [{ id: '1', content: oldContent }])
check('expanding relative paths to absolute raises no warning',
clean.length === 0, JSON.stringify(clean))

// And the real loss still lands: same expansion, but the URL is gone.
const lossy = 'runner lives at E:/Project/ws/memory/index.mjs and the log rotates via C:/tools/scripts/run.sh, token in API_TOKEN'
const lossy = 'runner lives at C:/work/ws/memory/index.mjs and the log rotates via C:/tools/scripts/run.sh, token in API_TOKEN'
const warned = checkSupersedeShrink(lossy, [{ id: '1', content: oldContent }])
check('a genuinely dropped identifier still warns',
warned.length === 1 && warned[0].dropped.some(d => d.includes('ops.example.com')),
Expand Down
Loading