- 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
5.6 KiB
SPIKE-06 — Emergency Baseline Architecture
- Phase: Architecture Validation
- Date: 2026-08-30
- Decision under test: ADR-007 (three-tier emergency architecture with an embedded floor).
- Outcome: decision confirmed; tier contents fixed; version/compatibility matrix resolved; one hardening rule added.
1. What belongs in each tier (fixed)
Tier 1 — Emergency Floor (embedded in app shell, immutable per build)
Must fit ≤ 16 KB and cover "what saves a life or prevents panic in the first minutes":
{
"floor": true,
"floorVersion": "1.0.0+2026.08.20",
"emergencySchemaVersion": 1,
"generatedAt": "2026-08-20T12:00:00Z",
"sourceContentVersion": 5,
"services": {
"emergencyNumber": "911",
"security": { "phone": "+1-555-0142" },
"firstAid": { "summary": "Behind Stage B, 10:00–02:00" }
},
"address": { "lines": ["…"], "coordinates": { "lat": 41.88, "lon": -87.63 } },
"musterPoints": [ { "name": "North Field", "directions": "…" } ],
"exits": [ { "name": "East Gate" }, { "name": "West Gate" } ],
"aedSummary": "AEDs at Info Tent and Main Gate (see map when available)",
"procedures": [
{ "id": "medical", "title": "Medical emergency", "steps": ["Call 911", "Alert security: +1-555-0142", "…"] },
{ "id": "weather", "title": "Severe weather", "steps": ["…"] },
{ "id": "fire", "title": "Fire", "steps": ["…"] },
{ "id": "lost", "title": "Lost person", "steps": ["…"] }
]
}
Excluded from the floor (by policy): full POI lists, per-location detail, vendor/operational info, anything that changes frequently. The floor is a life-safety minimum, not a small copy of the dataset section.
Tier 2 — Festival Emergency Dataset (signed section of the package)
Full detail: all emergency-relevant POIs with map links, complete procedure
text, per-role contacts, hours, notices, contentVersion/updatedAt
(SPIKE-04 fragment). Updateable by publishing a new package version.
Tier 3 — Optional live emergency notices (future, reserved)
Shape reserved: { id, severity, title, body, publishedAtUtc, expiresAtUtc, signature }, delivered with a package or via the transport seam; rendered
only when signed and unexpired; display-only, additive, never a replacement
for Tier 1/2. Not implemented in V1.
2. Resolution rules (normative)
render_emergency():
floor = embedded floor # always exists; parses from frozen schema
section = active dataset emergency section
if section exists
and section.emergencySchemaVersion ∈ shell.supportedEmergencySchemas
and section passes integrity (already guaranteed by activation):
render section (full detail), labeled "FESTIVAL DATA v<package> · <generatedAt>"
render floor-only fields if section omits any (defensive merge)
else:
render floor, labeled "BASELINE v<floorVersion>"
append Tier-3 notices if any signed+unexpired (future)
Hardening rule (new, F-1): the floor renderer is forward-tolerant — it ignores unknown fields and never throws on dataset content; and the floor path must be reachable with zero IDB access, because BASELINE_ONLY and eviction scenarios must still render emergency info.
3. The cases the spike must answer
| Case | What renders | Why the floor never disappears |
|---|---|---|
| Shell old, dataset newer (section schema v2 vs floor/shell supports v1) | Floor + "update app when online" note; known-v1 fields of the section may still render if backward-compatible | Floor is compiled into the shell; dataset incompatibility can only demote to floor, never remove it |
| Shell new, dataset old | Dataset section (old schema is within shell's supported range) or floor | Backward range support (C-23) |
| Dataset unavailable (never prepared) | Floor | Floor ships with shell bytes |
| Dataset corrupt (verification fails at staging — never activated) | Previous dataset section if active slot intact, else floor | Corruption blocks activation (SPIKE-02); floor unaffected |
| Storage evicted | Floor | Floor is shell bytes, not IDB; Ring-0 survival |
| Network unavailable | Whatever is local: active dataset section or floor | No network call exists in the emergency render path |
| Update fails mid-flight | Old active dataset (or floor) | A/B invariant (SPIKE-02); staging never touches shell or active slot |
4. Tradeoffs (re-stated with verdicts)
- Baseline staleness (floor frozen at shell build): accepted. Mitigations: same-source generation (no drift), floor version stamp on screen, Tier 2 updates for anything less-than-critical, organizer physical channels for urgency.
- Baseline scope creep: resisted. 16 KB cap + content policy (life-safety minimum only). Everything else belongs in Tier 2.
- Two copies drift: eliminated by generating floor + section from the same emergency source sheet in the pipeline (ADR-007/§10.3).
- Separate localStorage copy of emergency data: rejected again — it dies in eviction too; only shell bytes survive everything.
5. Cross-checks
- SPIKE-05 C8 asserts floor presence in the readiness predicate (defense against a broken build silently dropping the floor).
- SPIKE-04 F-3 gives the emergency section independent versioning used by the resolution rules above.
- ADR-013: the floor's provenance is the shell build itself (signed app delivery); Tier 2 inherits package signatures; Tier 3 will require per-notice signatures.
6. Verdict
ACCEPT. ADR-007 stands unchanged in direction; addendum records the fixed tier contents, the resolution/merge rules, the forward-tolerant floor renderer (F-1), and the zero-IDB requirement for the floor path.