Zusammenfassung mit Urteilsregister und STATE.md zum Quick-Vorgang 260921-m34. Der groesste Posten war ein einziges Missverstaendnis: 105 Stellen trugen eine Zusicherung an der Mandantenbindung, die nie noetig war - prisma.$extends() liefert laengst einen getypten Klienten. Die tenantId-Frage wurde hergeleitet statt nach Bequemlichkeit entschieden: string ohne Fragezeichen, belegt aus Pflichtspalte im Schema, Bestandstyp und dem Super-Admin-Zweig der Mandantenpruefung - der diesen Typ gar nicht liest und deshalb nicht zu totem Code werden kann. Der Waechter blieb ueber den ganzen Lauf unveraendert. Vier Befunde gemeldet statt still repariert. Zwei brauchen eine Entscheidung, beide wuerden Verhalten aendern - darunter ein sicherheitsrelevanter: die IMAP-Einstellung STARTTLS erzwingt nichts, weil die gesetzte Option in imapflow 1.4.3 nicht existiert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
22 KiB
phase, plan, subsystem, tags, status, requires, provides, affects, tech-stack, key-files, decisions, metrics, actuals, plan_head_before
| phase | plan | subsystem | tags | status | requires | provides | affects | tech-stack | key-files | decisions | metrics | actuals | plan_head_before | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260921-m34 | 01 | apps/api (Typdisziplin) |
|
complete |
|
|
|
|
|
|
|
8d845e7 |
Quick-Aufgabe 260921-m34: 288 any im Backend einzeln beurteilen Summary
Die 288 any-Befunde in apps/api sind auf 15 gefallen, jeder der 288 hat
ein Urteil mit Begruendung, und die Arbeit hat sieben falsche Annahmen im
Bestandscode aufgedeckt, die alle gemeldet und keine still repariert wurden.
Die Zahl, und was sie bedeutet
| Groesse | Ausgang | Ende |
|---|---|---|
lint/suspicious/noExplicitAny in apps/api/src |
288 (48 Dateien) | 15 (7 Dateien) |
dasselbe in apps/web/src |
1 | 0 |
lint/style/noNonNullAssertion in apps/api/src |
56 | 56 |
as unknown as in apps/api/src |
33 | 33 |
ts-expect-error / ts-ignore |
0 / 0 | 0 / 0 |
| Lint-Unterdrueckungsmarker | 1 | 1 |
Befunde der Schwere error |
0 | 0 |
Die vier Zeilen in der Mitte sind die wichtigsten der Tabelle. Sie belegen, dass die 273 verschwundenen Befunde tatsaechlich getypt und nicht bloss stillgelegt wurden: haette die Arbeit die bequeme Abkuerzung genommen, waere mindestens einer dieser Zaehlwerte gestiegen. Keiner ist gestiegen.
Aufteilung der 288 auf die drei Urteile (D-01)
| Urteil | Anzahl | Was dahintersteckt |
|---|---|---|
| typisiert | 252 | Die Zusicherung war ueberfluessig oder der richtige Typ war ableitbar — aus Prismas Erweiterungstypen, aus den beiden Signierstellen des Tokens, aus schema.prisma, oder aus den mitgelieferten Typen einer Fremdbibliothek. |
auf unknown umgestellt |
21 | 18 Fehlerfaenger, die beiden .then((results: unknown[]) => ...) in prisma-tenant.extension.ts und intercept(): Observable<unknown>. |
| bleibt | 15 | Register unten. Jede Stelle traegt ihre Begruendung ausserdem direkt im Code. |
| 288 |
Der Plan hat 20 bis 40 verbleibende Befunde erwartet; es sind 15 geworden. Der
Unterschied kommt nicht daher, dass hier mehr erzwungen wurde, sondern aus drei
Messungen, die guenstiger ausfielen als die Vorschau: @types/node-forge
beschreibt PKCS7 besser als angenommen (die vier p7: any liessen sich mit dem
mitgelieferten Captured<...>-Typ aufloesen), imapflow deklariert
node.parameters bereits vollstaendig, und expect.extend(matchers) in
apps/web brauchte seine Zusicherung schlicht nicht mehr. Die Zaehlwerte oben
sind der Beleg, dass dabei nichts gegen eine Behauptung getauscht wurde.
Urteilsregister: die 15 Stellen, die bleiben
Jede dieser Zeilen steht so auch als Kommentar an der Codestelle. Wer spaeter hier aufraeumen will, findet die Begruendung dort, wo er zuerst nachsieht.
| # | Datei:Zeile | Form | Begruendung (gemessen) |
|---|---|---|---|
| 1 | cert-manager/cert-manager.service.ts:296 |
cert.publicKey as any |
@types/node-forge kennt nur PublicKey = rsa.PublicKey | ed25519.Key (index.d.ts:232). Der EC-Zweig darunter liest curve und params.curve.q.bitLength() — Felder, die node-forge zur Laufzeit liefert, die der mitgelieferte Typ aber gar nicht kennt. Eine Umdeutung ueber zwei Stufen wuerde dieselbe Luecke verdecken und zusaetzlich geprueft aussehen. |
| 2 | cert-manager/cert-manager.service.ts:318 |
(e: any) |
Certificate.extensions ist in @types/node-forge als any[] deklariert (index.d.ts:435). Der mitgelieferte Typ sagt ueber den Inhalt einer Erweiterung nichts aus. |
| 3 | cert-manager/cert-manager.service.ts:319 |
(sanExt as any) |
wie 2 — sanExt stammt aus demselben any[]. |
| 4 | cert-manager/cert-manager.service.ts:319 |
(n: any) |
wie 2. Eine eigene Schnittstelle fuer altNames waere unbelegt: der Compiler koennte sie an keiner Stelle gegen etwas pruefen, sie saehe aber geprueft aus (D-02). |
| 5 | cert-manager/cert-manager.service.ts:589 |
null as any |
node-forge 1.4.0 nimmt hier einen fehlenden Schluessel an und erzeugt ein reines Zertifikatsbuendel; @types/node-forge schliesst null aus. Die mitgelieferten Typen beschreiben die Bibliothek an dieser Stelle nachweislich falsch. |
| 6 | cert-manager/cert-manager.service.ts:752 |
null as any |
wie 5, zweite Aufrufstelle. |
| 7 | dkv/dkv-scheduler.service.ts:144 |
job as any |
Ohne die Zusicherung meldet tsc, dass das lokale job nur die Form { start(): void } hat, waehrend addCronJob() einen vollstaendigen CronJob verlangt. Ursache ist der require()-Umweg aus 07-04 (pnpm-Isolation, cron ist nur mittelbare Abhaengigkeit). Aufloesen hiesse die Beschaffung der Klasse aendern (Verhaltensaenderung, D-03) oder cron direkt aufnehmen (neue Abhaengigkeit, D-04). |
| 8 | tenders/tender-digest.scheduler.ts:94 |
job as any |
wie 7. |
| 9 | tenders/tender-scheduler.service.ts:143 |
job as any |
wie 7. |
| 10 | groups/groups.service.ts:373 |
(u: any) |
Gefolge von 12: tx ist selbst any, und any.map() gibt dem Parameter keine kontextuelle Typisierung. Faellt automatisch mit 12. |
| 11 | groups/groups.service.ts:390 |
(a: any) |
wie 10. |
| 12 | prisma/prisma-tenant.extension.ts:264 |
fn: (tx: any) |
In Aufgabe 1 gemessen und verworfen: Prisma.TransactionClient erzwingt an den vier Aufrufstellen vollstaendige Prisma-Erzeugungstypen und bricht das absichtlich unvollstaendige Testdoppel in prisma-tenant.extension.spec.ts (TS2322). Das waere eine Aenderung an einer Teststruktur, kein ehrliches Typisieren. |
| 13 | prisma/prisma-tenant.extension.ts:266 |
async (tx: any) |
wie 12, dieselbe Funktion. |
| 14 | inbox/imap.provider.ts:78 |
(node as any).disposition... |
Befund B-05. Bleibt absichtlich sichtbar: der Ausdruck liest .parameters von einer Zeichenkette und ist zur Laufzeit immer undefined. Umbiegen auf dispositionParameters waere eine Verhaltensaenderung. |
| 15 | inbox/imap.provider.ts:402 |
} as any |
Befund B-06. Bleibt absichtlich sichtbar: die Zusicherung verdeckt, dass requireTLS in imapflow 1.4.3 gar nicht existiert. Die Option zu entfernen waere eine stille Reparatur. |
Die Gruppen dahinter sind klein: sechs Stellen an node-forge, drei an der Cron-Beschaffung, vier an der Transaktionshilfe, zwei absichtlich stehen gelassene Befunde an imapflow.
Die aufgedeckten falschen Annahmen (D-03)
Diese Aufgabe hat ohne bekannten Fehler begonnen. Das hier ist ihr eigentlicher Ertrag: sieben Stellen, an denen der Bestandscode etwas annimmt, was nicht stimmt. Keine davon wurde still repariert — das Verhalten der API ist unveraendert.
B-01 — tenders/tender-matching.service.ts:159 (Aufgabe 1).
Die Handannotation (match: { tender: unknown }) verengte den Wert falsch,
sobald der Prisma-Klient richtig getypt war. Sie existierte nur, um unter dem
any-Klienten TS7006 zu vermeiden. Annotation geloescht, damit der hergeleitete
Typ durchkommt; keine Zusicherung an ihrer Stelle.
B-02 — dashboard/dashboard.controller.ts:74 (Aufgabe 2b).
Der Handler las req.user?.role nach extractContext() und gab die Rolle an
getWidgets(role: Role) weiter, das sie zwingend verlangt. Die Annahme "hier
gibt es immer einen Aufrufer" stimmt — die Pruefung "No user context" erzwingt
sie —, aber sie stand in einer anderen Methode, wo der Compiler sie nicht sehen
konnte. extractContext() gibt die Rolle jetzt mit zurueck: keine neue Pruefung,
kein erfundener Wert, gleiche Reihenfolge, gleiche Meldungen.
B-03 — tenders/tenders.controller.ts:142 (Aufgabe 2b).
resolveRequestingTenantId() erklaerte string | undefined, liest aber
req.tenantId, das TenantGuard fuer einen SUPER_ADMIN ohne Mandanten auf
null setzt. Die Erklaerung war nie vollstaendig. Auf
string | null | undefined erweitert — reine Erklaerung: die Funktion
entscheidet seit jeher ueber den Wahrheitswert und faellt bei null wie bei
undefined zu (nur global sichtbare Ausschreibungen).
B-04 — Falle im Mandantentrennungs-Erkenner (Aufgabe 3b).
Die naheliegende Prisma-Schreibweise Prisma.UserGetPayload<{ select: typeof X }>
laesst rls-access-inventory.spec.ts rot werden: der Erkenner zaehlt jede
select:-Angabe ausserhalb eines erkannten Modellaufrufs als Verstoss und
unterscheidet Typposition nicht von Aufrufposition. Beim ersten Versuch gemessen.
Der Erkenner ist die Mandantenkontrolle (T-M34-03) und wurde nicht
aufgeweicht — stattdessen leitet der Zeilentyp ueber Pick<User, keyof typeof PLATFORM_USER_SELECT> her, was ohne das Wort select auskommt. Wer kuenftig
UserGetPayload einsetzen will, muss zuerst den Erkenner erweitern, nicht die
Ausnahmeliste.
B-05 — inbox/imap.provider.ts:78 (Aufgabe 3c). Sicherheitsnah, offen.
(node as any).disposition?.parameters?.filename liest .parameters von einer
Zeichenkette: imapflow deklariert disposition als string
(imap-flow.d.ts:448, also "attachment"/"inline"), die zugehoerigen Parameter
liegen in einem eigenen Feld dispositionParameters (:450). Der Ausdruck ist zur
Laufzeit immer undefined, dispositionFilename ist stets ''. Folge:
Anhaenge, die als application/octet-stream kommen (typisch fuer Outlook),
werden ueber den Dateinamen aus Content-Disposition nicht erkannt — nur ueber
den aus Content-Type. Betrifft den DKV-Rechnungseinzug. Nicht repariert, weil das
Umbiegen erstmals Anhaenge einsammeln wuerde, die heute uebersprungen werden —
eine Verhaltensaenderung, die ein Mensch entscheiden muss.
B-06 — inbox/imap.provider.ts:402 (Aufgabe 3c). Sicherheitsnah, offen.
requireTLS: config.encryption === 'starttls' wird an new ImapFlow(...)
uebergeben, aber requireTLS kommt in imapflow 1.4.3 nirgends vor — weder in
ImapFlowOptions (lib/imap-flow.d.ts) noch im Laufzeitcode
(lib/imap-flow.js), beides durchsucht. Die Option wird still verworfen; ein
STARTTLS-Zwang entsteht durch sie nicht. Genau das } as any hat es verdeckt.
Die Einstellung "STARTTLS" in der Postfach-Konfiguration bewirkt damit nicht das,
was ihr Name verspricht. Nicht repariert (D-03), Zusicherung bleibt sichtbar
stehen, damit der Befund in der Zaehlung nicht verschwindet.
B-07 — httpntlm-Antwortrumpf (Aufgabe 3c). Ohne Auswirkung, aber falsch.
Beide Exchange-Wege riefen res.body?.toString('utf-8') auf und nahmen damit
einen Buffer an. Gemessen: httpntlm reicht an httpreq durch, und httpreq gibt den
Rumpf als Zeichenkette zurueck, solange die Option binary nicht gesetzt ist
(httpreq@1.1.1/lib/httpreq.js:391) — keiner der beiden Aufrufer setzt sie. Das
ging bisher nur gut, weil String.prototype.toString() sein Argument ignoriert.
Die Testdoppel reichen umgekehrt wirklich einen Buffer herein, beide Formen kommen
also vor. NtlmResponse.body nennt jetzt beide; die Fallunterscheidung liefert
fuer jede exakt dasselbe Ergebnis wie zuvor.
Die tenantId-Entscheidung im gemeinsamen Aufrufer-Typ
AuthUser.tenantId ist string, nicht string | undefined. Die Messung
allein haette in die falsche Richtung gedraengt (string | undefined erzeugte
acht Fehler im Produktivcode, string keinen); entschieden wurde auf drei
Belegen:
apps/api/prisma/schema.prismadeklariertUser.tenantId Stringohne?. Die Spalte ist Pflicht, und beide Signierstellen schreiben genau diesen Spaltenwert — seit dem ersten Commit des Anmeldedienstes (6190f3d) gibt es keine Token-Erzeugung ohne diesen Anspruch.- Der Bestand beschreibt dasselbe Objekt in
SessionUser(bug-reports.service.ts) bereits alstenantId: string.SessionUserist jetzt einPick<>vonAuthUser, damit es keine zweite, abweichende Beschreibung desselben Objekts gibt. TenantGuardhaelt fuer SUPER_ADMIN einen Zweig ohne Mandanten vor und setzt dortreq.tenantId = null.
Beleg 3 spricht nicht gegen string, und genau daran haengt die
Sicherheitsfrage: der Zweig in TenantGuard ist eine Tiefenverteidigung gegen
ein Token ohne diesen Anspruch, und er liest AuthUser gar nicht — der Waechter
holt sein Anfrageobjekt ungetypt. Dieser Typ kann den Zweig also nicht zu totem
Code machen. Dass es den Zweig gibt, steht ausserdem weiterhin im Typsystem, nur
an der richtigen Stelle: AuthenticatedRequest.tenantId ist
string | null | undefined.
Am Typ steht dazu eine ausdrueckliche Warnung fuer spaetere Leser, dass der
SUPER_ADMIN-Zweig ein Schutzzweig ist und nicht entfernt oder wegtypisiert werden
darf (T-M34-01). tenant.guard.ts wurde in diesem ganzen Lauf nicht
angefasst — in Aufgabe 2 per git diff --stat nachgewiesen.
Was die Arbeit sonst noch geaendert hat
Zwei neue Dateien, beide klein und begruendet.
apps/api/src/auth/types/auth-user.ts traegt den gemeinsamen Aufrufer-Typ; jedes
Feld hat seine Herkunft als Kommentar. apps/api/src/prisma/prisma-error.ts
traegt prismaErrorCode() und prismaErrorTarget().
Warum die Fehlereingrenzung Form-Pruefungen macht und kein instanceof.
Der naheliegende Weg waere
err instanceof Prisma.PrismaClientKnownRequestError gewesen. Gemessen: samtliche
Testdoppel in apps/api werfen new Error(...) mit angehaengtem .code
(groups, user, ldap, tenders, module-grants, admin-seed) und
dashboard.service.spec.ts:451 ein reines { code: 'P2002' }. Ein
instanceof-Test haette all diese Werte in den jeweils anderen Zweig
geschickt — eine Verhaltensaenderung, und nach T-M34-06 genau die Art von
Aenderung, die einen Hintergrundlauf kuenftig abbrechen laesst, der heute
weiterlaeuft. Die Helfer bilden err?.code und err?.meta?.target deshalb eins
zu eins ab, nur ohne any.
Nebengewinne ohne neue Zusicherungen. In cert-manager.service.ts sind 25
Zusicherungen der Form file.buffer as Buffer weggefallen, weil file kein
any mehr ist. In dkv und settings fielen req.tenantId as string | undefined weg. as unknown as ist trotzdem bei 33 geblieben — dieselbe Zahl wie
zu Beginn.
Abweichungen vom Plan
1. [Regel 3 — blockierend] Neue Datei prisma/prisma-error.ts statt 18
Eingrenzungen von Hand. Der Plan nennt fuer Aufgabe 3 Schritt A keine neue
Datei. 18 Fehlerfaenger einzeln mit einer vierzeiligen Form-Pruefung zu versehen
haette dieselbe Logik achtzehnmal wiederholt und die Begruendung, warum kein
instanceof verwendet wird, achtzehnmal daneben. Die Datei liegt in prisma/,
weil alle Aufrufer Prisma-Fehlercodes pruefen. Keine neue Abhaengigkeit.
Commit: 32591b6.
2. [Regel 1 — Fehler] Erste Fassung von user.service.ts machte die
Mandanten-Spec rot. Prisma.UserGetPayload<{ select: typeof X }> hat
rls-access-inventory.spec.ts gebrochen (siehe B-04). Sofort im selben Schritt
auf Pick<User, ...> umgestellt, der Erkenner blieb unangetastet, Spec wieder
30/30. Commit: 3892c5f.
3. [Messung weicht vom Plan ab] calendar.service.ts:206/255 sind keine
Prisma-JSON-Eingaben. Der Plan vermutete Prisma.InputJsonValue. Gemessen:
es sind dynamisch gebaute Erzeugungs- und Aenderungseingaben fuer
CalendarSource. Richtig getypt mit
Prisma.CalendarSourceUncheckedCreateInput / ...UncheckedUpdateInput.
Commit: 3892c5f.
4. [Messung weicht vom Plan ab] node-forge war besser beschrieben als
erwartet. Der Plan rechnete damit, dass ein Teil der elf Stellen bleibt.
Gemessen: die vier p7: any liessen sich mit dem mitgelieferten
Captured<PkcsEnvelopedData | PkcsSignedData> aufloesen, cert.siginfo war
ohnehin getypt. Sechs bleiben, fuenf wurden getypt. Commit: d8fb9ae.
Pruefungen — die echten Ausgaben
noExplicitAny, noNonNullAssertion, error-Befunde
$ npx biome lint --reporter=json --max-diagnostics=2000 apps/api/src | python3 -c "..."
any 15 nonnull 56 error 0
Rueckgabewert: 0
Schranke der Aufgabe: any <= 45, nonnull <= 56, error == 0. Alle drei
eingehalten.
Vollstaendige Restliste (Pruefung 2 der Aufgabe)
apps/api/src/cert-manager/cert-manager.service.ts:296:40 | const pubKey = cert.publicKey as any;
apps/api/src/cert-manager/cert-manager.service.ts:318:48 | const sanExt = cert.extensions?.find((e: any) => e.name === 'subjectAltName');
apps/api/src/cert-manager/cert-manager.service.ts:319:41 | const san: string[] = ((sanExt as any)?.altNames ?? []).map((n: any) =>
apps/api/src/cert-manager/cert-manager.service.ts:319:71 | const san: string[] = ((sanExt as any)?.altNames ?? []).map((n: any) =>
apps/api/src/cert-manager/cert-manager.service.ts:589:19 | null as any, // cert-only PFX - null key accepted by node-forge 1.4.0
apps/api/src/cert-manager/cert-manager.service.ts:752:19 | null as any, // cert-only PFX - null key accepted by node-forge 1.4.0
apps/api/src/dkv/dkv-scheduler.service.ts:144:55 | this.schedulerRegistry.addCronJob(jobName, job as any);
apps/api/src/groups/groups.service.ts:373:33 | data: users.map((u: any) => ({
apps/api/src/groups/groups.service.ts:390:39 | data: activations.map((a: any) => ({
apps/api/src/inbox/imap.provider.ts:78:15 | ((node as any).disposition?.parameters?.filename as string | undefined)?.toLowerCase() ?? '';
apps/api/src/inbox/imap.provider.ts:402:10 | } as any);
apps/api/src/prisma/prisma-tenant.extension.ts:264:12 | fn: (tx: any) => Promise<T>,
apps/api/src/prisma/prisma-tenant.extension.ts:266:41 | return prisma.$transaction(async (tx: any) => {
apps/api/src/tenders/tender-digest.scheduler.ts:94:63 | this.schedulerRegistry.addCronJob(this.JOB_NAME, job as any);
apps/api/src/tenders/tender-scheduler.service.ts:143:61 | this.schedulerRegistry.addCronJob(this.JOB_NAME, job as any);
TOTAL 15
Jede dieser 15 Zeilen steht im Urteilsregister oben. apps/web/src liefert
keine Zeile mehr.
Unterdrueckungsmarker
### 3. Unterdrueckungsmarker
keine stillgelegten Stellen
Das heisst im Einzelnen: ts-expect-error 0, ts-ignore 0, biome-ignore 1
(der eine Bestandsmarker), as unknown as 33.
biome.json und Abhaengigkeiten
### 4. biome.json
biome.json unberuehrt
### 5. Abhaengigkeiten
keine neuen Abhaengigkeiten, keine Versionsspruenge
Geprueft ueber git diff --stat HEAD gegen biome.json, alle drei
package.json und pnpm-lock.yaml — jede Ausgabe leer.
Typlauf und Lint
### 6. type-check / lint
type-check 4/4, lint 5/5
Testsuiten
$ pnpm --dir apps/api run test
Test Files 72 passed (72)
Tests 1143 passed (1143)
Duration 8.05s
$ pnpm --dir apps/web run test
Test Files 73 passed (73)
Tests 531 passed (531)
Duration 23.48s
Unveraenderte Zahlen gegenueber dem Ausgang (72/1143 und 73/531).
Mandantentrennungs-Erkenner, ausdruecklich einzeln
$ pnpm --dir apps/api exec vitest run src/prisma/rls-access-inventory.spec.ts
Test Files 1 passed (1)
Tests 30 passed (30)
Duration 557ms
Das ist die Kontrolle aus T-M34-03. Sie war in Aufgabe 3b einmal rot (B-04) und wurde nicht durch Aufweichen, sondern durch eine andere Typschreibweise wieder gruen.
Commits
| Commit | Aufgabe | any in apps/api danach |
|---|---|---|
b188946 |
1 — Mandantenbindung entzaubert, 105 unnoetige Zusicherungen | 149 |
f2fc39f |
2a — gemeinsamer Aufrufer-Typ, aus den Signierstellen abgeleitet | 137 |
7c9d7c1 |
2b — getypte Anfrage in elf Controllern, zwei Befunde gemeldet | 66 |
52668c2 |
2c — Hochladewege getypt, 25 Zusicherungen fallen mit | 56 |
32591b6 |
3a — 18 Fehlerfaenger auf unknown, mit echter Eingrenzung |
38 |
3892c5f |
3b — Prisma-nahe Formen getypt, Erkenner-Falle gemeldet | 31 |
d8fb9ae |
3c — Randschicht beurteilt, drei Befunde gemeldet | 15 |
Jeder Commit war fuer sich gruen: nach jedem lief pnpm type-check 4/4,
pnpm lint 5/5 mit 0 Befunden der Schwere error, und beide Testsuiten mit
unveraenderten Zahlen (D-05, D-06).
Offene Punkte fuer den Menschen
Zwei der sieben Befunde brauchen eine Entscheidung, die diese Aufgabe nicht treffen durfte, weil beide das Verhalten aendern wuerden:
- B-05 (
imap.provider.ts:78): sollen Anhaenge mitapplication/octet-streamkuenftig auch ueber den Dateinamen aus Content-Disposition erkannt werden? Heute werden sie es nicht. - B-06 (
imap.provider.ts:402): soll die Postfach-Einstellung "STARTTLS" tatsaechlich einen Zwang bewirken? Heute wird die Option von imapflow verworfen.
Beide sind im Code markiert und stehen in der Zaehlung, verschwinden also nicht aus dem Blick.
Self-Check
BESTANDEN.
Geprueft, nicht behauptet:
- Beide neu angelegten Dateien existieren auf der Platte
(
apps/api/src/auth/types/auth-user.ts,apps/api/src/prisma/prisma-error.ts). - Alle sieben genannten Commits sind in
git logvorhanden. apps/api/src/tenant/tenant.guard.tsist ueber den gesamten Lauf (git diff --stat 8d845e7..HEAD) unveraendert — keine einzige Zeile.- Die 15 Zeilen der Restliste stammen aus der maschinellen Biome-Ausgabe, nicht aus dem Gedaechtnis, und stimmen eins zu eins mit dem Urteilsregister ueberein.
- Die Aufteilung 252 + 21 + 15 ergibt 288.