Skip to content

feat(dashboard): kanonische lebende Maschinenkarte (Grid + Detail, live) - #52

Merged
patricznr1 merged 2 commits into
mainfrom
feat/canonical-machine-card
Jun 25, 2026
Merged

feat(dashboard): kanonische lebende Maschinenkarte (Grid + Detail, live)#52
patricznr1 merged 2 commits into
mainfrom
feat/canonical-machine-card

Conversation

@patricznr1

@patricznr1 patricznr1 commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Was

Eine kanonische lebende Maschinenkarte als EINE FE-Komponente (MachineCard) + EIN Vertrag (MachineCardOut) ersetzt sowohl die Maschinenlisten-Reiter unter „Linie & Maschinen" (Grid, gruppiert nach Synoptik-Stufe) als auch die tote Stammdaten-Box der Detailsicht. Pro Datenpunkt jetzt Name · WERT · Einheit + Status-Indikator statt nur der Einheit. MachineList + MachineSpecs (+ Tests) entfernt — kein Doppel-Code. Synoptik-Vorbau (Anlagen_Synoptik.png).

Warum

Die Stammdaten-Box war tot (name · unit, kein Wert). Patrics Auftrag: eine überall identische, lebendige Karte — pro Datenpunkt aktueller Wert + Status, eine Quelle der Wahrheit. Entscheidungen (per AskUserQuestion bestätigt): Detektor-getreuer Status (kein neu erfundener Schwellwert) + Per-Maschinen-WS-Push.

Backend (Read-Core, kein Schema-Change / keine Migration)

  • reads/queries.latest_values_for_data_points — jüngster Wert je Datenpunkt via readings_1m (DISTINCT ON, kein Full-Scan).
  • reads/datapoint_status.derive_datapoint_status (pure) — Ehrlichkeitslinie: Alarm-Verdikt → Eigenprofil-Korridor (corridor_at, jetzt geteilte Detektor-Band-Quelle mit dem Trend-Overlay, DRY) → statisches Normalband → unknown. Kein erfundener Schwellwert.
  • reads/card.build_fleet_cards/build_machine_card (batched, kein N+1) + additive Schemas DataPointCardOut/MachineCardOut.
  • GET /api/v1/cards (scope-gefiltert je Rolle, visible_machine_scope) + GET /api/v1/machines/{id}/card (scope-gated); WS-machine:{id} trägt jetzt die ganze Karte (Superset des früheren MachineStatusOut).
  • NOTIFY-Anreicherung (machines_for_data_points): ein Readings-Tick frischt machine:{id} + overview auf → die Karte lebt pro Tick (Produzent/Live-Worker-Logik unangetastet, nur die Change-Bündelung). Nebeneffekt: die Stream-„aktiv"-Kachel wird endlich pro Tick ehrlich live.

Frontend

  • MachineCard — EINE Komponente, zwei Dichten (compact Grid / full Detail-Stammdaten), live über useTopicState<MachineCardOut>(machine:{id}) mit SSR-Erstbild; Stale ehrlich („Stand vor X" bei Stream-Stopp), Hallensprache (kein „Drift"/internes Vokabular). MachineCardGrid gruppiert nach Synoptik-Stufe (Fördern/Pressen/Handling/Bestücken/Endkontrolle). /machines zieht GET /cards, /machines/[id] zieht eine Quelle GET /machines/{id}/card.

Getestet

  • Backend: pytest 919 passed, 2 skipped, Coverage 94,45 % (Gate ≥85 %); mypy --strict 0; ruff clean.
  • Frontend: Vitest 679 passed; tsc --noEmit 0; eslint 0; tokens:check synchron (keine neuen Token); next build ok (/machines ~1,8 kB / 111 kB, /machines/[id] ~8,9 kB / 124 kB — keine Charting-Lib).
  • Adversariale 6-Dimensionen-Review (Workflow): AuthZ/Scope/PII clean; bestätigte Befunde gefixt (FE-NaN-Guard, machine-header-Typ, Test-Lücken: shift_lead-Scope, Multi-Maschinen-NOTIFY, quittierter-offener Alarm).
  • Doku (DoD): GROUND_TRUTH §4/§20.1/§21.6/§21.19 + WALKTHROUGH im selben Commit. Test-Isolation: CAGG-Reset im conftest (TRUNCATE invalidiert readings_1m nicht → Geister-Werte bei data_point_id-Wiederverwendung).

