Checkpoint: current Lumen state
Some checks failed
ci / check (push) Has been cancelled

This commit is contained in:
Lumen Stage1 2026-09-23 18:58:21 -05:00
commit fcc18ddcc8
96 changed files with 8074 additions and 214 deletions

56
pipeline/emergency.ts Normal file
View file

@ -0,0 +1,56 @@
/**
* Emergency unified derivation — floor + dataset section from same source sheet.
* Ensures no drift (ARCH 10.3, ARCH 13.1).
* Trace: ADR-007, SPIKE-06, IMPLEMENTATION-CONTRACT.md §14, ARCHITECTURE-DESIGN.md:345, §10.3
*/
import type { EmergencySource } from "./types.js";
import type { EmergencyFloor } from "../src/emergency-baseline/types.js";
import { FLOOR_SIZE_BUDGET } from "../src/emergency-baseline/types.js";
import { canonicalJson } from "./canonical-json.js";
import { sha256HexOfString } from "./hash.js";
import { checkFloorSize } from "./budgets.js";
export function deriveEmergencyFloor(
source: EmergencySource,
opts: { floorVersion: string; generatedAt: string },
): { floor: EmergencyFloor; bytes: number; sha256: string } {
// Summaries per ARCH 13.1 T1 floor contents — derive from same source
const floor: EmergencyFloor = {
floor: true,
floorVersion: opts.floorVersion,
emergencySchemaVersion: source.emergencySchemaVersion,
generatedAt: opts.generatedAt,
sourceContentVersion: source.contentVersion,
services: source.services,
address: source.address,
musterPoints: source.locations.musterPoints.map((m) => ({ name: m.name })),
exits: source.locations.exits.map((e) => ({ name: e.name })),
aedSummary:
source.locations.aeds.length > 0
? `AEDs: ${source.locations.aeds.length} locations`
: "AED on site",
procedures: source.procedures.map((p) => ({ id: p.id, title: p.title, steps: [...p.steps] })),
};
const json = canonicalJson(floor);
const bytes = new TextEncoder().encode(json).length;
const check = checkFloorSize(bytes);
if (!check.ok) throw new Error(check.reason);
if (bytes > FLOOR_SIZE_BUDGET) throw new Error(`floor exceeds 16KB budget: ${bytes}`);
const sha256 = sha256HexOfString(json);
return { floor, bytes, sha256 };
}
export function validateEmergencySource(
source: EmergencySource,
): { ok: true } | { ok: false; reason: string } {
if (!source) return { ok: false, reason: "emergency source missing" };
if (!Number.isInteger(source.emergencySchemaVersion) || source.emergencySchemaVersion < 1)
return { ok: false, reason: "emergencySchemaVersion must be integer >=1" };
if (!Number.isInteger(source.contentVersion) || source.contentVersion < 1)
return { ok: false, reason: "contentVersion must be integer >=1" };
if (typeof source.updatedAt !== "string" || Number.isNaN(Date.parse(source.updatedAt)))
return { ok: false, reason: "updatedAt must be ISO8601" };
if (source.section !== "emergency") return { ok: false, reason: "section must be emergency" };
// services/address/procedures presence checked via runtime validation in gates; keep light here
return { ok: true };
}