# Uitgaanskrant — werkinstructies voor Claude ## Werkdirectory Werk uitsluitend binnen deze projectdirectory (`/home/bob/Projects/ff-app/uitgaanskrant-1qhvtd`). Niet daarbuiten zoeken of scannen — scope alle bestandsoperaties tot dit project. ## Werkwijze binnen een sessie - **Meld bij elke nieuwe stap kort vooraf wat je gaat doen**, vóór je begint (staande voorkeur Bob, 2026-08-04). - Bob bespreekt elke taak in een **nieuwe, aparte chat** — geen eerdere conversatie om op terug te vallen. `CLAUDE.md` + `TASKS.md` zijn samen het volledige geheugen tussen sessies. - **Groepeer opgepakte taken per sessie op FlutterFlow-paginagebied** waar mogelijk (bv. twee taken op dezelfde pagina/component samen oppakken) — minder heen-en-weer-navigeren in de builder, minder tokens. - **`TASKS.md`-status kan achterlopen op de echte code** (Bob werkt gelijktijdig, en documentatie-updates lopen niet altijd synchroon met de export). Check een taak die er al even staat met `git log --oneline -S""` of een gerichte `grep` vóórdat je 'm oppakt — niet blind vertrouwen dat "open" betekent "nog niet gefixt". (Precedent: 2026-08-04 bleken 2 "open" P0-taken al op 2026-08-02 gefixt te zijn, git-bevestigd.) - **Elke taak in `TASKS.md` heeft een stabiel ID (bv. `P0-1`) en een `Eigenaar:`-regel** — `Bob` (sneller/simpeler voor hem zelf, meestal builder-UI met een bekend fragiele dialoog, zie hieronder), `Claude` (onbeklaimd, vrij op te pakken), of **`... — bezig`** (iemand is er *nu* actief mee bezig). Vuistregel voor wie een nieuwe taak zou moeten doen: een kort, mechanisch herhaald patroon zonder geneste dialogen → Claude; ConditionalBuilder/JSON-Path-condities, List-typed function-argumenten, of iets dat eerder al vastliep → Bob. - **⚠️ Concurrency: Bob start elke taak in een nieuwe chat, dus er kunnen meerdere sessies tegelijk actief zijn.** Check vóór je een taak oppakt of de Eigenaar-regel al "— bezig" zegt door iemand anders — zo ja, niet zelfstandig ook gaan bouwen aan hetzelfde bestand/component, vraag Bob eerst wie 'm afmaakt. **Zet zelf "— bezig" zodra je serieus begint — dit geldt óók voor puur onderzoek/ reproductie (bv. een eigen `flutter run`-sessie starten om een stack trace te vangen), niet alleen voor builder-edits.** (Precedent 2026-08-04: twee sessies pakten onafhankelijk dezelfde P0-taak op — Bob moest scheidsrechteren tussen twee stukken werk aan hetzelfde bestand. **Tweede precedent, 2026-08-09:** een sessie deed 20+ minuten actief P1-13-onderzoek — eigen `flutter run`-proces + een nieuwe bug gevonden (P1-19) — zonder ooit "— bezig" te zetten; een nieuwe sessie kwam er via `git diff`/proces-inspectie toevallig achter vlak vóórdat ze zelf hetzelfde pad zou inslaan. Geen schade, maar puur geluk — vandaar nu ook `ff-session-check.sh`, zie hieronder. **Derde precedent, 2026-08-21:** tijdens P1-26 (gemeente- hartje op `HeaderButtonsComponent` + het bijbehorende Drupal- endpoint) bleek een andere sessie al actief te bouwen — pas ontdekt via een onverwachte `git status`-diff (een halfklare `print('IconButton pressed ...')`-placeholder in de working tree), niet via een "— bezig"-marker in `TASKS.md`, want die was ook nu weer nooit gezet. Geen schade (beide sessies' werk sloot uiteindelijk netjes op elkaar aan), maar het bevestigt dat de regel hierboven in de praktijk niet gevolgd wordt.** - **⚠️ Scherpere regel (2026-08-21, Bob expliciet): "— bezig" zetten is geen mentale notitie voor bij het afsluiten — het is een directe `Edit` naar `TASKS.md` op schijf, uitgevoerd zodra je een taak *serieus* oppakt (vóór je in de builder/code begint), niet pas bij de afsluitroutine aan het eind van de sessie.** Sessies delen dezelfde working directory op Bob's machine, dus een geschreven bestandswijziging is voor een andere sessie **direct zichtbaar** zonder dat er gecommit hoeft te worden — een aantekening die pas bij sessie-einde geschreven wordt, is voor niemand anders zichtbaar precies op het moment dat het er het meest toe doet. **Symmetrische plicht bij het oppakken van een taak: check ook zelf eerst — vóór je begint — of de Eigenaar-regel al "— bezig" zegt** (verse `ff-session-check.sh` of een gerichte `grep` op de taak-ID/component- naam), niet er blind van uitgaan dat de lijst nog klopt sinds je 'm voor het laatst las. - **Start elke sessie met `/home/bob/Projects/ff-session-check.sh`** (géén argumenten nodig voor dit project) — bundelt in één keer git-status, welke devices/emulators draaien, welke flutter/ff-run-fvm/`script`-processen actief zijn (met leeftijd), en welke `TASKS.md`-taken al "— bezig" staan. Vervangt de losse handmatige `git status`/`adb devices`/`ps aux`-stappen hieronder — dat was voorheen makkelijk (deels) over te slaan, dit script niet. **Een draaiend `ff-run-fvm.sh`/`flutter run`-proces alléén is géén betrouwbaar signaal dat er "nu" iemand actief mee bezig is** — bevestigd 2026-08-07: meerdere van die processen bleken dagen oud (gestart Aug05/Aug06, nog steeds draaiend), puur omdat het interactieve hot-restart-loop-karakter ze nooit vanzelf afsluit. Het betrouwbaardere signaal voor "hier ligt nog niet-afgerond werk": een **niet-gecommitte `git status`/`git diff`** (vooral als `TASKS.md`/ `CLAUDE.md` zelf ook wijzigingen tonen t.o.v. de laatste commit) — dát is een aanwijzing dat een sessie iets heeft afgerond/uitgevoerd maar de afsluitroutine (commit+push, zie hieronder) nog niet heeft gedaan. **Beide signalen samen (proces + ongecommitte diff) zijn het sterkste bewijs van live werk** — het script hierboven toont ze gecombineerd. Zie zo'n situatie: bouw erop voort waar zinnig, maar commit niet over andermans nog-niet-afgeronde wijziging heen zonder navraag. ## Live pair-fix sessie — Bob doet de builder-klikken, Claude regisseert Bevestigd goed werkende aanpak (2026-08-10 avond) voor het gezamenlijk afwerken van `TASKS.md`: Bob voert alle builder-wijzigingen zelf uit in zijn eigen browser (geen clipping-/coördinaatproblemen daar), Claude geeft per taak de exacte stappen en **verifieert elke taak na afloop met een verse, losse export** in plaats van op de builder-UI ("Synced", geen foutmelding) te vertrouwen. In één avond leverde dit 9 afgeronde taken op tegen een prettig tempo, en ving het **minstens 2x** een edit die in de UI geslaagd leek maar bij export niet was doorgezet (zelfde stille-niet-opgeslagen-patroon als elders in dit bestand, nu ook bevestigd op een gewone Visibility-conditie, niet alleen bij de bekende clipping-gevallen). **Vaste aanpak per taak:** 1. Claude geeft exacte builder-stappen voor **precies één taak** uit `TASKS.md`, met taak-ID erbij (bv. "P1-3"). 2. Bob voert uit in eigen browser, meldt "gedaan". 3. Claude verifieert met een losse, snelle export (geen emulator/build nodig): ``` export PATH="/home/bob/fvm/bin:$HOME/.pub-cache/bin:$PATH" flutterflow export-code --project uitgaanskrant-1qhvtd \ --dest /tmp/ff-check --token "$(cat ~/.ff_token)" \ --no-parent-folder --as-debug ``` gevolgd door een gerichte `grep`/`Read` op de betreffende regel(s). Dit duurt seconden en is niet-destructief (los van de projectmap, geen commit, geen emulator). 4. Klopt het: taak-ID hardop bevestigen, meteen de eerstvolgende taak geven (liefst al vooruit gecheckt terwijl Bob met de huidige bezig is — zie punt hieronder). Klopt het niet: exact melden wat er nog in de export staat, niet aannemen dat "Confirm geklikt" gelijk staat aan "opgeslagen". 5. **Vooruit checken terwijl Bob bezig is**: zodra Bob aan een taak begint, kan Claude alvast de eerstvolgende taak in de wachtrij pre-verifiëren (is hij nog steeds nodig, of intussen al door iemand anders/een eerdere sessie opgelost?) — scheelt een aparte heen-en-weer ronde. 6. **Bob's expliciete volgorde-voorkeur (2026-08-11): eerst de volgende taak geven, dán pas de vorige verifiëren** — niet andersom. Bob wil na het melden van "gedaan" meteen door kunnen bouwen i.p.v. te wachten tot Claude klaar is met verifiëren; de verificatie van de zojuist afgeronde stap mag daarna, gerust gecombineerd met de volgende voortgangsmelding. 7. **Nooit stilzitten zolang er nog taken liggen (2026-08-14, expliciet bevestigd door Bob).** Zodra Bob "gedaan" meldt: altijd meteen de eerstvolgende taak geven, ook voor kleine/optionele restpunten (bv. een laatste losse plek uit een audit) — niet eerst vragen "wil je deze ook nog meepakken, of laten we 'm liggen?". Kies zelf een default (meestal: gewoon meegeven) en ga door; alleen pauzeren met een echte ja/nee-vraag als de keuze de scope wezenlijk verandert (bv. een hele taak overslaan) én Bob niet al liet blijken dat hij liever gewoon doorwerkt. 8. Bob geeft na afronding van een cluster ook een eigen commit in FlutterFlow's interne versiebeheer ("main"/"Synced" bovenin) — los vangnet naast Claude's export-verificatie. **Altijd het taak-ID noemen** bij elke gegeven stap en elke bevestiging (Bob's expliciete voorkeur) — voorkomt verwarring over welk punt van de lijst besproken wordt. **Standaardvraag om een nieuwe sessie mee te starten** (plak dit als eerste bericht in een nieuwe chat om meteen door te pakken): > Leg mijn actielijst (`TASKS.md`) voor me voor, één taak tegelijk — > ik voer de builder-stappen zelf uit, jij verifieert daarna met een > verse export voor je de volgende geeft. Noem altijd het taak-ID. > Begin met [P0 eerst / een specifiek gebied, bv. "Login-pagina" / > "verder waar we gebleven waren"]. ## Variant: Claude bouwt zélf in de builder (bevestigd 2026-08-31) Naast de pair-fix hierboven werkt ook de omgekeerde verdeling: **Claude doet alle builder-klikken via `mcp__claude-in-chrome__*` in Bob's eigen Chrome, Bob kijkt mee en beslist.** Op 2026-08-31 leverde dit in één sessie het complete merk-kleurwerk op (thema-kleuren licht+donker, Roboto, 9 knoppen, 6 tab-indicators, dark mode uit) zonder dat Bob één keer zelf hoefde te klikken. **Voorwaarde die je expliciet moet noemen:** Claude gaat hier niet vanzelf van uit — de default is "stappen aanreiken en Bob laten klikken", omdat `CLAUDE.md` vol staat met waarschuwingen over vastlopende dialogen. **Zeg dus letterlijk "je mag in de chrome browser"** (of "doe het zelf in de builder") in je eerste of tweede bericht. Dat ene zinnetje was 2026-08-31 het hele verschil. **Blijft gelden:** dit werkt alléén terwijl Bob daadwerkelijk achter zijn scherm zit (zie de waarschuwing over de CDP-brug elders in dit bestand), en Claude verifieert nog steeds élke wijziging met een verse export — de builder-UI toont regelmatig een waarde die de export niet haalt. **Standaardvraag voor deze variant:** > Pak [taak-ID's] uit `TASKS.md` op. Je mag zelf in de Chrome-browser > in de FlutterFlow-builder werken — ik zit erachter. Verifieer elke > wijziging met een verse export voor je verdergaat, en noem het > taak-ID. Vraag het aan mij als er een ontwerpbesluit te nemen valt. **Hoeveel taken per sessie — advies:** geen harde limiet, maar een sessie werkt het prettigst als hij **één samenhangend cluster** afmaakt (zelfde FlutterFlow-pagina/component-groep, sluit aan bij de bestaande "groepeer per paginagebied"-vuistregel hierboven) in plaats van kriskras door de hele lijst te gaan — dat scheelt heen-en-weer- navigeren én houdt de context overzichtelijk. Als praktisch richtgetal: **5-10 kleine, mechanische taken** (zoals vanavond) is een goede, vermoeidheid-arme klip; grotere/lastigere taken (P1-6's ~45 treffers, P1-15's conditie-gepuzzel) tellen zwaarder en verdienen een eigen sessie of een kleiner deelblok. Sluit elke sessie af met de afsluitroutine hieronder (`TASKS.md` bijwerken + committen) — dan kan een sessie ook prima na 2 taken stoppen zonder dat er iets verloren gaat. ## Sessiegeheugen — afsluitroutine Aan het eind van elke sessie/taak: 1. **`TASKS.md`**: een afgeronde taak wordt volledig **verwijderd** (niet gearchiveerd — onnodige context/kosten voor latere sessies). Elke resterende open taak moet zelfstandig te begrijpen zijn (concreet, met bestandspad) zonder de ontstaanschat gelezen te hebben. 2. **`CLAUDE.md`**: alleen aanvullen met blijvend herbruikbare inzichten (conventie, architectuurkeuze, bekend valkuil-patroon) die een latere sessie anders opnieuw zou moeten uitzoeken. Geen sessieverslag/changelog. Ruim verouderde info op i.p.v. eronder te plakken — dit bestand moet klein en scanbaar blijven. 3. Commit + push de gewijzigde `.md`-bestanden direct (geen FlutterFlow-export nodig voor pure documentatiewijzigingen). **Geen apart memory-systeem meer nodig voor projectfeiten** — die staan allemaal hier en in `TASKS.md`, wat al elke sessie automatisch geladen wordt. (Auto-memory-bestanden zijn per 2026-08-04 opgeschoond omdat ze dit bestand 1-op-1 dupliceerden.) ## FlutterFlow-workflow — belangrijk Dit project wordt gebouwd via FlutterFlow (app.flutterflow.io). De FlutterFlow-cloudomgeving is de bron van waarheid, niet deze lokale code-export. - Bob kan **geen** code rechtstreeks bewerken in dit repo. Alle wijzigingen aan pagina's, componenten en modellen moeten via de FlutterFlow-website. Enige uitzondering: custom functions/widgets (`lib/custom_code/`) — ook die voert Bob in via de Custom Code-editor op de website, niet hier lokaal. - Gevolg: directe Edit/Write-wijzigingen aan gegenereerde bestanden worden bij de volgende export overschreven — **niet duurzaam**. Gebruik deze repo om te lezen/ontwerpen/verifiëren (`flutter analyze`), maar voer het eindresultaat uit via de builder (zelf via browser-automation, of als instructie aan Bob). Ga nooit uit van behoud van een lokale bestandswijziging. - Werk je rechtstreeks in de builder (Claude in Chrome): commit na elke **afgeronde taak** binnen FlutterFlow's eigen versiebeheer ("main"/"Synced" bovenin), met duidelijke omschrijving. Geen lokale `git commit`. - **Gebruik `mcp__claude-in-chrome__*`** (Bob's gedeelde Chrome), niet de in-app Browser pane. - **Resize de browser niet zelf.** Bob's eigen gedeelde vensters — meld en vraag i.p.v. zelf te resizen. - Bob werkt vaak **gelijktijdig zelf** in dezelfde builder-sessie — check eerst of hij iets claimde ("dat regel ik zelf") voordat je wijzigingen overschrijft. - Check bij een mislukte export/pull eerst het **Issues-paneel** (badge rechtsboven) voordat je een bug bij jezelf zoekt — een rode teller blokkeert *elke* export, ook niet-gerelateerde, en is vaak Bob's eigen work-in-progress. - **De browser-automation naar de FlutterFlow-builder loopt via Bob's eigen, ingelogde Chrome-sessie op zijn machine — dus alleen betrouwbaar terwijl hij actief aanwezig is.** Bevestigd 2026-08-09: terwijl Bob een uur weg was, hing een simpele `navigate`-aanroep naar een FlutterFlow-URL 2x achter elkaar 5 minuten vast (op andere MCP-calls in dezelfde browser, bv. `tabs_context`, geen probleem) — vermoedelijke oorzaak: een vergrendeld/inactief scherm maakt de extensie/CDP-brug onbetrouwbaar. **Praktisch gevolg: builder-UI-werk is geen geschikte taak voor een sessie terwijl Bob niet achter zijn scherm zit** (ook niet via `/loop` of een geplande taak) — Bash/ code-audit/emulator-werk (geen browserafhankelijkheid) juist wel. - **Valt de extensie middenin een sessie weg ("Claude in Chrome is not connected"), check dan of Chrome überhaupt nog draait vóór je blijft retryen.** Bevestigd 2026-09-08: na een uur probleemloos builder-werk gaf elke aanroep opeens die melding. `ps aux | grep -iE "google-chrome|chromium"` gaf alleen nog crashpad-handlers, terwijl `pgrep -a chrome` een berg **Brave**-processen toonde — Bob's Chrome was gewoon afgesloten. Zes retries hielpen dus niets. Een enkele disconnect-melding midden in een `browser_batch` is wél vaak transient (kwam diezelfde sessie voor en herstelde vanzelf); het verschil zie je aan die `ps`-check. Draait er geen Chrome: stop met retryen, schrijf de resterende builder-stappen uit in `TASKS.md` en pak browserloos werk op. ## Lokale git-repo + pull/push-workflow Projectdirectory = eigen schone git-repo, `origin` `ssh://gogs.digitalforce.tv:2222/Uitgaanskrant.com/flutterflow.git`, branch `master`. Los van de grotere/rommelige repo hoger in de mappenstructuur (AndroidStudioProjects, Flutter-SDK e.d.) — commits en pushes horen hier. Vaste workflow na elke afgeronde taak (staand akkoord, geen aparte bevestiging nodig): niet los `flutterflow export-code`, maar: ``` export PATH="/home/bob/fvm/bin:$HOME/.pub-cache/bin:$PATH" && /home/bob/Projects/ff-run-fvm.sh emulator-5554 uitgaanskrant-1qhvtd -s ``` - **De `export PATH=...` prefix is verplicht** — Bash draait niet-interactief, `~/.bashrc` wordt niet geladen. Zonder prefix faalt het script stil ("fvm: command not found" — geen harde error). - **Standaard testen/QA-doorloop: `--profile`, niet debug (Bob's besluit 2026-08-21).** Aanleiding: na een schone herinstallatie van beide fysieke testtoestellen voelde de app "enorm traag" aan — bleek geen kapot toestel/instelling (Developer Options, animatie-schalen, achtergrondbelasting allemaal normaal, bevestigd via `adb shell settings get`/`top`), maar gewoon een **debug-build** (`dumpsys package com.uitgaanskrant.app` toonde `flags=[ DEBUGGABLE ... ]` op beide toestellen) — Flutter's debug-mode is met opzet veel trager (JIT i.p.v. AOT, extra assertions, hot-reload-machinery actief) en geeft dus geen reëel beeld van hoe de app voor een eindgebruiker aanvoelt. **Vaste regel vanaf nu:** gewoon rondkijken/een fix visueel verifiëren op een device → los van `ff-run-fvm.sh` direct ``` fvm flutter run --profile -d ``` (AOT-gecompileerd, dicht bij release-snelheid, DevTools/profiling blijven bereikbaar, echte runtime-excepties/crashes blijven gewoon zichtbaar — alleen hot-reload/-restart en debug-only asserts vervallen). **Volledige debug-mode (`ff-run-fvm.sh`, met de ingebouwde live-'r'-export-plus-hot-reload-loop) blijft gereserveerd voor het moment dat je daadwerkelijk een specifieke bug actief aan het jagen bent** (stack traces nodig, print-debugging, snel itereren op een fix) — niet voor een gewone testronde. `ff-run-fvm.sh` zelf heeft geen ingebouwde `--profile`-optie (start altijd kaal `fvm flutter run -d `, dus debug) — voor profile dus altijd het directe `fvm flutter run --profile`-commando gebruiken, niet het script. - **Gradle-build faalt plots met `Error resolving plugin [id: 'dev.flutter.flutter-plugin-loader' ...] > ` + een "restricted method"-warning erboven: check eerst welke Java Flutter gebruikt, niet de code.** Bevestigd 2026-08-17: Android Studio update zichzelf via snap automatisch, en de nieuwste snap-revisie bundelt een steeds nieuwere JBR (ingebouwde Java) — Flutter kiest bij het bouwen altijd "de JDK van de nieuwste Android Studio-installatie" als eerste prioriteit. Gradle 8.12 (dit project) kan niet overweg met Java 24+, en het versienummer achteraan die foutmelding is precies de Java-versie van die nieuwe JBR (bv. `25.0.2`) — een afgekapte/vervormde foutmelding, geen echte plugin-versie-mismatch. **Vaste fix, één keer nodig, overleeft een export (globale Flutter-CLI-instelling, geen projectbestand):** ``` fvm flutter config --jdk-dir=/usr/lib/jvm/java-17-openjdk-amd64 ``` (systeem-Java 17 is stabiel, geen snap-auto-update-risico). Check bij twijfel welke JDK's beschikbaar zijn met `ls /snap/android-studio/*/jbr/bin/java` (elke revisie los te aanroepen met `-version`) en `readlink -f /snap/android-studio/current`. - **Een losse exportmap (`/tmp/ff-checkN`) is niet zomaar te builden: kopieer er eerst `.fvmrc`, `.fvm/` én `pubspec.lock` uit het project naartoe.** Bevestigd 2026-09-03: `flutterflow export-code` levert geen van drieën op. Zonder `pubspec.lock` trekt `pub get` de nieuwste packages binnen; zonder `.fvmrc` valt `fvm flutter` terug op de **nieuwste geïnstalleerde** Flutter (3.44.6) i.p.v. de projectversie (3.35.7). De build faalt dan met misleidende package-fouten diep in `~/.pub-cache` (`The class 'IconData' can't be extended outside of its library`, `Couldn't find constructor 'CupertinoPageTransitionsBuilder'`) — die wijzen naar een SDK-mismatch, niet naar een kapotte dependency. Ga daar dus niet in de packages zoeken; check `fvm flutter --version` in de exportmap. **⚠️ Correctie 2026-09-11: `.fvmrc` + `.fvm/` kopiëren is NIET genoeg** — precies die twee `IconData`/`CupertinoPageTransitionsBuilder`-fouten kwamen gewoon terug, ook met beide bestanden op hun plek. Wat wél werkte is één expliciete `fvm use 3.35.7 -f` ín de exportmap (die herschrijft de `.fvm/`-symlink naar de juiste SDK); daarna bouwde en draaide dezelfde map meteen. Draai dat commando dus standaard, en controleer met `fvm flutter --version` dat er 3.35.7 staat vóór je `run` aanroept. - Interactief script (device-run + hot-restart-loop) → Bash met `run_in_background: true`. Volg tot minimaal "All done!" én idealiter een succesvolle app-launch (`Launching lib/main.dart...`, geen nieuwe `EXCEPTION CAUGHT BY RENDERING LIBRARY`). - **⚠️ `emulator-5554` is NIET vast de telefoon — de poort hangt af van de opstartvolgorde, niet van het toestel.** Bevestigd 2026-09-01: na een herstart van de tablet-service pakte de **tablet** poort 5554 en de telefoon 5556, precies omgekeerd aan wat hieronder staat. De AVD-namen kloppen ook niet meer met de oude notitie (de tablet heet `Medium_Tablet_no-google`). **Controleer dus altijd eerst wélk toestel je voor je hebt** met `adb -s shell wm size` — tablet = 2560x1600 @ 320dpi, telefoon = 1080x1920 @ 420dpi — vóór je een test of screenshot aan een device-id koppelt. - **Emulator weg uit `adb devices` terwijl de systemd-service "active" meldt: kijk naar de luisterpoorten, niet naar de service.** Een `ss -lnt | grep 555` laat zien of er überhaupt een console-poort geopend is. Twee bekende faalvormen, beide 2026-09-01 gezien: (1) de emulator crasht met `code=dumped, status=11/SEGV` (zie ook hieronder), (2) bij het herstarten terwijl de andere emulator nog draait komt `kvm_user_backed_ram_map: error registering slot: File exists` — dan boot hij nooit af. **Fix voor (2): beide services stoppen, wachten tot `pgrep qemu-system-x86` niets meer geeft, en dan één voor één starten.** Onder zware geheugendruk (dit gebeurde bij ~47 GB swap in gebruik) is dit extra waarschijnlijk. - **`mcp__android__screenshot` schaalt een tablet-screenshot omlaag — `adb shell input tap` wil de ECHTE coördinaten.** Bevestigd 2026-09-08: de tablet-AVD is 2560x1600, maar de screenshot komt als 1280x800 binnen. Coördinaten die je van zo'n plaatje afleest moet je dus met 2 vermenigvuldigen vóór je ze aan `input tap` geeft — doe je dat niet, dan land je stelselmatig linksboven van je doel (in dit geval op een kaart i.p.v. op de tabbalk, waarna de app naar een detailpagina navigeerde en de meting waardeloos was). Het `Read`-antwoord op een screenshotbestand noemt de echte afmeting plus de schaalfactor — lees die even af in plaats van hem aan te nemen. **Testdevices (vanaf 2026-08-09): twee lokale AVD's, geen fysieke toestellen meer.** Eén telefoon-AVD (`licht_avd`, laag RAM-profiel) en één tablet-AVD (`Medium_Tablet_no-google`) — **welke van de twee op poort 5554 en welke op 5556 zit wisselt met de opstartvolgorde, dus ga daar nooit vanuit** (zie de waarschuwing hierboven; op 2026-09-03 was 5554 de tablet). Beide starten automatisch bij Bob's desktop-login via systemd user-services (`~/.config/systemd/user/android-emulator*.service`). WayDroid en losse fysieke devices zijn niet meer in gebruik (WayDroid's `adb shell screencap` leed structureel aan PTY/CRLF-corruptie bij screenshots — vandaar de overstap). Check altijd eerst met `adb devices` welke van de twee daadwerkelijk draaien vóórdat je `ff-run-fvm.sh` of de android-mcp-tools gebruikt — draait geen van beide: navragen bij Bob i.p.v. blind op het eerste beschikbare device te draaien. De `android-mcp-server`-tools (`mcp__android__*`) accepteren een `device_id`-parameter per call, dus beide devices zijn los aan te sturen zonder config-wijziging — handig om ontwerp/layout op zowel telefoon- als tabletformaat te verifiëren (bv. relevant voor P1-11's responsive-grid-taak). **Correctie 2026-08-17: "geen fysieke toestellen meer" is niet meer hard waar** — Bob gebruikt voor een live pair-fix soms ook zijn eigen fysieke Xiaomi/MIUI-telefoon (adb-serial bv. `K7V8DYTSMVTW6XBI`, `ro.product.model=2409BRN2CY`), vooral geschikt om een device met echte on-screen 3-knops-navigatiebalk te testen (de twee AVD's hebben dat niet). Check dus met `adb devices` wat er *nu* verbonden is i.p.v. aan te nemen dat het altijd een van de twee AVD's is. **Let op MIUI- specifieke ANR's bij snelle geautomatiseerde adb-input:** op dit fysieke toestel triggerde een korte reeks losse `adb shell input text`/`input tap`-calls achter elkaar (zonder pauze) herhaaldelijk een "Uitgaanskrant.com isn't responding"-dialoog (MIUI's eigen "MIUIScout"-mechanisme, zichtbaar in `logcat` als `W MIUIScout ANR`) — dit is een MIUI/debug-build-artefact van de invoersnelheid, geen crash van de app zelf. Bouw bij dit toestel bewust een korte `sleep`/wachttijd tussen opeenvolgende input-acties in i.p.v. ze direct na elkaar te vuren. - **Screenshots van de website zelf (voor look&feel-vergelijkingen): headless Chromium werkt, maar met twee valkuilen.** (1) Snap-Chromium mag niet schrijven in `/tmp/claude-*` (Permission denied) — schrijf naar `~/uk-shots/` o.i.d. (2) De homepage opent met een cookiebanner + een JS-modal die het hele scherm vult, en `--blink-settings=scriptEnabled=false` laat `--screenshot` stil falen. Werkend recept: pagina ophalen met Python, `