Bewusste Entscheidungen / Hinweise

  • Status je Datenpunkt nutzt ausschließlich bestehende Bänder — der „außerhalb Normalbereich"-Punkt ist eine Beobachtung (wie der Chart-Akzent), kein Alarm-Verdikt; ein offener-aber-quittierter Alarm bleibt „alarm" (quittieren ≠ löschen, konsistent mit compose_status).
  • Out-of-scope-Detail: die Karte ist scope-gated → „nicht abrufbar" (konsistent mit dem Trend), bewusst strenger als die alte un-gegatete Specs-Box.
  • Vorgezogener Demo-Polish + Synoptik-Vorbau (Patric so gewollt) — kritischer Pfad bleibt Reasoner F4: Drift-Reasoner — erster vollständiger Reasoner (State-Gating, ADWIN, HITL, /metrics) #4.
  • Offen (nicht in diesem PR, pre-existing): die Review flaggte sichtbares Jargon „Eigenprofil"/„Erwartungskorridor" in machine-trend-panel.tsx/time-series-chart.tsx (bestehende B-Sektion, nicht mein Diff) — wäre ein eigener Wording-Politur-PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Neue Features
    • Einführung der kanonischen „lebenden Maschinenkarte“ für Übersicht und Detail mit aktuellen Werten, Statusdarstellung und Live-Aktualisierung.
    • Neues Karten-Grid gruppiert Maschinen nach Synoptik-Stufe und ersetzt die bisherige Listen-/Specs-Darstellung.
    • Neue API-Endpunkte für Karten (inkl. vollständigem WS-„machine:{id}“-Snapshot).
  • Bug Fixes
    • Status- und „Stand vor …“-Anzeige sind jetzt konsistent und basieren auf vorhandenen Signalen; Werte inkl. Zeitstempel sind zuverlässiger.
  • Tests
    • Umfangreiche Unit-/Integrationsabdeckung für Kartenaufbau, Statuslogik, Freshness/Realtime-Updates und Karten-Zugriff.

EINE MachineCard-Komponente + EIN Vertrag (MachineCardOut) ersetzt die
Maschinenlisten-Reiter (/machines-Grid, gruppiert nach Synoptik-Stufe) UND
die tote Stammdaten-Box der Detailsicht. Pro Datenpunkt jetzt der aktuelle
Wert + ehrlicher Status statt nur der Einheit. MachineList + MachineSpecs
entfernt (kein Doppel-Code).

Backend (Read-Core, kein Schema-Change):
- latest_values_for_data_points: jüngster Wert je Datenpunkt via readings_1m
  (DISTINCT ON, kein Full-Scan).
- derive_datapoint_status (pure): Alarm-Verdikt > Eigenprofil-Korridor
  (corridor_at, geteilte Detektor-Band-Quelle, jetzt DRY mit dem Trend-Overlay)
  > statisches Normalband > unknown. Kein neu erfundener Schwellwert
  (Ehrlichkeitslinie).
- build_fleet_cards/build_machine_card (batched, kein N+1) + DataPointCardOut/
  MachineCardOut (additiv).
- GET /api/v1/cards (scope-gefiltert je Rolle, visible_machine_scope) +
  GET /api/v1/machines/{id}/card (scope-gated); WS-machine:{id} trägt jetzt die
  ganze Karte.
- NOTIFY-Anreicherung (machines_for_data_points): ein Readings-Tick frischt
  machine:{id} + overview auf -> die Karte lebt pro Tick.

Frontend:
- MachineCard (compact Grid / full Detail), live über machine:{id} mit
  SSR-Erstbild; Stale ehrlich ("Stand vor X"), Hallensprache (kein internes
  Vokabular). MachineCardGrid gruppiert nach Synoptik-Stufe.

Tests/Doku: pytest 919 grün (94.45% Coverage), Vitest 679 grün, mypy --strict 0,
ruff clean, tsc/eslint 0, tokens:check synchron, next build ok. GROUND_TRUTH
(§4/§20.1/§21.6/§21.19) + WALKTHROUGH nachgezogen. Test-Isolation: CAGG-Reset
im conftest (TRUNCATE invalidiert readings_1m nicht -> Geister-Werte).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0a8d6bac-7533-48ca-9adc-44baecb0c583

