loam.dev
v0.1.4 · preview EN

Funktionsweise

loam.dev liest ein Dart/Flutter-Projekt semantisch und über die ganze Codebase — nicht Datei für Datei — und macht daraus eine deterministische Pass/Fail-Entscheidung in CI. Eine Baseline duldet den vorhandenen Code, sodass nur neu hinzugekommene Probleme den Build blockieren. Das geschieht in einer sechsstufigen Pipeline, ohne Raten, ohne Regex-Abkürzungen, ohne False Positives aus generiertem Code.

Die Pipeline

01
Loader

Der ProjectLoader speist das gesamte Projekt in Darts eigene AnalysisContextCollection. Jede Datei wird geparst und vollständig in ein typisiertes Element-Model aufgelöst — dasselbe Model, das das Dart-SDK intern verwendet. Das ist die Grundlage, die alles Nachgelagerte semantisch statt syntaktisch macht.

02
Rules

Eine Menge von Rules läuft über das aufgelöste Model. Jede Rule ist eine eigenständige Analyseeinheit hinter einem gemeinsamen Interface; eine neue Fähigkeit hinzuzufügen ändert die Pipeline nicht — nur die Rule-Liste. Rules sind entweder deterministisch (reines AST/Element-Model, reproduzierbar ohne Netz) oder LLM-gestützt (geplant, immer verdict-gecacht, bevor sie CI berühren).

03
Findings

Jede Rule emittiert Findings — strukturierte Ergebnisse der Form { ruleId, severity, location, message, fingerprint }. Jedes Finding trägt einen stabilen Fingerprint (einen positionsrobusten Hash), der Umformatierungen und Zeilennummernverschiebungen überlebt. Das ist der Schlüssel, der den Baseline-Diff exakt macht.

04
Baseline

Die Baseline ist ein eingefrorener Stand akzeptierter Findings, gespeichert in baseline.json. Beim Onboarding eines bestehenden Projekts führt man einen Vollaudit durch, bereinigt, was möglich ist, und friert den Rest mit loam baseline --write ein. Ab diesem Punkt interessiert das Gate nur noch neue Findings — nicht die bereits bekannten.

05
Gate

Das Gate ist der CI-Entscheidungspunkt: Es vergleicht aktuelle Findings mit der Baseline und gibt einen strukturierten Exit-Code zurück. Keine Regression → Exit 0. Neues Finding → Exit 1. Keine Überraschungen beim Merge.

06
Report

Der Reporter formatiert Ergebnisse für Menschen oder Maschinen: human für die Terminal-Ausgabe, json / sarif / markdown für Agent-Pipelines und html für einen interaktiven, in sich geschlossenen Report mit eingebautem Fix-Prompt-Builder.

loam scan vs. loam gate

Zwei Befehle, zwei Zwecke. Wer den richtigen kennt, hält den Workflow sauber.

loam scan

Vollaudit · baseline-unabhängig

Führt alle aktiven Rules über das gesamte Projekt aus und zeigt alle Findings — unabhängig vom Stand der Baseline. Dieser Befehl eignet sich beim erstmaligen Einsatz in einem bestehenden Repo: Gesamtbild sehen, bereinigen, was vertretbar ist, dann den Rest mit loam baseline --write einfrieren.

loam gate

CI-Ratchet · Baseline-bewusst

Der Alltagsbefehl für CI. Standardmäßig läuft er im Ratchet-Modus: Nur Findings, die neu sind (nicht in der Baseline), lassen den Build scheitern. Der Score kann sich nur verbessern — die Codebasis ratchet vorwärts, nie rückwärts. Für Greenfield-Projekte oder Pipelines, die null Findings erzwingen, gibt es --absolute als harte Schwelle.

Typische Onboarding-Sequenz: loam scan → relevante Findings bereinigen → loam baseline --writeloam gate ab sofort in CI.

Semantik vor Syntax

Die wichtigste Architekturentscheidung in loam.dev ist, worüber die Analyse läuft.

dart analyze meldet Typfehler, fehlende Imports und Style-Lint-Verletzungen — alles, was sich auf Deklarationsebene erkennen lässt. Was es nicht tut: über den Referenzgraphen des gesamten Projekts nachdenken — welche öffentlichen API-Member tatsächlich von außen erreichbar sind, welche Schichtgrenzen überschritten werden, welche Hilfsfunktionen als Duplikat vorliegen.

Diese Dinge per Regex oder String-Matching zu finden ist fragil. Ein Regex, der einen Bezeichnernamen sucht, kann nicht zwischen Definition und Referenz unterscheiden, nicht zwischen einer lokalen Variable und einem öffentlichen Export, nicht zwischen einer generierten Datei und handgeschriebenem Code.

loam.dev arbeitet auf dem aufgelösten Element-Model: Jedes Symbol ist ein typisiertes Element mit kanonischer Identität, jede Referenz ist ein aufgelöster Zeiger. Rules operieren auf diesem Model — nicht auf Rohtext. Das bedeutet konkret:

  • Keine False Positives durch zufällig ähnliche Namen.
  • Generierte Dateien werden automatisch ausgeschlossen — so wie das SDK sie kennt.
  • Das Umbenennen einer Klasse ist für die Rule unsichtbar — entscheidend ist, ob das Element referenziert wird, nicht wie es heißt.
  • Bibliotheks- und paketübergreifende Referenzen werden korrekt nachverfolgt.

Das ist „Semantik vor Syntax" in der Praxis: Rules sehen den Code so, wie der Compiler ihn sieht — nicht wie ein Texteditor.

Mehr in die Tiefe

Der Developer Guide (englisch) enthält die vollständige CLI-Referenz, Output-Formate, Konfiguration und ausgearbeitete Beispiele — darunter die vollständige Baseline-Onboarding-Sequenz und die Integration von loam gate in GitHub Actions.