Lokales Android-Cloud-Ops-Runbook
Dieses Runbook beschreibt den aktuell verifizierten lokalen Betriebs- und Debug-Pfad fuer den heute belegten Android-plus-Cloud-Lauf: lokales superheld-cloud, tenant-gebundenes Token-Minting, USB-Tablet mit adb reverse, sichtbare Job-/Trace-Pruefung und die heute tatsaechlich vorhandene Operator-Sicht.
Was heute wirklich abgedeckt ist
Abschnitt betitelt „Was heute wirklich abgedeckt ist“cmd/serverstartet lokal im Secure-Mux-Default mit Bootstrap-Token.- Tenant-gebundene App-Tokens koennen ueber
POST /tokensgemintet werden. - Die Android-App kann auf dem USB-Tablet
POST /devices,POST /events,GET /status,GET /alerts,GET /incidents,GET /incidents/{id},PATCH /incidents/{id},GET /jobsund fuer den letzten sichtbaren Job zusaetzlichGET /jobs/{id}gegenhttp://127.0.0.1:8080nutzen, solangeadb reverse tcp:8080 tcp:8080aktiv ist. - Auf dem Issues-Tab der App stehen alltagstaugliche Incident-Aktionen bereit: „Start review” und „Mark handled”. Die App fuehrt Incident-Transitionen ueber
PATCH /incidents/{id}aus; erledigte Incidents fallen aus der DAU-Zaehlung auf dem Hauptscreen heraus. Dafuer braucht das App-Token zusaetzlichincidents:write. - Ein host-seitig angelegter Demo-Job bleibt tenant-scoped ueber
GET /jobssichtbar, wird in der App zusaetzlich ueberGET /jobs/{id}nachgeladen, liefert einetrace_idund triggert in derselben Job-Karte danach zusaetzlichGET /traces/{id}plusGET /traces/{id}/steps. - Dieselbe
trace_idist host-seitig ueberGET /traces/{id}undGET /traces/{id}/stepslesbar und wurde auf dem USB-Tablet sichtbar verifiziert. - Die App signalisiert jetzt auch einen tenant-seitigen Konfigurationsdrift sichtbar: wenn die Eingabe-
tenant_idnicht mehr zur token-gebundenen Runtime passt, zeigt die KonfigurationskarteLast backend tenant: ...plus eine explizite Tenant-Mismatch-Warnung. - Zwei reale App-Starts derselben Installation loggen jetzt lokal
telemetry flow=app_launch ... method=APP path=/main_activity ... backend_version=app_localnachlogcatund lassen sich ueber denselbentelemetrycompare-CLI vergleichen.
1. Lokale Runtime starten
Abschnitt betitelt „1. Lokale Runtime starten“Ein explizites Data-Dir macht den Lauf reproduzierbarer und erleichtert spaeteres Debugging:
cd /Users/benediktpoller/code/sh/superheld-cloudSUPERHELD_DATA_DIR=/Users/benediktpoller/code/sh/workspace/runtime/android-cloud-ops \SUPERHELD_BOOTSTRAP_TOKEN=bootstrap-token \SUPERHELD_BOOTSTRAP_TENANT_ID=tenant-local \go run ./cmd/serverAlternativ kann der Lauf mit SQLite-Persistenz gestartet werden. SQLite ist heute die bevorzugte Option, wenn Daten ueber Server-Restarts hinweg erhalten bleiben sollen:
cd /Users/benediktpoller/code/sh/superheld-cloudSUPERHELD_SQLITE_PATH=/Users/benediktpoller/code/sh/workspace/runtime/android-cloud-ops/superheld.db \SUPERHELD_BOOTSTRAP_TOKEN=bootstrap-token \SUPERHELD_BOOTSTRAP_TENANT_ID=tenant-local \go run ./cmd/serverAktuelle Operator-Fakten fuer diesen Pfad:
- Default-Bind ist
127.0.0.1:8080. - Secure-Mux ist Default; ohne
SUPERHELD_BOOTSTRAP_TOKENundSUPERHELD_BOOTSTRAP_TENANT_IDstartet der sichere Lauf nicht. SUPERHELD_SQLITE_PATHaktiviert SQLite-Persistenz; ohne diesen Parameter nutzt die Runtime JSON-Dateien unterSUPERHELD_DATA_DIR.- Mit SQLite ueberleben Incidents, Tokens, Jobs und andere Daten einen Server-Restart. Mit JSON-Persistenz werden die Dateien beim Start neu geladen, aber aeltere Formate werden transparent migriert.
- Die Runtime schreibt ihre Basis-Logs nach
stdout/stderr; es gibt heute keine separate Log-Datei- oder Metrics-API. - Stop und Restart erfolgen im lokalen Dev-Pfad schlicht ueber Prozessabbruch und erneuten Start mit demselben Kommando.
2. Tenant-gebundenes App-Token minten
Abschnitt betitelt „2. Tenant-gebundenes App-Token minten“Fuer den heute verifizierten Android-MVP braucht das App-Token mindestens die Read-/Write-Scopes fuer den sichtbaren Pfad. incidents:write ist seit Commit 538e740 fuer die Incident-Aktionen auf dem Issues-Tab noetig. jobs:write ist nur noetig, wenn der Demo-Job aus diesem Runbook wirklich erzeugt werden soll.
curl -s \ -X POST http://127.0.0.1:8080/tokens \ -H "Authorization: Bearer bootstrap-token" \ -H "Content-Type: application/json" \ -d '{"scopes":["devices:write","events:write","status:read","alerts:read","incidents:read","incidents:write","jobs:read","jobs:write"]}' \ | jq .Wichtige Hinweise:
- Das rohe Token wird nur in der Create-Antwort zurueckgegeben.
- Das Token bleibt tenant-gebunden an
tenant-local, solange der Bootstrap-Lauf so gestartet wurde. jobs:readdeckt im aktuellen Secure-Mux auchGET /traces/{id}undGET /traces/{id}/stepsmit ab.
3. Tablet vorbereiten und App installieren
Abschnitt betitelt „3. Tablet vorbereiten und App installieren“adb devicesadb reverse tcp:8080 tcp:8080
cd /Users/benediktpoller/code/sh/superheld-androidANDROID_USER_HOME=/Users/benediktpoller/code/sh/workspace/.android \GRADLE_USER_HOME=/Users/benediktpoller/code/sh/workspace/.gradle-home \./gradlew connectedDebugAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.class=com.superheld.android.DeviceIdentityManagerInstrumentedTest
ANDROID_USER_HOME=/Users/benediktpoller/code/sh/workspace/.android \GRADLE_USER_HOME=/Users/benediktpoller/code/sh/workspace/.gradle-home \./gradlew installDebug \ -Psuperheld.baseUrl=http://127.0.0.1:8080 \ -Psuperheld.apiToken=<tenant-app-token> \ -Psuperheld.tenantId=tenant-local
adb shell am start -W -n com.superheld.android/.MainActivityDer aktuell verifizierte USB-Pfad nutzt bewusst http://127.0.0.1:8080. 10.0.2.2:8080 bleibt ein Emulatorpfad und ist in diesem Workspace derzeit nicht als realer Lauf belegt.
4. Happy Path verifizieren
Abschnitt betitelt „4. Happy Path verifizieren“App-seitig
Abschnitt betitelt „App-seitig“Auf dem Tablet wurde diese Reihenfolge real verifiziert:
Register DeviceRefresh StatusSend Demo Event- optional host-seitig Demo-Job anlegen
- erneuter
Refresh Status
Nach dem Event-Submit bleibt GET /status Teil des sichtbaren status_refresh-Pfads; fuer Alerts startet die App jetzt einen eigenen alert_read-Slice ueber GET /alerts, fuer Incidents einen eigenen incident_read-Slice ueber GET /incidents plus unmittelbar folgendes GET /incidents/{id}, und fuer Jobs einen eigenen job_read-Slice ueber GET /jobs mit den nachgeladenen Job- und Trace-Reads.
Der aktuell verifizierte status_refresh-Slice zeigt auf dem Tablet dabei zusaetzlich:
Target,Tenant,DeviceundAppin derselben Konfigurationskarte- bei tenant-seitigem Konfigurationsdrift zusaetzlich
Last backend tenantplus eine explizite Tenant-Mismatch-Warnung Latest app launch runWindowResultLast successful syncLatest refresh runWindowResultBackend version- bei Scope- oder Backend-Fehlern zusaetzlich
Error code
Der aktuell verifizierte alert_read-Slice zeigt in der Alert-Karte auf demselben Tablet sichtbar:
No tenant alerts are currently visible.oder den letzten sichtbaren AlertLatest alert runWindowResultBackend version- bei Auth-, Scope- oder Backend-Fehlern zusaetzlich
Error code
Der aktuell verifizierte device_register-Slice zeigt nach Register Device auf demselben Tablet sichtbar:
Registered for tenant tenant-local at ...Latest registration runWindowResultBackend version
Der aktuell verifizierte event_submit-Slice zeigt nach Send Demo Event auf demselben Tablet sichtbar:
Submitted demo event ... at ...Latest event runWindowResultBackend version
Der aktuell verifizierte incident_read-Slice zeigt in der Incident-Karte auf demselben Tablet sichtbar:
Latest incident detail from /incidents/...Latest incident runWindowResultBackend version- bei Auth-, Scope- oder Backend-Fehlern zusaetzlich
Error code
Der aktuell verifizierte job_read-Slice zeigt in der Job-Karte auf demselben Tablet sichtbar:
Latest job detail from /jobs/...Trace detail from /traces/...Latest trace step from /traces/.../stepsLatest job runWindowResultBackend version- bei Scope- oder Backend-Fehlern zusaetzlich
Error code
Host-seitig Job und Trace pruefen
Abschnitt betitelt „Host-seitig Job und Trace pruefen“Zuerst einen kleinen Demo-Job anlegen:
JOB_ID=$(curl -s \ -X POST http://127.0.0.1:8080/jobs \ -H "Authorization: Bearer <tenant-app-token>" \ -H "Content-Type: application/json" \ -d '{"job_class":"incident_triage","workflow_id":"incident_triage_v1","input_refs":{"event_ids":["evt-job-read-demo-missing"]}}' \ | jq -r '.job_id')Danach denselben Job lesen und auf die asynchron gesetzte trace_id warten:
curl -s http://127.0.0.1:8080/jobs/$JOB_ID \ -H "Authorization: Bearer <tenant-app-token>" | jq .
TRACE_ID=""for _ in 1 2 3 4 5; do TRACE_ID=$(curl -s http://127.0.0.1:8080/jobs/$JOB_ID \ -H "Authorization: Bearer <tenant-app-token>" \ | jq -r '.trace_id // empty') if [ -n "$TRACE_ID" ]; then break fi sleep 1done
test -n "$TRACE_ID"
curl -s http://127.0.0.1:8080/traces/$TRACE_ID \ -H "Authorization: Bearer <tenant-app-token>" | jq .
curl -s http://127.0.0.1:8080/traces/$TRACE_ID/steps \ -H "Authorization: Bearer <tenant-app-token>" | jq .Fuer den heute verifizierten Demo-Job gilt:
workflow_idistincident_triage_v1- ohne passendes Quellereignis landet der Job erwartbar in
failed_terminal - die Trace enthaelt mindestens einen Step fuer
load_source_events - der Step traegt im Fehlerfall
error_code=event_refs_missing - der reale Tablet-Lauf zeigte in derselben Job-Karte sichtbar
Trace detail from /traces/...sowieLatest trace step from /traces/.../steps: Load Source Events is Failed Terminal. Guardrail passed. Error code event_refs_missing.
5. Sichtbare Fehlerpfade
Abschnitt betitelt „5. Sichtbare Fehlerpfade“Folgende Negativfaelle sind fuer den lokalen Android-Pfad bereits sichtbar und reproduzierbar:
- Token ohne
events:write, aber mit den Read-Scopes unddevices:write: Die App zeigt nachSend Demo Eventim sichtbaren BannerEvent token is missing events:write. Mint a token with events:write for the intended tenant, then retry the demo event.plusLatest event run ... Error code: insufficient_scopeund den rohenHTTP 403 insufficient_scope-Detailtext. - Token ohne
alerts:read: Die App zeigtAlert read token is missing alerts:read.plusMint a token with alerts:read for the intended tenant, then refresh again., den rohenHTTP 403 insufficient_scope-Detailtext sowieLatest alert run ... Error code: insufficient_scope. - Token ohne
incidents:read: Die App zeigtIncident read token is missing incidents:read.plusMint a token with incidents:read for the intended tenant, then refresh again.und den rohenHTTP 403 insufficient_scope-Detailtext. - Token ohne
jobs:read: Die App zeigtJob read token is missing jobs:read.plusMint a token with jobs:read for the intended tenant, then refresh again.und den rohenHTTP 403 insufficient_scope-Detailtext. - komplett ungueltiger API-Token: Der sichtbare Refresh-Banner zeigt
Refresh rejected by backend authentication.plusError code: unauthorized; die Alert-, Incident- und Job-Karten zeigen im selben Lauf jeweils... rejected by backend authentication.mit ihren eigenenLatest ... run-IDs und dem rohenHTTP 401 unauthorized: Invalid token. - Token bleibt tenant-local-gebunden, aber die App startet mit
tenant-debug: Die Konfigurationskarte zeigt sichtbarLast backend tenant: tenant-localplusConfigured tenant tenant-debug does not match backend tenant tenant-local. Update the app tenant field or mint a token for the intended tenant. - Netzwerkausfall nach zuvor erfolgreichem Refresh: Die App haelt
Last successful sync: ...aus dem vorigen Lauf. Alle Read-Karten zeigen... could not reach the backend.mitError code: network_error. Dieser Pfad ist als wiederholbarer Geraetetest verifiziert, bei dem der lokale Server nach einem erfolgreichen ersten Refresh verschwindet. - Downstream-Detailfehler
GET /incidents/{id}404 nach erfolgreichem Listenread: Die App zeigtIncident list loaded, but the latest incident detail read failed.plusIncident read failed with an unexpected backend response.undHTTP 404 not_found. Verifiziert als Geraetetest mit geraetelokalem Sequenzserver. - Downstream-Detailfehler
GET /traces/{id}403tenant_mismatchnach erfolgreichem Job-Read: Die App zeigtJob detail loaded, but linked trace ... could not be read.plusTrace read is using the wrong tenant context.undHTTP 403 tenant_mismatch. Verifiziert als Geraetetest mit geraetelokalem Sequenzserver. - Partieller Scope-Fehler bei erneutem Refresh: Nach einem erfolgreichen ersten Refresh kann ein zweiter Refresh nur
GET /alertsmit403 insufficient_scopescheitern lassen, waehrend Status, Incidents und Jobs weiter erfolgreich laden. Die App zeigt dann die dedizierte Alert-Scope-Guidance neben den erfolgreichen anderen Karten. Verifiziert als Geraetetest. - fehlendes
adb reverse: Das USB-Tablet erreicht127.0.0.1:8080nicht. - fehlende oder falsche Geraetesignatur auf Schreibpfaden:
POST /devicesundPOST /eventsscheitern sichtbar am Signatur-Contract.
6. Logging, Monitoring und SIEM im aktuellen Ist-Stand
Abschnitt betitelt „6. Logging, Monitoring und SIEM im aktuellen Ist-Stand“Diese drei Sichten sind im lokalen Workspace-Pfad bewusst getrennt:
- Logging: Basis-Startmeldungen und Store-Fallbacks erscheinen im
go run ./cmd/server-Prozess aufstdout/stderr. - Logging: Die Android-App schreibt fuer reale App-Starts unter
SuperheldTelemetrycomparebaretelemetry flow=app_launch ...-Zeilen nachlogcat. - Logging: Wenn die App
X-Superheld-Run-Idmitsendet, schreibt der Backend-Prozess zusaetzlich eine Telemetrie-Zeile pro Request, aktuell verifiziert fuer/devices,/events,/status, fuer den dediziertenalert_read-Pfad auf/alerts, fuer den dediziertenincident_read-Pfad auf/incidentsund/incidents/{id}sowie fuer den dediziertenjob_read-Pfad auf/jobs,/jobs/{id},/traces/{id}und/traces/{id}/steps; fehlgeschlagene korrelierte Requests haengen dabeierror_code=...an dieselbe Logzeile an. - Logging: Wenn
X-Superheld-Tenant-Idnicht zum tenant-gebundenen Token passt, schreibt der Secure-Mux jetzt zusaetzlich eine grepbare Operator-Zeiletenant_hint_mismatch token_tenant_id=... requested_tenant_id=... token_id=... flow=... run_id=... method=... path=... device_id=... app_version=.... - Logging: Fuer den verifizierten Alert-Happy-Path teilten die Alert-Karte und der Backend-Prozess denselben
alert_read-run_id=alert-read-942bc64f-6cac-4daa-909e-efa64112c556; im Backend erschien dazuGET /alerts status=200 result=success. - Logging: Fuer den verifizierten Event-Scope-Fehler teilten Banner, Event-Karte und der Backend-Prozess denselben
event_submit-run_id=event-submit-4cec7916-b952-4530-bfcf-d379f71e48c2; im Backend erschien dazuPOST /events status=403 result=failure error_code=insufficient_scope. - Logging: Fuer den verifizierten Alert-Scope-Fehler teilten die Alert-Karte und der Backend-Prozess denselben
alert_read-run_id=alert-read-90df8959-d5b9-41de-9dd5-46bc9db48c86; im Backend erschien dazuGET /alerts status=403 result=failure error_code=insufficient_scope, waehrend/status,/incidentsund/jobsunter ihren eigenen Run-IDs erfolgreich blieben. - Logging: Fuer den verifizierten Job-Scope-Fehler teilten die Job-Karte und der Backend-Prozess denselben
job_read-run_id=job-read-e2d9a9ca-a82b-4bff-8ceb-ba22954039ae; im Backend erschien dazuGET /jobs status=403 result=failure error_code=insufficient_scope, waehrend die nachgelagerten Job- und Trace-Reads erwartbar ausblieben. - Logging: Fuer den verifizierten Tenant-Mismatch-Lauf zeigte die App sichtbar
Last backend tenant: tenant-local. Ein zusaetzlicher verifizierter lokaler/status-Read mitrun_id=status-refresh-tenant-hint-test-1,X-Superheld-Tenant-Id: tenant-debugund tenant-local-gebundenem Token schrieb davor jetzt explizittenant_hint_mismatch token_tenant_id=tenant-local requested_tenant_id=tenant-debug ..., bevor die normaletelemetry flow=status_refresh ... tenant_id=tenant-debug ...-Zeile erschien; die host-seitige Runtime-Wahrheit blieb dabei weiter tenant-local-gebunden. - Monitoring: Es gibt derzeit keine separate Metrics- oder
/healthz-API;GET /statusist der leichtgewichtige Runtime-Check fuer den app-relevanten Schutzstatus. - SIEM: Der aktuell belegte Exportpfad ist event-zentriert ueber
GET /eventsund Webhooks. Jobs, Incidents und Traces sind heute Operator-/Runtime-Reads, kein eigener verifizierter SIEM-Exportstrom.
Fuer den verifizierten Job-/Trace-Pfad sind diese Operator-Sichten heute praktisch:
GET /jobsfuer den tenant-scoped Job-UeberblickGET /jobs/{id}fuer den EinzelstatusGET /traces/{id}fuer Korrelation uebertrace_idGET /traces/{id}/stepsfuer den aktuell feinsten belegten Ausfuehrungsblickgo run ./cmd/server-Output fuertelemetry flow=status_refresh ...,telemetry flow=alert_read ...,telemetry flow=device_register ...,telemetry flow=event_submit ...,telemetry flow=incident_read ...undtelemetry flow=job_read ... run_id=... tenant_id=... device_id=... app_version=... backend_version=...; bei Fehlerlaeufen zusaetzlicherror_code=...rg 'tenant_hint_mismatch|<run_id>' /pfad/zum/server.logwenn App-Tenant-Hinweis und token-gebundener Runtime-Tenant auseinanderlaufen sollen
7. Kleine Run-Compare-Berichte erzeugen
Abschnitt betitelt „7. Kleine Run-Compare-Berichte erzeugen“Der erste verifizierte app-lokale Compare-Schnitt nutzt exportierte logcat-Zeilen von zwei realen App-Starts derselben Installation:
adb logcat -cadb shell am force-stop com.superheld.androidadb shell am start -W -n com.superheld.android/.MainActivityadb shell am force-stop com.superheld.androidadb shell am start -W -n com.superheld.android/.MainActivityadb logcat -d -s SuperheldTelemetry:I \ > /Users/benediktpoller/code/sh/workspace/runtime/app-launch-compare-e2e-20260317/app-launch.log
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/app-launch-compare-e2e-20260317/app-launch.log \ -flow app_launch \ -device-id android-a1cb63bc-5160-4c6c-8ff9-b83819bc7733 \ -app-version 0.1.0Der verifizierte Bericht zeigte dabei:
Run A: app-launch-772767fb-f8dd-42b1-81d4-1558fac5b636Run B: app-launch-efcaa925-326b-47f7-af08-03d52bedbd09- denselben stabilen
device_id=android-a1cb63bc-5160-4c6c-8ff9-b83819bc7733 APP /main_activityals comparebaren Request-Keybackend_version=app_localund das Laufzeitdelta von385msauf366ms
Wenn derselbe lokale Cloud-Lauf nach stdout oder stderr zusaetzlich per tee in eine Datei gespiegelt wird, kann der erste kleine Compare-Schnitt direkt auf diesen echten Backend-Logzeilen laufen:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/status-refresh-compare-e2e-20260317/server.log \ -flow status_refresh \ -run-a status-refresh-d8a9ae69-972f-45de-818f-3541d79e92c4 \ -run-b status-refresh-5c829384-e399-4b81-aee8-9c931389e08bDer aktuell verifizierte Lauf nutzte fuer den status_refresh-Vergleich explizite Run-IDs, weil die beiden Tablet-Laeufe nach pm clear unterschiedliche lokale device_id-Werte erzeugten. Sichtbar war dabei:
Run A: status-refresh-d8a9ae69-972f-45de-818f-3541d79e92c4blieb aufGET /statusmit200 successerfolgreichRun B: status-refresh-5c829384-e399-4b81-aee8-9c931389e08bzeigte aufGET /statusden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte denselben Request-Key
GET /statusmit dem Delta von183µsauf83µssichtbar - derselbe
server.logzeigte im Fehlerrun weiterhin getrennte und erfolgreichealert_read-,incident_read- undjob_read-Slices unter eigenenrun_id-Werten
Ein weiterer verifizierter Lauf nutzte denselben CLI-Schnitt fuer den dedizierten alert_read-Slice:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/alert-read-telemetry-e2e-20260317/server.log \ -flow alert_read \ -tenant-id tenant-local \ -app-version 0.1.0Sichtbar war dabei:
Run A: alert-read-942bc64f-6cac-4daa-909e-efa64112c556blieb aufGET /alertsmit200 successerfolgreichRun B: alert-read-90df8959-d5b9-41de-9dd5-46bc9db48c86zeigte aufGET /alertsden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte fuer denselben Slice den Delta-Wechsel von
73µsauf69µssichtbar
Ein weiterer verifizierter Lauf nutzte denselben CLI-Schnitt fuer den Gold-Flow device_register. Weil der Fehlerrun nach adb shell pm clear mit einer neuen lokalen device_id lief, wurde der Bericht bewusst ueber explizite Run-IDs fixiert:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/device-register-compare-e2e-20260317/server.log \ -flow device_register \ -run-a device-register-05aa2ac5-fc1c-432a-8735-64375aea2844 \ -run-b device-register-83ba260e-6db7-4103-a401-2492a59e7518Sichtbar war dabei:
Run A: device-register-05aa2ac5-fc1c-432a-8735-64375aea2844blieb aufPOST /devicesmit201 successerfolgreichRun B: device-register-83ba260e-6db7-4103-a401-2492a59e7518zeigte aufPOST /devicesden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte fuer denselben Gold-Flow den Delta-Wechsel von
1.947msauf77µssichtbar
Ein weiterer verifizierter Lauf nutzte denselben CLI-Schnitt fuer den Gold-Flow event_submit. Weil der Fehlerrun nach adb shell pm clear mit neuer lokaler device_id lief, wurde die automatische Run-Auswahl hier ueber denselben tenant_id und dieselbe app_version eingegrenzt:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/event-submit-compare-e2e-20260317/server.log \ -flow event_submit \ -tenant-id tenant-local \ -app-version 0.1.0Sichtbar war dabei:
Run A: event-submit-76e907bb-731e-43e6-ae96-d7dff8c8acbcblieb aufPOST /eventsmit202 successerfolgreichRun B: event-submit-114e32c8-ac30-4325-95c5-71a7c364ec6dzeigte aufPOST /eventsden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte fuer denselben Gold-Flow den Delta-Wechsel von
5.826msauf44µssichtbar
Ein weiterer verifizierter Lauf nutzte denselben CLI-Schnitt fuer den dedizierten incident_read-Gold-Flow:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/incident-read-compare-e2e/server.log \ -flow incident_read \ -tenant-id tenant-local \ -app-version 0.1.0Sichtbar war dabei:
Run A: incident-read-ea31daf4-67d0-4a4b-8511-373c4c78bb70blieb ueberGET /incidentsund den nachgeladenen Detail-ReadGET /incidents/incident-89092c694dc7a3e9erfolgreichRun B: incident-read-89ec180d-b38c-4416-bafc-a3efc04ecd1azeigte aufGET /incidentsden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte sichtbar, dass der Detail-Read im Fehlerrun nicht mehr stattfand und deshalb fuer
GET /incidents/incident-89092c694dc7a3e9alsnot presentim Delta auftauchte
Ein weiterer verifizierter Lauf nutzte denselben CLI-Schnitt fuer den dedizierten job_read-Slice:
cd /Users/benediktpoller/code/sh/superheld-cloudgo run ./cmd/telemetrycompare \ -log /Users/benediktpoller/code/sh/workspace/runtime/job-read-telemetry-e2e-20260317/server.log \ -flow job_read \ -tenant-id tenant-local \ -app-version 0.1.0Sichtbar war dabei:
Run A: job-read-750be845-48f0-4344-9e29-2702a0ffd2eeblieb ueberGET /jobs,GET /jobs/job-1364710f79d6161572c2b0fd,GET /traces/trc-9b532b6c0bb196a4d43b6edaundGET /traces/trc-9b532b6c0bb196a4d43b6eda/stepserfolgreichRun B: job-read-e2d9a9ca-a82b-4bff-8ceb-ba22954039aezeigte aufGET /jobsden Wechsel auf403 failuremiterror_code=insufficient_scope- der Bericht machte sichtbar, dass
GET /jobs/{id},GET /traces/{id}undGET /traces/{id}/stepsim Fehlerrun nicht mehr stattfanden und deshalb alsnot presentim Delta auftauchten
Optional kann derselbe CLI-Schnitt die automatische Run-Auswahl zusaetzlich ueber -app-version oder -backend-version auf dieselbe Android- oder Backend-Buildkombination eingrenzen.
Das Tool ist bewusst klein gehalten: Es vergleicht heute vorhandene korrelierte Backend-Logzeilen, ersetzt aber noch keine eigene Telemetrie-API, keine Compare-UI und keinen Langzeit-Store.
8. Persistenz und Cleanup
Abschnitt betitelt „8. Persistenz und Cleanup“JSON-Persistenz
Abschnitt betitelt „JSON-Persistenz“Mit SUPERHELD_DATA_DIR=/Users/benediktpoller/code/sh/workspace/runtime/android-cloud-ops schreibt der lokale Lauf seine JSON-Backends unter anderem in diese Dateien:
tokens.jsondevices.jsonevents.jsonalerts.jsonincidents.jsonjobs.jsontraces.jsonartifacts.jsonwebhooks.jsontoken_audit.jsonjob_audit.json
Die JSON-Persistenz laedt bestehende Dateien beim Start. Aeltere Formate (z. B. incident_id statt id) werden beim Lesen transparent migriert.
SQLite-Persistenz
Abschnitt betitelt „SQLite-Persistenz“Mit SUPERHELD_SQLITE_PATH=/pfad/zur/superheld.db nutzt die Runtime eine einzelne SQLite-Datenbank statt separater JSON-Dateien. SQLite ist heute die bevorzugte Option fuer Laeufe, bei denen Daten zuverlaessig ueber Server-Restarts hinweg erhalten bleiben sollen:
- Incidents, Tokens, Jobs, Token-Audit und Job-Audit werden in SQLite-Tabellen persistiert.
- Aeltere Datensaetze mit fehlenden Feldern werden beim Lesen aus den vorhandenen Spalten rekonstruiert.
- Incident-Reads nach einem Server-Restart sind mit SQLite verifiziert und stabil.
Cleanup
Abschnitt betitelt „Cleanup“Wenn ein frischer Dev-Lauf noetig ist, den Server zuerst stoppen und danach nur das lokale Runtime-Verzeichnis oder die SQLite-Datenbank gezielt entfernen oder ersetzen. Die Workspace-Grenze bleibt dabei innerhalb von /Users/benediktpoller/code/sh.