Phase 8 — Product foundations + ORSA module (wave 1)¶
Status: Defined (exploration session 5, 2026-07-26); reframed showcase-first same day (owner direction) — build fast toward a defined Showcase; commercialization mechanics deferred until an external user exists. Ready for
/phase-split. Scope: the A2-sequenced track — foundations properly built, then the ORSA-shaped report module on top; no external gates between streams. Source decisions: exploration/02-personas.md (personas + product sequencing), exploration/04-answer-layer-rfc.md (ratified RFC, amendments A1/A2/A3), exploration/05-rat-convergence.md. Predecessor: Phase 6b (closed). Phase 7 remains parked pending re-cut — its adapter items return after the licensing verdict; nothing in Phase 8 publishes anything.
Goal — the Showcase¶
Reframed 2026-07-26 (owner direction): this is a showcase-stage project, not a product with customers. The phase is showcase-driven: build fast, make capability visible, defer commercialization mechanics (licensing, GDPR formalities, sign-offs, channel validation) until someone external actually shows up. The market-validation questions from 02-personas remain questions to ask opportunistically — nothing in this phase blocks on them. One standing rule survives because it is free: nothing publishes publicly (code, images, packages) until the licensing decision — repos are private anyway.
The Showcase walkthrough — the phase's verifiable goal. From a clean stack, one sitting, no hand-waving:
- Search a Greek address (or drop a pin) → instant multi-hazard score card with plain-language bands and a "why this score" drawer.
- Open the map → hazard/exposure/result layers render (tiles working in prod).
- Upload a portfolio CSV → per-asset scores + book rollup appear without a compute wait.
- Run a scenario matrix (2 climate scenarios × 3 horizons) on real scenario-conditioned Greek data → watch the batch complete.
- Run the same scenario through two engines (climate-lama-engine + CLIMADA sidecar) → see the agreement view.
- Download a composed, provenance-cited PDF report pack (the ORSA-shaped template) from the UI.
Every work item below exists because it makes one of those six moments real.
Amendment 2026-08-02 (owner direction) — the Showcase walks
river_floodonly, and says so. §Risks below pre-authorised this: "if a peril lacks usable projections, the showcase ships with fewer perils and says so." That risk materialised. Both Greek catalogs recordriver_floodasingestedandwildfire/storm_europeasstatus: gap— source-verified 2026-07-27, with the rejected sources and reasons inline (scripts/scenario_hazards_manifest.json,scripts/historical_catalog_manifest.json);tropical_cycloneis out of region, not missing. So moment 1 demonstrates one peril, not four, and moments 2–6 run on flood. Sourcing the remaining perils stays in Phase 9 via #412 — pulling it back here would invert the dependency and stall the exit gate. Evidence and the alternatives rejected: phase-8-walkthrough-readiness.md; findings: mid-review-phase-8.md F-1.
Entry conditions¶
- [ ] GitHub Actions unblocked (account billing self-resolves 2026-08-01) →
dispatch
ci.yml+sdk-smoke.ymlgreen onmainin all three repos — the never-yet-exercised validation of the on-demand CI model. - [ ] Beat + titiler compose changes (#368/#369) rolled out on the prod host
(manual
docker compose pull && up -dper DEPLOYMENT.md; automation is #356, not a gate). - [x] Answer-layer RFC ratified (A1/A2/A3). Epics #366/#367 aligned.
Out of scope (deliberately)¶
- Anything publishing code or images publicly (the one free-standing rule kept from the commercialization track).
- Commercialization mechanics: licensing resolution, GDPR/processor formalities, actuarial sign-off, channel/pricing validation — deferred until an external user/pilot exists. Recorded, not scheduled.
- OpenQuake/seismic (the quarter-plus project — wave 2, #366). The CLIMADA sidecar (8.15) covers the multi-engine showcase moment instead.
- Portfolio workbench full product surface (#367 — wave 3); this phase ships the upload→scores→rollup slice only (showcase moment 3).
- Public citizen funnel deployment (the lookup + score card ship here and demo fine; putting them on the open internet waits for the deferred items above).
- Transition-risk ORSA content (the consultant's half of a real filing).
- Desktop counterpart — parked; the web UI is the showcase surface. When wanted, a Tauri/Electron wrap of the existing UI is the cheap path (weeks, not a rebuild) — record as a parking-lot candidate, not phase scope.
Stream F — Foundations (start immediately, parallelizable)¶
8.1 — Fix #370: eai_exp position→centroid mapping (bug, load-bearing)¶
- [ ] Failing test first: sparse/non-contiguous centroid assignment → geojson and report top-exposures attach EAI to correct coordinates (acceptance in #370).
- [ ] Fix by re-joining exposure rows with the compute-time ORDER BY; correct the
models/result.pydocstring ("per exposure point", not "per-centroid"). - Why in Stream F: the surface writer (8.4) inherits this exact trap otherwise.
- Suggested
/analyzetier: 3.
8.2 — Report composer (the shared primitive)¶
- [ ] Replace the placeholder PDF path in
reports.pywith a real composer: template-driven sections (cover, summary metrics, charts, methodology with provenance-stamp citations, attribution annex). - [ ] Renderer decision recorded as ADR-039* ("Report generator choice"): WeasyPrint-in-worker vs Quarto container — decide during build; WeasyPrint is the default lean candidate, Quarto the heavy fallback (inverts old 7.4).
- [ ] Celery task
render_report(scenario_id, template=...); 202 + job polling; PDF to object store per ADR-029 layout. - [ ] One generic template shipped and smoke-rendered in tests.
- Suggested
/analyzetier: 4 (worker + template + storage + API).
8.3 — Answer-plane schema: RiskSurface + RiskCell¶
- [ ] Migrations per the ratified RFC with A3.4: reference tables org-less (like
admin_boundaries, no RLS) and org-scoped tables under the standard FORCE-RLS pattern — two table pairs, one contract. Isolation invariant in the migration docstring: org-derived cells never readable cross-org; promotion to reference is manual. - [ ] H3 index columns + generated geometry for tiling; DB cells capped at r8.
- [ ] Size accounting: per-surface rows/bytes recorded (usage_events pattern);
surfaced in
/metrics. - [ ] Retention: org run-saves evictable (owner can re-run); reference surfaces replaced atomically by versioned rebuilds only (A3.6). Miss semantics defined in the API contract: partial answer + "surface not built here" provenance.
- [ ] ADR-040* "Two-plane answer layer" authored from the RFC.
- Suggested
/analyzetier: 4.
8.4 — Surface writer (factory-side run-saves)¶
- [ ] Worker writes spatial results into org-scoped cells on every impact run (A1 default-on; single-digit MB/run bound verified in the reassessment), geolocating by exposure re-join (8.1's rule), never array position.
- [ ] Deliberate reference-surface build path: a management task that runs a designated scenario matrix and writes org-less reference cells.
- [ ] Depends on: 8.1, 8.3.
- Suggested
/analyzetier: 4.
8.5 — Asset entity + GDPR posture¶
- [ ]
Assetmodel per ADR-041* (identity: address, geocoded point, attributes JSONB, org-scoped, score history) +portfolio_assetsjunction (A3.5) with a migration story for existing exposure-based portfolios. - [ ] One-directional Asset→Exposure generation service;
dataset_sha256recipe for generated batches = hash over canonicalized rows (A3.5) so result-cache and provenance keep working. - [ ] A short data-handling note in the Asset ADR (addresses are personal data; design erasure-friendly: Asset deletable without breaking result provenance). The formal GDPR/processor posture is deferred until an external user exists — this note just keeps the schema from painting us into a corner.
- Suggested
/analyzetier: 4 (schema + generation service).
8.6 — Score schemes v1 (feature-flagged)¶
- [ ]
score_schemesversioned + seeded with citations (published thresholds — JBA/ThinkHazard-style ordinal categories as v1 per the ratified ship-and-polish decision); banding precedence per A3.3: flood/wildfire band from COG point intensity, cell bands for rollups/smooth hazards. - [ ] Rollup functions: asset, portfolio (value-weighted + worst-N), admin unit (cells within GADM polygon).
- [ ] Behind a feature flag; advisory note recorded: external actuarial/scientific review before the first paid engagement.
- [ ] ADR-043* "Score schemes + rollup semantics".
- Suggested
/analyzetier: 3.
8.7 — Geocoding adapter + Nominatim (Greece)¶
- [ ]
core/geocoding.pyinterface + Nominatim adapter (the only file importing the provider client); Greece OSM extract, self-hosted service in compose (dev + prod), sized in 8.11's capacity note. - [ ] Low-confidence fallback contract: pin-drop path needs no geocoder.
- [ ] ADR-044* "Geocoding adapter + provider".
- Suggested
/analyzetier: 3.
8.8 — Point lookup read path¶
- [ ]
GET /v1/risk/lookup?lat&lon[&scenario&horizon]— new code (A3.3: no point path exists): COG point read (titiler/cog/pointproxy or rasterio window)- org/reference cell fetch + score card assembly with provenance refs.
- [ ] Latency budget stated and tested (cells indexed lookup; COG read measured, not assumed).
- [ ] Depends on: 8.3, 8.6; titiler prod rollout (entry condition).
- Suggested
/analyzetier: 4.
8.9 — Data foundation: Greek multi-hazard, multi-scenario catalog¶
The weakest layer of the stack today is data: only historical JRC river flood (bbox demo) + LitPop exposures. A showcase lives or dies on data richness — this is a headline stream, not a checkbox.
- [ ] Scenario-conditioned hazard datasets for Greek climate perils ingested and cataloged: river flood mandatory; wildfire/windstorm as source availability allows — each at ≥2 climate scenarios × ≥3 horizons, from original public sources (05-convergence rule: own pipeline, own attribution).
- [ ] Broaden the historical catalog while at it: full-Greece (not bbox) RF at usable resolution; WF/WS national coverage; a curated Greek exposure set beyond LitPop (building-stock proxy) — the same dataset that seeds the national reference surfaces (8.4).
- [ ] A citable mapping doc: EIOPA below-2°C / well-above-2°C → concrete RCP/SSP
dataset choices per hazard × horizon (
docs/concepts/). - [ ] Demo scenario matrix runs end-to-end on the ingested pack.
- Note: today "time horizon" is growth extrapolation — this item is what makes the scenario story honest.
- Suggested
/analyzetier: 4 (data sourcing + science documentation). Start FIRST — least controllable lead times.
8.10 — UI: the showcase surface¶
- [ ]
climate-lama-uicarries the showcase moments: (1) address/pin search → score card + explainability drawer; (3) portfolio CSV upload → per-asset scores + book rollup view (thin slice, not the full workbench); (5) engine picker + agreement view on a scenario run; (6) matrix-run trigger/status/report download. - [ ] #355's remaining half: same-origin LayerSpec tile URLs through the proxy
(backbone
layer_spec.py+ UI wiring) — showcase moment (2). - [ ] UI issues opened in the UI repo (it currently has zero open issues — the forward queue starts here).
- Suggested
/analyzetier: 4 (multiple surfaces; still slices, not products).
8.11 — Ops minimum: scheduled backup¶
- [ ] Scheduled pg_dump + object-store backup with one documented restore test. (Capacity sizing for Nominatim/factory runs: solve when something actually strains the box — a sentence in the deployment doc, not a study.)
- Suggested
/analyzetier: 2.
8.15 — CLIMADA sidecar engine + agreement view (showcase moment 5)¶
- [ ] Pull Phase 7.3's design forward, private-only: engine registry +
X-Enginerequest-time dispatch in the worker; CLIMADA in an isolated sidecar container (process boundary, no in-process import — ADR-024 untouched); input/output translation toModelInterface. - [ ] Agreement view: same scenario through both engines → side-by-side metrics + divergence percentages (the parity harness grows a user-visible face).
- [ ] No PyPI, no public repo — distribution rules wait for the licensing decision; everything ships inside the private compose stack.
- Suggested
/analyzetier: 5 (cross-process IPC; the phase's hardest item).
Interview questions — opportunistic, never blocking¶
The 02-personas ORSA questions (willingness-to-pay, channel, incumbent tooling, cycle reality) stay on file to ask whenever conversations naturally happen. No stream, item, or merge waits on them. The persona checkpoint (P1 vs P3) remains a strategy-session topic for the exploration track, not a build gate.
Stream O — ORSA module (build when 8.2 + 8.9 land; no external gate)¶
8.12 — Scenario-matrix runner¶
- [ ] One API call → a tracked batch (2 scenarios × 3 horizons × portfolio) of existing impact jobs; batch status, partial-failure semantics, one result set.
- [ ] Depends on: 8.9 (data), existing compute path (unchanged — factory primacy).
- Suggested
/analyzetier: 3.
8.13 — ORSA report template¶
- [ ] Composer template: per-scenario × horizon results, EP curves, horizon comparison, methodology + scenario-mapping citations (8.9's doc), reproducibility stamp, assumptions annex, explicit "physical-risk module — transition risk out of scope" framing.
- [ ] Rendered pack reviewed against EIOPA's application-guidance mock examples.
- Suggested
/analyzetier: 4.
8.14 — Module packaging¶
- [ ] Docs-site page (what it is, what it is not, how the consultant/actuary completes the filing); demo walkthrough on the seeded stack; SDK example.
- Suggested
/analyzetier: 2.
ADRs authored in this phase¶
| ID (assigned at merge; next free is 039) | Title | Item |
|---|---|---|
| ADR-039* | Report generator choice | 8.2 |
| ADR-040* | Two-plane answer layer (RiskSurface/RiskCell, A1/A3 rules) | 8.3 |
| ADR-041* | Asset entity + portfolio_assets + generated-batch hashing | 8.5 |
| ADR-042* | Engine registry + request-time dispatch (CLIMADA sidecar, private) | 8.15 |
| ADR-043* | Score schemes + rollup semantics | 8.6 |
| ADR-044* | Geocoding adapter + provider | 8.7 |
Exit criteria¶
The Showcase walkthrough (Goal section) runs end-to-end in one sitting — all six moments, on a clean stack. Plus:
- Surfaces accumulate from runs with visible size accounting; reference surfaces exist for at least one hazard × scenario × horizon triple.
- Zero public-release steps taken (the one standing rule).
Risks¶
- 8.9 data sourcing is the least controllable item (availability/licensing of scenario-conditioned Greek hazard data) — start it first; if a peril lacks usable projections, the showcase ships with fewer perils and says so.
- 8.15 CLIMADA sidecar is the hardest engineering item (cross-process IPC, CLIMADA env in a container) — it is showcase moment 5, not a dependency of anything else: if it drags, it drops to the phase tail without blocking moments 1–4 and 6.
- Score credibility — v1 bands are self-set with citations; keep the "why this score" drawer visible in every demo so bands never stand naked.
- Scope creep toward product polish — this phase ships showcase slices (thin portfolio view, one report template), not finished products; the wave 2/3 epics (#366/#367) hold the full versions.
- Solo-maintainer bandwidth — sized for
/phase-split+/phase-buildorchestration; items are single-repo except 8.10.