Lumen/tests/unit/boundaries.test.ts
Lumen Stage1 fcc18ddcc8
Some checks failed
ci / check (push) Has been cancelled
Checkpoint: current Lumen state
2026-09-23 18:58:21 -05:00

108 lines
3.5 KiB
TypeScript

import { describe, it, expect } from "vitest";
import { readdirSync, existsSync } from "node:fs";
import { join } from "node:path";
function walkFiles(dir: string, exts = [".ts", ".js"]): string[] {
const out: string[] = [];
function walk(d: string) {
if (!existsSync(d)) return;
for (const e of readdirSync(d, { withFileTypes: true })) {
const p = join(d, e.name);
if (e.isDirectory()) walk(p);
else if (exts.some((ext) => p.endsWith(ext))) out.push(p);
}
}
walk(dir);
return out;
}
describe("architectural boundaries — Stage 1 gate (B-1…B-7)", () => {
it("src/ contains shell, verifier, and Stage 8 activation coordinator", () => {
const tsFiles = walkFiles("src", [".ts"]).sort();
// Stage 6 adds pipeline (canonical-json/hash/budgets/gates/manifest/package/sign/emergency/fixtures) on top of Stage 5 persistence
expect(tsFiles).toEqual(
expect.arrayContaining([
"src/app/layout.ts",
"src/app/main.ts",
"src/ui/router/router.ts",
"src/data/festival-package/types.ts",
"src/domain/clock/logic.ts",
"src/platform/idb/wrapper.ts",
"src/platform/idb/names.ts",
"src/data/system-meta/store.ts",
"src/data/slot/store.ts",
"src/data/user/store.ts",
"src/sync/verifier/ed25519.ts",
"src/sync/verifier/hash.ts",
"src/sync/verifier/types.ts",
"src/sync/activation.ts",
]),
);
const pipelineFiles = walkFiles("pipeline", [".ts"]).sort();
expect(pipelineFiles).toEqual(
expect.arrayContaining([
"pipeline/package.ts",
"pipeline/manifest.ts",
"pipeline/gates.ts",
"pipeline/hash.ts",
"pipeline/canonical-json.ts",
"pipeline/budgets.ts",
"pipeline/emergency.ts",
"pipeline/sign.ts",
]),
);
// Stage 9 adds only the byte transport seam; no later sync orchestration is present.
expect(tsFiles).toEqual(
expect.arrayContaining([
"src/sync/transport/types.ts",
"src/sync/transport/http.ts",
"src/sync/pull.ts",
]),
);
});
it("directory structure matches IMPLEMENTATION-CONTRACT.md §4", () => {
const requiredDirs = [
"src/platform/idb",
"src/platform/cache",
"src/platform/sw",
"src/storage",
"src/data",
"src/sync/transport",
"src/sync/verifier",
"src/domain/emergency",
"src/domain/schedule",
"src/domain/map",
"src/domain/festival",
"src/domain/readiness",
"src/domain/clock",
"src/domain/favorites",
"src/ui/components",
"src/ui/views",
"src/ui/router",
"src/ui/render",
"src/app",
"src/emergency-baseline",
"public",
"content",
"pipeline",
"tests/unit",
"tests/integration",
"tests/device-matrix",
];
for (const d of requiredDirs) expect(existsSync(d), `missing dir ${d}`).toBe(true);
});
it("forbidden v1 scope is not present (§2 — mesh/accounts/auth)", () => {
const allFiles = [...walkFiles("src"), ...walkFiles("tests")].join("\n");
expect(allFiles).not.toMatch(/mesh/i);
expect(allFiles).not.toMatch(/auth/i);
});
it("eslint boundaries config exists and lists B-1…B-7 elements", async () => {
// eslint check is via lint job; dynamic import of .js config has no types
// @ts-expect-error — no types for flat config
const cfg: unknown = await import("../../eslint.config.js");
expect(cfg).toBeDefined();
});
});