# 08 — Changelog Chronik der Entwicklungsschritte. **Regel: jede zukünftige Änderung bekommt hier einen Eintrag** (Datum, Was, Warum, betroffene Dateien/Backups). ## 2026-07-17 — Round-Robin-Meetings: Sektions-Pfad statt Whole-Pass ab 5 Sprechern (Recency-Bias-Fix) - **Problem:** #74 (33-min-Weekly, 13 Sprecher, 31k Zeichen) lief knapp unter `WHOLE_MAX_CHARS` als Whole-Pass → Summary enthielt fast nur die letzten Sprecher. 4B kann 15+ gleichwertige Themen in einem ~10k-Token-Prompt nicht gewichten; Whole-Pass taugt nur für narrative Gespräche mit wenigen Sprechern. - **Fix (llm.js, `.bak-standup`):** `analyze()` routet labeled Transkripte mit ≥ 5 Sprechern (`MANY_SPEAKERS`, `countSpeakers()`) immer in `analyzeLong` (Sektions-Konglomerat). Sektions-Pfad auf Besprechungsnotizen-Niveau ausgebaut: `thema`-Überschrift pro Chunk, Pflicht zur Erwähnung JEDER berichtenden Person, Smalltalk-Dämpfung (Privates max. Halbsatz), Todos nur beruflich mit Verantwortlichem in Klammern, Überblick-Mikro-Call (`PROMPT_OVERVIEW`, Key-tolerant: Qwen schreibt teils `"überblick"`), Summary-Cap 6 000 → 16 000 (alter Cap schnitt 10 Sektionen mitten im Satz ab). - **Validierung:** 3 Iterationen per `reanalyze-llm` auf #74 — final alle 13 Sprecher + alle Themen abgedeckt (Intro-Absatz, 10 Themen-Sektionen, 30 saubere Todos mit Verantwortlichen), kein Recency-Bias. Temporärer `/api/debug/ask` fürs Overview-Prompt-Tuning wieder entfernt (server.js unverändert). ## 2026-07-17 — GUI: Aufnahme-Tab gestrichen, Record-Button in der Kopfzeile + Stille-MP3-Fix - Der Reiter "Aufnahme" ist weg: Quelle (CallRecMix), HFP-Codec (auto) und Sprecherzahl (auto) waren eh die Defaults. Aufnahme-Knopf (roter Kreis) + Laufzeit sitzen jetzt MITTIG in der Kopfzeile zwischen Logo und Tabs; beim Aufnehmen pulsiert er rot. Start legt SOFORT ein rotes "Aufnahme laeuft..."-Kaestchen mit Live-Timer ganz oben in der Liste an; Stop erzeugt daraus die echte Zeile (transcribing) und oeffnet sie rechts. Standard-Tab ist jetzt "Aufnahmen". - **recorder.js (`.bak-silentmp3`):** lame crashte auf komplett stiller Aufnahme (`psymodel.c calc_energy: el >= 0` — seit dem Mic-Gate real: niemand sprach = Null-Samples, loudnorm-Kette triggert die Assertion) -> Fallback-Encode ohne Filter statt Stop-Fehler. E2E getestet (3-s-Stille-Aufnahme: Stop ok, Zeile erstellt, transkribiert, wieder geloescht). Bundle `index-UPMXRPJp.js`. ## 2026-07-17 — GUI: Scrollbalken im Logo-Kupfer Alle Scrollbalken (Liste, Transkript-Panel, Sprechblase, Seite) jetzt im Akzent-Kupfer: Firefox via scrollbar-color, Chromium/WebKit via ::-webkit-scrollbar-* (10 px, runder Daumen, transparente Schiene). Bundle `index-U7lT-ig5.js`. ## 2026-07-17 — GUI: Listenbreite per Splitter ziehbar Zwischen Liste und Detail sitzt jetzt ein 6-px-Splitter (Hover/Ziehen = Kupfer-Schimmer, col-resize-Cursor): Liste zwischen 340 px (alte Festbreite = Minimum) und 680 px (Maximum = doppelt) frei ziehbar, Breite persistiert in localStorage['aime-list-width']. Auf schmalen Screens (gestapelt) ausgeblendet. Playwright-getestet (Clamp 340/680 + Persistenz). Bundle `index-BbmdfFEI.js`. ## 2026-07-17 — GUI: Kupfer-Zaehler, Favicon, Tab-Reihenfolge Tages-Zaehler in der Liste jetzt im Logo-Kupfer (accent-soft-Pille); Wellenform-Logo als Favicon (SVG-data-URI in index.html, Browser-Tab); Tab-Reihenfolge neu: Aufnahme, Aufnahmen, Stimmen, Glossar, Bluetooth (Bluetooth ans Ende). Bundle `index-Bt2IsJIF.js`. ## 2026-07-17 — GUI: Liste startet mit nur dem neuesten Tag geoeffnet Beim Betreten des Aufnahmen-Tabs ist nur noch die aktuellste Tagesgruppe aufgeklappt, alle aelteren sind eingeklappt (Zaehler-Badge zeigt die Anzahl). Manuelles Auf-/Zuklappen bleibt bis zum naechsten Tab-Wechsel erhalten (state.resetCollapse-Flag, angewandt beim ersten Listen-Build). Bundle `index-C_-UUeU5.js`. ## 2026-07-17 — GUI: Transkript/Am-Tisch-Panel ebenfalls verschiebbar (zwei Drop-Spalten) Alle Bloecke — Zusammenfassung, ToDos UND das Transkript-/Tisch-Panel — sind jetzt per Drag & Drop frei anordenbar, auch SPALTENUEBERGREIFEND: zwei Drop-Zonen (links 54 % / rechts 46 %), Layout persistiert als localStorage['aime-detail-layout'] {main:[...], side:[...]} (altes aime-detail-order wird migriert). Eine leere Spalte kollabiert zu einem schmalen gestrichelten Streifen und bleibt Drop-Ziel (JS-Klasse .empty — :empty scheitert an Template-Whitespace). Bundle `index-B1y2-Z_b.js`. ## 2026-07-17 — GUI: Sprecher-Modul entfernt, Umbenennen direkt am Verlauf Das separate "Sprecher"-Modul war redundant zu den Spur-Labels. Jetzt: Klick auf einen Namen links im Sprecher-Verlauf oeffnet ein Popover (Name aendern + "als Stimme lernen" + Speichern) — gleiche API wie vorher (POST /speaker). Klick-Seek in den Spuren zuendet nur noch IN einer Spur, nicht mehr auf der Label-Spalte. Bundle `index-Bj1pQQtk.js`. ## 2026-07-17 — GUI: Blasen-Oeffnung zeigt exakt auf den Sprecher Bei mehreren Sprechern je Tischkante (5-/6-Sitz-Layouts) zeigte der Schwanz nur auf die Kantenmitte. Jetzt wird die Sitz-x-Position in Blasen-Koordinaten umgerechnet (CSS-Variable --ax, BUBBLE_W in main.js synchron zur CSS-Breite) — die Oeffnung wandert entlang der Ober-/Unterkante exakt zum Sprechenden; bottomleft/bottomright-Sonderklassen entfallen. Bundle `index-FKbNFs-A.js`. ## 2026-07-17 — GUI: Tisch-Blase fix, Oeffnung wandert zum Sprecher Feinschliff nach User-Feedback: Die Sprechblase liegt wieder FEST auf dem Tisch (54 % Breite), nur ihr Schwanz/die Oeffnung springt per arrow-Klasse zum jeweils Sprechenden; Rand-/Namensfarbe wechseln weich mit (border-color-Transition). Wort-Highlight, internes Mitscrollen und Klick-Seek bleiben. Bundle `index-CpZJOt3u.js`. ## 2026-07-17 — GUI: Sprechblase am Sprecher mit Wort-Highlight + Mitscrollen Tisch-Ansicht verfeinert: Die Blase haengt jetzt klassisch am MUND des Sprechers (dynamisch zwischen Sitz und Tischmitte positioniert, Schwanz zeigt zum Kopf) statt zentral auf dem Tisch. Inhalt = der komplette Redebeitrag als einzelne Wort-Spans: aktives Wort wird synchron zum Audio gehighlightet (wie im Transkript), die Blase scrollt intern mit (innere .tb-scroll-Huelle, damit der Pfeil nicht mitscrollt), Klick auf ein Wort springt im Audio dorthin. Bundle `index-BK0gpRp9.js`. ## 2026-07-17 — GUI: Konferenztisch-Ansicht (Umschalter neben "Analyse neu") Neuer Umschalt-Button (Icon: drei Personen am Tisch <-> Textblatt) in der Status-Zeile: ersetzt das Transkript rechts durch eine animierte Szene — Sprecher als Figuren in ihren Spurfarben um einen abgerundeten Tisch, Sprechblase AUF dem Tisch (Rand/Name in Sprecherfarbe, Pfeil zeigt zum Sprecher, Text = aktueller Redebeitrag), alle anderen Personen drehen die Pupillen zum Sprechenden, dessen Mund animiert beim Reden (reduced-motion respektiert). Sitzordnungen fuer 1-6 Teilnehmer vordefiniert. Wahl bleibt in localStorage['aime-side-view']. Bundle `index-DXTNo40e.js`. ## 2026-07-17 — GUI: Aufnahmen-Tab nutzt die volle Fensterbreite `#app.wide` war auf 1180 px gedeckelt — auf breiten Monitoren blieb rechts/links viel Leerraum und die Zusammenfassung wurde unnötig schmal/lang. Deckel entfernt (max-width: none, Padding 28 px); die Liste bleibt 340 px fix, das Detail bekommt den Rest. Bundle `index-RpsXFTh8.js`. ## 2026-07-17 — GUI: Live-Text-Box entfernt Die Box rechts neben den Sprecher-Spuren (aktueller Redebeitrag) flog auf User-Wunsch raus — redundant zum mitscrollenden Transkript daneben. Spuren nutzen jetzt die volle Breite. Bundle `index-BiCA5LX5.js`. ## 2026-07-17 — GUI: Sprecher-Verlauf als Vollbreiten-Streifen unter dem Player Der Sprecher-Verlauf (Spuren + Live-Text) sitzt jetzt fix unter der Audio-Laufleiste und zieht sich ueber BEIDE Spalten (oberhalb von Zusammenfassung und Transkript); aus den Drag&Drop-Modulen entfernt. Lanes ~2/3, Live-Box ~1/3 Breite. Bundle `index-COpkdtd3.js`. ## 2026-07-17 — GUI: Transkript als eigene Scroll-Spalte Transkript (+ Dialog) aus den Drag&Drop-Modulen herausgelöst: eigene, sticky Spalte rechts neben Zusammenfassung/Verlauf/ToDos/Sprecher, Höhe auf Viewport begrenzt, scrollt INTERN durch und folgt dem aktiven Wort im Panel (statt die Seite zu ziehen). Unter 1100 px stapeln die Spalten (Transkript max. 60 vh). Bundle `index-DQmY8pnQ.js`. ## 2026-07-17 — GUI: Sprecher-Verlauf-Visualisierung + Drag&Drop-Module Detail-Ansicht ist jetzt modular: fester Kopf (Titel, Player, Status), darunter Blöcke **Zusammenfassung / Sprecher-Verlauf / ToDos / Sprecher / Transkript** — jeder Block hat einen Grip-Header (⠿) und lässt sich per Drag & Drop umsortieren; die Reihenfolge liegt in `localStorage['aime-detail-order']` und gilt für alle Aufnahmen. **Sprecher-Verlauf** (neu): pro Sprecher eine farbige Spur (sp0–sp3) übereinander mit Redeabschnitts-Blöcken (Wörter mit ≤ 1,2 s Lücke zusammengefasst), Kupfer-Playhead wandert beim Abspielen mit, die Spur des gerade Sprechenden leuchtet (Label fett, Punkt pulsiert; respektiert `prefers-reduced-motion`), Klick in die Spuren springt an die Stelle. Rechts daneben die **Live-Box**: zeigt Sprecher + Text des aktuellen Redebeitrags. Per Playwright-Screenshots verifiziert (beide Themes, Playback mit aktiver Spur). Bundle `index-WaE171bv.js`. ## 2026-07-17 — GUI: „Weggezogen"-Bug gefixt + Redesign mit Dark/Light-Switch (`.bak-theme`) - **Bug:** lief beim ausgewählten Eintrag eine Analyse, feuerte ein 5-s-Timer `openRecording(alteId)` als **stale closure** — auch nachdem der Nutzer längst eine andere Aufnahme hörte → riss ihn zurück und stoppte den Player. Fix: Poll bricht bei Auswahl-/Tab-Wechsel ab, prüft während der Analyse NUR den Status (kein DOM-Rebuild) und baut das Detail genau EINMAL neu, wenn die Ergebnisse da sind — inkl. Wiederherstellung von Player-Position und Play-Zustand. - **Redesign:** Themes über CSS-Variablen (`data-theme` auf ``, vor First-Paint aus localStorage/ OS-Einstellung, Toggle ☀️/🌙 im Header). Dunkel = neutrales Anthrazit, Hell = warmes Papier; Akzent = Kupfer (#e8804c/#c05f2d — Rot bleibt der Aufnahme vorbehalten), Wortmarke mit Wellenform-Glyph, Pill-Tabs, weichere Karten, sichtbarer Tastatur-Fokus, `prefers-reduced-motion` respektiert. Sprecherfarben (sp0–sp3) als Variablen mit hell/dunkel abgestimmten Werten. - Bundle `index-C2xK4eql.js` / `index-ClT74fBX.css`. Dateien: `web/index.html`, `web/src/main.js`, `web/src/style.css` (Backups `.bak-theme`). ## 2026-07-17 — Hall auf der Gegenseite + verschmolzene Sprecher: Mikro→Mix jetzt GEGATET (`.bak-gatedmix`) User: Gegenseite klingt „wie in einem schallenden Raum", Diarization macht aus zwei entfernten Personen eine. **Diagnose per Cepstral-Analyse** auf #71: Gegenseiten-Segment hat einen felsenstabilen Peak bei **79–80 ms** (22/26 Frames) = deterministische verzögerte Kopie; User-Segment sauber. Ursache: der direkte `cr_mic2mix`-Loopback (immer offen) legte die Gegenseite doppelt in den Mix — digital (`cr_pc2mix`) UND als Kopfhörermuschel-Bleed durchs Mikro (~80 ms Latenz). Der Hall verschmiert zusätzlich die TitaNet-Embeddings → zwei Remote-Stimmen (gleicher Kanal + gleicher „Raum") rücken über die 0,5-Kosinus-Schwelle zusammen. - **Fix** (`aime-usb-audio-setup.sh`): direkter `cr_mic2mix`-Loopback ENTFERNT; stattdessen `pw-link micgate.out → callmix` — dieselbe Gate-Auskopplung wie beim Teams-Selbstecho-/iPhone-Uplink-Fix. In Sprechpausen des Nutzers ist das Mikro komplett aus der Aufnahme. Fallback ohne Gate = alter Loopback. - Verifiziert strukturell (`pw-link -l`: callmix ← cr_pc2mix + micgate.out, kein HSMIC-Direktpfad) und funktional (4 s callrec_mix bei Stille = RMS 0/Peak 0). **Echter Call steht noch aus.** - **Nebenbei entdeckt:** OOM-Ereignis 17:47 (die fünf 60-s-READY-Timeout-Retries beim ersten Qwen3-Start luden je 5,3 GB, NPU-Speicher der gekillten Loads wurde nicht schnell genug frei) riss mariadb, callrec UND pipewire weg — Audio-Topologie war seitdem TOT. Mit dem 180-s-Timeout (Changelog unten) behoben; Topologie neu aufgebaut. Lehre: nach OOM immer `pw-link -l` prüfen. ## 2026-07-16 — Glossar: Einträge bearbeitbar (`.bak-gedit`) User-Wunsch: gespeicherte Glossar-Begriffe nachträglich ändern. Neu: `PUT /api/glossary/:id` (`db.updateGlossary`), GUI-Stift-Button je Eintrag lädt Begriff+Soundalikes ins Formular (Titel „… bearbeiten", Speichern/Abbrechen), Update statt Neuanlage. Bundle `index-NRK6cGUI.js`. API-verifiziert (POST→PUT→DELETE). Dateien: `server.js`, `db.js`, `web/src/main.js`. ## 2026-07-16 — rkllm vor Diar/Identify freigeben (TitaNet-OOM) + #71 validiert - **Bug:** residenter rkllm (5,9 GB) ließ den TitaNet-spk-embed-Helper OOM-sterben („spk beendet" pro Cluster) → Konsolidierung bekam NULL Centroids → #71 bekam still **48 Roh-Sprecher**. Fix (`server.js`): `llm.stopServer()` am Anfang von `rediarize()` UND `analyzeRecording()` (Reload ~96 s, egal bei 15-min-Analysen). - **#71 E2E danach:** Diar 48 → **2 Sprecher** (5 schwache gefoldet), Qwen3-Whole-Pass auf 31,3k Zeichen → „Steuergestaltung für wachsendes Unternehmen" mit konkreten Zahlen (30 MA, 3 Mio Umsatz, 15-20 %-Ziel, Kick-off Hamburg, Termin 23.) — alter Titel war generisch, alte Sprecherzahl 28. - **OFFEN:** `identify … spk beendet` schlägt auch MIT freiem RAM fehl → Voice-Auto-Naming (Voiceprints) aktuell tot; Teilnehmer erscheinen als „Sprecher N". Separater Bug, noch zu untersuchen (spk.js/Helper). ## 2026-07-16 — ✅ LLM → **Qwen3-4B-Instruct-2507** (Nacht; Gemma-Rollback vorhanden) Auf User-Wunsch Qwen3-4B selbst konvertiert und im A/B gegen Gemma getestet — **3/3 Prompts klar besser**, produktiv geschaltet und E2E validiert. - **Konvertierung:** wiederverwendetes Kit (`rkllm-convert:1.3.0`-Docker neu gebaut), HF `Qwen/Qwen3-4B-Instruct-2507` (7,6 GB bf16) → `w8a8_g128`/grq, max_context 16384, auf RTX 3090 in ~35 min → 5,3 GB `.rkllm`, pscp aufs Board. - **A/B (gleiche Prompts wie Gemma-Tests):** Chunk 1 (Com4Tec-Story) in 140 s mit ALLEN Nuancen (50 %-Kappa, kein Body Leasing, Perinko/Icon); Auto-Chunk 91 s inkl. Detail-Korrektur „Michael Wagner, nicht Fabienne"; **Whole-Pass 21,8k Zeichen in 691 s fehlerfrei gewichtet** — exakt der Fall, in dem Gemma englisch schwafelte bzw. nur das Ende zusammenfasste. Qwen3 = ChatML-Template statt Gemma-Turns (`rkllm_server.cpp`). - **Produktiv-Swap:** Drop-in `RKLLM_MODEL=qwen3-4b-w8a8g128-16k.rkllm`, prod `rkllm_server` mit ChatML neu gebaut (Rollback: `.bak-gemmatmpl` + Drop-in zurückstellen), `WHOLE_MAX_CHARS` 20 000 → **32 000** (bis ~35-min- Aufnahmen Single-Pass; Sektions-Konglomerat bleibt für längere). **GOTCHA:** Qwen3 lädt ~96 s → llm.js READY-Timeout 60 s → 180 s (sonst Endlos-Retry-Schleife, real passiert). - **E2E validiert:** #70 Whole-Pass 15,4 min → „Neue Kontakte und Stellenangebote", Auto raus, Comfort Tech/ Adem Marlock/Nico-Profil-Todo konkret; #68 Kurzclip (analyzeSingle+ChatML) 22,2 min inkl. Queue → sauber. - Damit ist die 4B-Synthese-Decke aus dem Sektions-Konglomerat-Eintrag (unten) für ≤ 32k Zeichen GESCHLOSSEN; das Konglomerat bleibt als >32k-Pfad und Fallback. ## 2026-07-16 — A/B-Test Qwen2.5-3B vs Gemma-3-4B im neuen Chunk-Pfad: Gemma bleibt Auf User-Wunsch das noch vorhandene `qwen2.5-3b.rkllm` gegen die neuen 4,2k-Chunk-Prompts getestet (Test-Binary mit ctx 4096 in /tmp, direkt übers Stdin-Protokoll — kein App-Umbau). Ergebnis: **3 von 3 Outputs unbrauchbar** (Feldbeschreibungs-Echo ohne Inhalt; Abbruch nach ~100 Zeichen mitten im Satz; Struktur-Müll mit der Feldbeschreibung als JSON-Key) — Gemma lieferte im selben Job 8/8 verwertbare Sektionen. Dazu prinzipiell: Qwen2.5 hat fix 4096 Kontext → der validierte Whole-Pass (≤ 20k Zeichen) wäre unmöglich. Testartefakte entfernt. Offene Alternative (ungetestet, ~½ Tag): Qwen3-4B neu konvertieren. ## 2026-07-16 — Sektions-Konglomerat statt LLM-Reduce (Abend, `.bak-sectionsum`) Auftrag: Lang-Transkript-Summary (> 20k Zeichen) inhaltlich retten. Prompt-Lab auf #70 mit temporärem `/api/debug/ask`-Endpoint (nach Abschluss wieder entfernt), ~15 Reduce-/Chunk-Varianten in je ~2 min statt 9-min-Vollanalysen. - **Befund 1: Chunk-Größe ist der Fidelity-Hebel.** 8k-Chunks → generisches namenloses Blabla; 4k-Chunks → geerdete Summaries mit echten Eigennamen (Com4Tec, René, Tobi+Niklas, 20 Bewerbungen). `CHUNK_CHARS` 8000 → **4200**. - **Befund 2: Cross-Section-Synthese unmöglich auf Gemma-3-4B.** Jede LLM-Reduce-Variante (Gewichtungsregeln, Abschnitts-Labels, Themen-Tabellen) → Regeln ignoriert, Namen durch Rollen ersetzt, Dubletten, Loops. **LLM-Reduce abgeschafft.** - **Neue `analyzeLong`-Pipeline** (`llm.js`): 4,2k-Chunks sequenziell mit **Rolling Context** (1-Satz- Kurzfassungen der Vorgänger → erkennt geänderte Entscheidungen: „jetzt X, vorher Y") + **eigennamen- Extraktionsfeld**; Echo-Guard (Feldbeschreibungs-Echo ist INHALTS-abhängig reproduzierbar → bis 3 Versuche mit variiertem Prompt: ohne Kontext, ohne Hint) + Feld-Salvage per Regex + Prosa-Rettung (≥ 60 Zeichen); **Titel-Mikro-Call** ohne letzten Abschnitt (Smalltalk-Filter); **Konglomerat baut Code**: „Gesprächsverlauf in n Teilen — genannte Namen: …" + „Teil i/n: …" chronologisch. Kap. 05 (Mermaid + Marotten aktualisiert). - **E2E #70 (3 Läufe):** Titel ohne Auto-Smalltalk ✅, alle Abschnitte mit echten Namen ✅, Auto nur noch in Teil 7 ✅, 12-14 min für 26-min-Aufnahme. Restgrenze: Abschnitts-Summaries variieren pro Lauf in Schärfe (Sampling), keine thematische Verdichtung ÜBER Abschnitte (4B-Decke). ≤ 20k Zeichen weiter Whole-Pass. ## 2026-07-16 — #70-Debug: Phantom-Sprecher, Summary-Fehlgewichtung, Thermal-Leck (Nachmittag) Auslöser: Aufnahme #70 (26 min, 4 Personen) — 7 Sprecher erkannt, Titel/Summary aus Randthemen (Auto-Smalltalk der letzten 3 min statt Recruiting-Hauptteil). 9 Analyse-Iterationen auf #70. - **Diarization Stufe 3 „Weak-Fold"** (`diar.js`, `.bak-weakfold`): finale Sprecher < `DIAR_MIN_TOTAL_SEC` (20 s, Segment-Zeiten!) werden in den akustisch nächsten starken Sprecher gefaltet — ein einzelner ≥ 3-s-Streu-Cluster konnte vorher einen Phantom-Anchor eröffnen (#70: 3 Phantome mit 2,5–4,8 s). 10 s reichte NICHT (9,2-s-Phantom kam durch). **Verifiziert: #70 konstant 50 Roh-Cluster → exakt 4.** Kap. 04. - **Whole-Pass-Grenze = Modellgrenze bewiesen** (Runden 2–5): rkllm-Runtime-Kontext 8192 → **12288** (`rkllm_server.cpp`, `.bak-ctx12k`, Rebuild) und `WHOLE_MAX_CHARS` testweise 32k → Gemma-3-4B kippt > ~6k Input-Token reproduzierbar: englisches Geplauder statt Analyse, Recency-Bias (fasst nur das Gesprächsende zusammen), JSON-Zerfall (typografische Quotes, Wiederholungsschleifen). `WHOLE_MAX_CHARS` zurück auf **20 000** (dort validiert gut); ctx 12288 bleibt (Headroom). Kap. 05 neuer Abschnitt. - **Robustheit `llm.js`** (`.bak-ctx12k`): End-Instruktion nach dem Transkript (ohne Platzhalter-Skelett — Gemma kopiert `...` wörtlich!); JSON-Repair-Call (repariert kaputten Output OHNE das große Transkript); Sanity-Check (Zusammenfassung ≥ 20 Zeichen) → sonst Chunk-Fallback statt Hard-Error; `extractJson()` repariert typografische Anführungszeichen + trailing commas; **1 Retry pro Chunk** (Parse = Sampling- Münzwurf: 3/3 ok vs 1/3 im nächsten Lauf; Retry live bestätigt); Reduce-Input mit „Abschnitt i von n"- Labels + Gewichtungsregeln (Hauptthema = mehrere Abschnitte; Nur-letzter-Abschnitt = Smalltalk). - **Regression bestätigt: Chunk-Prompt MUSS minimal bleiben** — eine zusätzliche Anweisungszeile (Namen/Firmen/Zusagen) kippte 2/3 Chunks in Prosa (Runde 6). Zurückgebaut. - **Thermal-Leck geschlossen** (`server.js`, `.bak-anacap`): `analyzeRecording()` lief als einziger schwerer Pfad OHNE A76-Takt-Cap → 95–97 °C bei langer Gemma-Generierung (lüfterlos!). Jetzt Cap wie `transcribeWav`/`rediarize`. Kap. 03/05. - **Ehrliches Ergebnis #70:** Sprecher exakt 4 ✅, Analyse crashfrei in ~9 min ✅, Summary führt jetzt mit Recruiting, ABER Auto-Smalltalk bleibt in Titel/Kernpunkten und konkrete Namen (Com4Tec, Kandidaten) fehlen — **Qualitätsdecke des 4B-Modells im Chunk-Pfad (> 20k Zeichen)**. Aufnahmen ≤ ~23 min laufen über den validierten Whole-Pass. ## 2026-07-16 - **Codebase ins Repo aufgenommen:** `app/` = Spiegel von `/opt/callrec` (Backend, Frontend-Quellen, Inferenz-Python, Skripte, `rkllm_server.cpp`), `system/` = systemd-Units + WirePlumber/PipeWire-Drop-ins + sudoers. Modelle/Binaries/Aufnahmen bewusst außen vor (`.gitignore`). - **Projekt umbenannt in „Aime“** (vormals CallRec, wie der BT-Name des Boards): Gitea-Repo → `sascha/Aime`, Web-GUI-Titel/Header → „Aime“ (Bundle `index-CuWeUh1j.js`, Backups `index.html.bak-aime`/`main.js.bak-aime`), Doku rebranded. Technische Bezeichner auf dem Board bleiben `callrec*` (Stabilität). - **Doku-Repo angelegt** (dieses Repo). Ab jetzt verbindliche Ablage inkl. Diagrammen. ## 2026-07-15/16 — Strukturierte Analyse + Teilnehmer-Fix (`.bak-structsum`) - Teilnehmer kommen aus der **Diarization** statt vom LLM (das listete alle *erwähnten* Namen → 11 statt 3 bei #69). - Summary strukturiert: Überblick + „Kernpunkte“ + „Entscheidungen“ als Bullets (`composeSummary`, CSS `pre-line`). - Chunk-Salvage-JSON-Leak gefixt; Reduce-Input gekappt + Retry; `cleanList` filtert `null`/`[object Object]`/Objekt-Todos. - Referenz #69 (71,6 min): Analyse ~20 min, Ergebnis sauber. Bundle `index-B2dSaBty.js`. ## 2026-07-15 — LLM-Wechsel auf Gemma-3-4B + Marker-Fix - Qwen2.5-3B → **Gemma-3-4B-it** (`gemma3-4b-w8a8g128-16k.rkllm`, grouped w8a8; plain w8a8 kaputt, w4a16 nicht unterstützt). - rkllm-Runtime 1.2.1 → **1.3.0**. `analyzeWhole` (≤ 20k Zeichen) ersetzt Map-Reduce im Mittelbereich. - Qualität ≈ Gemini, ~3× langsamer. Wort-Highlight-Marker lief ~1 Wort voraus → SYNC_MS=250 (`index-CLero27-.js`). ## 2026-07-14 — Kurzclip-Beschleunigung + Analyse-Timer - Clips ≤ 30 s über warmen CPU-Whisper-Daemon ohne rkllm-Swap: 10-s-Clip 120 s → **53 s** (`.bak-shortdaemon`). - GUI zeigt Analysezeit live (`analysis_ms`/`analysis_started_at`, `.bak-anatimer`). ## 2026-07-13 — Diarization stabil + NPU-Meilenstein 2 + iPhone-Repair - **Greedy-Anchor-Merge** ersetzt Union-Find: derselbe Call ergab vorher 2/3/7 Sprecher, jetzt konstant 27→3 (`.bak-anchor`). - **Meilenstein 2:** Whisper-turbo-Encoder auf NPU produktiv — RTF 1,51 → 0,61, Temp 90 °C → 59 °C; batched (batch=8) → RTF 0,389. - iPhone neu gekoppelt, `Trusted=yes` gesetzt (fehlte → keine HFP-Nodes → #58 ohne Gegenseite). ## 2026-07-09 — Meilenstein-1-Snapshot, Auto-Diarization, Glossar, Whisper-Kalibrierung - Snapshot `/opt/callrec/milestones/m1-20260709/` (Rollback-Punkt). - Auto-Diarization: 2-stufige Konsolidierung (17→2 verifiziert), `reanalyze` re-diarisiert immer (0=auto / >0=gepinnt). - **Glossar Phase 1:** deterministische Ganzwort-Ersetzung + LLM-Hinweis, GUI-Tab, „Aime“ geseedet. - Whisper-Kalibrierung: medium beam1 optimal (11,3 % WER vs large-v3); `--initial-prompt` mit Termliste = Echo-Loop (tabu). - 46-min-E2E über Nacht sauber (Long-Rec-Fixes produktionsvalidiert). ## 2026-07-08 — Echo-Fix, Thermal-Crashes, Whisper medium, Sprecher-Lernen, Long-Rec-Analyse - **Selbst-Echo der Gegenseite gelöst:** LADSPA-Noise-Gate `micgate` im Mikro→PC-Pfad (Thr −45 dB, Mic-HW niedrig); AEC verworfen. Reboot-verifiziert. - **Thermal-Schutzabschaltungen gefixt:** A76-Cap 1,6 GHz über die ganze `transcribeWav` (Whisper+Diar), SIGSTOP-Guard >90 °C; crash-sicheres asynchrones Speichern (`stopAndSave` persistiert vor Transkription); `/retranscribe` für hängende Zeilen. - Whisper small → **medium** (Hörfehler). - **Sprecher-Umbenennen + Stimm-Lernen** (Voiceprint-Zentroide) + Leertaste Play/Pause. - Lange Aufnahmen (> 20 min) analysierbar: Chunked Map-Reduce gegen 4096-Token-Limit; Diar-Timeout skaliert mit Dauer; Lösch-Confirm. ## 2026-07-07 — MEILENSTEIN 1: USB-Headset-Pfad komplett - Logi H390 ersetzt toten ES8323-Mikrofonpfad; callmix + 4 Loopbacks + `callrec_mix`-Remap; Volume-Bridge; Inline-Tasten. - Kaltstart-verifiziert. Clip-sicheres Gain-Staging (PC→Mix 60 %) — Übersteuerung hatte Diarization zerstört (14 Sprecher, #41). - Re-Diarization mit fester Sprecherzahl (`numSpeakers`), #41 14→2 verifiziert. - LLM-Fixes: Phantom-Todo (Prompt-Beispiel-Echo) entfernt, KV-Cache-Clear, leere Todos → `[]`. ## 2026-07-06 - ES8323-3,5mm-Mikro als defekt diagnostiziert (Verstärkung fest −42,14 dB) → Entscheidung für USB-Headset. ## 2026-07-05 — „Helikopter“-Debugging (Referenz) - ES8323 S16-Modus = Treiberbug (S24 nutzen); PipeWire/alsaloop-Capture des ES8323 injizierte ~13 Klicks/s, arecord nicht; Windows-Shared-Mode-AGC = separates 20-Hz-Pumpen (exklusiv sauber). - Sauberer Fallback damals: dual native-clock arecord. Durch Headset-Pfad obsolet. ## Früher - iPhone-BT-HFP-Pfad aufgebaut (Rollen-Drop-in, frischer Pair, Echo-Fix Uplink←micgate, Route-Watcher) — Details Kap. 06. - BT-Buds No-Bonding-Quirk: LinkKey manuell persistiert (Referenz, Dongle entfernt).