Lumen/SPIKE-06-EMERGENCY-BASELINE.md
Lumen Stage1 c0bfd413ff 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
2026-08-30 23:25:35 -05:00

5.6 KiB
Raw Permalink Blame History

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.