Chronik aller geschlagenen Schlachten im ToAdapt-Repo (2026-04-06 bis 2026-07-08): Symptom → Root Cause → Beleg-Commit → Status. Lade diese Skill, wenn du (a) verstehen willst, WARUM der Code so aussieht wie er aussieht (toter websocket_url, BUILD_MARKER, doppelte Commits, load_dotenv vor den Imports), (b) eine Änderung planst, die eine alte Wunde berühren könnte (WebSockets, CORS, Anthropic-SDK, dotenv/Nixpacks, Mongo-Env, Judge-JSON, Git-History), (c) auf CLAUDE.md oder dev-docs/ stößt und sie für aktuelle Doku hältst, (d) Fragen zu PII-Vorfall, git filter-repo, Force-Push, duplizierten Juni-Commits oder dem Branch security-hardening hast, oder (e) wissen willst, welche Dateien historisch am meisten Churn hatten und warum. Schlüsselwörter: git history, Commit-Archäologie, Regression, "warum ist das so", Pivot, Fossil, Railway-Kapitulation, History-Rewrite.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Chronik aller geschlagenen Schlachten im ToAdapt-Repo (2026-04-06 bis 2026-07-08): Symptom → Root Cause → Beleg-Commit → Status. Lade diese Skill, wenn du (a) verstehen willst, WARUM der Code so aussieht wie er aussieht (toter websocket_url, BUILD_MARKER, doppelte Commits, load_dotenv vor den Imports), (b) eine Änderung planst, die eine alte Wunde berühren könnte (WebSockets, CORS, Anthropic-SDK, dotenv/Nixpacks, Mongo-Env, Judge-JSON, Git-History), (c) auf CLAUDE.md oder dev-docs/ stößt und sie für aktuelle Doku hältst, (d) Fragen zu PII-Vorfall, git filter-repo, Force-Push, duplizierten Juni-Commits oder dem Branch security-hardening hast, oder (e) wissen willst, welche Dateien historisch am meisten Churn hatten und warum. Schlüsselwörter: git history, Commit-Archäologie, Regression, "warum ist das so", Pivot, Fossil, Railway-Kapitulation, History-Rewrite.
ToAdapt Failure-Archaeology — Chronik der geschlagenen Schlachten
Wann diese Skill NICHT gilt
Du willst …
Lies stattdessen
ein AKTUELLES Symptom triagieren (Bug jetzt, Symptom→Ursache-Tabelle)
toadapt-debugging-playbook
wissen, wie Änderungen klassifiziert/gegated werden und welche Regeln unverhandelbar sind
toadapt-change-control
die tragenden Designentscheidungen und Invarianten des heutigen Systems
toadapt-architecture-contract
wissen, welche Dokumente Wahrheit vs. Fossil sind (vollständige Liste + Stil)
toadapt-docs-and-writing
am q4/Bloom-6-Judge-Alignment arbeiten (das härteste LEBENDE Problem)
toadapt-judge-alignment-campaign
Env-Variablen und Magic Numbers nachschlagen
toadapt-config-and-flags
Diese Skill ist ein Nachschlagewerk der Vergangenheit: Sie existiert, damit
niemand eine bereits geschlagene Schlacht neu führt oder ein Relikt für einen
Bug hält.
Historie: 2026-04-06 bis 2026-07-08, 92 Commits auf main (Stand: 2026-07-08).
Die Historie wurde am 2026-07-08 per git filter-repoumgeschrieben
(PII-Vorfall, s.u.) — Commit-Hashes aus älteren Notizen/Chats lösen daher
ggf. nicht mehr auf.
"TP" = Touchpoint (einer von 4 Meilensteinen des BWL-A-Kurses).
"Judge" = der LLM-Rubric-Evaluator, der Studierenden-Antworten bewertet.
WARNUNG: Die Fossilien-Falle (wichtigster Eintrag)
CLAUDE.md und dev-docs/phase1/*.md beschreiben ein System, das nicht
existiert. Sie dokumentieren die verworfene Gruppen-Echtzeit-Architektur
(WebSocket-Gruppenchat, GroupMemory, RAG/ChromaDB, PostgreSQL/Redis,
6er-Gruppen-Login). Lies sie NIEMALS als Ist-Doku und implementiere NIEMALS
"fehlende" Komponenten daraus nach.
CLAUDE.md ist seit Commit 4bd0d7b (2026-04-07, "Remove CLAUDE.md from
repo, add to .gitignore") gitignored und untracked — eine lokale Datei,
die den Stand vor dem Pivot einfriert (.gitignore Zeile 8).
dev-docs/phase1/schritt1-backend-skeleton.md, schritt2-base-agent.md,
schritt3-orchestrator.md sind getrackte Fossile derselben toten Architektur.
TODO.md ist ein eingefrorenes Security-Review-Transkript; die Punkte sind
großteils behoben.
Dokument der Wahrheit für Status/Roadmap ist ROLLOUT_PLAN.md (Stand:
2026-07-08). Details zur Doku-Landkarte: Skill toadapt-docs-and-writing.
Symptom: Repo-Struktur, CLAUDE.md und dev-docs passen nicht zum Code;
backend/realtime/, GroupMemory, RAG existieren nicht (mehr).
Root Cause: Das Projekt startete als Gruppen-Echtzeit-Scaffolding-System
(WebSocket-Gruppenchat für 6er-Gruppen). Am 2026-04-30 wurde es am selben
Tag, an dem der erste Deploy-Versuch lief, zum individuellen
Transfer-Trainer umgebaut: Studierende bearbeiten einzeln AI-generierte
Mini-Cases zur Vorbereitung auf die Gruppenarbeit.
8df4cfd (2026-04-30, "refactor: individual transfer trainer
architecture") — entfernt Group/GroupMemory/Presence, führt User/Case/
Submission, CaseGenerator, RubricEvaluator, AgentOrchestrator ein.
e57ed3f (2026-04-30) zog nur das README nach; CLAUDE.md/dev-docs nie.
825f656 (2026-04-30) strippte die requirements auf reale Dependencies.
Status: gelöst (der Pivot IST das heutige System). Die Fossile bleiben
als Falle liegen — siehe Warnung oben.
Nicht neu schlagen: Baue keine Gruppen-Features "nach CLAUDE.md" nach.
Gruppen existieren fachlich als Assessment-Einheit (Tutor beurteilt
Gruppenabgaben in Präsenz), aber im Code gibt es derzeit kein
Gruppenkonzept — nur matrikelnummer pro Person. Ob ein Gruppen-Umbau
kommt, ist eine offene Grundsatzentscheidung (ROLLOUT_PLAN.md;
Kontext: toadapt-architecture-contract).
2. WebSocket vs. Railway (die Kapitulation)
Symptom (damals): Chat-Verbindungen brachen auf Railway (Backend-Host,
Nixpacks-Build hinter Railway-Proxy) ständig ab; Session-Recovery-Versuche
und readyState-Handler halfen nicht.
Root Cause: WebSocket-Verbindungen über den Railway-Proxy waren mit dem
damaligen Setup nicht zuverlässig zu betreiben.
Beleg (alle 2026-04-30, in dieser Reihenfolge):
17323ad "fix: WebSocket session recovery after Railway restart"
e2cc925 "fix: replace WebSocket with HTTP POST chat (Railway WS
compatibility)" — die Kapitulation.
Status: umgangen. Der Chat läuft seither über POST /sessions/{id}/chat.
Relikt:SessionResponse.websocket_url (backend/models/session.py:37,
befüllt in backend/api/routes.py:161 mit /ws/{session_id}) ist tot —
es gibt keinen WS-Endpoint. Das README erwähnte den toten Endpoint zeitweise
ebenfalls.
Nicht neu schlagen: Führe KEINE WebSockets über Railway wieder ein, ohne
vorher mit einem minimalen Spike zu beweisen, dass sie dort stabil laufen.
Der tote websocket_url ist kein Bug-Report, sondern ein Grabstein.
3. CORS-500er
Symptom (damals): Browser-Requests scheiterten an CORS; zusätzlich
fehlten CORS-Header auf 500er-Antworten, sodass der Client echte
Server-Fehler nicht sehen konnte (sah wie ein CORS-Problem aus, war ein
Backend-Fehler).
Root Cause: Zwei verschränkte Probleme: (a) Origin-Konfiguration der
FastAPI-CORS-Middleware, (b) unbehandelte Exceptions liefern Antworten OHNE
CORS-Header — der Browser blockt sie, der echte Fehler bleibt unsichtbar.
Beleg:
7bb936e (2026-04-30) "fix: allow all CORS origins (wildcard not
supported by FastAPI middleware)" — Wildcard-Workaround, öffnete alles.
dca2da5 (2026-04-30) "fix: global exception handler with CORS headers
on 500 errors".
Aufgeräumt erst in der Security-Härtung 8b21fc1/15d6b14 (2026-07-07):
Origins kommen jetzt aus der Env-Variable ALLOWED_ORIGINS
(kommagetrennt; leer = nur localhost; siehe backend/main.py,
_allowed_origins() um Zeile 93–107, Stand: 2026-07-08).
Status: gelöst.
Nicht neu schlagen: Wenn der Browser "CORS-Fehler" meldet, prüfe ZUERST,
ob das Backend in Wahrheit 500 wirft (Details: toadapt-debugging-playbook).
Öffne niemals wieder Wildcard-Origins als "Fix".
Status: gelöst durch Architekturwechsel. Heute läuft ALLES über das
OpenAI-SDK gegen OpenRouter (backend/llm.py: AsyncOpenAI,
OPENROUTER_BASE_URL default https://openrouter.ai/api/v1, Modell via
OPENROUTER_MODEL, default anthropic/claude-sonnet-4.5; Stand:
2026-07-08). Das Anthropic-SDK ist NICHT mehr im Einsatz — README-Zeilen,
die es behaupten, sind falsch.
Nicht neu schlagen: Keine synchronen LLM-Clients in async-Routen.
Kein Rückwechsel des SDKs "nebenbei" — das ist ein gegateter Eingriff
(toadapt-change-control).
5. Nixpacks/Env-Saga
Symptom (damals): Auf Railway gesetzte Env-Variablen (API-Key!) kamen
im Prozess nicht an; lokal funktionierte alles.
Root Cause: Eine ins Image gelangte .env-Datei + python-dotenv
überschrieb im Nixpacks-Build die von Railway injizierten Variablen.
Beleg:
c19097f, 0627491 (beide 2026-04-30) — Blind-Debugging: Logging von
Key-Präsenz und ALLEN ANTHROPIC*-Env-Keys.
783bb5c (2026-04-30) "fix: remove .env.example and python-dotenv
(nixpacks was overriding Railway vars)".
Status: gelöst — mit kontrolliertem Rückbau: dotenv ist heute wieder da
(load_dotenv(...) in backend/main.py Zeile 12–14, vor den
Backend-Imports, weil deren Konfiguration env-abhängig ist). Genau deshalb
existieren die absichtlichen E402-Ruff-Ignores für backend/main.py und
backend/db/submission_store.py in pyproject.toml (Zeile 19–22, Stand:
2026-07-08). .env.example existiert wieder und ist aktuell.
Nicht neu schlagen: "Repariere" die E402-Ignores nicht durch
Import-Umsortierung — load_dotenv MUSS vor den Imports laufen. Und lasse
keine echte .env ins Deploy-Artefakt gelangen.
6. Mongo-Diagnostik-Kampagne (Blind-Debugging gegen Railway)
Symptom (damals): Experiment-Events aus Prolific-Läufen (Prolific =
Plattform zur Teilnehmer-Rekrutierung) landeten nicht in MongoDB; unklar,
ob Env-Vars, Init-Reihenfolge oder Kontext-Verlust schuld waren. Railway
bot keinen direkten Einblick in den laufenden Prozess.
Root Cause: Mehrere kleine Fehler in Initialisierung und
Kontext-Weitergabe des Experiment-Loggings; erschwerend: keinerlei
Introspektionsmöglichkeit im Deployment → tagelanges Deploy-and-Pray.
Status: gelöst. Relikt:BUILD_MARKER = "railway-mongo-env-diagnostics-2026-05-14-1809z" in backend/main.py:55
(ausgegeben in /health/diagnostics, Zeile 147; Stand: 2026-07-08) — ein
Fossil dieser Kampagne, damit man sehen konnte, WELCHER Build gerade lief.
Nicht neu schlagen: Für Mongo-/Env-Fragen im Deployment existiert heute
GET /health/diagnostics (X-API-Key-geschützt). MESSEN statt
Marker-Bumping — Werkzeuge: toadapt-diagnostics-and-tooling.
7. Judge-JSON-Fragilität (der chronische Patient)
Symptom: Der LLM-Judge (bewertet Freitext-Antworten gegen Rubrics)
liefert gelegentlich kein parsebares JSON → Bewertungen scheiterten.
Root Cause: LLM-Ausgaben sind nie garantiert schema-konform; anfangs
gab es keinen Reparatur-/Fallback-Pfad.
Beleg:4dd79da (2026-05-14) "Harden rubric evaluator JSON parsing".
backend/evaluator/rubric_evaluator.py wurde in 12 Commits geändert —
die chronisch instabilste Backend-Komponente (siehe Churn-Tabelle).
Status: umgangen mit einer Fallback-Kette (Stand: 2026-07-08):
3 Extraktions-Kandidaten (raw / ohne Code-Fences / erstes-{-bis-letztes-})
→ EIN Repair-LLM-Call → technical_fallback (0 Punkte,
needs_human_review=True, evaluation_status="technical_fallback").
Nachträgliche Reparatur: scripts/retry_technical_fallback_scores.py
(macht ECHTE LLM-Calls — nur bewusst ausführen).
Nicht neu schlagen: Die Fragilität ist per Fallback eingehegt, nicht
beseitigt. Jede Änderung an Judge-Prompts/Kalibrierung erfordert einen
Alignment-Recheck gegen Teacher-Scores VOR Deploy (toadapt-change-control);
das inhaltliche Kernproblem (q4) lebt in toadapt-judge-alignment-campaign.
8. Guardrail-Nachjustierung nach Test 1
Symptom: Erster realer Testlauf zeigte Guardrail-Lücken/Fehltreffer im
Agenten-Output (Guardrails = Filter, die direkte Antworten, Framework-Namen
etc. aus Agenten-Antworten fernhalten).
Beleg:9d2567b (2026-05-17) "guardrail update after test1".
Status: gelöst (für damals). Merke: Guardrail-Patterns sind empirisch
nachjustiert worden und werden es wieder — bekannte offene Lücke: in
TP_CONFIGS[4] fehlt der forbidden_framework_names-Key (Triage dazu:
toadapt-debugging-playbook).
9. Teacher-Alignment-Studie und die q4-Wunde
Symptom: Judge-Scores wichen systematisch von Lehrkraft-Scores ab.
Beleg:9a8077f (2026-05-31) "human alignment with teacher scores";
Report: docs/teacher_alignment_report_20260531_17submissions.md
(Achtung: Dateiname sagt "17submissions", tatsächlicher Scope sind
16 Submissions / 64 Frage-Zeilen).
Status/Ergebnis (Stand: 2026-07-08): Kalibrierung verbesserte
Pearson r 0.631→0.796, machte den Judge aber systematisch STRENGER
(Unterbewertung in 48/64 Fällen). q4 (Bloom-Level 6, Integration,
30 Punkte) bleibt die Schwachstelle (MAE ~4.97) — das härteste lebende
Problem. Kalibrierungsanker sind hartkodiert pro question_id in
rubric_evaluator.py (_format_calibration_notes).
Nicht neu schlagen: Erfinde keine eigene Vergleichsmethodik — die
Blind-Review-Pipeline existiert (scripts/export_review_workbooks.py,
scripts/compare_teacher_rubric_scores.py). Aktive Arbeit an q4:
toadapt-judge-alignment-campaign.
10. PII-Vorfall + History-Rewrite (2026-07-08)
Symptom: Echte Prolific-Teilnehmerdaten (Prolific-IDs + Freitext-
Antworten) lagen in Commits eines zeitweise öffentlichen Repos.
Root Cause: Forschungsdaten wurden direkt ins Repo committet, bevor
eine Datenhygiene-Regel existierte.
Maßnahmen (2026-07-08):
git filter-repo über alle Branches + Force-Push → die GESAMTE
Historie wurde umgeschrieben. Alle Commit-Hashes änderten sich; alte
Hashes (z.B. e722310, der Commit, mit dem die Daten ursprünglich
hereinkamen, oder 44b4b84 aus älteren Notizen) lösen im heutigen Repo
nicht mehr auf — das ist erwartet, kein Korruptions-Zeichen.
Daten + Backup-Bundle der ALTEN History verschoben nach
~/ToAdapt_sensitive_data/ (enthält u.a.
ToAdapt_backup_pre_filter_2026-07-08.bundle, backend/, data/).
NIEMALS von dort zurückkopieren oder committen.
Die GitHub-PR-Ref refs/pull/1/head zeigt noch auf die alte History
(Objekt 56eeb70…; lokal nicht vorhanden, remote via
git ls-remote origin 'refs/pull/*' sichtbar). Nur für Collaborators
sichtbar; Repo ist privat und bleibt es, bis die PII-Fragen final geklärt
sind.
DSGVO-/Prolific-Meldepflicht-Klärung ist organisatorisch offen.
Status: umgangen (Working Tree und erreichbare History sind sauber),
Restrisiko dokumentiert offen.
Nicht neu schlagen: Echte Teilnehmerdaten kommen NIE wieder ins Repo —
nicht in Fixtures, nicht in Tests, nicht in Skills. Synthetische Daten
verwenden. Regel-Rationale und Gating: toadapt-change-control.
11. Duplizierte Juni-Historie (Rebase-Unfall)
Symptom:git log auf main zeigt Commits vom 2026-06-18 doppelt —
gleiche Message, gleicher Tag, verschiedene Hashes, nahezu identischer Diff:
"en version teacher": 33c17b2 (main-Seite) / 1ddec46 (Branch-Seite)
Root Cause: Rebase-Unfall — dieselben Änderungen existierten auf main
und auf dem Branch security-hardening mit unterschiedlichen Hashes; der
spätere Merge brachte beide Seiten in die Historie.
Beleg: Merge-Commit 764e89a ("Merge branch 'main' into
security-hardening") + 0a705fb ("Merge pull request #2 from
koizachek/security-hardening"), beide 2026-07-08.
Status: gelöst — der Merge hat den Zustand konsolidiert; der Working
Tree ist eindeutig. Die Duplikate in der Historie sind kosmetisch und
bleiben (nach dem filter-repo-Force-Push wird die History nicht noch einmal
umgeschrieben, nur um Kosmetik zu fixen).
Aufräum-Kandidat (offen, Stand: 2026-07-08): Der Branch
security-hardening (lokal + origin) ist vollständig gemergt
(git log main..security-hardening ist leer) und redundant — Löschung ist
ein Kandidat, aber eine mutierende Git-Operation: nicht nebenbei erledigen,
sondern über den normalen Change-Prozess (toadapt-change-control).
Nicht neu schlagen: Wenn du doppelte Commits siehst: NICHT rebasen,
NICHT force-pushen, NICHT "History reparieren". Es ist bekannt und erklärt.
12. Lasttest gegen die Produktions-Mongo (die find_dotenv-Falle, 2026-07-10)
Symptom: Ein "isoliert" gestarteter Lasttest-Probelauf (Backend aus
fremdem Arbeitsverzeichnis, LLM auf Stub, keine Mongo-Variablen gesetzt)
zeigte 26-s-Latenzen und Timeouts schon bei 60 simulierten Studierenden —
und schrieb dabei 643 Testdatensätze in die ECHTE Atlas-Datenbank.
Root Cause:load_dotenv() in backend/main.py sucht die .env per
find_dotenv vom Modulpfad aus, nicht vom Arbeitsverzeichnis — ein
Start außerhalb des Repos lädt trotzdem die Repo-.env mit den
MAS-Credentials. Explizit gesetzte Env-Variablen gewinnen zwar
(LLM-Stub griff), aber die NICHT gesetzten Mongo-Variablen kamen aus der
.env. Die Latenz war der zweite Lerneffekt: synchrone pymongo-Writes pro
Request über eine Transatlantik-Strecke sättigen den Default-Threadpool
(asyncio.to_thread) — Backend und Atlas MÜSSEN in derselben Region
liegen, sonst misst ein Lasttest nur das Netz.
Beleg: Commit 324d937 (Warnung + Env-Overrides im Docstring von
scripts/load_test.py); ROLLOUT_CHECKLIST.md W1.
Status: Behoben/dokumentiert. Regel daraus: Vor jedem Test-Start mit
echtem Backend-Code IMMER mongo_connection_mode im Startup-Log prüfen —
mas_credentials heißt: du redest mit der Produktion.
DAS umkämpfte File: gesamter Studenten-Flow (Case-Ansicht, Glossar-Chips, Chat, Antworten) in einer Datei; Glossar + Canvas-Blöcke dort HARTKODIERT pro Case
17
backend/main.py
Deploy-Schmerz kondensiert: CORS, dotenv, Diagnostics, BUILD_MARKER — fast jede Infrastruktur-Schlacht (Nr. 3, 5, 6) hinterließ hier Spuren
15
backend/api/routes.py
Studenten-Flow-API; wuchs mit jedem Feature (Sessions, Chat, Submissions, Auth, Rate-Limits)
Erstellt: 2026-07-08, gegen den damaligen Stand von main (92 Commits,
HEAD 141bb63) verifiziert. Alle Kommandos vom Repo-Root
/Users/dianakozachek/ToAdapt ausführen.