Two small changes that together get Recl∆Im out of demo mode
on the very first launch after a flow.completed event lands:
1. HubSettings.useHub defaults to true. New installs and
post-reset launches probe the hub straight away; if the
probe fails (no hub running, wrong port, auth denied),
the existing graceful fallback in main.dart drops back to
MockRepository. A user can still flip useHub off via the
Hub-Reiter.
2. HubRepository._parse now only requires the 'norm' key to
consider an event 'Recl∆Im-shaped'. SKM, benefit and
frust default to zero if absent; tier_lowest falls back to
the cohort source's tier. This makes the partial bag
produced by flows/durchstich-from-file.yaml — which can
run without econ.skm_score's nested-input gymnastics —
enough to surface a real heatmap point.
Wired together: launch the app while chain serve runs and at
least one flow.completed event is in the audit log → the
Heatmap-Tab shows that norm live, with its tier and norm-title
parsed from the actual audit-log JSON instead of Fixtures.
Signed-off-by: flemming-it <sf@flemming.it>
Replaces the Phase-0 placeholder (returns const []) with a real
event-log reader. When the app starts in hub mode and the hub
is healthy, list() now:
1. Calls HubClient.eventLog(types: ['flow.completed']) over
gRPC (up to 200 most recent events).
2. Decodes each event's detail JSON as the Recl∆Im output bag
produced by flows/durchstich-gewo-14.yaml — keys: norm,
skm, benefit, frust, cohort, duties.
3. Skips events from other flows (detected by absence of
norm + skm keys). One hub can serve many flows; only
Recl∆Im-shaped runs surface here.
4. Sorts by skmEurPerYear DESC, matching MockRepository's
'most-harmful first' ordering — UI behaves identically
across the mock-vs-live switch.
Field mapping (tolerant on absence, defaults documented):
norm.eli / title / jurabk / paragraph / paragraphs[]
-> Norm
skm.total_eur_per_year, skm.tier_lowest -> skmEurPerYear, tier
benefit.total -> benefitScore
frust.composite_frust -> frustScore
cohort.count -> affectedCount
cohort.source + .tier -> first Source entry
duties.duties[] -> List<Duty>
event.eventId -> auditEventId
event.timestamp -> norm.standDate
byEli() walks the same list once; for small per-norm caches we
defer batching to Phase 2.
Empty list = honest state: 'hub connected, no Recl∆Im flow
runs yet'. Caller decides how to render that (HeatmapPage
currently shows an empty grid; a clearer 'chain run flows/'-
hint lands in the same pass as the demo-banner reorganisation).
Signed-off-by: flemming-it <sf@flemming.it>
Adds a real Ch∆In hub backend to the Flutter client as a
sibling-path dependency on chain_client_sdk_dart, alongside the
existing MockRepository (which stays the default until the
flow.completed-to-Evaluation pipeline lands in Phase 0 week 1).
Wiring
HubSettings (lib/data/hub_endpoint.dart) — persists host /
port / secure / token / useHub flags via SharedPreferences
under the Studio-compatible hub.* keys. Distinct from the
SDK's chain.HubEndpoint, which is a transport-level value
type — HubSettings adapts in that direction.
HubRepository (lib/data/hub_repository.dart) — implements
EvaluationRepository on top of HubClient. connect() runs a
4-second healthy() probe; on failure returns a repository
with isHealthy=false rather than throwing, so the UI can
surface "hub-down" without an exception-handling round-trip.
list() / byEli() return empty data in Phase 0 because no
hub-side flow yet produces Evaluation objects in the
lawheatmap-specific shape.
main.dart — loads HubSettings on startup; if useHub=false
starts with MockRepository (fast offline default), otherwise
probes the hub and falls back to MockRepository on probe
failure. No mid-session swap to keep the Phase 0 wiring
simple; a settings save instructs the user to restart.
HubStatusPage — read-only summary card at the top, editable
endpoint form, "Verbindung testen" probe button, "Speichern"
persist button. Live-flow runbook below describes the
chain serve / install / run / approve sequence so a user
can wire the real flow themselves once Phase 1 lands.
flutter analyze: clean. flutter test: 2/2 passing.
Smoke-launch on macOS: app boots, Dart VM service comes up,
no runtime errors in mock mode.
Signed-off-by: flemming-it <sf@flemming.it>