Files
mnote/scripts/task539-local-agent-audit-scope-contract.js
lix-2026 9551d4c1dc feat(rag): harden post-LightRAG runtime
Retire legacy OCR/media/evidence fallbacks, add local-folder event bus and Page Aggregate guards, and archive completed design checklists.

Validation: cargo test -p mnote-web -- --test-threads=1; cargo test --workspace -- --test-threads=1; git diff --check; codegraph sync .; codegraph_status.
2026-06-07 10:35:21 +08:00

95 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
"use strict";
const assert = require("node:assert");
const fs = require("node:fs");
const path = require("node:path");
const { execFileSync } = require("node:child_process");
const ROOT = process.env.MNOTE_REPO_ROOT || "/mnt/Data1T/mnote";
const TASK535 = path.join(ROOT, "scripts", "task535-page-ai-local-agent-clean-edit-smoke.js");
const OUTPUT_DIR = path.join(ROOT, "tmp", "task539-local-agent-audit-scope-contract");
const RESULT_PATH = path.join(OUTPUT_DIR, "result.json");
function run(command, args, options = {}) {
return execFileSync(command, args, {
cwd: ROOT,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
...options,
});
}
function parseLastJsonObject(output) {
const trimmed = String(output || "").trim();
const start = trimmed.lastIndexOf("\n{");
const jsonText = start >= 0 ? trimmed.slice(start + 1) : trimmed;
return JSON.parse(jsonText);
}
function parseRunBody(task535Result) {
const runRecord = (task535Result.captured || []).find((item) => item.kind === "run");
assert(runRecord, "task535 result 缺少 run payload");
return JSON.parse(runRecord.body || "{}");
}
function main() {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
const task535Output = run("node", [TASK535]);
const task535Result = parseLastJsonObject(task535Output);
assert.equal(task535Result.ok, true, "task535 clean edit smoke 必须通过");
const runBody = parseRunBody(task535Result);
const allowedFiles = runBody.targetPackage?.allowedFiles || [];
assert.deepEqual(allowedFiles, [task535Result.relativePath], "targetPackage.allowedFiles 应只包含当前目标文件");
assert.equal(runBody.targetPackage?.currentFile?.relativePath, task535Result.relativePath, "currentFile 应冻结为当前目标文件");
assert.equal(runBody.runTargetSnapshot?.schema, "mnote.page_ai_run_target_snapshot.v1", "run payload 应携带 frozen target snapshot");
assert(runBody.runTargetSnapshot?.frozenAt, "frozen target snapshot 应有 frozenAt");
if (runBody.agentTargetPackage) {
assert.deepEqual(runBody.agentTargetPackage.allowedFiles || [], [task535Result.relativePath], "agentTargetPackage.allowedFiles 应只包含当前目标文件");
}
assert.equal(task535Result.usedDocumentsSave, false, "clean edit 不应调用 /api/documents/save");
assert.equal(task535Result.usedMarkdownEdit, false, "clean edit 不应调用 mnote.doc.markdown_edit");
assert.equal(task535Result.usedPageSave, false, "clean edit 不应调用 mnote.page.save");
const cargoOutput = run("cargo", ["test", "-p", "mnote-web", "local_agent_audit", "--", "--test-threads=1"], {
cwd: path.join(ROOT, "rust"),
});
assert(cargoOutput.includes("local_agent_audit_allowed_files_override_folder_context"), "cargo test 应覆盖 allowedFiles 优先于 folder context");
assert(cargoOutput.includes("local_agent_audit_reads_allowed_files_from_agent_run_envelope"), "cargo test 应覆盖 agentRunEnvelope.allowedFiles");
assert(cargoOutput.includes("local_agent_audit_event_carries_agent_run_receipt"), "cargo test 应覆盖 receipt auditScope");
const result = {
ok: true,
task: "task539-local-agent-audit-scope-contract",
task535: {
resultPath: path.join(ROOT, "tmp", "task535-page-ai-local-agent-clean-edit-smoke", "result.json"),
relativePath: task535Result.relativePath,
targetAllowedFiles: allowedFiles,
frozenAt: runBody.runTargetSnapshot.frozenAt,
usedDocumentsSave: task535Result.usedDocumentsSave,
usedMarkdownEdit: task535Result.usedMarkdownEdit,
usedPageSave: task535Result.usedPageSave,
},
backendAudit: {
command: "cargo test -p mnote-web local_agent_audit -- --test-threads=1",
expectedScope: "allowed_files",
expectedFileCount: 1,
},
};
fs.writeFileSync(RESULT_PATH, `${JSON.stringify(result, null, 2)}\n`, "utf8");
console.log(JSON.stringify(result, null, 2));
}
try {
main();
} catch (error) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
fs.writeFileSync(
path.join(OUTPUT_DIR, "failure.json"),
`${JSON.stringify({ ok: false, error: error.stack || error.message || String(error) }, null, 2)}\n`,
"utf8",
);
console.error(error.stack || error.message || String(error));
process.exit(1);
}