📥 Commits

Reviewing files that changed from the base of the PR and between 14c9a98 and 173c735.

📒 Files selected for processing (9)
  • frontend/app/(app)/machines/[id]/page.tsx
  • frontend/app/(app)/machines/page.tsx
  • frontend/components/machine/machine-card-grid.test.tsx
  • frontend/components/machine/machine-card-grid.tsx
  • frontend/components/machine/machine-card.test.tsx
  • frontend/components/machine/machine-detail-view.test.tsx
  • frontend/lib/machine/grouping.test.ts
  • frontend/lib/machine/testing/card-fixture.ts
  • src/foreman/realtime/authz.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • frontend/components/machine/machine-card-grid.test.tsx
  • frontend/lib/machine/grouping.test.ts
  • frontend/components/machine/machine-card-grid.tsx
  • frontend/app/(app)/machines/page.tsx
  • frontend/components/machine/machine-detail-view.test.tsx
  • src/foreman/realtime/authz.py
  • frontend/components/machine/machine-card.test.tsx
  • frontend/app/(app)/machines/[id]/page.tsx

📝 Walkthrough

Walkthrough

Die PR führt eine kanonische lebende Maschinenkarte ein. Backend liefert Kartenlisten, Einzelkarten und WS-Snapshots aus dem Read-Core; Reading-Ticks aktualisieren betroffene Maschinen. Das Frontend rendert die Karte in Übersicht und Detailansicht und ersetzt die alten Listen-/Specs-Komponenten.

Changes

Kanonische lebende Maschinenkarte

Layer / File(s) Summary
Datenpunktstatus und neueste Werte
src/foreman/reasoners/drift/baseline.py, src/foreman/reads/trend.py, src/foreman/reads/queries.py, src/foreman/reads/datapoint_status.py, tests/conftest.py, tests/unit/test_datapoint_status.py, tests/unit/test_drift_corridor.py, tests/integration/test_reads_latest_values.py
corridor_at, latest-value Queries und derive_datapoint_status definieren die Read-Core-Basis für Datenpunktzustände; die Tests und der Aggregate-Reset-Hook decken die Pfade ab.
Kartenmodell und HTTP-Verträge
src/foreman/reads/card.py, src/foreman/schemas/dashboard.py, src/foreman/api/routers/dashboard.py, src/foreman/realtime/authz.py, tests/integration/test_reads_card.py, tests/integration/test_dashboard_routes.py, tests/integration/test_realtime_authz.py, tests/unit/test_dashboard_schemas.py, GROUND_TRUTH.md, docs/WALKTHROUGH.md
MachineCard-Aufbau, Dashboard-Routen, Schema-Modelle und Scope-Regeln liefern MachineCardOut für Kartenlisten und Einzelkarten.
Live-Refresh bei Reading-Ticks
src/foreman/api/routers/readings.py, src/foreman/ingestion/service.py, src/foreman/realtime/ws.py, tests/integration/test_dashboard_routes.py, tests/integration/test_realtime_ws.py, GROUND_TRUTH.md
ChangeSets enthalten jetzt betroffene Maschinen, und machine:{id}-Topics senden nach Reading-Updates vollständige Karten-Snapshots.
Frontend-Kartenbausteine
frontend/lib/api/contracts.ts, frontend/lib/machine/card*.ts, frontend/lib/machine/grouping*.ts, frontend/lib/machine/testing/card-fixture.ts, frontend/components/machine/machine-card*.tsx, frontend/components/machine/machine-card-grid*.tsx, frontend/app/(app)/machines/page.tsx, frontend/components/machine/machine-list.tsx, frontend/components/machine/machine-list.test.tsx, frontend/components/machine/machine-specs.tsx, frontend/components/machine/machine-specs.test.tsx, GROUND_TRUTH.md, docs/WALKTHROUGH.md
MachineCardOut, Statusformatierung, Stufengruppierung, MachineCard und MachineCardGrid ersetzen den alten Listen-/Specs-Pfad in der Übersichtsseite.
Frontend-Detailseite und Header
frontend/app/(app)/machines/[id]/page.tsx, frontend/components/machine/machine-detail-view.tsx, frontend/components/machine/machine-header.tsx, frontend/components/machine/machine-detail-view.test.tsx
Die Detailseite, der Header und die Detailtests beziehen die Maschinenkarte aus MachineCardOut und rendern die Kartenansicht im Detail.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • patricznr1/foreman#18: Erweitert denselben WebSocket-/ChangeSet-Pfad, den diese PR für machine:{id}-Karten und Snapshot-Updates nutzt.
  • patricznr1/foreman#26: Berührt denselben Maschinen-Detail-Flow, den diese PR auf MachineCardOut und die neue Detailansicht umstellt.
  • patricznr1/foreman#35: Arbeitet an denselben Drift-/Korridor-Pfaden, die hier in corridor_at, profile_band und der Datenpunktstatus-Logik zusammenlaufen.

