79 lines
3.8 KiB
JavaScript
79 lines
3.8 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("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"));
|
|||
|
|
});
|