From 8596951cef7be1c8efa3a72e01c9773f731cb12c Mon Sep 17 00:00:00 2001 From: Nils Stinnesbeck Date: Tue, 27 Oct 2026 10:36:31 +0100 Subject: [PATCH] Skill car-logs: fetch and read the car's recordings Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6 --- .claude/skills/car-logs/SKILL.md | 69 ++++++++++++++++++++++++++++++++ AGENTS.md | 2 +- SPECS.md | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/car-logs/SKILL.md diff --git a/.claude/skills/car-logs/SKILL.md b/.claude/skills/car-logs/SKILL.md new file mode 100644 index 0000000..4fd7009 --- /dev/null +++ b/.claude/skills/car-logs/SKILL.md @@ -0,0 +1,69 @@ +--- +name: car-logs +description: Download the signal recordings the MG4 sent to the car server (fetch-logs) and read them. Use when the owner says a recording is on the server, asks to get, download or look at the car's logs or recordings, or after a test drive with the signal recorder. +--- + +# Fetch and read the car's recordings + +The app's signal recorder (Logs tab, `SignalRecorder`) sends each finished recording to the +car server (`LogOutbox`, `PUT /v1/logs/{name}`); the server keeps the newest 200 +(`server/logs.go`). `fetch-logs` in the dev shell downloads the ones not yet in `logs/`. + +## Fetch + +```sh +nix develop -c fetch-logs +``` + +It prints each new file (`logs/signal-recording-YYYYMMDD-HHMMSS.txt`) and `fetch-logs: N new`. +The token comes from `~/.config/nilsmg4/logs-token` (the server's `LOGS_TOKEN`) and goes only in +a header. + +- **Never print, cat or echo the token**, and never pass it on a command line you show. Do not + read the token file. +- `no token`: ask the owner to put the server's `LOGS_TOKEN` in `~/.config/nilsmg4/logs-token` + (and in `k8s/secrets/secrets.yaml`, then apply it). Do not create or fill it yourself. +- HTTP 401: the file and the server's Secret differ. HTTP 404: reading is off (no + `LOGS_TOKEN` on the server) or the server is older than 2.9.0. The owner applies manifests and + Secrets; never run `kubectl` against the cluster, not even read-only. +- `0 new`: nothing arrived. In the car, the Logs tab says "Sent to the server." or how many wait + and why (no server set up, server not reached, an HTTP status); the car retries every 2 + minutes while the service runs. + +## Read + +The files are plain text but `file` may call them data; search with `rg -a`. Newest first: +`ls -t logs/`. If the owner said what they did and when (e.g. "ACC on at 08:50, set speed +100→90 at 08:51"), line those times up with the timeline. + +A recording has four parts, in this order: + +1. Header: captures, start time, app version. +2. **Steering-wheel keys and notes.** The first note says whether listening worked: + `listening to N assistance properties (M refused)`, or `not possible ()`. +3. **Assistance properties heard** (`EVHardware.listenToProperties` on `AssistBlock`, the + `0x21x0A1xx` block): change events, properties whose value changed first. This is where a + value shows up that the head unit fills only while someone listens. +4. **Changed values (polled)**, rarest first, then **Everything, in order**: every capture + (about every 5 s) with what changed since the last. + +Useful cuts: + +```sh +rg -a 'listening to' logs/ # did listening work +awk '/^Assistance properties heard/,/^$/' logs/ # what listening heard +rg -a 'A15B|A15A' logs/ # one property's history +rg -a 'getLatestSpeed' logs/ | head # the car's speed over time +``` + +Known leads (SPECS.md, 2026-10-27): `0x2160A15B` is `AAD_EPTCCTRGTSPD`, by its name the cruise +control's target speed (0.0 when only polled); `0x2140A15A` moved between 3 and 7; +`0x2160A1A3`/`0x2160A1A4` counted up by 0.1. A value that tracks what the owner did at the +times they name is a lead; say how sure it is, and that it is not confirmed until a second +drive shows the same. + +## Rules + +- Recordings are the car's data: `logs/` and `/signal-recording-*.txt` are gitignored. Never + commit, publish or upload them anywhere. +- Findings that change what the project knows go into a `SPECS.md` done-log entry, as usual. diff --git a/AGENTS.md b/AGENTS.md index 2331ed0..b37bc4b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -111,7 +111,7 @@ nix develop # JDK 21, Android SDK, Go ./gradlew testStableDebugUnitTest testUnstableDebugUnitTest lintStableDebug build-car # build/car/NilsMG4-unstable-.apk + .sha256 publish-car # pre-release car- on the forge (needs a token) -fetch-logs # the car's recordings from the server into logs/ (needs LOGS_TOKEN) +fetch-logs # the car's recordings from the server into logs/ (needs LOGS_TOKEN; skill car-logs) cd server && go vet ./... && go test ./... && govulncheck ./... ``` diff --git a/SPECS.md b/SPECS.md index eaf0491..1733cd8 100644 --- a/SPECS.md +++ b/SPECS.md @@ -140,6 +140,7 @@ tyre pressures, GPS (lat, lon, elevation, heading) and the is_* flags. It does * confirmed car facts, app structure, UI conventions, build/test/ship, documents. It replaces upstream's EVABRPUploader text. The test emulator is now in the flake: `nix run .#car-emulator` (Android 9 AOSP at 1920×720, 160 dpi; the car build installs as the system user — checked). +- 2026-10-27 — Skill `car-logs` (`.claude/skills/car-logs/SKILL.md`; owner: "can we write a skill for downloading the logs?"): fetch with `fetch-logs` without ever showing the token, what its errors mean, how a recording is laid out, the cuts that find a lead, the leads so far, and that recordings are never committed. Its commands tried on the 08:52 recording. - 2026-10-27 — Server 2.9.0 pushed (`sha256:c68837f0e53cfca150644987be535e04d5e999bd4c91064d40973db67235df48`, pinned in `k8s/server.yaml`); app 2.41.0 published (`car-2.41.0`). - 2026-10-27 — App 2.41.0, server 2.9.0: **recordings reach the server** (owner: "can we make it so that we can upload the logs to an endpoint in the server, and you can get the logs from