Files
stack/packages/cli/tests/optional-tracker.test.mjs
jason.woltje a8d9eecf65 organization: move packages/business to packages/organization (rename r2 stage B1)
git mv packages/business -> packages/organization (@mosaic/organization). The
old package stays as one-line re-export shims of each moved module, with
src/business.mjs re-exporting src/organization-config.mjs and src/cli.mjs
forwarding to the moved executable. BusinessError is OrganizationConfigError
(one constructor, name kept BusinessError); OrganizationError stays distinct.
The bus adapter gains organization-context.mjs (busOrganization), with
business.mjs (busBusiness) as the same function.

Import consumers, manifests, the lockfile, scripts/mosaic, stack-copy.sh
COPY_PATHS (both roots), seat sandbox RUNNER_FILES and the copy closure
walker (organization-imports.mjs, both roots required) move to the new path.
v1 serialization, v1 writers and the stage A fixtures are unchanged; the stage
A contract tests stay where they were and pass as before.
2026-11-09 11:47:48 -06:00

73 lines
3.8 KiB
JavaScript

// Q247 / row 324 (#1820): no tracker adapter, credential registration or Console sync row.
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdirSync, readFileSync, rmSync } from "node:fs";
import { join } from "node:path";
import { bootConfig } from "../src/config.mjs";
import { startBroker } from "../../bus/src/runtime.mjs";
import { Client } from "../../bus/src/client.mjs";
import { loadBusiness } from "../../organization/src/index.mjs";
import { businessDoc, launchDoc, REPO_ROLES, systemConfig, tmp, writeJson } from "../../organization/tests/helpers.mjs";
import { businessView } from "../../webui/src/reads.mjs";
function fixture(t, { present = false } = {}) {
const root = tmp();
t.after(() => rmSync(root, { recursive: true, force: true }));
const doc = businessDoc(root);
// Credential-free roles, so an empty runtime credential list proves no phantom @sync entry.
doc.roles = {
chief: { definition: "chief-of-staff", vars: { harness: "claude-code", model: "claude-opus-5-5", thinking: "high" } },
assistant: { definition: "assistant", vars: { harness: "claude-code", model: "claude-opus-5-5", thinking: "high" } },
};
doc.arbiters = { delivery: "chief", technical: "chief" };
doc.launch = launchDoc("chief", ["assistant"]);
doc.plugins = { harness: ["claude-code"] };
// Deliberately retain fixture tracker.baseUrl; missing business tracker must still mean no sync.
if (!present) delete doc.tracker;
// No credential files remain, so boot cannot accidentally rely on the old fixture's sync token.
rmSync(join(root, "secrets"), { recursive: true });
writeJson(join(root, "project/.mosaic/project.json"), { projectVersion: 1, id: "stack", vars: { "tracker.project": 3 } });
const config = systemConfig(root);
const system = JSON.parse(readFileSync(config, "utf8"));
mkdirSync(system.dataRoot, { mode: 0o700 });
writeJson(join(root, "config/businesses/acme.json"), doc);
const env = { HOME: root, MOSAIC_CONFIG: config, MOSAIC_ROLES_DIR: REPO_ROLES };
return { root, doc, system, env, b: loadBusiness("acme", { dir: join(root, "config"), rolesDir: REPO_ROLES }) };
}
test("Q247: bootConfig omits tracker setup even with tracker variables left in the business", (t) => {
const x = fixture(t);
assert.ok(x.doc.vars["tracker.baseUrl"]);
const boot = bootConfig({ system: x.system, businessId: "acme", env: x.env });
assert.equal(boot.businesses.acme.tracker, null);
assert.equal(Object.hasOwn(boot, "trackers"), false);
});
test("Q247: trackerless business boots and registers no @sync credential", async (t) => {
const x = fixture(t);
const boot = bootConfig({ system: x.system, businessId: "acme", env: x.env });
const runtime = await startBroker(boot);
t.after(() => runtime.close());
assert.deepEqual(runtime.credentials.status(), []);
await assert.rejects(runtime.credentials.useFile("acme/@sync", "vikunja", () => assert.fail("no sync token may be used")),
(e) => e.code === "credential-unknown");
const reader = new Client({ path: runtime.path, cap: runtime.readers[0].cap });
assert.deepEqual(await reader.call("credentials"), []);
});
test("Q247: Console business read works with tracker absent and shows no sync credential", (t) => {
const x = fixture(t);
const view = businessView(x.b, { system: x.system });
assert.equal(view.id, "acme");
assert.deepEqual(view.credentials, []);
assert.deepEqual(view.instances.map((entry) => entry.instance), ["chief", "assistant"]);
});
test("Q247: a present tracker with a missing token still refuses bus boot", async (t) => {
const x = fixture(t, { present: true });
const boot = bootConfig({ system: x.system, businessId: "acme", env: x.env });
assert.equal(boot.businesses.acme.tracker.sync.bot, x.doc.tracker.sync.bot);
await assert.rejects(startBroker(boot), (e) => e.code === "credential-file");
});