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

98
SPIKE-07-BOOTSTRAP.md Normal file
View file

@ -0,0 +1,98 @@
# SPIKE-07 — Installation & Bootstrap
- **Phase:** Architecture Validation
- **Date:** 2026-08-30
- **Decisions under test:** ADR-002 (installed-first PWA) and the bootstrap
design in ARCH §11/§12 (C-16, C-17).
- **Outcome:** confirmed; introduces explicit preparation levels (L0–L2) and
the Minimum Safe Experience definition.
## 1. Intended journey
```mermaid
flowchart TD
A["Discovery: QR / link / poster / word of mouth"] --> B["First visit (online): shell loads ~1 MB, SW registers"]
B --> C["Install coach (iOS manual steps; Android native prompt)"]
C --> D["Preparation: 'Get festival data'"]
D --> E["Data acquisition: pointer → manifest → sections (priority order) → assets; resumable"]
E --> F["Validation: signature → hashes → schema → atomic activation"]
F --> G["OFFLINE READY ✓ confirmation + status chip"]
G --> H["Festival use: everything offline; sync opportunistic when online"]
C -. skip/dismiss .-> D
E -. interrupted .-> P["PARTIAL state; resume later"]
P --> E
```
Stage persistence: after first visit the shell is cached (SW); after prep each
section is staged/committed independently; favorites persist from first
creation. No stage depends on completing later stages.
## 2. Preparation levels (new, normative)
| Level | Contents | Meaning | Chip state |
|---|---|---|---|
| **L0** | Shell + embedded emergency floor | "Emergency works, nothing else" | NOT_READY (or BASELINE_ONLY if storage blocked) |
| **L1 — Minimum Safe** | L0 + dataset `emergency` section + `schedule` section | Core festival survival: emergency detail + what's on when | PARTIAL → "core ready" note |
| **L2 — Full** | L1 + `map` + `info` + all required assets | Complete promise | READY |
Download order is exactly `emergency → schedule → info → map-base → assets`,
so an interrupted prep always yields the highest achievable level. The prep UI
names the levels ("Emergency ready", "Schedule ready", "Map ready") so users
always know what they have.
## 3. Failure-point analysis
| # | Failure | Architecture behavior | User experience |
|---|---|---|---|
| FP-1 | **User doesn't install** (esp. iOS tab) | Works while open; storage eviction risk after 7 days of tab inactivity (ITP); coach re-surfaces | Coach + honest note: "install to keep your festival data" |
| FP-2 | **User closes browser mid-prep** | Staged files + progress persist; nothing activated prematurely | Resume banner next open; prep continues where it stopped |
| FP-3 | **Internet lost during prep** | Downloads pause; partial staged data retained; app remains fully usable for installed levels | "Paused — you have Emergency + Schedule so far" |
| FP-4 | **Insufficient storage** | `storage.estimate()` pre-check refuses staging if free < 2× package; QuotaExceeded handled | Plain guidance: free space / reinstall; L0/L1 still possible if a full package can't fit — prep offers partial (sections only, skip heavy assets) as degraded option |
| FP-5 | **iOS install flow fails / user can't find Add to Home Screen** | Step-by-step coach with images; retry detection (still in tab after coach); fallback: continue in Safari with eviction warning | No dead end: app works in tab, warns about persistence |
| FP-6 | **User arrives unprepared** | App boots to whatever exists (L0 floor minimum); honest status; one-tap prep if any connectivity appears; organizer physical fallback for critical info | No blank screen; explicit "what's missing" list |
| FP-7 | **User clears browser data / uninstalls PWA** | Everything local is gone; floor returns only after shell reloads from network; RECOVERY state otherwise | Re-prep path; nothing to do offline except reload shell when online |
| FP-8 | **Private browsing session** | Storage probes fail early → BASELINE_ONLY mode with explanation; no crash, no fake READY | "Offline saving unavailable in this mode" + install/normal-mode guidance |
Additional adjudications:
- **Prep before install (iOS tab) is allowed** and valuable: data staged in tab
storage survives until eviction; install later preserves it (same origin).
The coach therefore offers "install first (recommended)" *and* "get data now".
- **First-visit ordering:** shell precache completes before prep is offered, so
L0 is guaranteed before any dataset work begins.
- **Leaving prep early is never punished:** no state is invalidated by
abandonment; the worst case is staying at the current level.
## 4. Minimum Safe Experience (normative)
For an attendee who **never completed offline preparation**, the app must
still provide, in this order of guarantees:
1. **Always (after any successful shell load):** the emergency floor — dial
action, address/coordinates, security contact, muster points, core
procedures (L0). This is Ring-0 and requires no storage.
2. **If any prep succeeded even partially:** whatever levels completed, each
fully functional (L1 core = emergency detail + schedule).
3. **Honest status at all times:** the chip and status screen state exactly
which levels are met and what to do about the rest.
4. **No feature silently pretends:** map/info screens for missing sections show
"not downloaded" cards with the prep action, not broken UI.
Product/ops corollary (cannot be solved by architecture alone): distribution
before arrival (OQ-3) and physical fallback info at the venue remain necessary
for the unprepared minority.
## 5. Cross-checks
- Readiness mapping: L0↔NOT_READY/BASELINE_ONLY, L1↔PARTIAL, L2↔READY
(SPIKE-05 taxonomy).
- Emergency floor independence from storage (SPIKE-06) makes L0 unconditional.
- Install-first persistence reality (SPIKE-01 §3.12) motivates the coach but
tab usage is never blocked.
## 6. Verdict
**ACCEPT WITH CHANGES.** Bootstrap architecture stands; changes: formal L0–L2
levels with the fixed download order, Minimum Safe Experience definition, and
the tab-install sequencing rule (allow prep before install). ADR-002 addendum
records the levels; no direction change.