Poem

(_/)

( •_•) Die Karte lebt, der Strom ist klar,

/ >🥕 im machine:{id} wird alles wahr.

Die Werte hüpfen, frisch und fein,

und ich, der Hase, nicke: „Möhrig! fein!“

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Der Titel beschreibt treffend die zentrale Änderung: eine kanonische lebende Maschinenkarte für Grid und Detail mit Live-Update.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/canonical-machine-card

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
src/foreman/realtime/authz.py (1)

100-104: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: geteilte Linien-Maschinen-Abfrage extrahieren.

Der shift_lead-Zweig wiederholt exakt die Abfrage aus overview_scope (Zeilen 80-82): select(Machine.id).where(Machine.line_id.in_(user.assigned_line_ids)). Eine kleine private Hilfsfunktion (z. B. _machines_of_user_lines(session, user)) würde die Duplikation entfernen und beide Resolver konsistent halten.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/foreman/realtime/authz.py` around lines 100 - 104, The shift_lead branch
duplicates the same machine-by-assigned-lines query already used in
overview_scope. Extract the shared
select(Machine.id).where(Machine.line_id.in_(user.assigned_line_ids)) logic into
a private helper such as _machines_of_user_lines(session, user), then call that
helper from both branches to keep authz lookups consistent and remove
duplication.
frontend/components/machine/machine-card-grid.tsx (1)

27-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

key und aria-label besser an machineClass koppeln.

group.stage ist ein Anzeige-Label. Da stageLabel unbekannte Klassen als Rohnamen zurückgibt, kann eine Maschinenklasse mit dem Rohnamen einer bekannten Stufe (z. B. "Fördern") dasselbe Label wie eine echte Stufe erzeugen und einen doppelten React-key verursachen. group.machineClass ist der eindeutige Gruppierungsschlüssel.

♻️ Vorschlag
-        <section key={group.stage} aria-label={group.stage} className="flex flex-col gap-3">
+        <section key={group.machineClass ?? "__none__"} aria-label={group.stage} className="flex flex-col gap-3">
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/components/machine/machine-card-grid.tsx` around lines 27 - 31, The
grouping section in machine-card-grid should not use the display label from
group.stage as the React key or aria-label, because stageLabel can collide with
a raw machine class name and create duplicate keys. Update the <section> in
MachineCardGrid to use group.machineClass as the stable unique identifier for
key and aria-label, while keeping group.stage only for the visible heading text.
Ensure the change is applied in the groups.map render path so each group stays
uniquely identified even when labels overlap.
frontend/app/(app)/machines/page.tsx (1)

20-31: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fehlerfälle werden still in eine leere Liste verwandelt.

Bei !response.ok und im catch wird ohne Logging [] zurückgegeben. Downstream rendert MachineCardGrid daraufhin „Keine Maschinen in deinem Zugriff." — ein Backend-/Netzwerkfehler erscheint also als „kein Zugriff". Das widerspricht dem ehrlichen Zustands-Anspruch der PR und erschwert die Diagnose (kein Server-Log). Erwäge zumindest, den Fehler zu loggen, um einen echten leeren Scope von einem Ausfall zu unterscheiden.

♻️ Vorschlag
     if (!response.ok) {
+      console.error(`fetchCards: /api/v1/cards antwortete mit ${response.status}`);
       return [];
     }
     return (await response.json()) as MachineCardOut[];
