Wissensbasis›Methodik›Versionshistorie
Was sich an GPTSpy selbst geändert hat — Schema, Fragensatz, Bookmarklet, Runner, Umgebung. Ein Befund ist nur belastbar, wenn sich das Instrument an dem Tag nicht selbst geändert hat; Baseline-Brüche sind markiert. JSON
| Datum | Komponente | von → nach | Bruch | Grund |
|---|---|---|---|---|
| 03.10.2026 | runner | dismissOverlays: Schliessen-X oder Escape; Klick-Timeouts nur als Playwright-Text → dismissOverlays mit Bestaetigen-Knopf im Dialog + ehrlichem Beleg; error_class overlay_blocked; Einmal-Wiederholung des ersten Prompts | additiv | Der Memory-Einfuehrungsdialog eines frisch angelegten Free-Accounts (modal-m3m-nux) blockierte am 03.10. den ersten Prompt eines Tageslaufs: er hat kein Schliessen-X und ignoriert Escape — dismissOverlays drueckte dreimal Escape, zaehlte den Dialog trotzdem als geschlossen, und der Composer-Klick lief in locator.click: Timeout 30000ms. Jetzt: dritter Griff Bestaetigen-Knopf IM Dialog (ueber Klassen/data-testid, nicht Text — lokalisierungsfest), als geschlossen zaehlt nur, was danach wirklich weg ist (sonst Warnzeile im Log). Klick-/Tipp-Timeouts stehen in results.json als error_class overlay_blocked. Scheitert der ERSTE Prompt eines Laufs daran und wurde nie abgeschickt (kein Prompt-Ordner), wird er genau einmal am Lauf-Ende wiederholt — die Wiederholung zaehlt als der eine Tageslauf (Regel 4), mit retry_of_first und first_attempt_error als Beleg. Gilt fuer alle Plaene. Vergleichbarkeit: Keine Mess- oder Schemaaenderung. results.json traegt zusaetzlich error_class/retry_of_first/first_attempt_error (nur in Fehler-/Wiederholungsfaellen); mode_evidence.overlays_dismissed listet jetzt nur noch wirklich geschlossene Dialoge. |
| 02.10.2026 | extractor | schema 23 → schema 24 | additiv | TODO 1.26 (Beworbene URLs, Entscheidung Alin 02.10.): parsed.cards je Anzeigen-Karte als Array {url, url_clean, url_params, title} statt der blossen Kartenzahl — url wie geliefert (Token-Parameter oppref/olref/ad_data_token gestrichen, jetzt per Suffix-Match, der auch die seit ~23.09. beobachtete oa_-Fassung oa_oppref trifft), url_clean als bereinigte Landingpage (Host klein, Fragment weg, Trailing-Slash normiert, Kampagnenkennungen utm_*/oa_*/wpset/adVariant/campaign_id/ic_id/camp/tid/gclid/fbclid/msclkid heraus; Liste in src/ads-urls.js), url_params = die gestrichenen Kennungen. Register adsUrlRegister() -> /ads/urls/ + /api/ads/urls.json + urls.csv. Waechter: EIN gebuendeltes Tagesereignis "n neue Landingpages" (seen ads_landingpages, Backfill ueber 20 Ads-Messtage = 204 Zeilen). Vergleichbarkeit: Additiv bis auf den Typwechsel von parsed.cards (Zahl -> Array; von 1.26a so verlangt) — Leser tragen eine Array.isArray-Weiche (metrics.js), alte Snapshots bleiben gueltig und liefern ihre URLs ueber parseAdEntry(raw). Re-Extraktion (reextract-all) auf dem Messrechner zieht die cards-Arrays in die Snapshots; das URL-Register rechnet unabhaengig davon immer frisch aus raw. |
| 02.10.2026 | runner | erstes goto ohne Wiederanlauf → startGoto: 3 Versuche, Chrome-Neustart vor dem letzten bei Cert-/Netzfehlern (TODO 1.20) | additiv | Befund 23.09.: launchd- und Handstart brachen beide nach ~10 s mit page.goto: net::ERR_CERT_VERIFIER_CHANGED ab (Chrome-Update 21.09., Rechner 31 Tage uptime) — der Messtag fiel aus, erst ein von Hand vorgestarteter Chrome lief durch. Jetzt: erstes goto mit drei Versuchen (10 s Abstand); bei ERR_CERT_VERIFIER_CHANGED/ERR_NETWORK_CHANGED/ERR_CONNECTION_RESET wird vor dem LETZTEN Versuch Chrome beendet und neu verbunden (frischer Prozess setzt den Cert-Verifier-Zustand zurueck). Dazu daily-run.sh: die Doppellauf-Sperre zaehlt einen Tagesordner nur noch als gelaufen, wenn er mindestens einen <Prompt>__<mode>/-Ordner traegt — ein leerer Abbruch-Ordner wird nach <Guard>__failed-HHMM/ verschoben und der Lauf startet; Abbruchmeldung vor dem ersten Prompt sagt jetzt "Lauf hat nicht begonnen — keine Rohdaten, kein finalize" statt auf finalize zu verweisen. Vergleichbarkeit: Keine Mess- oder Schemaaenderung — nur Startrobustheit und Wrapper-Logik. Ein per Wiederanlauf gestarteter Lauf ist von einem normalen Lauf nicht unterscheidbar (und soll es nicht sein); die Log-Zeilen "Start-goto Versuch n/3" belegen den Hergang im Tageslog. |
| 30.09.2026 | bookmarklet | 2.7.4 → 2.7.5 | additiv | TODO 1.25 (Doppel-Abruf seit 25.09.): Endpunktwahl nach FORMAT statt nach "zuletzt gesehen". Die Performance-Liste des Tabs fuehrte seit dem Doppel-Abruf auf conversation/{id} (mapping, ohne search_model_queries) — das Panel zeigte dann "Keine Aufruftexte", obwohl die messages-Fassung sie traegt. Neu: messages-Kandidaten zuerst (Sortierung im Build), singular nur als Fallback; hat der Tab beide Formate geladen, holt das Bookmarklet beide und nimmt messages (meta.format_seen, meta.dropped_by_mapping aus der Nachrichten-Differenz); Panel-Kopf "Quelle: <endpoint> (<format>) · n Nachrichten · n nur hier"; gelbe Hinweiszeile bei nur-mapping (meta.mapping_only). Analyse-App: Banner-Fall mapping-only, format_seen/dropped_by_mapping in Meta und Exporten (JSON automatisch, CSV-Kopf). Vergleichbarkeit: Bookmarklet-Daten ab 2.7.5 kommen bei erreichbarem conversations/{id} immer aus der messages-Fassung — aeltere Einsendungen koennen je nach Tab-Zustand die mapping-Fassung tragen (erkennbar an meta.format bzw. source_format). format_seen existiert erst ab 2.7.5. |
| 30.09.2026 | extractor | schema 22 → schema 23 | additiv | TODO 1.24 (Doppel-Abruf seit 25.09., Befund docs/_eingang/befund-doppelabruf-conversation-mapping.md): run.conversation_bodies_seen (welche Conversation-Bodies der Runner sah — Pfad, Format, Anzahl; der Runner speichert messages mit VORRANG, last-wins kostete 25.-29.09. je Tag einen Lauf die Suchanfragen), har.conversation_fetch_paths (Reihenfolge der Conversation-GETs im Fenster) und schema_fingerprint.messages_only_keys (Metadata-Schluessel, die nur die messages-Fassung traegt; leer ohne Doppel-Abruf im Fenster; SET_FIELDS highVariance mit Erstsichtungs-Backfill der fuenf bekannten). extract-only rettet mapping-Laeufe aus der HAR (messages-Antwort derselben Unterhaltung), sonst Vermerk. Waechter: Minderheits-Regel (Conv-Abruf-Familie, >=3 Tage, >=1 Lauf, <50% -> observed minority, nie revertiert) + ?-Summary-Bug behoben (Vorher-Pfad = Conv-Endpunkt des Vortags). Vergleichbarkeit: Additiv. Die 4 mapping-Snapshots (25.09. K3-02, 26.09. K12-01, 28.09. K9-01, 29.09. K1-01/thinking) werden erst mit der Re-Extraktion auf dem Messrechner repariert — wenn die Tages-HAR die messages-Antwort traegt; sonst bleiben sie mapping mit Vermerk im Log. Re-Extraktion noetig (reextract-all), sonst Differ-Marker am Folgetag. |
| 25.09.2026 | runner | Pillen-Selektor button.__composer-pill → Kandidatenliste ueber data-Attribute (HOTFIX 1.21) | additiv | ChatGPT entfernte die Klasse __composer-pill (Rollout 24.09. als Kohorte 7/26 instant-Ausfaelle, 25.09. vollstaendig — Lauf brach nach 3 Prompts ab). Die Pille traegt jetzt stabile data-Attribute (data-composer-navigation-target=reasoning, data-codex-intelligence-trigger, data-selected-reasoning-effort) bei unveraendertem Menue/Slider. Fix: Kandidatenliste in fester Folge (data-Attribute zuerst, alter Selektor als letzter Kandidat), erste sichtbare gewinnt, Treffer im Log und als pill_selector im Beleg; mode_evidence.effort_attr(+_after) aus data-selected-reasoning-effort als zweite Zielpruefung (Widerspruch kippt ok); bei nicht gefundener Pille zusaetzlich <id>-<mode>-effort-failed.html (Composer-form, 40 KB) + Button-Inventar im Log — der PNG-Screenshot zeigte die Pille, erst das DOM den Klassen-Wegfall. Vergleichbarkeit: Kein Schemabruch, kein Feld geaendert — nur die UI-Steuerung. mode_evidence traegt zusaetzlich pill_selector und effort_attr(_after); der Differ vergleicht davon nur den aussagekraeftigen Kern (unveraendert). Ausgefallene Laeufe 24./25.09. sind Messluecken, keine Drift. |
| 22.09.2026 | extractor | schema 21 → schema 22 | additiv | TODO 1.19 (A-3, Feldbenennung aus 95 Karten 19.-22.09.): ads.entries[] traegt parsed = { advertiser, advertiser_url, advertiser_id, unit_type, format, cards, titles[], target_hosts[] (Host ohne Query), header_label } aus ads_response.content (advertiser_brand + ad_cards). Aus dem SANITISIERTEN raw fliegen favicon_url, logo_url, ad_data_token sowie die Query-Parameter oppref/olref/ad_data_token in target.value (~10 KB Base64/Tracking je Eintrag; utm_* bleibt als Kampagnen-Dokumentation; das Roharchiv behaelt alles). adsKennzahlen/adsDayStats lesen parsed (Bestand ohne Re-Extraktion via parseAdEntry(raw)): Register aus advertiser_id (34 Werbetreibende, 8 CHECK24-Vertikalen — deckungsgleich mit Coworks CSV), Formate (image_card_v2/product_card_v2), karten_je_unit, product_unit_anteil. Neue Erstsichtungs-Regeln Kategorie ads: neues Format, neuer unit_type, Feld erstmals gefuellt (ad_survey, ad_unit_presentation, ...); Backfill --backfill-ads-seen erweitert und gelaufen (+38). Werbetreibenden-Wechsel je Prompt ist DARSTELLUNG (Prompt-Matrix mit Kuerzeln), kein Ereignis. Vergleichbarkeit: parsed ist additiv; das Streichen der Base64-/Token-Felder aendert die publizierten raw-Eintraege (Snapshots schrumpfen) — Vergleiche auf raw-Schluessel-Ebene bleiben gueltig (Schluessel-Namen unveraendert, nur favicon_url/logo_url/ad_data_token entfallen; ads_raw_keys-Erstsichtungen tragen sie weiter als historisch gesehen). Re-Extraktion der Ads-Tage auf dem Messrechner empfohlen (reextract-all), sonst Differ-Marker am Folgetag. |
| 14.09.2026 | extractor | schema 20 → schema 21 | additiv | TODO 1.9 (Befund probe-1957, 12.09. 23:15): run.stream_transport bekommt eine ZWEITE Belegquelle — ws-frames.jsonl. Mindestens ein stream-item-Frame fuer die conversation_id des Laufs belegt ws; die HAR-SSE-Antwort belegt sse; beides zusammen ws (die Frames sind der Antwortkanal); keins null. Neues Beleg-Feld run.stream_transport_source (har|ws-frames|null). Damit faellt die indirekte Heuristik aus Schema 20 weg (HAR erfasst + POST + stream_status-Poll ohne SSE) — probe-1957 hatte 440 stream-item-Frames, aber keine HAR-Antwort (failedBodies), und blieb faelschlich null. Alle Extraktionswege (run-all, extract-only, finalize, probe-run) lesen ws-frames*.jsonl und schneiden aufs Lauf-Fenster. Fixtures K5-01/K4-02 tragen je einen ECHTEN, sanitisierten stream-item-Frame aus probe-1845. Vergleichbarkeit: Additiv bis auf die Belegquelle des bestehenden Felds: measure-Bestandstage bleiben sse aus der HAR (getestet); Astra-Probelaeufe wechseln von null auf ws, sobald re-extrahiert wird — das ist die Korrektur des Befunds, keine Drift. Tagesregel 4e und Differ-Regel unveraendert. Re-Extraktion der Bestandstage auf dem Messrechner noetig (reextract-all), sonst faellt am Folgetag je Lauf der schema_version-Marker. |
| 12.09.2026 | bookmarklet | 2.7.3 (GPT-6-Astra-Datenstruktur, A1) → 2.7.4 (Kohorten-Wortlaut Aufruftexte) | additiv | Befund 11.09. 21:40 (Kohorte): Die Abschaltung der web.run-Aufruftexte betrifft nicht alle Accounts — zwei Beobachter mit kostenlosen Accounts sahen die Texte am selben Abend noch. Die Lv-Zeile des Bookmarklets behauptete global "ChatGPT liefert seit 11.09.2026 keine Aufruftexte mehr"; neu kontoneutral: "Keine Aufruftexte in dieser Unterhaltung (Typ, Frische, Ort fehlen) — seit 11.09.2026 je nach Account-Kohorte". Das Bookmarklet laeuft auf fremden Accounts, deren Kohorte wir nicht kennen. Groesse 26,6 KB (Budget 27). Vergleichbarkeit: Nur Anzeigetext der Ehrlichkeitszeile; Parsing, postMessage und Zaehlung unveraendert. |
| 12.09.2026 | extractor | schema 18 → schema 19 | additiv | Ads A-1 (Plan docs/_eingang/ads-tracker-plan-v1.md, Befund Free-Sonde): neuer Block ads.* aus dem bazaar-Endpunkt (GET /backend-api/bazaar/conversation/{id}/ads; leere entries_by_turn_id = Messwert keine Anzeige) — requested/delivered/entries(turn_id+raw, roh; Sanitizer schrubbt auf dem Publikationsweg)/segment_id/opt_out/account/country. Aus /backend-api/me gehen BEWUSST nur zwei Werte in den Snapshot: ads_segment_id und der Laendercode (sonst weiter nur Key-Namen). Dazu run.plan (measure|ads) und run.prompt_set (v2|ads-v1) als Tagesplan-Identitaet; Bestandslaeufe bekommen measure/v2 bei der Re-Extraktion. Neuer eingefrorener Promptsatz prompts/prompt-set-ads-v1.json (20 Prompts, 10 kaufnahe Kategorien, Free-Account, Modus auto, Tagesplan ads 10:00 via com.alinr.gptspy.ads; wartet auf das measure-Lock, max 30 min; free_limit-Sofortabbruch). Der ads-Plan schreibt bis A-2 KEINE Events (events.jsonl bleibt vom Free-Lauf unberuehrt); Differ-Feldregeln ads_requested/ads_delivered high als Beleg. Vergleichbarkeit: Additiv: alle Schema-18-Felder unveraendert. Der Differ setzt am Uebergangstag je Lauf den schema_version-Marker aus; darum heute Abend Re-Extraktion aller Bestandstage auf dem Messrechner (bash scripts/reextract-all.sh; node src/metrics.js --init; npm run publish), damit morgen frueh kein Marker faellt. ads-Laeufe liegen getrennt unter data/<Tag>/ads/ und fliessen in keine bestehende Reihe. |
| 12.09.2026 | extractor | schema 19 → schema 20 | additiv | Nachbesserung astra 6 (Befund docs/_eingang/befund-astra-probe-messaccount.md, probe-1845): run.stream_transport (sse|ws|null — Astra streamt ueber wss://ws.chatgpt.com; die WS-Verbindung erscheint weder im Request-Log noch im HAR, belastbar ist nur die HAR-Antwort: SSE-Ereignistypen = sse, HAR erfasst + POST /f/conversation + stream_status-Poll ohne SSE = ws, ohne HAR null) und behavior.stream_status_polls (GET /conversation/{id}/stream_status im Prompt-Fenster — auch der SSE-Weg pollt einmal, das Feld allein diskriminiert nicht). fanout.open_urls: nackte URLs in search_model_queries sind open-Aufrufe (ref-Typ view) und zaehlen nicht mehr als Suchanfragen. site-Punktform (site.tagesschau.de) fuellt fanout.queries[].domain_filter (auf Astra IST die Punktform der Domain-Filter; Pipe-Syntax gewinnt). Ereignisregeln aus A1 SCHARF (ASTRA_REGELN_SCHARF=true; ref_types laeuft als eigene Kategorie ref_type, nicht als web.run-Modus). Fixture test/fixtures/astra-probe-1845-k5.json aus echten, sanitisierten probe-1845-Daten (K5-01); probe-1813 als FEHLVERSUCH.md gekennzeichnet. Vergleichbarkeit: Additiv: alle Schema-19-Felder unveraendert bis auf search.queries, das nackte URLs nicht mehr enthaelt (auf allen Bestandstagen identisch — URL-Queries treten erst mit Astra auf). stream_transport ist auf Bestandstagen sse (HAR vorhanden) bzw. null (HAR-Ausfall), nie geraten; der Differ stellt null nie gegen einen belegten Wert. Re-Extraktion der Bestandstage auf dem Messrechner noetig (reextract-all), sonst faellt am Folgetag je Lauf der schema_version-Marker. |
| 11.09.2026 | bookmarklet | 2.7 → 2.7.1 (schnell, zustandserhaltend, ehrlich) | additiv | Sechs additive Aenderungen in spy.src.js (auftrag-v271-schlank.md): (1) Startkette parallel — erst rendern, Kontoabrufe danach; der langsamste der drei (~1 s) hatte die Erstanzeige blockiert. (2) Render zustandserhaltend: offene Sektionen, ausgeklappte Weitere-Listen und Scrollposition ueberleben jeden Neuaufbau (Offers-Replay, Refresh), unveraenderte Daten rendern gar nicht erst (Hash inkl. produktDaten). (3) Query-Quellen vereint: code-Aufrufe plus metadata.search_model_queries/map_search_model_queries (Typ search, keine Frische), Dedupe ueber den Text, Code gewinnt; sind web.run-Nachrichten entkernt (Stand 11.09.2026), steht eine Hinweiszeile unter Search Queries. (4) Sektionskopf Results nennt n roh, wenn Rohzahl von der utm-bereinigten abweicht; die App dedupliziert seither mit derselben Regel (nur utm, je Exchange). (5) Bild-Proxy-URLs (images.openai.com/static-rsc) als eine Zaehlzeile statt Listeneintraege. (6) Version 2.7.1 ueber neue Patch-Schiene in bookmarklet-state.json (patch-Feld; build-site.js zaehlt dort weiter, naechste Nebenversion von Hand). Groesse 24,8 KB (Budget 25, Ziel des Auftrags <25). Zwei Verhaltenstests in test-bookmarklet.js (echtes Chromium): Replay-Re-Render erhaelt op/Xt.on, entkernte Aufrufe liefern Metadata-Queries plus Hinweiszeile. Vergleichbarkeit: Keine Messdaten betroffen — Bookmarklet ist Leser-Werkzeug. postMessage-Format unveraendert (meta.v jetzt String 2.7.1); App zaehlt Results seither utm-dedupliziert wie das Panel — Analysen derselben Unterhaltung zeigen dadurch ggf. kleinere Results-Zahlen als vorher (die Rohzahl steht im Panel-Sektionskopf). |
| 11.09.2026 | bookmarklet | 2.7.1 → 2.7.2 (Fan-out im Panel, Paket F3) | additiv | Fan-out-Profilzeile unter Search Queries (Queries, Modus-Mix, Fenster, site:, Standort, Nachschlagerunden) — NUR wenn Aufruftexte vorhanden sind; seit der Entkernung vom 11.09.2026 ist die Hinweiszeile der Standardfall, kein Fake-Profil aus metadata-Strings. Query-Zeilen tragen Scope-Chip (18 Zeichen), |domain- und site:-Ziele als Domain-Chips; lookup-Runden (business|Ort||Name;Name) als eigene Zeile statt Wegfall; search(...) an recipient web ist Prompt-Echo (Tracker Schema 17) und zaehlt nicht ins Profil. Analyze-Unterzeile nennt das Fan-out-Profil. postMessage unveraendert — die App parst selbst (dort: Profilzeile, Banner als Standardfall, Typwert-Vergleich aus /api/fanout-typ.json mit Datumszusatz, Seeds-Trichter Queries->Domains->geoeffnet->zitiert, Direktiven-Zeilen, CSV-Spalten mode/freshness/domain_filter/scope/lookup_names/lang/call_index). Groesse 25,9 KB (Budget 26, Ziel des Auftrags <26). Vergleichbarkeit: Keine Messdaten betroffen — Bookmarklet ist Leser-Werkzeug. postMessage-Format unveraendert; aeltere Analysen rendern weiter. Die App zaehlt lookup-Runden und Direktiven jetzt als eigene Zeilen in der Queries-Collection — Zaehlungen derselben Unterhaltung koennen dadurch minimal von v2.7.1 abweichen. |
| 11.09.2026 | bookmarklet | 2.7.2 → 2.7.3 (GPT-6-Astra-Datenstruktur, A1) | additiv | Markdown-Links in der finalen Antwort zaehlen als Zitate (Ref md, Kachel summiert; Treffer werden ueber die URL als cited markiert), NUR wenn weder content_references noch cite-Marker existieren; ref_id kommt als String (turn1search0) und wird auf die alten refIndex-Schluessel abgebildet (neuer Typ news; citeRe kannte news bereits); Modellzeile zeigt thinking_effort (gpt-6-astra-wm · extended); der sichtbare Denk-Vorspann (is_thinking_preamble_message) zaehlt nicht als Antwort. Groesse 26,5 KB — Budget auf 27 KB: A1 war im Auftrag MIT F3 als eine 26-KB-Stufe geplant, real sind es zwei Versionen (F3 allein 25,9; A1 ~0,7). Vergleichbarkeit: Keine Messdaten betroffen — Bookmarklet ist Leser-Werkzeug. postMessage unveraendert. Auf Astra-Unterhaltungen steigt die Citations-Zahl von 0 auf die Zahl der Markdown-Quellenlinks — das ist die Korrektur des im Befund beschriebenen Fehlstands, keine Drift. |
| 11.09.2026 | bookmarklet | 2.9 (2.8-pre/2.9-pre, Auftrag 1 + Nachbesserung) → 2.7 (Ruecknahme per git revert, Anzeige v2.7) | additiv | Entscheidung Alin 11.09. 16:00: v2.8-pre und v2.9-pre zurueckgenommen (git revert 80e10764 und 477a4c14, keine Reset-/Force-Historie). Grund: Panel spuerbar langsamer (37,7 KB Href, zusaetzlicher Abruf des alten Endpunkts, Schluessel-Inventar ueber das ganze Objekt), angezeigte Zahlen weichen von v2.7 ab. Der geteilte Extractor (extract-core) kommt erst wieder, wenn er auf den Live-Fixtures bewiesen ist. Die Versionszeilen 2.8/2.9 wurden mit den Commits revertiert; diese Zeile haelt die Episode fest. Vergleichbarkeit: Keine Messdaten betroffen — Bookmarklet ist Leser-Werkzeug. Panel und App zeigen wieder die v2.7-Zahlen; kurzzeitig mit 2.8/2.9 erstellte Analysen koennen abweichende Zaehlungen tragen. |
| 11.09.2026 | extractor | schema 15 → schema 16 | additiv | Fan-out als Kernbeobachtung (Paket F1): neuer Block fanout.* je Lauf — calls, tool_call_text_present (Entkernungs-Waechter 11.09.), queries je Zeile mit mode/query/freshness_days/domain_filter/scope/lookup_names/lang/turn/call_index/source (code|metadata), directives, lookup_rounds, site_queries, domain_filters, scopes. Eigener Parser parseFanoutCall mit drei Korrekturen, die parseToolCall bewusst NICHT bekommt (Regel 7, Bestandsfelder byte-stabil): lookup-Runden business|Ort||Name;Name fallen nicht mehr weg, image|q|n liest das dritte Feld als Anzahl statt Frische, click/find sind Aktionen. Metadata-Queries (search_model_queries/map_search_model_queries) als eigene Quelle dedupliziert dahinter (Code gewinnt). Dazu Differ-Regeln fanout_* (Beleg-Futter), sieben Tages-Ereignisregeln Kategorie fanout in changelog.js (Modus >=70% high, Frische-Klasse high, site:-0 medium, Filter-Domains low, Scope +-30 medium, Aufruftext >=90% high mit Symptom-Buendelung, Queries-7-Tage-Mittel low), zehn fanout-Metrikreihen, Seite /tracker/fanout/ (de+en). Rueckwirkende Re-Extraktion aller Messtage via scripts/reextract-all.sh auf dem Messrechner (Rohdaten liegen nur dort); bis dahin bleiben die Bestandstage auf Schema 15 und die neuen Regeln stumm. Vergleichbarkeit: Additiv: alle Schema-15-Felder unveraendert (parseToolCall und alle Aggregate unangetastet; Pipeline-Test prueft die Bestands-Query-Liste explizit). Der Differ setzt Feld-Diffs am Uebergangstag je Lauf aus (meta/schema_version); events.jsonl bleibt unangetastet, die Re-Extraktion schreibt nur Snapshots und Metriken. |
| 11.09.2026 | extractor | schema 16 → schema 17 | additiv | Nachbesserung F1: die Funktionsform search(...) an recipient web traegt prompt_echo: true — sie spiegelt den Prompt, sie faechert nicht auf. Solche Eintraege zaehlen weder als Modus (fanout-modes-Metrik liest jetzt den fanout-Block statt routing.query_modes, ohne Aktionen und Echos; Tagesregeln via fanoutDayStats) noch ins Query-Volumen (fanout-queries-per-run, queriesTotal der 7-Tage-Regel); im Drilldown der Fan-out-Seite bleiben sie als Prompt-Echo sichtbar. Dazu Erstsichtungs-Backfill der fanout-Felder (fanout_domain_filters/_modes/_scopes) ueber alle 23 Messtage (node src/changelog.js --backfill-fanout-seen) und Ruecknahme der acht 2026-09-11-fanout-filter-*-added-Ereignisse per changelog-overrides.json (Status retracted: seen-values nicht nachgefuellt, Messfehler). Vergleichbarkeit: Additiv am Snapshot (neues optionales Feld prompt_echo je Query); Bestandsfelder und parseToolCall unveraendert. Empfohlen: reextract-all erneut laufen lassen, damit alle Tage Schema 17 tragen und die fanout-Zaehlungen (ohne Echo/Aktionen) ueber die ganze Reihe konsistent sind — sonst setzt der Differ am 12.09. je Lauf einen schema_version-Marker und vergleicht ab 13.09. wieder normal. |
| 11.09.2026 | extractor | schema 17 → schema 18 | additiv | Auftrag A1 (GPT-6-Astra-Datenstruktur, Befund Unterhaltung 6aa43533): refs.citation_md_count (Markdown-Links als Zitate, nur wenn die finale Antwort weder content_references noch cite-Marker traegt; der sichtbare Denk-Vorspann is_thinking_preamble_message zaehlt nicht als Antwort); search.ref_id_form (object|string|mixed) und search.ref_types (String-Form turn1search0, neuer Typ news — citeRe kennt news); site-Operator in Punktform (site.adidas.de): site_query_count und fanout.site_queries erkennen site[:.], neu search.site_dot_count; search.entry_fields (Schluessel-Set der Treffer-Eintraege — Astra ohne snippet/pub_date, mit thumbnail_url) und search.group_entry_ratio (Astra: 1 Gruppe = 1 Eintrag); routing.thinking_effort/preamble_message_present/work_activity_kinds (cot_version und tool_summary_types waren bereits erfasst). Differ-Feldregeln als Beleg; die TAGES-Ereignisregeln (Zitatform Marker->Markdown >=70% high, Punktform >=70% medium, entry_fields weg/da >=90% high mit snippet-Symptom, Astra-Sets) sind ANGELEGT, ABER NICHT SCHARF (ASTRA_REGELN_SCHARF=false, getestet ueber buildChangelog astraScharf) — scharf erst nach dem Astra-Probelauf (probe-run --modes=astra, K2-01 + lokal + News). Fixture: SYNTHETISCH aus dem Befund nachgebaut (Rohdaten liegen nicht auf diesem Geraet); echte Dateien unter test/fixtures/live/astra-6aa43533.*.json gewinnen automatisch. Vergleichbarkeit: Additiv: alle Schema-17-Felder unveraendert bis auf site_query_count, das seither auch die Punktform zaehlt (bewusst, Befund; auf allen Bestandstagen identisch, weil dort nur die Doppelpunktform vorkommt). Kein Re-Extraktions-Zwang; der Differ setzt am Uebergangstag je Lauf den schema_version-Marker. |
| 26.08.2026 | bookmarklet | 2.6 → 2.7 | additiv | product_update-Replay (Paket E3): Nach dem Einsammeln der Conversation macht das Bookmarklet je Produkt-ID aus den content_references denselben Abruf wie die ChatGPT-Oberflaeche beim Rendern des Karussells — POST /backend-api/search/product_update mit {product_query, product_lookup_key}, sequenziell mit 300–500 ms Abstand, Obergrenze 24 Produkte, bei 429 sofort Schluss, Einzelfehler fail-soft (Produkt behaelt die Basiskarte). Die product_entities gehen TOKEN-FREI in meta.product_entities an die Auswertung: product_lookup_key/-data, provider_metadata (id_to_token_map), checkout_payload, launcherPayload, debug_info, checkout_image_urls, oppcref werden vor dem Senden entfernt, checkout_payload/provider_metadata nur als *_present-Flag (Scrub-Linie wie Tracker Schema 15; gilt damit auch fuer CSV/JSON-Export der App). Panel: Offers-Zahl je Produkt-Zeile plus Kennzeichnung Haendlerdaten live nachgeladen (DE+EN). Groesse: 23,8 KB Href, Budget von 22 auf 24 KB angehoben (test-bookmarklet.js, Begruendung dort). Abgenommen am Pruefstand mit ECHTEN Daten: K2-01 vom 23.08. (Conversation + 17 product_update-SSE-Bodies aus dem Tages-HAR) durch den gebauten Code — 3 Produkte, 7 Offers, 100 % utm, Token-frei bis in CSV/JSON. Vergleichbarkeit: Keine Messdaten betroffen — das Bookmarklet ist ein Werkzeug fuer Leser, nicht Teil der taeglichen Messkette. Die postMessage-Uebergabe ist abwaertskompatibel erweitert (meta.product_entities zusaetzlich); aeltere Lesezeichen melden sich in der App ueber meta.v als veraltet, Alt-Analysen ohne product_entities rendern weiter (Basiskarte + Hinweis). Ein product_update-POST je Produkt veraendert das Request-Verhalten des Nutzers auf chatgpt.com — im Widget gekennzeichnet, im Plan (E3) so abgewogen. |
| 26.08.2026 | extractor | schema 14 → schema 15 | additiv | E-Commerce-Tiefe (Pakete E1+E2): shopping.*-Block je Lauf — Produkte aus content_references (Basiskarte, offers dort leer) zusammengefuehrt mit den product_entity-Frames aus POST /backend-api/search/product_update im HAR (Volltiefe: offers mit merchant/seller, Preiszerlegung base/shipping/tax/total, Streichpreis, Verfuegbarkeit, Lager-/Liefertext, Best-Price-Tag, checkoutable, provider, utm_source-Bool). Dazu schema_fingerprint.product_entity_keys/product_offer_keys (Feldlisten, 32/22 Felder Stand 26.08.), har.product_update_posts/product_carousel_posts, Karussell-Kurzbeschreibungen (IDs + Texte) aus metadata.shopping. Token bewusst ausgespart: product_lookup_key.data, provider_metadata.id_to_token_map und checkout_payload nur als Existenz-Bools; der Sanitizer schrubbt diese Token jetzt auch aus publizierten Conversations (rueckwirkend ueber alle Messtage), zwei neue Leak-Patterns sichern das ab. Rueckwirkende Re-Extraktion 20.–23.08. (lokale HARs), Additivitaet belegt: kein Bestandsfeld veraendert; 24.–26.08. bleiben auf Schema 14, bis die HARs auf dem Messrechner nachgezogen werden bzw. ab dem naechsten Tageslauf. Vergleichbarkeit: Additiv: alle Schema-14-Felder unveraendert (verifiziert ueber 107 Snapshots alt/neu). Der Differ setzt Feld-Diffs am Uebergangstag aus (meta/schema_version). Neue Felder messen ab 20.08. (re-extrahierte Tage) bzw. ab dem ersten v15-Lauf. |
| 26.08.2026 | runner | HAR + Request-Log + Kontext-Snapshot → zusaetzlich ws-frames.jsonl (WebSocket-Frame-Mitschnitt ueber die CDP-Network-Domain) | additiv | Paket E4: Die Produkt-Panel-Sektionen Wissenswertes / Was andere sagen (Review-Synthese je Quelle) stehen weder im Conversation-Objekt noch in den product_update-Antworten — Verdacht WebSocket, und das HAR traegt keine WS-Frames. Neuer WsRecorder (src/ws-recorder.js) hoert auf derselben CDP-Session wie der HarRecorder mit (Network.webSocket*-Events) und schreibt die Frames als ws-frames.jsonl neben das HAR ins private Tagesarchiv. Fail-soft auf jeder Ebene: Handler fangen selbst, write() wirft nie, ein Fehler kann den Messlauf nicht gefaehrden. Obergrenzen: 256 KB je Frame (Rest gekappt), 100 MB gesamt (danach nur noch Metadaten). CDP-Falle dokumentiert: webSocketFrame*-Timestamps sind MonotonicTime, keine Wanduhr — Wanduhr kommt von uns, die Monotonic-Zeit bleibt als mono-Feld erhalten. Die Auswertung folgt, sobald der erste regulaere Lauf Frames liefert. Vergleichbarkeit: Additiv: eine neue Rohdatei im privaten Archiv, kein bestehender Mitschnitt veraendert. Snapshots und Differ unberuehrt; publiziert wird aus ws-frames.jsonl erst nach einer eigenen Auswertung und dann ueber den Sanitizer. |
| 25.08.2026 | bookmarklet | 2.2 → 2.3 | additiv | Vier Aenderungen in einer Version (Bookmarklets aktualisieren sich nicht selbst, jede Version heisst „neu in die Leiste ziehen“): (a) Query-Badges — die Pipe-Zeilen von web.run tragen Modus, Frischefenster und Domain-Beschraenkung, das wurde bisher beim Parsen weggeworfen; Direktiven (length …) stehen jetzt als eigene Zeile statt zu verschwinden. (b) 429-Haertung — geladene Daten bleiben bei einem Fehler stehen, Statuszeile im Kopf statt Vollflaechenmeldung; Backoff 60→120→300 s, Retry-After wird respektiert; Abruf ereignisgetrieben (PerformanceObserver) mit Auffangtakt 12 s statt 2 s, Pause bei verborgenem Tab, Access-Token wird zwischengespeichert. Gemessen am Pruefstand: 58,3 → 6,2 Abrufe/min (−89 %), bei verborgenem Tab 0. (c) Analyze-Knopf ueber die volle Breite mit Unterzeile, Endpunkt-Text in die Fusszeile, einmaliger Hinweis-Puls. (d) Radien vereinheitlicht (Panel 10, Kaesten 6, Chips Pille). Nebenbefund beim Pruefen: open(…) im Thinking-Modus wurde als Suchanfrage gezaehlt und blaehte den Fan-out auf — gefixt. Vergleichbarkeit: Keine Messdaten betroffen — das Bookmarklet ist ein Werkzeug fuer Leser, nicht Teil der taeglichen Messkette. Die Uebergabe an die Auswertungs-App ist unveraendert (Rohobjekt per postMessage); aeltere Fassungen melden sich dort weiterhin ueber meta.v als veraltet. |
| 25.08.2026 | bookmarklet | 2.3 → 2.4 | additiv | Panel-Redesign nach abgenommener Vorlage (docs/examples/bookmarklet-panel-v24.html): (a) Farbwechsel Slate/Violett auf Navy/Koralle, Token exakt aus der Vorlage. (b) Aktions-Block sticky am Panelfuss, rahmenlos: fuenf Kacheln plus Analyze volle Breite mit Unterzeile; beim Scrollen der Sektionsliste (scrollTop > 24) klappen Kacheln und Unterzeile animiert weg, im Button stehen die Kompakt-Zahlen. Die .D-Statistikzeile und die Teaser-Fusszeile entfallen. (c) Einheitliche Zeilen-Sprache (Turn-Marker, Domain-Chip, Titel, Status-Pillen): Results tragen open/cited, Citations eine Ref-Pille, Entities farbige Typ-Chips, Safe URLs Domain-Chip plus Pfad; lange Listen zeigen 5 Zeilen plus aufklappbares Restglied. (d) Vier neue Sektionen nur bei Daten: Places (entity mit Orts-Kategorie: Name, Rating, Bewertungszahl), Products (products/product_entity: Name, Preis, cited), Merchants (aggregiert aus den Produkt-Haendlern), Widgets (genui-Marker: Typ, Bezeichnung, Turn, 0-Citations-Hinweis). Felder erscheinen nur, wenn sie im Rohobjekt stehen — geprueft am Espresso-Lauf K2-01 vom 23.08. Href 21,9 KB, Budget neu 22 KB (vorher 19). Vergleichbarkeit: Keine Messdaten betroffen — das Bookmarklet ist ein Werkzeug fuer Leser, nicht Teil der taeglichen Messkette. Die postMessage-Uebergabe an die Auswertungs-App ist unveraendert; aeltere Fassungen melden sich dort ueber meta.v als veraltet. |
| 25.08.2026 | bookmarklet | 2.4 → 2.5 | additiv | Mini-Korrektur auf Nutzer-Anweisung (Nachpruefung durch Cowork): Das Frischefenster einer Query rendert als grauer Badge direkt hinter dem Typ-Badge ([fast][30d] Query ...) statt wie in 2.3/2.4 als gedimmter Suffix hinter dem Query-Text (... · 30d · domain). Neue Badge-Klasse T.f (grau #334155/#cbd5e1) neben T.p/T.g; die Domain-Beschraenkung bleibt als Suffix. Kein Badge, wenn kein Frischefenster gesetzt ist. Startseiten-Nachbau (index DE+EN) an denselben Look angeglichen. Vergleichbarkeit: Keine Messdaten betroffen — das Bookmarklet ist ein Werkzeug fuer Leser, nicht Teil der taeglichen Messkette. Die postMessage-Uebergabe an die Auswertungs-App ist unveraendert; aeltere Fassungen melden sich dort ueber meta.v als veraltet. |
| 25.08.2026 | bookmarklet | 2.5 → 2.6 | additiv | Analyze haengt den Marker #gptspy an die Adresse der Auswertungs-Seite (window.open(APP_URL + Marker)). Die Seite erkennt daran (plus window.opener als Rueckfallebene fuer aeltere Lesezeichen), dass sie vom Bookmarklet geoeffnet wurde, und zeigt statt der Landing-Sektion einen Lade-Zustand (pulsierendes Keyhole-Logo, Zeile Unterhaltung wird geladen); kommt binnen 12 s kein Payload, faellt sie auf den normalen Leerzustand mit Hinweiszeile zurueck. Sonst keine Aenderung an Abruf oder Uebergabe. Vergleichbarkeit: Keine Messdaten betroffen — das Bookmarklet ist ein Werkzeug fuer Leser, nicht Teil der taeglichen Messkette. Die postMessage-Uebergabe an die Auswertungs-App ist unveraendert; aeltere Fassungen melden sich dort ueber meta.v als veraltet. |
| 22.08.2026 | environment | — → gpt-5-6 | additiv | Basiseintrag der Mess-Umgebung beim Start des Auto-Appends: Modell gpt-5-6 (UI: GPT-5.6 Sol) auf dem Plus-Mess-Account, konstant seit dem ersten Lauf am 20.08. Kein Wechsel — ab jetzt meldet jede Modelländerung hier einen Stub. Vergleichbarkeit: Kein Bruch; dokumentiert den Ausgangszustand. |
| 22.08.2026 | extractor | schema 13 → schema 14 | additiv | Schema 14 für die Kennzahlen (Umbau Paket 5): search.queries_en_count (Stoppwort-Heuristik) und search.freshness_days_median — die Frische-Fenster der Pipe-Syntax wurden geparst, aber nie gespeichert. Rein additiv; der 22.08. wurde re-extrahiert, damit der 23.08. nicht in die Schema-Aussetzung des Differs läuft. Vergleichbarkeit: Additiv; bestehende Felder unverändert vergleichbar. Die neuen Felder haben erst ab 22.08. Werte — fanout-freshness-days und fanout-language-en-share beginnen dort. |
| 22.08.2026 | site | Deutsch an der Wurzel, Englisch unter /en/ → Englisch an der Wurzel (Default), Deutsch unter /de/; App unter /analysis/ und /de/analyse/, zweisprachig; Sprachumschalter DE|EN; hreflang/canonical auf jeder Seite; /credits/ (nur en) | additiv | Sprach-Flip: Die Zielgruppe ist zur Hälfte nicht deutschsprachig, Englisch wird die Default-Sprache. /en/* leitet per 301 auf die Wurzel, /analyse/ auf /de/analyse/. Die App rendert keinen eigenen Kopf mehr — die geteilte NAV kommt aus build-site, der Kopf ist auf allen Seiten pixelgleich. Vergleichbarkeit: Keine Messdaten betroffen; reine Darstellungs- und Adressänderung. Alte Adressen leiten um. |
| 22.08.2026 | site | Timeline-Darstellung (Stufen 0-3, Sichten, Vollbefundliste) → Vier Ebenen: Heute, Lage, Changelog, Messreihen; Wissensbasis als Register | additiv | Umbau der Darstellung (Konzept GPT-Spy_Brief_v2). Ereignis-Modell (changelog.jsonl) statt Feld-Diff-Liste; Objekt-Register; RSS. Die Messung bleibt unverändert, nur die Aufbereitung ändert sich. Vergleichbarkeit: Keine Daten betroffen; die Interpretation älterer Feld-Diffs erfolgt rückwirkend über das neue Ereignis-Modell. |
| 21.08.2026 | bookmarklet | 2.0 → 2.2 | additiv | Bookmarklet an das neue conversations/{id}-Format und die messages-Paginierung angepasst (siehe changelog 2026-08-21-conversations-endpoint). Version zählt automatisch hoch bei Quelltext- oder Endpunktlisten-Änderung (config/bookmarklet-state.json). Betrifft nur die Ad-hoc-Analyse, nicht die Messreihe. Vergleichbarkeit: Ohne Einfluss auf die tägliche Messung. |
| 21.08.2026 | runner | — → closeChrome() + WAIT_UNTIL + caffeinate | additiv | Zwei Betriebsfehler behoben: browser.close() beendete Chrome bei CDP-Attach nicht (ein Chrome lief 23 h, Tab-Absturz → Lauf 0/14); sleep zählt im Systemschlaf nicht (Zufallsversatz hing >1h45). daily-run.sh wartet jetzt gegen die Uhr und umschließt den Lauf mit caffeinate. Kein Einfluss auf die Daten, aber auf die Vollständigkeit der Läufe. Vergleichbarkeit: Kein Datenbruch; erhöht die Ausfallsicherheit. |
| 21.08.2026 | extractor | schema 10 → schema 13 | additiv | Weitere additive Verfeinerungen des Extractors (Zwischenschritte 11-13 nicht einzeln datiert; aktueller Stand der Snapshots ab 21.08.). Feld-Diffs vom Differ bei schema_version-Wechsel ausgesetzt, damit kein Tag voller Fake-Events entsteht. Vergleichbarkeit: Additiv; Differ setzt bei Schemawechsel aus. |
| 21.08.2026 | site | — → gptspy.alinr.com live (Cloudflare Pages) | additiv | Öffentliche Site: Startseite, Tracker-Timeline, Wissensbasis, Analyse-App. Reine Darstellung, keine Messung. Vergleichbarkeit: Ohne Einfluss auf Daten. |
| 20.08.2026 | account | — → Mess-Account (ChatGPT Plus, Memory aus, keine Custom Instructions), model_slug gpt-5-6 / gpt-5-6-thinking | Baseline-Bruch | Dedizierter Mess-Account ab Tag 1 der Automation (statt Haupt-Account). Baseline der gesamten Zeitreihe. Vergleichbarkeit: Alle Daten ab 20.08. gegen diesen Account. Ein späterer Account-Wechsel wäre ein neuer Bruch. |
| 20.08.2026 | prompt-set | v1 (24 Prompts, 12 Kategorien) → v2 (26 Prompts, 14 Kategorien) | Baseline-Bruch | Kategorie K14 (Introspektion, 2 Prompts) ergänzt. Die 24 v1-Prompts byte-identisch übernommen (Regel 1). Der Differ meldet den Wechsel zusätzlich als changelog-Ereignis. Vergleichbarkeit: Vergleiche über diesen Tag hinweg für die neuen K14-Prompts erst ab 20.08. gültig; die 24 alten Prompts bleiben vergleichbar. |
| 20.08.2026 | extractor | schema 1 → schema 2 | Baseline-Bruch | Erster echter Lauf: die aus dem Analyzer portierten Felder (sonic_classification_result, search_model_queries, entry.source, entity-Inline-Marker) existierten nicht mehr. Extractor auf routing.*, web.run-Parser, group.domain umgestellt. Snapshots davor gab es nicht produktiv. Vergleichbarkeit: Kein Bruch in der Zeitreihe (vor dem ersten publizierten Lauf). |
| 20.08.2026 | extractor | schema 9 → schema 10 | additiv | introspection.identifiers als fünfte Signalebene (K14). Bewusst getrennt von den Beobachtungs-Ebenen, weil Modell-Output, keine Messung. Vergleichbarkeit: Additiv. |
| 20.08.2026 | extractor | schema 2 → schema 9 | additiv | Am ersten Messtag additiv erweitert: Verhaltens-Ebene und echtes Timing (3), platform.* Kontext-Snapshot (4), HAR-/Netzwerk-Ebene und response_shapes (5-6), Treffer-Signatur als Pipeline-Indikator (7), Zwei-Modi instant/think (8), Fan-out-Korrekturen Semikolon/open/genui (9). Rein additiv, keine bestehenden Felder geändert. Vergleichbarkeit: Additiv; frühere Felder unverändert vergleichbar. |