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
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.
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).
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.
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.
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.
Der Reporter formatiert Ergebnisse für Menschen oder Maschinen: human für die Terminal-Ausgabe,json / sarif / markdownfür Agent-Pipelines und html für einen interaktiven, in sich geschlossenen Report mit eingebautem Fix-Prompt-Builder.
Ein echter Report
Das ist exakt der html-Report, den loam.dev schreibt — erzeugt aus einem kleinen, bewusst unordentlichen Demo-Projekt. Live, kein Screenshot: nach Rule oder Severity filtern, die relevanten Findings auswählen und den fertigen, versionierten Fix-Prompt für deinen Agenten kopieren.
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 zeigtalle 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 imRatchet-Modus: Nur Findings, die neusind (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 --write →loam gate ab sofort in CI.
Semantik vor Syntax
Die wichtigste Architekturentscheidung in loam.dev ist, worüberdie 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 vonloam gate in GitHub Actions.