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,119 @@
# 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":
```json
{
"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.