Commit graph

7 commits

Author SHA1 Message Date
1ad523a91a fix(ui): make T1–T4 readable + lift Recl∆Im into the nav rail
Three small frictions a first-time reader hit at the same time,
fixed in one pass:

  1. The TierBadge said 'T1' without context. Default form is
     now 'T1 · amtlich' / 'T2 · Verband' / 'T3 · Erhebung' /
     'T4 · Signal'. Compact form (heatmap chip wrap) keeps the
     bare code. Tooltip spells out the long form + cites the
     Regel der niedrigsten Stufe (Studie §6.7) so the meaning
     of the cap is at hand on hover.

  2. The Legende's tier row was the abstract one of the four —
     it now inlines all four stage names (amtlich / Verband /
     Erhebung / Signal) and explains why a single T4 component
     drags a whole figure to T4. No more 'what is Tier?' on
     screen.

  3. The DemoBanner repeated 'Tier T4' without explaining what
     T4 is. Now: 'qualitatives Signal — bis NKR/Verbands-
     Pipeline + Juristen-Approval laufen'. The cause-and-cure
     is visible at a glance.

  4. The NavigationRail leading column showed only 'F∆I' as
     brand mark. Now shows 'Recl∆Im' prominently (petrol-signal,
     bold) with 'F∆I' as a small muted vendor tag below.
     Product first, vendor second.

EvidenceTierLabel extension grows a new 'headline' getter for
the one-word default ('amtlich'/'Verband'/…), and 'description'
gets longer, source-naming text (NKR / DESTATIS / DIHK / IHK /
ZDH / BDI). Code paths that used the old short-only badge keep
working because 'short' still returns 'T1'.

flutter pub get refreshed against chain_client_sdk 0.18, which
the fai_chain agent confirmed already carries the gRPC-Web
channel — no SDK bump needed for the web-hub-mode wire.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 14:44:14 +02:00
dff5685686 feat(hub): implement HubRepository.list() — flow.completed → Evaluation
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>
2026-06-18 14:18:10 +02:00
12b6961f7e docs(fixtures): expose P/F/T/h component-tier rationale per pilot norm
Each of the five fixture Evaluations now carries a notes field
that breaks the lowest-tier-rule (Studie §6.7) into its four
SKM components (Population, Frequenz, Tarif, Zeitaufwand) and
names which one is the bottleneck. Tier markings stay
conservatively T4 on the surface — what changes is that a
reviewer reading the norm-detail panel now sees:

  - which Komponenten are real T1 numbers (DESTATIS-derived P,
    Verdiensterhebung-T) vs. where the demo extrapolates
  - which Komponenten still wait on NKR-Validierung (mostly h)
  - the political bottom line per norm: GewO §14 needs an
    NKR-h-Wert; KassenSichV is largely documented; DSGVO Art.30
    is EU-bound, reform-Hebel sits in Brüssel; BauO Bln §60 is
    Land-domain without Bundes-NKR support; MiLoG §17 is under
    Bürokratieentlastungsgesetz-IV-Bewegung.

No data-model change. Same fixtures, more honest reading.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 14:15:51 +02:00
116310b65b feat(ui): inline the normative text + open-source URL
Adds the actual paragraphs of the law right next to the
evaluation panel on the norm-detail page. A reviewer no longer
has to leave the app to confirm what a score is about; the
canonical source URL stays one click away via 'Im Browser
öffnen' (url_launcher) and one click away as a clipboard copy.

Schema

  models.dart gains a NormParagraph (number + text). Norm carries
  a List<NormParagraph> paragraphs, defaulted to const [] so
  norms harvested by text.akoma_normalize@^0 in live mode slot
  in without breaking the Mock path.

Demo data

  fixtures.dart embeds the public source paragraphs verbatim
  under §5 UrhG (amtliche Werke) for the five pilot norms.

Plumbing

  NormTextCard (lib/widgets/norm_text_card.dart) is the renderer:
  per-paragraph hanging label, selectable body text, source URL
  in mono at the bottom, two action buttons. NormDetailPage
  drops the card between the metric row and the duties card so
  the eye lands on it during a 'why this score?' read-through.

macOS sandbox

  The Release entitlement file gains
  com.apple.security.network.client so url_launcher's NSWorkspace
  call and the HubRepository's gRPC channel can both reach the
  network. The DebugProfile already had server; client matches
  the production posture.

  GeneratedPluginRegistrant.swift was re-generated by
  flutter pub get after url_launcher was added — no hand edits.

flutter analyze: clean. flutter test: 2/2 passing. The macOS
build via build-macos.sh launches and the new card renders the
GewO § 14, KassenSichV, DSGVO Art. 30, BauO Bln § 60 ff and
MiLoG § 17 fixtures with their actual normative text.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 13:43:22 +02:00
852f9da703 fix(ui): sort evaluations by SKM €/year descending
Repository.list() now hands the UI a list sorted by the harm
proxy (Studie §6 SKM-€/Jahr). Most-harmful first, deterministic
across launches and across mock-vs-hub repositories. Removes
the perceived non-determinism in the Norms list and gives the
heatmap chip-wrap a politically meaningful first row.

Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 13:18:30 +02:00
39733628b6 feat: wire chain_client_sdk gRPC client + HubRepository scaffold
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>
2026-06-18 11:45:48 +02:00
8ee6a294a1 feat: initial F∆I Law-Heatmap Phase 0 scaffold
First end-to-end-buildable cut of the pflicht-/graph-basierte
Wirkungsanalyse von Rechtsnormen, running on Ch∆In. Demo runs
without external dependencies and without a hub connection so
the methodology + UI stack can be reviewed before any Verbands-
Kooperation or Beirats-Validierung kicks in.

Tree layout

  MACHBARKEITSSTUDIE.md       v0.3 — pflicht-basierte Methodik,
                              4-Tier-Evidenz, 8 law*-Module
                              auf Ch∆In statt der alten F∆I-
                              Plattform.
  RUN.md                      one-page how-to-run.
  flows/durchstich-gewo-14.yaml
                              vertical Phase-0 flow: pull →
                              normalize → duties → citations →
                              cohort → skm → frust → benefit →
                              attribution → system.approval.
  app/                        Flutter macOS client, design
                              language pulled from fai_web
                              (ink #08090A, paper #F4F3EF,
                              petrol signal #2E8F9E). Mock
                              repository ships five fixture
                              norms with real source URLs and a
                              permanent T4 demo-banner so no
                              figure can be mistaken for a
                              validated one.

Module repos (separate, see chain-modules*/):

  text-akoma-normalize, text-deontic-extract, graph-citation-
  extract, text-readability-score, stats-cohort-size, graph-
  shapley-attribution, econ-skm-score, law-benefit-score.

What runs today

  - flutter analyze: 0 issues
  - flutter test: 2/2 (landing + nav-to-shell smoke)
  - flutter build macos (via app/build-macos.sh) and ad-hoc
    codesign, app launches and the Dart VM service comes up
  - native cargo test green on every module
  - cargo build --release --target wasm32-wasip2 produces a
    130 KiB artefact for text-akoma-normalize

What is deliberately mock / stub

  - gRPC wire from the client to a chain serve hub (Repository
    abstraction is in place; live impl is the next step)
  - NKR Bürokratiekosten-Datenbank ingestion (for the canonical
    h-Werte that close out the Engpass per Studie §6.7)
  - DESTATIS GENESIS-API adapter for stats.cohort_size

License: Apache-2.0. Author/contact in MACHBARKEITSSTUDIE.md.
Signed-off-by: flemming-it <sf@flemming.it>
2026-06-18 11:26:28 +02:00