85 lines
4.1 KiB
JavaScript
85 lines
4.1 KiB
JavaScript
import assert from "node:assert/strict";
|
||
import { execFileSync } from "node:child_process";
|
||
import fs from "node:fs";
|
||
import path from "node:path";
|
||
import test from "node:test";
|
||
import { fileURLToPath } from "node:url";
|
||
import { BOOTSTRAP_LIMIT_BYTES, bootstrap, readNode, route, verifyTree } from "./hldp-memory.mjs";
|
||
|
||
function validTree() {
|
||
return {
|
||
protocol: "HLDP-v1.0",
|
||
root: "root",
|
||
nodes: {
|
||
root: {
|
||
path: "root", summary: "总入口", trigger: "用户需要恢复", emergence: "长历史 → 根索引", lock: "按需展开", why: "避免全量加载",
|
||
children: ["root/protocol", "root/decision"], sources: ["source://root"], rejected: []
|
||
},
|
||
"root/protocol": {
|
||
path: "root/protocol", summary: "HLDP 协议与递归折叠", trigger: "需要解码", emergence: "摘要 → 因果树", lock: "使用v1", why: "保留为什么",
|
||
children: [], sources: ["hldp/HLDP-RUNTIME-ROOT-v1.0.hdlp"], rejected: ["每轮注入全文:会撑爆上下文"]
|
||
},
|
||
"root/decision": {
|
||
path: "root/decision", summary: "方案变化与最终决策", trigger: "出现三个方案", emergence: "A失败 → B不足 → C锁定", lock: "采用C | 失效=证据变化", why: "后续执行依赖转折",
|
||
children: [], sources: ["source://decision"], rejected: ["A:失败", "B:不足"]
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
test("validates a bounded causal tree", () => assert.deepEqual(verifyTree(validTree()), []));
|
||
|
||
test("rejects more than ten siblings and missing why", () => {
|
||
const tree = validTree();
|
||
tree.nodes.root.children = Array.from({ length: 11 }, (_, i) => `child-${i}`);
|
||
tree.nodes["root/protocol"].why = "";
|
||
tree.nodes["root/decision"].sources = [];
|
||
const errors = verifyTree(tree);
|
||
assert(errors.some((error) => error.includes("more than 10")));
|
||
assert(errors.some((error) => error.includes("missing why")));
|
||
assert(errors.some((error) => error.includes("sources must be a non-empty array")));
|
||
});
|
||
|
||
test("route returns paths and summaries only, capped at three", () => {
|
||
const candidates = route(validTree(), "最终决策 方案", 9);
|
||
assert.equal(candidates.length, 2);
|
||
assert.equal(candidates[0].path, "root/decision");
|
||
assert.deepEqual(Object.keys(candidates[0]).sort(), ["path", "score", "summary"]);
|
||
assert(!JSON.stringify(candidates).includes("A失败"));
|
||
});
|
||
|
||
test("route ranks a matching Chinese branch instead of treating a sentence as one token", () => {
|
||
const candidates = route(validTree(), "为什么最终方案发生变化", 3);
|
||
assert.equal(candidates[0].path, "root/decision");
|
||
assert(candidates[0].score > 0);
|
||
});
|
||
|
||
test("read-node reads exactly one bounded node", () => {
|
||
const node = readNode(validTree(), "root/decision");
|
||
assert.equal(node.path, "root/decision");
|
||
});
|
||
|
||
test("bootstrap is small and contains no memory body", () => {
|
||
const text = bootstrap("hldp/HLDP-RUNTIME-ROOT-v1.0.hdlp");
|
||
assert(Buffer.byteLength(text) <= BOOTSTRAP_LIMIT_BYTES);
|
||
assert(!text.includes("capsule"));
|
||
assert(!text.includes("session log"));
|
||
});
|
||
|
||
test("Codex hook emits context only for SessionStart", () => {
|
||
const script = fileURLToPath(new URL("./codex-session-bootstrap.mjs", import.meta.url));
|
||
const started = execFileSync(process.execPath, [script], { input: JSON.stringify({ hook_event_name: "SessionStart" }), encoding: "utf8" });
|
||
assert(JSON.parse(started).hookSpecificOutput.additionalContext);
|
||
const prompt = execFileSync(process.execPath, [script], { input: JSON.stringify({ hook_event_name: "UserPromptSubmit" }), encoding: "utf8" });
|
||
assert.equal(prompt, "");
|
||
});
|
||
|
||
test("repository routes HLDP to v1 root and marks v3 historical", () => {
|
||
const repo = path.resolve(fileURLToPath(new URL("../../", import.meta.url)));
|
||
const index = fs.readFileSync(path.join(repo, "INDEX.hdlp"), "utf8");
|
||
const tower = fs.readFileSync(path.join(repo, "BROADCAST-TOWER.hdlp"), "utf8");
|
||
const v3 = fs.readFileSync(path.join(repo, "hldp/HLDP-SPEC-v3.0-TECHNICAL.md"), "utf8");
|
||
assert(index.includes("hldp/HLDP-RUNTIME-ROOT-v1.0.hdlp"));
|
||
assert(tower.includes("先读 hldp/HLDP-RUNTIME-ROOT-v1.0.hdlp"));
|
||
assert(v3.includes("HISTORICAL-EVOLUTION-DRAFT"));
|
||
});
|