Files
stack/packages/business/tests/vars.test.mjs
T
jason.woltjeandClaude Opus 5.5 179697a8a3 bus: tester identity for PM tests (row 110, #1604)
A tester binds with a process proof from the bus's own tester-cli.mjs
when the business var bus.tester is true. It may send [mos test] messages
to a role, receive replies on the tester address and use the read verbs;
every other verb refuses. Messages store from_role tester and write no
human.input event. turnRequest() marks them as never Jason's instruction.
human.mjs is unchanged.

Candidate manifest bdaf7f476abd0b2b5095ab2f7f43e38540e6ba48ee14a02a4f4995a1469b79df
(Darkwing round 2, packet 9f1563ec1), BASE badfa52b9. Approved by Filbert
(comment 28360) and Sage (comment 28361). Sage gate rerun passed.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 20:43:40 -05:00

127 lines
7.2 KiB
JavaScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { BusinessError, LAYERS, REGISTRY, checkVars, mergeVars } from "../src/index.mjs";
function refuses(fn, pattern) {
assert.throws(fn, (error) => {
assert.ok(error instanceof BusinessError, `expected BusinessError, got ${error}`);
assert.equal(error.exitCode, 2);
assert.match(error.message, pattern);
return true;
});
}
test("every key names known layers and a merge rule", () => {
for (const [key, entry] of Object.entries(REGISTRY)) {
assert.ok(entry.layers.length > 0, key);
for (const layer of entry.layers) assert.ok(LAYERS.includes(layer), `${key}: ${layer}`);
assert.ok(["replace", "intersect"].includes(entry.merge), key);
if (entry.merge === "intersect") assert.ok(key.startsWith("limits."), key);
}
});
test("unknown keys and wrong layers refuse", () => {
refuses(() => checkVars({ colour: "blue" }, "business", "b.vars"), /b\.vars: unknown variable "colour"/);
refuses(() => checkVars({ harness: "pi" }, "business", "b.vars"), /can't be set at the business layer \(allowed: agent\)/);
refuses(() => checkVars({ "tracker.baseUrl": "http://x" }, "project", "p.vars"), /project layer/);
refuses(() => checkVars({ "tracker.project": 3 }, "agent", "a.vars"), /agent layer/);
refuses(() => checkVars({ dataRoot: "/x" }, "business", "b.vars"), /business layer/);
refuses(() => checkVars(["harness"], "agent", "a.vars"), /JSON object/);
refuses(() => checkVars({ constructor: 1 }, "agent", "a.vars"), /unknown variable "constructor"/);
assert.throws(() => checkVars({}, "fleet", "x"), /unknown layer/);
});
test("types", () => {
const ok = (vars, layer) => assert.deepEqual({ ...checkVars(vars, layer, "v") }, vars);
ok({ "tracker.baseUrl": "https://tasks.example:3456", "tracker.reconcileMinutes": 1, "tracker.pollSeconds": 10, "human.discordUserId": "123456789012345678", "bus.tester": true }, "business");
ok({ "tracker.project": 3, "git.workingBranch": "refactor", "git.protectedBranches": ["main", "next"], suites: ["scripts/test-task.sh"], "issues.repo": "mosaicstack/stack", "tracker.descendants": true }, "project");
ok({ harness: "claude-code", model: "claude-opus-5-5", thinking: "high", "limits.tools": [], "limits.network": "none", "limits.authority": ["message.send"] }, "agent");
const bad = [
[{ "tracker.baseUrl": "ftp://x" }, "business", /http or https/],
[{ "tracker.baseUrl": "https://x/" }, "business", /trailing slash/],
[{ "tracker.baseUrl": "https://u:p@x" }, "business", /no credentials/],
[{ "tracker.baseUrl": "https://x?a=1" }, "business", /query/],
[{ "tracker.baseUrl": "not a url" }, "business", /http or https URL/],
[{ "tracker.kind": "jira" }, "business", /one of: vikunja/],
[{ "tracker.pollSeconds": 9 }, "business", /at least 10/],
[{ "tracker.pollSeconds": "30" }, "project", /at least 10/],
[{ "tracker.reconcileMinutes": 0 }, "business", /at least 1/],
[{ "human.discordUserId": 123456789012345678 }, "business", /as a string/],
[{ "human.discordUserId": "0123456789012345678" }, "business", /Discord user id/],
[{ "tracker.project": 0 }, "project", /positive integer/],
[{ "tracker.descendants": "true" }, "project", /true or false/],
[{ "tracker.descendants": 1 }, "project", /true or false/],
[{ "tracker.descendants": true }, "business", /business layer \(allowed: project\)/],
[{ "bus.tester": "true" }, "business", /true or false/],
[{ "bus.tester": 1 }, "business", /true or false/],
[{ "bus.tester": true }, "project", /project layer \(allowed: business\)/],
[{ "bus.tester": true }, "agent", /agent layer \(allowed: business\)/],
[{ "bus.tester": true }, "system", /system layer \(allowed: business\)/],
[{ "git.workingBranch": "-x" }, "project", /git branch name/],
[{ "git.workingBranch": "a..b" }, "project", /git branch name/],
[{ "git.workingBranch": "x.lock" }, "project", /git branch name/],
[{ "git.workingBranch": "feat/" }, "project", /git branch name/],
[{ "git.protectedBranches": [] }, "project", /must not be empty/],
[{ "git.protectedBranches": ["main", "main"] }, "project", /duplicate/],
[{ suites: "scripts/test-task.sh" }, "project", /must be an array/],
[{ "issues.repo": "stack" }, "project", /owner\/name/],
[{ harness: "codex" }, "agent", /one of: pi, claude-code/],
[{ thinking: "max" }, "agent", /one of/],
[{ model: "" }, "agent", /non-empty string/],
[{ "limits.tools": ["render3d"] }, "agent", /unsupported tool/],
[{ "limits.network": "lan" }, "agent", /one of: none, api-only, open/],
[{ "limits.authority": ["deploy.prod"] }, "agent", /unknown action/],
];
for (const [vars, layer, pattern] of bad) refuses(() => checkVars(vars, layer, "v"), pattern);
});
test("merge: defaults, then the most specific layer wins", () => {
const { vars, provenance } = mergeVars([
{ layer: "business", source: "business", vars: checkVars({ "tracker.pollSeconds": 60 }, "business", "b") },
{ layer: "project", source: "project", vars: checkVars({ "tracker.pollSeconds": 20 }, "project", "p") },
]);
assert.equal(vars["tracker.pollSeconds"], 20);
assert.equal(provenance["tracker.pollSeconds"], "project");
assert.equal(vars["tracker.reconcileMinutes"], 60);
assert.equal(provenance["tracker.reconcileMinutes"], "default");
assert.equal(vars["tracker.kind"], "vikunja");
assert.equal(vars["tracker.descendants"], false);
assert.equal(provenance["tracker.descendants"], "default");
assert.equal(vars["bus.tester"], false);
assert.equal(provenance["bus.tester"], "default");
assert.equal(vars.harness, undefined);
assert.equal(provenance.harness, undefined);
});
test("merge: limits only narrow, and provenance lists each source", () => {
const layer = (source, layerName, v) => ({ layer: layerName, source, vars: checkVars(v, layerName, source) });
const { vars, provenance } = mergeVars([
layer("business", "business", { "limits.network": "none", "limits.tools": ["read", "grep", "bash"] }),
layer("project", "project", { "limits.network": "open", "limits.tools": ["read", "bash", "write"] }),
layer("agent", "agent", { "limits.tools": ["bash", "read", "edit"] }),
]);
assert.equal(vars["limits.network"], "none");
assert.deepEqual(provenance["limits.network"], ["business", "project"]);
assert.deepEqual(vars["limits.tools"], ["read", "bash"]);
assert.deepEqual(provenance["limits.tools"], ["business", "project", "agent"]);
const widen = mergeVars([
layer("business", "business", { "limits.authority": ["message.send"] }),
layer("agent", "agent", { "limits.authority": ["message.send", "task.close"] }),
]);
assert.deepEqual(widen.vars["limits.authority"], ["message.send"]);
const empty = mergeVars([layer("agent", "agent", { "limits.tools": [] })]);
assert.deepEqual(empty.vars["limits.tools"], []);
});
test("merge doesn't change its inputs", () => {
const business = checkVars({ "limits.tools": ["read", "bash"] }, "business", "b");
const snapshot = JSON.stringify(business);
mergeVars([
{ layer: "business", source: "business", vars: business },
{ layer: "agent", source: "agent", vars: checkVars({ "limits.tools": ["read"] }, "agent", "a") },
]);
assert.equal(JSON.stringify(business), snapshot);
});