Zum Inhalt springen

Requirements-Coverage

Wie req coverage bidirektionale Traceability misst — Rollups pro Requirement, klassifizierte unjustified Methods, die Infrastructure-Exemption und das optionale Tolerated-Legacy-Gate.

codecharter req coverage und das MCP-Tool req_coverage melden ein Coverage-Modell aus beiden Richtungen der Traceability, berechnet von einem einzigen gemeinsamen Aggregator, damit die beiden Oberflächen bei keiner Zahl auseinanderlaufen können:

  • Requirement → Code: Hält die Evidenz jedes Requirements gerade noch?
  • Code → Requirement: Welche Methoden tragen überhaupt keine [Satisfies]-Rechtfertigung, und warum?

Beide Hälften nutzen dieselben Evaluatoren und Indizes, die schon Requirements und Anforderungen über MCP beschreiben, kein Criterion, Verdict oder Justification-Walk wird für diesen Report neu implementiert.

Requirement → Code: Rollups

Jedes Criterion eines Requirements wird genau einmal ausgewertet, mit demselben Pin-Evaluator, den req check --with-code und req_verify verwenden, und dann zu einem einzigen Worst-of-Verdict aufgerollt, nach dieser festen Rangfolge:

Rang Verdict Warum dieser Rang
5 (schlechtest) violated Nachweislich gebrochen gegen den aktuellen Code.
4 stale Eine verfallene positive Aussage: hat einmal gehalten, die gepinnte Evidenz hat sich seitdem geändert, in einer alten Traceability-Matrix aktiv irreführend, deshalb rangiert es vor einer ehrlichen Nicht-Antwort.
3 unknown Auswertung konnte sich nicht entscheiden. Eine ehrliche Nicht-Antwort, kein Zeichen für Zustand oder Verfall.
2 open Eine deklarierte Lücke, das am wenigsten alarmierende nicht-grüne Ergebnis, weil bewusst statt entdeckt.
1 (best) holds Jedes Criterion hält.

Nie unverdient grün. Ein Requirement ohne Criteria rollt nicht zu holds auf, es rollt zu open mit einem unbound-Grund von no-criteria auf. Dasselbe gilt für null Anchors (no-anchors) und Anchors, die alle nicht aufgelöst werden konnten (anchors-unresolved). Dasselbe Prinzip "nie Holds melden, ohne geprüft zu haben", das die Criterion-Evaluatoren schon anwenden, nur auf Requirement-Ebene erweitert.

Der Frontmatter-Key status fließt nie in das Rollup ein, er wird daneben gemeldet. Ein Requirement, dessen deklarierter Status vom Rollup abweicht (status: implemented bei einem Rollup ungleich holds, oder status: open bei einem Rollup von holds), wird als Status-Divergenz gemeldet: zur Sichtbarkeit, nie um das Rollup zu ändern.

Code → Requirement: klassifizierte Methoden

Jede Methode im analysierten Codemodell fällt in genau einen von drei disjunkten Buckets, gemeldet als zwei Kopfzahlen, die nie zu einer einzigen mehrdeutigen Zahl zusammengeführt werden:

  • justified: von mindestens einem Justification-Walk eines Nicht-Infrastructure-Requirements erreicht.
  • infrastructure-declared: siehe Infrastructure-Exemption.
  • unjustified, weiter unterteilt in:
    • dead-candidate: kein Caller ist für den Justification-Walk sichtbar, und die Methode ist auch kein Dispatch-Ziel (weder eine Interface-Implementierung noch ein Override noch eine Implementing-Method erreicht sie). Nie als bewiesen ungenutzt zu verstehen, nur als nicht erreichbar über die sichtbaren Kanten dieses Walks (keine Reflection, kein Delegate-Aufruf, kein dynamischer Dispatch wird verfolgt). Der Report sagt immer "candidate", nie "dead" allein.
    • undocumented-requirement-candidate: hat sichtbare Caller, aber kein Anchor erreicht sie über seinen Justification-Walk. Trägt einen nearest_anchored_neighbour: die nächste justified Method, gefunden durch eine begrenzte Rückwärtssuche über Caller und Dispatch-Vorgänger (auf vier Hops gedeckelt), zusammen mit den Requirement-Ids, die sie rechtfertigen, null, wenn die Grenze erreicht wird, nie eine Vermutung. Genau dieser Hinweis speist req_draft beim Entwurf eines neuen Requirements.

justified_percent = justified / total_methods; accounted_percent = (justified + infrastructure_declared) / total_methods. Hat der Corpus überhaupt keine [Satisfies]-Anchors, melden beide Prozentwerte 0 mit einem expliziten Hinweis, und es wird keine klassifizierte Liste erzeugt, ein Repository, das Anchoring noch nicht eingeführt hat, soll beim ersten Lauf keine zehntausend "dead candidates" bekommen.