-  } catch {
+  } catch (error) {
+    console.error("fetchCards: Anfrage an /api/v1/cards fehlgeschlagen", error);
     return [];
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/app/`(app)/machines/page.tsx around lines 20 - 31, The fetch logic
in the machines page currently swallows backend and network failures by
returning an empty array from both the !response.ok branch and the catch block.
Update the data-loading code in the page component that calls fetch for
/api/v1/cards to log the failure with enough context before returning [], so
MachineCardGrid can still render safely while real outages remain diagnosable.
Use the existing backendUrl()/token fetch flow and keep the empty-list fallback,
but add error logging in both failure paths.
frontend/components/machine/machine-card-grid.test.tsx (1)

17-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optionale Konsolidierung der card-Test-Factory.

Diese card-Hilfsfunktion ist nahezu identisch mit der in frontend/lib/machine/grouping.test.ts (Zeilen 14–31) und überschneidet sich mit dem Fixture in frontend/components/machine/machine-detail-view.test.tsx. Eine gemeinsame Test-Factory (z. B. makeMachineCard(overrides)) würde Drift vermeiden, wenn sich MachineCardOut erweitert.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/components/machine/machine-card-grid.test.tsx` around lines 17 - 34,
The card test helper in machine-card-grid.test.tsx duplicates the same
MachineCardOut fixture logic used in grouping and machine-detail-view tests, so
move this into a shared factory like makeMachineCard(overrides). Update the
local card helper to delegate to that shared builder and keep the unique symbols
card and MachineCardOut aligned so future schema changes only need one fixture
update.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@frontend/app/`(app)/machines/page.tsx:
- Around line 20-31: The fetch logic in the machines page currently swallows
backend and network failures by returning an empty array from both the
!response.ok branch and the catch block. Update the data-loading code in the
page component that calls fetch for /api/v1/cards to log the failure with enough
context before returning [], so MachineCardGrid can still render safely while
real outages remain diagnosable. Use the existing backendUrl()/token fetch flow
and keep the empty-list fallback, but add error logging in both failure paths.

In `@frontend/components/machine/machine-card-grid.test.tsx`:
- Around line 17-34: The card test helper in machine-card-grid.test.tsx
duplicates the same MachineCardOut fixture logic used in grouping and
machine-detail-view tests, so move this into a shared factory like
makeMachineCard(overrides). Update the local card helper to delegate to that
shared builder and keep the unique symbols card and MachineCardOut aligned so
future schema changes only need one fixture update.

In `@frontend/components/machine/machine-card-grid.tsx`:
- Around line 27-31: The grouping section in machine-card-grid should not use
the display label from group.stage as the React key or aria-label, because
stageLabel can collide with a raw machine class name and create duplicate keys.
Update the <section> in MachineCardGrid to use group.machineClass as the stable
unique identifier for key and aria-label, while keeping group.stage only for the
visible heading text. Ensure the change is applied in the groups.map render path
so each group stays uniquely identified even when labels overlap.

In `@src/foreman/realtime/authz.py`:
- Around line 100-104: The shift_lead branch duplicates the same
machine-by-assigned-lines query already used in overview_scope. Extract the
shared select(Machine.id).where(Machine.line_id.in_(user.assigned_line_ids))
logic into a private helper such as _machines_of_user_lines(session, user), then
call that helper from both branches to keep authz lookups consistent and remove
duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99bd51e3-40f7-4338-8b3f-21d9decce69d

📥 Commits

Reviewing files that changed from the base of the PR and between 4722e81 and 14c9a98.

📒 Files selected for processing (40)
  • GROUND_TRUTH.md
  • docs/WALKTHROUGH.md
  • frontend/app/(app)/machines/[id]/page.tsx
  • frontend/app/(app)/machines/page.tsx
  • frontend/components/machine/machine-card-grid.test.tsx
  • frontend/components/machine/machine-card-grid.tsx
  • frontend/components/machine/machine-card.test.tsx
  • frontend/components/machine/machine-card.tsx
  • frontend/components/machine/machine-detail-view.test.tsx
  • frontend/components/machine/machine-detail-view.tsx
  • frontend/components/machine/machine-header.tsx
  • frontend/components/machine/machine-list.test.tsx
  • frontend/components/machine/machine-list.tsx
  • frontend/components/machine/machine-specs.test.tsx
  • frontend/components/machine/machine-specs.tsx
  • frontend/lib/api/contracts.ts
  • frontend/lib/machine/card.test.ts
  • frontend/lib/machine/card.ts
  • frontend/lib/machine/grouping.test.ts
  • frontend/lib/machine/grouping.ts
  • src/foreman/api/routers/dashboard.py
  • src/foreman/api/routers/readings.py
  • src/foreman/ingestion/service.py
  • src/foreman/reads/card.py
  • src/foreman/reads/datapoint_status.py
  • src/foreman/reads/queries.py
  • src/foreman/reads/trend.py
  • src/foreman/realtime/authz.py
  • src/foreman/realtime/ws.py
  • src/foreman/reasoners/drift/baseline.py
  • src/foreman/schemas/dashboard.py
  • tests/conftest.py
  • tests/integration/test_dashboard_routes.py
  • tests/integration/test_reads_card.py
  • tests/integration/test_reads_latest_values.py
  • tests/integration/test_realtime_authz.py
  • tests/integration/test_realtime_ws.py
  • tests/unit/test_dashboard_schemas.py
  • tests/unit/test_datapoint_status.py
  • tests/unit/test_drift_corridor.py
💤 Files with no reviewable changes (4)
  • frontend/components/machine/machine-list.test.tsx
  • frontend/components/machine/machine-list.tsx
  • frontend/components/machine/machine-specs.tsx
  • frontend/components/machine/machine-specs.test.tsx

Zweiter Reviewer (CodeRabbit) auf PR #52 — 4 Nitpicks (alle Trivial),
verifiziert + adressiert:
- authz.py: geteilten Linien-Resolver _machines_of_user_lines extrahiert
  (overview_scope + visible_machine_scope teilen jetzt EINE Linien-Abfrage).
- machine-card-grid.tsx: React-key auf group.machineClass (statt Anzeige-Label
  group.stage) — verhindert Kollision, falls ein roher Klassenname ein
  Stufen-Label trifft; aria-label bleibt das lesbare Stufen-Label.
- machines/page.tsx + machines/[id]/page.tsx: Fehlerfälle (!ok / catch) loggen
  serverseitig statt still leere Liste/null — ein Ausfall sieht nicht mehr aus
  wie "kein Zugriff" (Ehrlichkeitslinie); 404/403 im Detail bleiben stiller
  Normalpfad.
- Test-Fixtures: geteilte makeMachineCard-Factory (lib/machine/testing/
  card-fixture.ts) ersetzt die duplizierte MachineCardOut-Literal-Logik in
  grouping/grid/card/detail-view-Tests (kein Drift bei Vertrags-Erweiterung).

Gates grün: Vitest 679, tsc/eslint 0, Backend authz 28 (mypy --strict 0,
ruff clean).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@patricznr1

Copy link
Copy Markdown
Owner Author

CodeRabbit-Nitpicks abgearbeitet (Commit 173c735)

Alle 4 Nitpicks verifiziert + adressiert (keine waren blockierende Bugs — alle Trivial):

# Datei Befund Erledigt
1 realtime/authz.py shift_lead-Zweig dupliziert die Linien-Abfrage aus overview_scope _machines_of_user_lines extrahiert, beide Resolver nutzen sie
2 machine-card-grid.tsx React-key = Anzeige-Label kann kollidieren (roher Klassenname == Stufen-Label) key auf group.machineClass; aria-label bleibt lesbares Stufen-Label
3 machines/page.tsx (+ Detail) stiller Fehler → leere Liste sieht aus wie „kein Zugriff" ✅ Fehlerfälle serverseitig geloggt (404/403 im Detail bleiben stiller Normalpfad)
4 machine-card-grid.test.tsx u. a. dupliziertes MachineCardOut-Fixture über mehrere Tests ✅ geteilte makeMachineCard-Factory (lib/machine/testing/card-fixture.ts), 4 Test-Dateien darauf umgestellt

Gates nach den Fixes: Vitest 679 · tsc/eslint 0 · Backend authz 28 (mypy --strict 0, ruff clean).

@patricznr1
patricznr1 merged commit e24da81 into main Jun 25, 2026
3 checks passed
@patricznr1
patricznr1 deleted the feat/canonical-machine-card branch June 25, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant