Bestandsaufnahme-Grundgeruest (rls-access-inventory.spec.ts, drei Erkennungsformen), WINDOWS #27 aufgedeckt
Vierte Erkennungsform in rls-access-inventory.spec.ts: Relationszugriffe (include:/select:/_count:/Relationsfilter) werden ueber schema.prisma auf ihr Zielmodell aufgeloest und als eigene Fundstelle gefuehrt
72 (Datei, Modell)-Paare in der Bestandsaufnahme (65 -> 72, sieben neue, drei fortgeschriebene Staende)
WINDOWS #27 fixed mit Nachweis; neuer Ledger-Eintrag #33 fuer die von allen vier Formen unerreichbare Restmenge (tenders.seed.ts, backfill-tender-source.ts)
Kontextstapel-Parser (scanRelationKeys) fuer verschachtelte Prisma-Query-Objekte, aufgeloest gegen ein zur Testzeit geparstes schema.prisma
String-Blanking (blankStringLiterals) fuer klammertiefen-sichere Argumentbereichs-Erkennung, getrennt von der unveraenderten Kommentarfrei-Quelle der Formen 1-3
created
modified
apps/api/src/prisma/rls-access-inventory.spec.ts
docs/mandantentrennung-zugriffsklassifikation.md
docs/mandantentrennung-etappe2-fehlerrichtung.md
.planning/WINDOWS.md
Vierte Erkennung schreibt Relationsziele direkt in unboundModels/boundModels (Klientenname = Modellname mit kleinem Anfangsbuchstaben) statt eines eigenen Fundstellentyps, damit findAccessSites/computeStandByKey und die bestehenden Vergleichstests unveraendert bleiben
ldap-config.service.ts/ldapFieldMapping wechselt von muss-mandantengebunden auf beides — der Elternpfad getAllActiveConfigs() ist bereits als Hintergrunddienst-Fall an Etappe 3 uebergeben, kein neuer Befund
RELATION_SPEC_EXCEPTIONS bleibt schmal (eine Datei, backfill-tender-source.ts); die zweite unerreichbare Datei (tenders.seed.ts, kein Relationszugriff) wird stattdessen als eigener Ledger-Eintrag #33 gefuehrt, nicht stillschweigend mit #27 mitgeschlossen
WINDOWS-27
ETAPPE-4-VORAUSSETZUNG
~45min
2026-09-11
complete
Phase quick-260911-mkj: WINDOWS #27 schliessen — Relations-Blindstelle Summary
Vierte Erkennungsform in rls-access-inventory.spec.ts macht Relationszugriffe (include:/select:/_count:/Relationsfilter) sichtbar, die Prisma als Unterabfrage auf eine zweite Tabelle unter DEREN Regel rendert — Bestandsaufnahme waechst von 65 auf 72 Paare, WINDOWS #27 ist geschlossen.
Performance
Duration: ~45 min
Completed: 2026-09-11
Nachweis WINDOWS #27
Zwischenmessung (Aufgabe 1, VOR dem Nachziehen der Bestandsaufnahme) — woertlich, wie im Plan verlangt:
× jede im Quelltext gefundene (Datei, Modell)-Fundstelle ist im Dokument eingetragen
Fehlende Eintraege im Dokument:
apps/api/src/groups/module-grants.service.ts::module
apps/api/src/ldap/ldap-config.service.ts::tenant
apps/api/src/module-registry/module-access.service.ts::group
apps/api/src/module-registry/module-access.service.ts::groupMembership
apps/api/src/tenders/tender-digest.scheduler.ts::tender
apps/api/src/tenders/tender-digest.scheduler.ts::tenderSavedSearch
apps/api/src/tenders/tenders.controller.ts::tenderSource
× der eingetragene Stand stimmt mit dem im Quelltext gemessenen ueberein
Abweichender Stand (Dokument vs. Quelltext):
apps/api/src/ldap/ldap-config.service.ts::ldapFieldMapping — dokumentiert=gebunden, gemessen=gemischt
apps/api/src/module-registry/module-registry.service.ts::module — dokumentiert=ungebunden, gemessen=gemischt
apps/api/src/tenders/tender-matching.service.ts::tender — dokumentiert=ungebunden, gemessen=gemischt
Test Files 1 failed (1)
Tests 2 failed | 22 passed (24)
Das ist EXAKT die zur Planungszeit gemessene Untergrenze: 7 fehlende Paare,
3 Stand-Abweichungen. Der Detektor SIEHT die Relationszugriffe, bevor das
Dokument nachgezogen ist — der geforderte Beweis der Wirkung.
Zahlen (Aufgabe 1/2, aus der Ausgabe von rls-access-inventory.spec.ts und den Gates entnommen, nicht geschaetzt):
7 neue Paare, 3 fortgeschriebene Staende, davon 1 Klassenwechsel (ldap-config.service.ts/ldapFieldMapping: muss-mandantengebunden → beides)
Bestandsaufnahme: 65 → 72 Paare (35 muss-mandantengebunden, 21 keine-mandantengebundene-tabelle, 14 beides, 2 bewusst-uebergreifend — exakt die zur Planungszeit projizierte Verteilung)
Acht gepinnte Proben, darunter A (WINDOWS #27 ungebunden) und B (WINDOWS #27 gebunden, derselbe Aufruf auf einem forTenant(-Klienten) — beide bestanden
WINDOWS-Ledger: #27 fixed; neuer Eintrag #33 fuer die von allen vier Erkennungsformen unerreichbare Restmenge (tenders/tenders.seed.ts, tenders/backfill-tender-source.ts). Kopf nach diesem Lauf: open_count: 14, total_count: 33.
analyzeFile in analyzeSource(source, relPath) herausgeloest (testbar gegen Probestrings)
parseSchemaRelations() liest schema.prisma zur Testzeit, SCHEMA_RELATIONS (Map Modell -> Map Feld -> Zielmodell), CLIENT_NAME_TO_MODEL fuer den Anker; Lookahead (?=\s|$) bewusst gesetzt (ohne ihn verliert die Feldzeilen-Regex jede Listenrelation am Zeilenende — der im Plan benannte erste Prototyp-Fehler, hier vermieden)
Vierte Erkennung: Ankerregex nur ueber bekannte Empfaenger (this.prisma, boundNames, Transaktionsparameter beider Formen), Argumentbereich per Klammertiefe auf einer string-geblankten Kopie (blank), Wertform-Aufloesung gegen gleichnamige Konstanten derselben Datei, Kontextstapel-Scan (scanRelationKeys) fuer verschachtelte Relationsfelder inkl. _count: true
Drei neue Waechter (Rohzahl vs. erkannte Modellaufrufe, Stale-Check RELATION_SPEC_EXCEPTIONS, unresolvedRelationSpecValues leer), zwei Schema-Tests, acht gepinnte Proben — alle 24 Tests der Spec-Datei gruen
Bestandsaufnahme fortgeschrieben: sieben neue Zeilen, drei geaenderte Staende, Kopfabsatz "Erkennungsluecke GESCHLOSSEN" ersetzt den alten "seit 260911-e2s vermessen"-Absatz
Task 2 (docs(quick-260911-mkj): Abschnitte abgeleitet, WINDOWS #27 geschlossen, Restmenge als eigener Eintrag, Commit 388690f):
Klassifikationsdokument: Uebersichtsabsatz ("Zweite methodische Luecke ... geschlossen"), Klassen-Verteilung (Ueberschrift + Summenzeile + Tabelle, aus der Bestandsaufnahme GEZAEHLT: 35/21/14/2/72), Hintergrunddienst-Nachtrag zum ersten Fall (getAllActiveConfigs() reicht auch in LdapFieldMapping hinein — kein neuer Fall, Ueberschrift bleibt "sechs Faelle")
Kritikschrift: Nachtrag (260911-mkj) unter (n4) im ## Bereich tenant (verweist auf Befund G/(b) und die Restmenge), Vermerk im ## Etappe 2 — Abschluss, dass #27 geschlossen ist
Ledger: neuer Eintrag #33 angelegt (Ledger fuer die Restmenge), dann #27 auf fixed gesetzt, dann der WINDOWS #TBD-MKJ-Platzhalter im Spec-Kommentar durch WINDOWS #33 ersetzt
Deviations from Plan
Auto-fixed Issues
None — plan executed exactly as specified for the actual detector/document logic.
Documented Drift (nicht auto-fixed, nicht Teil dieses Plans)
1. [Vorbestehende Abweichung, nicht dieser Plan] docs/mandantentrennung-etappe3-auftrag.md und Teile von .planning/HANDOFF.json weichen bereits VOR Beginn dieser Ausfuehrung von der Basis cc26197 ab.
Gefunden bei: dem Allowlist-Diff-Gate in Aufgabe 1 (git diff --name-only cc26197)
Ursache: Commit 926359b ("docs: Auftrag fuer Etappe 3 der Mandantentrennung, gemessen statt erinnert", Autor Schalli) landete auf main, BEVOR diese Ausfuehrung begann — die im Auftrag genannte Basis-HEAD 261e736 war zu diesem Zeitpunkt bereits um einen fremden Commit veraltet.
Pruefung:git show --stat 926359b zeigt ausschliesslich docs/mandantentrennung-etappe3-auftrag.md (neu) und .planning/HANDOFF.json — nichts unter apps/api/src, kein Schema, keine Migration, keine Compose-/Umgebungsdatei. Ausserhalb des Geltungsbereichs dieses Plans, nicht angefasst.
Auswirkung auf die Verify-Gates: das im Plan definierte Allowlist-Gate (git diff --name-only cc26197 gegen eine feste Dateiliste) meldet docs/mandantentrennung-etappe3-auftrag.md als "unerwartete Aenderung", weil es diesen fremden, bereits gemergten Commit mitzaehlt. Die tatsaechlich von dieser Ausfuehrung veraenderten Dateien sind ausschliesslich die vier oben genannten (bestaetigt durch git status --short vor jedem Commit und durch die beiden Commits 5ad23d0/388690f selbst — je genau die im Plan als Deliverables genannten Dateien, keine mehr).
Nicht behoben, weil: ausserhalb der Erlaubnisliste dieses Plans (nur die Spec-Datei, apps/api/prisma/**, zwei benannte Dokumente, .planning/) — ein fremder, bereits abgeschlossener Commit gehoert nicht in diesen Auftrag.
Known Stubs
None — dieser Plan aendert ausschliesslich Testcode und Dokumentation, keine UI/keine Laufzeitpfade.
Threat Flags
None — die Aenderungen liegen vollstaendig innerhalb des im Plan definierten threat_model (T-MKJ-01 bis T-MKJ-05), keine neue Angriffsflaeche ausserhalb dessen.
BEFUND — nicht behoben
Keiner. Die Zwischenmessung lieferte exakt 7 fehlende Paare / 3 Stand-Abweichungen (die geplante Untergrenze, keine zusaetzlichen ungenannten Funde); jedes der sieben neuen Paare wurde einzeln am Quelltext geprueft (siehe Zeilenverweise in der Bestandsaufnahme-Tabelle) und ist entweder keine-mandantengebundene-tabelle (Elternbindung wirkungslos, nicht schaedlich) oder muss-mandantengebunden/gebunden (Relationsfilter auf einem bereits gebundenen Klienten in eine Tabelle desselben Mandanten). Keine ungebundene Einbindung in eine geschuetzte Tabelle auf ungeschuetztem Elternpfad, die nicht bereits als Hintergrunddienst-Fall benannt waere.
docs/mandantentrennung-etappe2-fehlerrichtung.md: FOUND, Nachtrag (260911-mkj) unter (n4) und im Abschluss-Abschnitt
.planning/WINDOWS.md: FOUND, #27 Status fixed, #33 neu mit Status open, Kopfzaehler (open_count: 14, total_count: 33) konsistent mit den Tabellenzeilen