Infrastructure-Exemption

Ein Requirement mit kind: infrastructure befreit genau die Methoden, die seine [Satisfies]-Anchors direkt benennen, ein Method-Anchor befreit diese Method, ein Type-Anchor befreit alle Methods dieses Typs. Diese Befreiung ist deklariert, nie erraten: Es gibt keine Heuristik, die von sich aus ableitet, "das sieht nach Glue-Code aus", eine fälschlich als Infrastructure eingestufte Fachlogik ist deshalb immer eine sichtbare Attribut-Änderung in einem Diff, nie eine stille Klassifikator-Entscheidung.

Sie ist außerdem bewusst nicht transitiv. Ein Anchor auf Program oder eine DI-Registrierungsklasse befreit nicht alles, was diese Methoden aufrufen, nur die direkt verankerten Deklarationen selbst. Eine transitive Befreiung würde ein Attribut am Composition-Root die halbe Solution befreien lassen, genau die Art Fehletikettierung, die dieser Report sichtbar halten soll. Erreicht der Justification-Walk eines Nicht-Infrastructure-Requirements eine Methode, die auch direkt als Infrastructure befreit ist, gibt der Report einen Info-Hinweis req-infrastructure-overreach aus, ein Signal, dass das Infrastructure-Label möglicherweise auf Code angewendet wurde, von dem Fachlogik tatsächlich abhängt.

Diff-Scope

--git-ref/git_ref (oder rohes diff-Text über MCP) schränkt die klassifizierte Methoden- und die Rollup-Liste auf das ein, was der Diff berührt. Jede Summe und jeder Prozentwert, einschließlich justified_percent und accounted_percent, bleibt corpus-weit, nur die beiden Listen schrumpfen, mit einem scope: diff-Hinweis, der das benennt. Dasselbe Muster wie graph_hubss eigenes scope-Feld: eine diff-eingeschränkte Ansicht verengt nie still, was eine Summenzahl zu umfassen behauptet.

Das Tolerated-Legacy-Gate

Coverage meldet eine Zahl ab dem Moment der Einführung, selbst auf einer großen, nur teilweise verankerten Codebase, aber diese Zahl muss nicht erst 100% sein, um nützlich zu sein, und sie soll auch nicht still zurückfallen. req coverage liefert deshalb ein Einweg-Ratchet, dasselbe Muster wie die Findings-Baseline:

  1. codecharter req coverage --write-baseline schreibt einmalig die Identität jeder aktuell unjustified Method (Roslyn-Deklarations-Id, mit Fallback auf einen Graph-Key, wenn der Compiler keine erzeugt hat, ein Rename macht einen Fallback-Eintrag absichtlich ungültig) nach .codecharter/req/coverage-baseline.json.
  2. Ab dann rendert eine in der Baseline stehende Method als tolerated; eine neue unjustified Method, eine, die nicht in der Baseline steht, rendert als new und beendet den Lauf, sobald das Gate aktiv ist, mit einem Fehler-Exit.
  3. Das Gate selbst (Exit ungleich 0 bei jeder new-Method) ist Opt-in, hinter req.coverage.gate.enabled: true in .codecharter/config.yml (Default false). Die Mechanik und der fehlschlagende Exit-Code existieren und sind getestet, unabhängig davon, ob ein Repository bereits opted-in hat.

Als Infrastructure deklarierte Methoden sind bewusst befreit und zählen nie als Baseline-Schuld, nur dead-candidate- und undocumented-requirement-candidate-Methoden werden verfolgt. Die Baseline weitet sich nie von selbst aus: Nur --write-baseline schreibt sie, und wiederholtes Schreiben derselben Menge ist bytegenau identisch (sortiert, dedupliziert, ohne Zeitstempel).

Zuerst Report, dann Gate: ein Goodhart-Hinweis

Attributes are diff-visible and review-carried; the metric is not a target until the gate exists.

[Satisfies]-Anchors sind etwas, das ein Reviewer in einem Pull-Request-Diff sieht wie jede andere Code-Änderung auch, keine Punktzahl, die ein Tool still im Hintergrund ableitet. Coverage existiert, um eine ehrliche Zahl sichtbar zu machen und ihr stilles Zurückfallen zu verhindern, sobald das gewünscht ist, nicht um selbst zum verfolgten Ziel zu werden. Direkt auf die Prozentzahl zu optimieren, etwa Requirements wahllos an Code zu ankern, nur um justified_percent zu erhöhen, verfehlt den Zweck: Die Zahl ist nur so vertrauenswürdig wie die Anchors, die ein Mensch tatsächlich reviewt hat.