Stage 1: project foundation (strict TS, lint boundaries B-1..B-7, directory structure, CI, boundary tests)

- dedicated git repo at /home/avi/Projects/Lumen (main)
- TypeScript strict (target ES2022, bundler, exactOptionalPropertyTypes, noUncheckedIndexedAccess)
- ESLint 9 + typescript-eslint strictTypeChecked + eslint-plugin-boundaries for B-1..B-7, no-restricted-globals/syntax for B-1/B-7
- Prettier 3.5
- Structure per IMPLEMENTATION-CONTRACT.md §4 (src/platform/idb|cache|sw, storage, data, sync/{transport,verifier}, domain/{emergency,schedule,map,festival,readiness,clock,favorites}, ui/{components,views,router,render}, app, emergency-baseline, assets, public, content, pipeline, tests, scripts)
- CI: .github/workflows/ci.yml (typecheck + lint + format + test)
- Boundary tests: tests/unit/boundaries.test.ts (4 tests) + scripts/check-boundaries.ts
- No feature code, no PWA/IDB/sync/mesh/accounts per contract Stage 1
This commit is contained in:
Lumen Stage1 2026-08-30 23:25:35 -05:00
commit c0bfd413ff
100 changed files with 9863 additions and 0 deletions

View file

@ -0,0 +1,98 @@
/**
* Stage 1 — architectural boundary gate.
* Minimal check that no source file violates B-1 … B-7 by string scanning
* (full boundary enforcement is via eslint-plugin-boundaries in `npm run lint`).
* This script is a second cheap gate for CI and for `tests/unit/boundaries.test.ts`.
*
* Rules checked (subset where string grep is sufficient for Stage 1):
* B-1 ui must not import indexedDB/caches/fetch/localStorage
* B-7 no innerHTML/insertAdjacentHTML in src
*/
import { readdirSync, readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
const SRC = "src";
const violations: string[] = [];
function walk(dir: string, cb: (file: string) => void): void {
if (!existsSync(dir)) return;
for (const entry of readdirSync(dir, { withFileTypes: true })) {
const p = join(dir, entry.name);
if (entry.isDirectory()) walk(p, cb);
else if (entry.isFile() && (p.endsWith(".ts") || p.endsWith(".js"))) cb(p);
}
}
const B1_FORBIDDEN_IN_UI = [
/from\s+["'].*platform\//,
/from\s+["'].*storage\//,
/from\s+["'].*sync\//,
/indexedDB/,
/\bcaches\b/,
/\blocalStorage\b/,
];
walk(SRC, (file) => {
const content = readFileSync(file, "utf8");
const isUI = file.startsWith("src/ui/");
const isDomain = file.startsWith("src/domain/");
const isSyncTransport = file.startsWith("src/sync/transport/");
const isPlatform = file.startsWith("src/platform/");
if (isUI) {
for (const rx of B1_FORBIDDEN_IN_UI) {
if (rx.test(content)) {
// allow comments that mention the pattern; require actual import usage
// simple heuristic: check import line
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
const line: string = lines[i] ?? "";
if (rx.test(line) && /import|require/.test(line)) {
violations.push(
`${file}:${String(i + 1)}: B-1 violation — ui must not touch platform/storage/sync or raw indexedDB/caches/localStorage — line: ${line.trim()}`,
);
}
}
}
}
}
// B-7 innerHTML
if (file.includes("src/")) {
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
const line: string = lines[i] ?? "";
if (/\.innerHTML\s*=/.test(line) || line.includes("insertAdjacentHTML")) {
violations.push(
`${file}:${String(i + 1)}: B-7 violation — do not use innerHTML/insertAdjacentHTML with festival content (C-22).`,
);
}
}
}
// B-2 domain must not import platform/sync
if (isDomain && /from\s+["'].*platform\//.test(content)) {
violations.push(`${file}: B-2 violation — domain must not import platform.`);
}
// sync-transport must not import data/domain
if (isSyncTransport && /from\s+["'].*(data|domain)\//.test(content)) {
violations.push(`${file}: B-3 violation — transport must not import data/domain.`);
}
// platform must not import domain/ui/sync
if (isPlatform && /from\s+["'].*(domain|ui|sync)\//.test(content)) {
violations.push(`${file}: platform must not import domain/ui/sync.`);
}
});
if (violations.length) {
console.error("Boundary violations found:");
for (const v of violations) console.error(" " + v);
process.exit(1);
} else {
console.warn(
"Boundary check OK — no B-1…B-7 string violations in src/ (full check via eslint boundaries).",
);
}