var test = require("node:test"); var assert = require("node:assert/strict"); var fs = require("fs"); var os = require("os"); var path = require("path"); var mateSync = require("../lib/mate-knowledge-sync"); var knowledgeImport = require("../lib/knowledge-import"); function tmp(label) { return fs.mkdtempSync(path.join(os.tmpdir(), "clay-sync-" + label + "-")); } function write(target, content) { fs.mkdirSync(path.dirname(target), { recursive: true }); fs.writeFileSync(target, content); } function digest(topic) { return JSON.stringify({ date: "2026-04-09", type: "session", topic: topic }); } function fixture(label) { var home = tmp(label); var mateDir = path.join(home, "mates", "mate_sync"); fs.mkdirSync(path.join(mateDir, "knowledge"), { recursive: true }); var baseDir = path.join(home, "knowledge"); return { home: home, mateDir: mateDir, knowledge: path.join(mateDir, "knowledge"), baseDir: baseDir, scope: mateSync.scopeForMateDir(mateDir), importer: function () { return knowledgeImport.createKnowledgeImporter({ scopeId: mateSync.scopeForMateDir(mateDir).scopeId, baseDir: baseDir, }); }, }; } function sync(f, fileName, actor) { return mateSync.syncMateSource({ mateDir: f.mateDir, fileName: fileName, baseDir: f.baseDir, actor: actor }); } function find(entries, importKey) { for (var i = 0; i < entries.length; i++) if (entries[i].importKey === importKey) return entries[i]; return null; } var USER = { type: "user", userId: "u1", displayName: "Ada" }; var AGENT = { type: "agent", vendor: "claude" }; test("write-through creates, revises, and tombstones a knowledge file", function () { var f = fixture("file"); var target = path.join(f.knowledge, "architecture.md"); write(target, "# Architecture\nAppend-only.\n"); var created = sync(f, "architecture.md", USER); assert.equal(created.created, 1); assert.equal(created.failed, 0); var entry = find(f.importer().entries(), "file:architecture.md"); assert.equal(entry.kind, "knowledge-file"); assert.equal(entry.content, "# Architecture\nAppend-only.\n"); assert.equal(entry.actor.type, "user"); assert.equal(entry.actor.userId, "u1"); assert.equal(entry.actor.displayName, "Ada"); // Repeated sync with no change writes nothing. var before = f.importer().stats().records; assert.equal(sync(f, "architecture.md", USER).unchanged, 1); assert.equal(sync(f, "architecture.md", USER).unchanged, 1); assert.equal(f.importer().stats().records, before, "idempotent sync appends no record"); write(target, "# Architecture\nAppend-only, revised.\n"); assert.equal(sync(f, "architecture.md", USER).revised, 1); var revised = find(f.importer().entries(), "file:architecture.md"); assert.equal(revised.revisions, 2); assert.match(revised.content, /revised/); // Deleting the legacy file appends a tombstone rather than leaving it live. fs.unlinkSync(target); assert.equal(sync(f, "architecture.md", USER).deleted, 1); assert.equal(find(f.importer().entries(), "file:architecture.md"), null); var tombstoned = find(f.importer().entries({ includeDeleted: true }), "file:architecture.md"); assert.equal(tombstoned.deleted, true); assert.equal(sync(f, "architecture.md", USER)["already-deleted"], 1, "a repeated delete sync is a no-op"); // Recreating the file revives the record instead of duplicating it. write(target, "# Architecture\nBack again.\n"); assert.equal(sync(f, "architecture.md", USER).revived, 1); var revived = find(f.importer().entries(), "file:architecture.md"); assert.equal(revived.deleted, false); assert.match(revived.content, /Back again/); assert.equal(f.importer().entries().filter(function (e) { return e.importKey === "file:architecture.md"; }).length, 1); }); test("nested Markdown sources use the same isolated record interface", function () { var f = fixture("nested-file"); var target = path.join(f.knowledge, "guides", "start.md"); write(target, "# Start\nNested source.\n"); var created = sync(f, "guides/start.md", USER); assert.equal(created.created, 1); assert.equal(created.failed, 0); var entry = find(f.importer().entries(), "file:guides/start.md"); assert.equal(entry.content, "# Start\nNested source.\n"); assert.equal(entry.source.relPath, "knowledge/guides/start.md"); fs.unlinkSync(target); var reconciled = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(reconciled.deleted, 1); assert.equal(find(f.importer().entries(), "file:guides/start.md"), null); }); test("an emptied knowledge file becomes a tombstone, not a blank record", function () { var f = fixture("empty"); write(path.join(f.knowledge, "notes.md"), "content\n"); sync(f, "notes.md", USER); write(path.join(f.knowledge, "notes.md"), " \n"); var summary = sync(f, "notes.md", USER); assert.equal(summary.empty, 1); assert.equal(summary.deleted, 1); assert.equal(find(f.importer().entries(), "file:notes.md"), null); }); test("journal appends mirror through and repeated sync is idempotent", function () { var f = fixture("journal"); var journal = path.join(f.knowledge, "session-digests.jsonl"); write(journal, digest("first") + "\n"); assert.equal(sync(f, "session-digests.jsonl", AGENT).created, 1); fs.appendFileSync(journal, digest("second") + "\n"); var second = sync(f, "session-digests.jsonl", AGENT); assert.equal(second.created, 1); assert.equal(second.unchanged, 1); var before = f.importer().stats().records; assert.equal(sync(f, "session-digests.jsonl", AGENT).unchanged, 2); assert.equal(f.importer().stats().records, before); var entries = f.importer().entries(); assert.equal(entries.length, 2); assert.equal(entries[0].kind, "session-digest"); assert.equal(entries[0].actor.type, "agent"); assert.equal(entries[0].actor.vendor, "claude"); }); test("digest deletion reconciles: the removed line is tombstoned, the rest stay live", function () { var f = fixture("delete"); var journal = path.join(f.knowledge, "session-digests.jsonl"); write(journal, digest("keep-one") + "\n" + digest("remove-me") + "\n" + digest("keep-two") + "\n"); sync(f, "session-digests.jsonl", AGENT); assert.equal(f.importer().entries().length, 3); var removedKey = mateSync.journalKey("session-digests.jsonl", knowledgeImport.contentHash(digest("remove-me"))); // Exactly what handleMemoryDelete does: splice the line and rewrite the file. var lines = fs.readFileSync(journal, "utf8").trim().split("\n"); lines.splice(1, 1); fs.writeFileSync(journal, lines.join("\n") + "\n"); var summary = sync(f, "session-digests.jsonl", USER); assert.equal(summary.deleted, 1, "the vanished line is tombstoned"); assert.equal(summary.unchanged, 2, "surviving lines are untouched"); assert.equal(summary.created, 0); var live = f.importer().entries(); assert.equal(live.length, 2); assert.equal(find(live, removedKey), null, "a deleted memory is not left active"); var tombstoned = find(f.importer().entries({ includeDeleted: true }), removedKey); assert.equal(tombstoned.deleted, true); assert.equal(tombstoned.actor.type, "agent", "original authorship is preserved"); assert.equal(tombstoned.deletedBy.type, "user", "the deletion records who caused it"); assert.equal(tombstoned.deletedBy.userId, "u1"); assert.ok(tombstoned.deletedAt > 0); // Reconciling again changes nothing. var repeat = sync(f, "session-digests.jsonl", USER); assert.equal(repeat.deleted, 0); assert.equal(repeat["already-deleted"], 0); assert.equal(f.importer().entries().length, 2); // Emptying the journal entirely tombstones everything that remained. fs.unlinkSync(journal); var cleared = sync(f, "session-digests.jsonl", USER); assert.equal(cleared.deleted, 2); assert.equal(f.importer().entries().length, 0); }); test("large sources are stored losslessly as chunks and reassemble exactly", function () { var f = fixture("chunks"); // Deliberately larger than one record, with multibyte and escape-heavy text. var body = ""; for (var i = 0; i < 4000; i++) body += "line " + i + " éü\"\\\t ends\n"; assert.ok(body.length > knowledgeImport.MAX_CONTENT_CHARS * 3); write(path.join(f.knowledge, "big.md"), body); var summary = sync(f, "big.md", USER); assert.equal(summary.created, 1); assert.equal(summary.chunked, 1); assert.equal(summary.failed, 0, "a large source must not be reported as failed"); var importer = f.importer(); var entry = find(importer.entries(), "file:big.md"); assert.equal(entry.chunked, true); assert.ok(entry.chunkCount > 3); assert.equal(entry.content, "", "no partial content masquerades as the whole source"); var read = importer.readContent(entry); assert.equal(read.complete, true); assert.equal(read.content, body, "reassembly is byte-exact"); assert.equal(knowledgeImport.contentHash(read.content), entry.contentHash); // Chunk records never surface as knowledge entries. assert.equal(importer.entries().length, 1); assert.ok(importer.entries({ includeChunks: true }).length > 4); assert.ok(importer.stats().chunks > 3); // Idempotent, and a revision re-chunks correctly. assert.equal(sync(f, "big.md", USER).unchanged, 1); write(path.join(f.knowledge, "big.md"), body + "one more line\n"); assert.equal(sync(f, "big.md", USER).revised, 1); var revised = find(f.importer().entries(), "file:big.md"); assert.equal(f.importer().readContent(revised).content, body + "one more line\n"); // Shrinking back below the chunk threshold returns to inline content. write(path.join(f.knowledge, "big.md"), "small again\n"); sync(f, "big.md", USER); var small = find(f.importer().entries(), "file:big.md"); assert.equal(small.chunked, false); assert.equal(f.importer().readContent(small).content, "small again\n"); }); test("NUL and multibyte Unicode survive a chunked round trip exactly", function () { var f = fixture("nul"); var NUL = String.fromCharCode(0); // Larger than one chunk, and deliberately hostile: NUL (which JSON escapes // rather than carries literally), astral-plane characters whose UTF-16 // surrogate pairs can straddle a chunk boundary, combining marks, and every // C0 control character. var controls = ""; for (var c = 0; c < 32; c++) controls += String.fromCharCode(c); var body = ""; for (var i = 0; i < 900; i++) { body += "line " + i + " " + NUL + " ünïcode 漢字 🎉 é " + controls + " \\ \" \t end\n"; } assert.ok(body.length > knowledgeImport.CHUNK_CHARS * 2, "the source must span several chunks"); assert.ok(body.indexOf(NUL) !== -1); write(path.join(f.knowledge, "hostile.md"), body); var summary = sync(f, "hostile.md", USER); assert.equal(summary.created, 1); assert.equal(summary.chunked, 1); assert.equal(summary.failed, 0, "a representable source must never be reported as failed"); assert.deepEqual(summary.errors, []); var importer = f.importer(); var entry = find(importer.entries(), "file:hostile.md"); assert.equal(entry.chunked, true); var read = importer.readContent(entry); assert.equal(read.complete, true); assert.equal(read.content, body, "reassembly is character-exact"); assert.equal(read.content.length, body.length); assert.equal(Buffer.byteLength(read.content, "utf8"), Buffer.byteLength(body, "utf8")); assert.equal(read.content.indexOf(NUL), body.indexOf(NUL), "NUL is preserved, not stripped"); assert.equal(knowledgeImport.contentHash(read.content), entry.contentHash); // Force a chunk boundary to fall inside a surrogate pair. var split = new Array(knowledgeImport.CHUNK_CHARS).join("a") + "🎉" + new Array(knowledgeImport.CHUNK_CHARS).join("b"); var high = split.charCodeAt(knowledgeImport.CHUNK_CHARS - 1); var low = split.charCodeAt(knowledgeImport.CHUNK_CHARS); assert.ok(high >= 0xd800 && high <= 0xdbff, "the chunk boundary lands on a high surrogate"); assert.ok(low >= 0xdc00 && low <= 0xdfff, "the next chunk starts with its low surrogate"); assert.deepEqual(knowledgeImport.splitChunks(split).length, 2); write(path.join(f.knowledge, "surrogate.md"), split); var surrogateSummary = sync(f, "surrogate.md", USER); assert.equal(surrogateSummary.failed, 0); var surrogate = find(f.importer().entries(), "file:surrogate.md"); assert.equal(f.importer().readContent(surrogate).content, split, "a split surrogate pair reassembles"); // A NUL-bearing journal line, which is line-addressed rather than file-addressed. var line = JSON.stringify({ date: "2026-07-01", topic: "nul" + NUL + "topic", body: "漢字 🎉 " + new Array(20000).join("q") }); write(path.join(f.knowledge, "session-digests.jsonl"), line + "\n"); var journalSummary = sync(f, "session-digests.jsonl", AGENT); assert.equal(journalSummary.created, 1); assert.equal(journalSummary.chunked, 1); assert.equal(journalSummary.failed, 0); var journalEntry = f.importer().entries().filter(function (e) { return e.kind === "session-digest"; })[0]; var journalRead = f.importer().readContent(journalEntry); assert.equal(journalRead.complete, true); assert.equal(journalRead.content, line); assert.equal(JSON.parse(journalRead.content).topic, "nul" + NUL + "topic", "NUL survives into the parsed record"); // Idempotent: the same hostile source imports nothing on a second pass. var before = f.importer().stats().records; var repeat = sync(f, "hostile.md", USER); assert.equal(repeat.unchanged, 1); assert.equal(repeat.failed, 0); assert.equal(sync(f, "session-digests.jsonl", AGENT).unchanged, 1); assert.equal(f.importer().stats().records, before, "no record is appended for unchanged hostile content"); }); test("stored content always verifies against its own hash, chunked or inline", function () { var f = fixture("hash-invariant"); var NUL = String.fromCharCode(0); write(path.join(f.knowledge, "small.md"), "inline " + NUL + " 漢字\n"); write(path.join(f.knowledge, "session-digests.jsonl"), JSON.stringify({ date: "2026-07-02", t: NUL }) + "\n"); var summary = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: USER }); assert.equal(summary.failed, 0); var importer = f.importer(); var entries = importer.entries({ includeChunks: true }); assert.ok(entries.length >= 2); for (var i = 0; i < entries.length; i++) { var entry = entries[i]; var read = importer.readContent(entry); assert.equal(read.complete, true, entry.importKey + " must verify"); // The stored content hash is derived from what was written, never from a // fingerprint the caller supplied. if (!entry.chunked) { assert.equal(knowledgeImport.contentHash(entry.content), entry.contentHash, entry.importKey); } assert.equal(knowledgeImport.contentHash(read.content), entry.contentHash, entry.importKey); } var inline = find(importer.entries(), "file:small.md"); assert.equal(inline.chunked, false); assert.equal(importer.readContent(inline).content, "inline " + NUL + " 漢字\n"); // A corrupted inline record is caught rather than returned as complete. assert.equal(importer.readContent({ importKey: "x", chunked: false, content: "tampered", contentHash: "deadbeef" }).complete, false); }); test("a missing chunk is reported, never returned as partial content", function () { var f = fixture("torn-chunk"); var body = new Array(30000).join("x"); write(path.join(f.knowledge, "big.md"), body); sync(f, "big.md", USER); var importer = f.importer(); var entry = find(importer.entries(), "file:big.md"); assert.equal(importer.readContent(entry).complete, true); // Tombstone one chunk behind the reader's back. importer.removeRecord(knowledgeImport.chunkKey("file:big.md", 1), { actor: { type: "system" } }); var broken = knowledgeImport.createKnowledgeImporter({ scopeId: f.scope.scopeId, baseDir: f.baseDir }); var read = broken.readContent(find(broken.entries(), "file:big.md")); assert.equal(read.complete, false); assert.equal(read.content, "", "no partial string is ever handed back"); assert.equal(read.reason, "missing-chunk"); }); test("provenance is relative and carries no absolute filesystem path", function () { var f = fixture("provenance"); write(path.join(f.knowledge, "notes.md"), "content\n"); write(path.join(f.knowledge, "session-digests.jsonl"), digest("topic") + "\n"); sync(f, "notes.md", USER); sync(f, "session-digests.jsonl", AGENT); var entries = f.importer().entries({ includeChunks: true, includeDeleted: true }); assert.ok(entries.length >= 2); for (var i = 0; i < entries.length; i++) { var source = entries[i].source; if (!source) continue; assert.equal(source.path, undefined, "no absolute path key is persisted"); var serialized = JSON.stringify(source); assert.equal(serialized.indexOf(f.home), -1, "no filesystem prefix leaks into provenance"); assert.equal(serialized.indexOf(os.tmpdir()), -1); } var file = find(entries, "file:notes.md"); assert.equal(file.source.relPath, "knowledge/notes.md"); assert.equal(file.source.fileName, "notes.md"); assert.equal(file.source.mateId, "mate_sync"); assert.equal(file.source.namespace, "mate-knowledge"); assert.ok(file.source.ownerKey); var journalEntry = f.importer().entries().filter(function (e) { return e.kind === "session-digest"; })[0]; assert.equal(journalEntry.source.relPath, "knowledge/session-digests.jsonl"); assert.equal(journalEntry.source.sourceDate, "2026-04-09"); assert.equal(typeof journalEntry.source.lineIndex, "number"); }); test("identity and sticky notes are never mirrored", function () { var f = fixture("excluded"); write(path.join(f.knowledge, "sticky-notes.md"), "- a note\n"); write(path.join(f.knowledge, "base-template.md"), "# template\n"); write(path.join(f.knowledge, "identity-backup.md"), "# identity\n"); write(path.join(f.knowledge, "identity-history.jsonl"), JSON.stringify({ at: 1 }) + "\n"); assert.equal(sync(f, "sticky-notes.md", USER).excluded, 1); assert.equal(sync(f, "base-template.md", USER).identitySkipped, 1); assert.equal(sync(f, "identity-backup.md", USER).identitySkipped, 1); assert.equal(sync(f, "identity-history.jsonl", USER).identitySkipped, 1); assert.equal(mateSync.sourceKindFor("sticky-notes.md"), null); var reconciled = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: USER }); assert.equal(reconciled.created, 0); assert.equal(reconciled.excluded, 1); assert.equal(reconciled.identitySkipped, 3); assert.equal(f.importer().entries({ includeDeleted: true, includeChunks: true }).length, 0); }); test("a file deleted while the daemon was stopped is tombstoned at startup", function () { var f = fixture("absent-file"); write(path.join(f.knowledge, "keep.md"), "still here\n"); write(path.join(f.knowledge, "gone.md"), "will be removed\n"); write(path.join(f.knowledge, "session-digests.jsonl"), digest("a digest") + "\n"); var first = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: AGENT }); assert.equal(first.created, 3); assert.equal(f.importer().entries().length, 3); // Deleted by direct filesystem tooling, with no sync call for it. fs.unlinkSync(path.join(f.knowledge, "gone.md")); var restart = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(restart.deleted, 1, "the absent source is discovered from its own records"); assert.equal(restart.unchanged, 2, "sources still on disk are untouched"); assert.equal(restart.created, 0); var live = f.importer().entries(); assert.equal(live.length, 2); assert.equal(find(live, "file:gone.md"), null, "no stale live record remains"); assert.ok(find(live, "file:keep.md")); // History is retained, with the removal attributed. var tombstoned = find(f.importer().entries({ includeDeleted: true }), "file:gone.md"); assert.equal(tombstoned.deleted, true); assert.equal(tombstoned.content, "will be removed\n", "the last known content is still readable"); assert.equal(tombstoned.deletedBy.type, "system"); assert.ok(tombstoned.revisions >= 2); // A second startup changes nothing. var before = f.importer().stats().records; var second = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(second.deleted, 0); assert.equal(second.unchanged, 2); assert.equal(f.importer().stats().records, before, "an idempotent restart appends nothing"); assert.equal(f.importer().entries().length, 2); }); test("a whole journal deleted while the daemon was stopped tombstones every line", function () { var f = fixture("absent-journal"); var journal = path.join(f.knowledge, "session-digests.jsonl"); write(journal, digest("one") + "\n" + digest("two") + "\n" + digest("three") + "\n"); write(path.join(f.knowledge, "user-observations.jsonl"), JSON.stringify({ date: "2026-04-01", note: "keep me" }) + "\n"); write(path.join(f.knowledge, "notes.md"), "unrelated\n"); var first = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: AGENT }); assert.equal(first.created, 5); fs.unlinkSync(journal); var restart = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(restart.deleted, 3, "every line of the missing journal is tombstoned"); assert.equal(restart.unchanged, 2, "the other journal and the markdown file are untouched"); var live = f.importer().entries(); assert.equal(live.length, 2); assert.equal(live.filter(function (e) { return e.kind === "session-digest"; }).length, 0); assert.equal(live.filter(function (e) { return e.kind === "user-observation"; }).length, 1); assert.ok(find(live, "file:notes.md")); var withDeleted = f.importer().entries({ includeDeleted: true }); assert.equal(withDeleted.filter(function (e) { return e.kind === "session-digest"; }).length, 3, "history is retained"); var before = f.importer().stats().records; var second = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(second.deleted, 0); assert.equal(f.importer().stats().records, before); // Restoring the journal revives the lines rather than duplicating them. write(journal, digest("one") + "\n"); var restored = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: AGENT }); assert.equal(restored.revived, 1); assert.equal(restored.created, 0); assert.equal(f.importer().entries().filter(function (e) { return e.kind === "session-digest"; }).length, 1); }); test("absent-source reconciliation ignores records from other namespaces and versions", function () { var f = fixture("namespaces"); write(path.join(f.knowledge, "mine.md"), "mine\n"); mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: AGENT }); // Records that this module must never reconcile, all naming files that do // not exist on disk. var importer = f.importer(); importer.importRecord({ importKey: "logs:some-entry", kind: "decision", name: "elsewhere.md", content: "other subsystem", source: { namespace: "project-logs", sourceVersion: 1, relPath: "knowledge/elsewhere.md", fileName: "elsewhere.md" }, }); importer.importRecord({ importKey: "file:future.md", kind: "knowledge-file", name: "future.md", content: "from a newer build", source: { namespace: mateSync.SOURCE_NAMESPACE, sourceVersion: mateSync.SOURCE_VERSION + 1, relPath: "knowledge/future.md", fileName: "future.md" }, }); importer.importRecord({ importKey: "file:mismatched.md", kind: "knowledge-file", name: "mismatched.md", content: "inconsistent provenance", source: { namespace: mateSync.SOURCE_NAMESPACE, sourceVersion: mateSync.SOURCE_VERSION, relPath: "somewhere/else.md", fileName: "mismatched.md" }, }); importer.importRecord({ importKey: "file:traversal.md", kind: "knowledge-file", name: "traversal.md", content: "unsafe name", source: { namespace: mateSync.SOURCE_NAMESPACE, sourceVersion: mateSync.SOURCE_VERSION, relPath: "knowledge/../escape.md", fileName: "../escape.md" }, }); assert.equal(mateSync.isMateSourceEntry(find(f.importer().entries(), "logs:some-entry")), false); assert.equal(mateSync.isMateSourceEntry(find(f.importer().entries(), "file:future.md")), false); assert.equal(mateSync.isMateSourceEntry(find(f.importer().entries(), "file:mismatched.md")), false); assert.equal(mateSync.isMateSourceEntry(find(f.importer().entries(), "file:traversal.md")), false); assert.equal(mateSync.isMateSourceEntry(find(f.importer().entries(), "file:mine.md")), true); var before = f.importer().entries().length; var restart = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(restart.deleted, 0, "foreign and future records are never tombstoned"); assert.equal(f.importer().entries().length, before, "every foreign record is still live"); assert.ok(find(f.importer().entries(), "logs:some-entry")); assert.ok(find(f.importer().entries(), "file:future.md")); assert.ok(find(f.importer().entries(), "file:mismatched.md")); assert.ok(find(f.importer().entries(), "file:traversal.md")); // The module's own record is still reconciled normally alongside them. fs.unlinkSync(path.join(f.knowledge, "mine.md")); var afterDelete = mateSync.reconcileMate({ mateDir: f.mateDir, baseDir: f.baseDir, actor: { type: "system" } }); assert.equal(afterDelete.deleted, 1); assert.equal(find(f.importer().entries(), "file:mine.md"), null); assert.ok(find(f.importer().entries(), "file:future.md"), "a future-version record is still untouched"); }); test("a journal line from another namespace is not tombstoned by journal reconciliation", function () { var f = fixture("journal-namespace"); var journal = path.join(f.knowledge, "session-digests.jsonl"); write(journal, digest("mine") + "\n"); sync(f, "session-digests.jsonl", AGENT); var importer = f.importer(); importer.importRecord({ importKey: "journal:session-digests.jsonl:foreignkey000000000000", kind: "session-digest", name: "session-digests.jsonl", content: "{\"foreign\":true}", source: { namespace: "some-other-subsystem", sourceVersion: 1, relPath: "knowledge/session-digests.jsonl", fileName: "session-digests.jsonl" }, }); // Emptying the journal must tombstone only this module's own line. fs.unlinkSync(journal); var summary = sync(f, "session-digests.jsonl", { type: "system" }); assert.equal(summary.deleted, 1, "only the record this module imported is tombstoned"); var live = f.importer().entries(); assert.equal(live.length, 1); assert.equal(live[0].importKey, "journal:session-digests.jsonl:foreignkey000000000000"); }); test("sync is quiet and safe on bad input", function () { var f = fixture("safe"); var absent = sync(f, "missing.md", USER); assert.equal(absent.deleted, 0, "a source that was never mirrored needs no tombstone"); assert.equal(absent.absent, 1); assert.equal(sync(f, "notes.txt", USER).unsupported, 1); assert.equal(sync(f, "", USER).failed, 0); assert.equal(mateSync.syncMateSource({ mateDir: path.join(f.home, "not-a-mate"), fileName: "a.md" }).failed, 0); // A path-traversal file name is reduced to its basename before use. write(path.join(f.knowledge, "safe.md"), "ok\n"); var traversal = mateSync.syncMateSource({ mateDir: f.mateDir, fileName: "../../../etc/passwd", baseDir: f.baseDir, actor: USER, }); assert.equal(traversal.created, 0); assert.equal(traversal.unsupported, 1); // A malformed journal line is counted, not fatal. write(path.join(f.knowledge, "session-digests.jsonl"), digest("good") + "\nnot json\n[1,2]\n"); var summary = sync(f, "session-digests.jsonl", AGENT); assert.equal(summary.malformedLines, 2); assert.equal(summary.created, 1); assert.equal(summary.failed, 0); assert.doesNotThrow(function () { mateSync.syncQuietly({ mateDir: null, fileName: "a.md" }); }); }); test("scope derivation agrees between layouts and isolates users", function () { var home = tmp("scopes"); var flat = path.join(home, "mates", "mate_x"); var userOne = path.join(home, "mates", "user-one", "mate_x"); fs.mkdirSync(flat, { recursive: true }); fs.mkdirSync(userOne, { recursive: true }); var flatScope = mateSync.scopeForMateDir(flat); var userScope = mateSync.scopeForMateDir(userOne); assert.notEqual(flatScope.scopeId, userScope.scopeId, "identical Mate ids under different roots do not collide"); assert.equal(flatScope.mateId, "mate_x"); assert.equal(userScope.mateId, "mate_x"); // Derivation is a pure function of the path, so the importer and the bridge // always agree without sharing context. assert.equal(mateSync.scopeForMateDir(flat).scopeId, flatScope.scopeId); assert.equal(mateSync.scopeForMateDir(flat + path.sep).scopeId, flatScope.scopeId); assert.equal(mateSync.scopeForMateDir(path.join(home, "mates", "not-a-mate")), null); });