- 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
115 lines
7.1 KiB
Markdown
115 lines
7.1 KiB
Markdown
# SPIKE-05 — Offline Ready Model
|
||
|
||
- **Phase:** Architecture Validation
|
||
- **Date:** 2026-08-30
|
||
- **Decision under test:** the readiness state machine in ARCH §12 (R1–R7).
|
||
- **Outcome:** model confirmed; predicate formalized, tightened (time
|
||
independence, optional sections), and failure-state taxonomy completed.
|
||
|
||
## 1. What READY must actually guarantee
|
||
|
||
Deriving from the product promise ("everything attendees need works with zero
|
||
connectivity"), READY must guarantee, **from local evidence only**:
|
||
|
||
1. The app can launch and render without network (shell complete).
|
||
2. Emergency information is available (floor always; dataset section if present).
|
||
3. The schedule is browsable and Now/Next computable (schedule section present;
|
||
note: computable even with a wrong clock — a clock problem is a warning,
|
||
never a readiness failure).
|
||
4. The map is usable (map section + its required assets present).
|
||
5. Festival info is readable (info section present).
|
||
6. The dataset is authentic and untampered (signature + hashes verified).
|
||
7. The dataset is compatible with this shell (schema envelope).
|
||
8. The claim itself is evidenced (a stored verification record matching the
|
||
active version, not a memory of success).
|
||
|
||
## 2. The exact predicate (normative)
|
||
|
||
```
|
||
OFFLINE_READY ⟺
|
||
C1 shell_valid: every precache entry present in the current shell cache
|
||
∧ C2 dataset_present: active slot exists for the active edition
|
||
∧ C3 authenticity: manifest signature verified against embedded key set
|
||
(recorded verification matches active packageVersion)
|
||
∧ C4 integrity: all manifest-listed files present, sizes match;
|
||
hashes verified at staging (recorded), spot-check at boot
|
||
∧ C5 schema_compatible: package schemaVersion ∈ shell.supportedRange
|
||
∧ package.appCompatibility satisfied by APP_VERSION
|
||
∧ C6 required_sections: every section with required=true present and parseable:
|
||
{emergency, schedule, map, info, assets-inventory}
|
||
∧ C7 required_assets: every asset referenced by a required section present
|
||
(size-verified; hash verified at staging)
|
||
∧ C8 emergency_floor: embedded baseline present (trivially true; asserted
|
||
so a broken build cannot silently lose the floor)
|
||
```
|
||
|
||
**Rules of evaluation:**
|
||
|
||
- **Time independence (new, F-1):** the predicate must not consult any clock.
|
||
A device with a wildly wrong clock must still be able to know it is READY.
|
||
(No expiration fields exist in the package — SPIKE-04 F-2 — so nothing tempts
|
||
a time check.)
|
||
- **Optional sections never gate READY (new, F-2):** sections with
|
||
`required=false` (future announcements, i18n packs) report their own presence
|
||
in the status detail but cannot demote READY.
|
||
- **Evidence-based:** C3/C4 rely on the stored verification record (SPIKE-02
|
||
F-2) keyed to the active `packageVersion`; if the record is absent or
|
||
mismatched, a full re-verification is required before READY can be claimed.
|
||
- **All-or-nothing for READY; everything else is enumerated.**
|
||
|
||
## 3. State taxonomy (complete)
|
||
|
||
| State | Definition | User sees | Primary action offered |
|
||
|---|---|---|---|
|
||
| `READY` | C1–C8 all true | Green chip "OFFLINE READY ✓" | None (status detail on tap) |
|
||
| `PARTIAL(list)` | Shell valid; one or more required sections/assets missing, none corrupt; e.g., prep interrupted | Amber chip; status screen enumerates exactly what is missing and what still works | "Continue setup" (resumes staging) |
|
||
| `NOT_READY` | Shell valid; no dataset staged or active (fresh install) | Neutral chip "Get festival data" | Preparation flow |
|
||
| `RECOVERY(reason)` | Previously-verified state now fails checks: storage evicted (`missing`), verification mismatch (`corrupt`), incompatibility after app/dataset skew (`incompatible`) | Red chip; honest explanation of what happened | "Restore festival data" (re-prep; needs connectivity) — emergency floor works meanwhile |
|
||
| `BASELINE_ONLY` | Storage unavailable (private mode, blocked website data, quota 0) and app cannot persist anything | Distinct notice: offline saving unavailable; emergency info still here | Install / normal-mode / free-space guidance |
|
||
| `FAILED(op)` | A specific operation failed and no automatic recovery applied (activation transaction repeatedly failing, IDB errors) — distinct from RECOVERY because the *cause is an error, not missing data* | Error screen with plain cause + diagnostics entry | Retry; if persistent, re-prep; diagnostics share option |
|
||
|
||
Notes:
|
||
- The brief's example predicate listed `schedule_present`, `map_present`,
|
||
`festival_info_present`, `emergency_baseline_present` individually. This
|
||
model keeps them (C6/C8) but wraps them in the required-section mechanism so
|
||
future optional sections don't require predicate surgery.
|
||
- `FAILED` is the added state: RECOVERY means "data is gone/wrong"; FAILED
|
||
means "an operation errored". Keeping them separate keeps user messaging and
|
||
diagnostics accurate.
|
||
|
||
## 4. Evaluation cadence and cost
|
||
|
||
| When | What | Cost target |
|
||
|---|---|---|
|
||
| Every boot | Light check: C1 (cache list), C2 (slot existence), C4-light (sizes + verification-record match), C5 | ≤ ~150 ms; no hashing |
|
||
| After staging completes | Full: all hashes + schema (C3–C7 full) | Seconds; once per update |
|
||
| Activation | Record written atomically with the flip; readback spot-check (pending flag, SPIKE-02 F-3) | ms |
|
||
| User-initiated "Check my data" | Full re-verification | Seconds, with progress |
|
||
| After any IDB error | Full re-verify of active slot; quarantine on failure | Seconds |
|
||
|
||
## 5. Edge cases adjudicated
|
||
|
||
| Case | State | Why |
|
||
|---|---|---|
|
||
| Eviction between install and festival | RECOVERY(missing) | Light check finds no slot; floor still works |
|
||
| Verification record present but files gone | RECOVERY(missing) | Sizes check fails |
|
||
| Files present but record missing (e.g., partial restore) | PARTIAL → full re-verify path | READY cannot be claimed without evidence |
|
||
| New shell, dataset schema too old | RECOVERY(incompatible) with "update data when online" guidance; floor + status usable | C5 false |
|
||
| Wrong device clock | **READY unaffected**; separate clock warning (SPIKE-08) | Time independence |
|
||
| Optional announcements section missing | READY | F-2 |
|
||
| Private browsing, nothing persistable | BASELINE_ONLY | Storage probes fail early |
|
||
| Activation failed twice | FAILED(activation) | Distinct from data loss |
|
||
|
||
## 6. Cross-checks
|
||
|
||
- Consistent with SPIKE-02 (verification record + readback pending flag).
|
||
- Consistent with SPIKE-04 (`required` flag, no expiration).
|
||
- Consistent with SPIKE-06 (floor assertion C8; emergency never depends on READY).
|
||
- Consistent with SPIKE-07 (prep levels map onto PARTIAL/READY transitions).
|
||
|
||
## 7. Verdict
|
||
|
||
**ACCEPT (with formalization).** The ARCH §12 model was directionally correct;
|
||
it is now normative: predicate C1–C8, time independence, optional-section rule,
|
||
and the full six-state taxonomy including `FAILED`. Changes are refinements of
|
||
the design document, not a direction change; no ADR-level reversal.
|