id: c4ce3b9410f14b11974a2a0de228868f
parent_id: 
item_type: 1
item_id: 395bc805650d44b6bfec423ca095ed64
item_updated_time: 1780501745571
title_diff: "[{\"diffs\":[[1,\"Telemetry Feed Analysis — Session 2026-06-03\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":44}]"
body_diff: "[{\"diffs\":[[1,\"# Telemetry Feed Analysis — Session 2026-06-03\\\n\\\n## Executive Summary\\\n\\\nTwo sessions were captured on 2026-06-03. The **Telemetry Tool feed (port 10101)** is the clear winner: reliable, high-frequency (~60 Hz), and data-rich. The **KSUDP handshake feed (port 9996)** proved extremely sparse — only 13 packets in ~5 minutes where thousands were expected. The **Lua plugin feed (port 5005)** never initialized (0 bytes). The Lua plugin would provide **complementary** data to 10101, not necessarily *better* data — but it would add CSP-specific fields we can't get elsewhere.\\\n\\\n---\\\n\\\n## 1. Raw Data Summary\\\n\\\n| Feed | Port | Session 1 (12:03) | Session 2 (17:23) | Packets | Rate |\\\n|---|---|---|---|---|---|\\\n| **KSUDP** (handshaked) | 9996 | 0 bytes | 5,356 bytes | 13 pkts | ~0.04 Hz (!) |\\\n| **Telemetry Tool** | 10101 | 4.55 MB | 6.05 MB | 17,496 pkts | ~60 Hz |\\\n| **Lua Plugin** | 5005 | 0 bytes | 0 bytes | 0 | — |\\\n\\\n---\\\n\\\n## 2. KSUDP (Port 9996) — The Sparse Feed\\\n\\\n### What happened\\\n\\\nSession 1: rusty-telemetry bound to :9996 first → AC couldn't bind its listener → 0 packets.\\\n\\\nSession 2: handshake protocol implemented → rusty-telemetry sends registration to AC's :9996 → AC responded with 13 packets of 408 bytes each, then went silent.\\\n\\\n### Why so sparse?\\\n\\\nAt the documented ~20 Hz over a ~5-minute session, we should have received **~6,000 packets**. We got 13. That's **0.2%** of expected volume. Possible causes:\\\n\\\n1. **Incorrect handshake packet**: The registration packet (`1u32.to_le_bytes()`) may be incomplete or wrong — AC may need additional fields (e.g., a return port, a version byte, a response address). AC might have sent a few packets as a courtesy then stopped because the registration was malformed.\\\n\\\n2. **Registration timeout**: AC may require periodic re-registration (keep-alive). The current code sends every 10 seconds, but the format or interval might be wrong.\\\n\\\n3. **AC's RemoteTelemetryUDP is a legacy/abandoned feature**: Kunos may have shipped this half-broken. Community references to KSUDP are sparse and old.\\\n\\\n4. **AC responded once, then the socket pairing broke**: Maybe AC streams to the source address of the registration packet, but the ephemeral port changed between sends.\\\n\\\n### KSUDP data decoded (408 bytes per packet)\\\n\\\nThe 13 packets contain basic info: car name (\\\"abarth500\\\"), driver name, track name, world position, and what appear to be orientation/quaternion values. There's **no wheel slip, no tyre temps, no G-forces as separate fields** — it's a far shallower data set than 10101.\\\n\\\n### Verdict on KSUDP\\\n\\\n**Low priority.** Even if we fix the handshake protocol to get a reliable 20 Hz stream, the data depth is inferior to both 10101 and 5005. KSUDP lacks:\\\n- Wheel slip ratios / angles\\\n- Tyre core temperatures\\\n- Per-wheel normalized slip\\\n- World/local velocity vectors\\\n- Ride height\\\n- Multi-car data\\\n\\\nThe only thing KSUDP adds that 10101 doesn't already provide is **suspension at 200 Hz** — and even that's questionable given the feed's unreliability.\\\n\\\n**Recommendation**: Deprioritize KSUDP. Focus engineering effort on keeping 10101 rock-solid and getting 5005 working.\\\n\\\n---\\\n\\\n## 3. Telemetry Tool (Port 10101) — The Gold Standard\\\n\\\n### Performance\\\n\\\n- **17,496 data packets** in session 2 (~4.9 minutes)\\\n- **~60 Hz** — one packet per rendered frame\\\n- **359 bytes per data packet** — rich binary struct\\\n- Plus 17 heartbeat packets (5 bytes each)\\\n- **Data integrity**: All validation markers present (`test_float=666.666`, `test_int=666`, trailer validation)\\\n- **Zero packet loss observed** in the capture\\\n\\\n### Data richness — what we actually got\\\n\\\n| Category | Fields | Example Values |\\\n|---|---|---|\\\n| **Driver inputs** | steer, throttle, brake, clutch | 0.000–1.000 |\\\n| **Drivetrain** | gear, RPM, speed km/h | gear 1–5, RPM 0–6494, speed 0–137 |\\\n| **Position** | world_pos (x,y,z), spline_position | spline 0.0–1.0 |\\\n| **G-forces** | acc_vertical, acc_horizontal, acc_frontal | full 3-axis |\\\n| **Wheel dynamics** | tyre_slip_ratio[4], tyre_slip_angle[4] | per-wheel |\\\n| **Wheel grip** | nd_slip[4], wheel_slip[4] | per-wheel normalized |\\\n| **Tyre thermal** | tyre_core_temps[4] | per-wheel °C |\\\n| **Tyre condition** | tyre_dirty_level[4] | marbles buildup |\\\n| **Vehicle state** | ride_height (F/R), turbo_boost | |\\\n| **Velocity** | world_speed[3], local_speed[3] | full 3-axis |\\\n| **Session** | lap_time, best_lap, lap_count, splits | |\\\n| **Status flags** | in_pit, in_pitlane, valid, connected | |\\\n| **Metadata** | driver_name, car_name, tyre_name, nationality | \\\"abarth500\\\", \\\"SM\\\" |\\\n\\\n### What 10101 already covers for coaching\\\n\\\n| Coaching Use Case | Supported? | Data Source |\\\n|---|---|---|\\\n| Braking point analysis | ✅ | speed, spline, brake input |\\\n| Racing line tracking | ✅ | world_pos, spline_pos |\\\n| Throttle/traction control | ✅ | tyre_slip_ratio, nd_slip, wheel_slip |\\\n| Understeer/oversteer detection | ✅ (~95%) | slip_angle + nd_slip per wheel |\\\n| Tyre management | ✅ | tyre_core_temps, tyre_dirty_level |\\\n| Lap time comparison | ✅ | lap_time, best_lap, splits |\\\n| G-force analysis | ✅ | 3-axis accelerations |\\\n| Ride height / setup validation | ✅ | ride_height F/R |\\\n| Multi-car tracking | ✅ | all drivers in packet |\\\n\\\n**This is excellent data for Phase 2–4 (analysis, visualization, AI coaching).**\\\n\\\n---\\\n\\\n## 4. Lua Plugin (Port 5005) — Root Cause Analysis\\\n\\\n### ⚠️ ROOT CAUSE IDENTIFIED: `LAZY = FULL` in manifest.ini\\\n\\\nThe Lua plugin never executed a single line of code during either session. The script was never loaded by CSP. **The fix is a one-line change in `manifest.ini`.**\\\n\\\n### Evidence Chain\\\n\\\n**1. CSP log shows the app was discovered but never activated:**\\\n```\\\nLoading app: '...apps\\\\lua\\\\ac-telemetry-plugin'\\\nApp is prepared for loading: '...apps\\\\lua\\\\ac-telemetry-plugin'\\\nApp is loaded: '...apps\\\\lua\\\\ac-telemetry-plugin', impl.: 0000000000000000, windows: 1\\\n```\\\nThe app's manifest was parsed, a window slot was created, and it was added to the taskbar. But `impl.: 0000000000000000` means no Lua code executed.\\\n\\\n**2. Zero `ac.log()` diagnostic messages in any log file:**\\\nThe code has three `ac.log()` checkpoints at module level in `src/telemetry.lua`:\\\n```lua\\\nac.log(\\\"[ACTelemetry] Before require('socket')\\\")  -- before socket require\\\nac.log(\\\"[ACTelemetry] require('socket') succeeded\\\")  -- after socket require\\\nac.log(\\\"[ACTelemetry] socket.udp() succeeded\\\")  -- after socket creation\\\n```\\\n**None of these appeared in `log.txt`, `custom_shaders_patch.log`, or `errors.txt`.** This means `src/telemetry.lua` was never `require()`'d — the module-level code never ran.\\\n\\\n**3. No app state file was created:**\\\nThe directory `cfg/extension/state/lua/app/` contains only `AppShelf.ini`. No state file for `ac-telemetry-plugin` exists, confirming the app was never activated during a session.\\\n\\\n**4. The imgui settings show a window slot was allocated:**\\\n```\\\nIMGUI_LUA_actelemetryplugin_main=60,60,366,164\\\nTASKBAR_APPS_0='AC Telemetry'\\\n```\\\nThe app appears in the taskbar (first position), and a window position was stored. But the window was never rendered — the stored size (366x164) is a default imgui allocation, not the manifest's `SIZE = 160, 30`.\\\n\\\n### The Root Cause: CSP's LAZY Loading Mode\\\n\\\nCSP's **App Shelf** (a built-in CSP app by x4fab) contains the definitive documentation in its own `manifest.ini`:\\\n\\\n```ini\\\nLAZY = FULL  ; Possible values:\\\n; • NONE (or 0, default value): load script when Assetto Corsa is loading, run it until it's closed\\\n; • PARTIAL (or 1): load script only when app is first opened, after that keep it running until AC is closed.\\\n; • FULL (or 2): load script when app is opened, when all windows are closed, unload an app completely.\\\n```\\\n\\\nOur `manifest.ini` has `LAZY = FULL`. This means:\\\n- CSP parses the manifest at startup (creates window slot, adds to taskbar)\\\n- **CSP does NOT execute `main.lua` until the user clicks the app icon in the in-game taskbar**\\\n- If the user never clicks the icon, no Lua code ever runs\\\n- The user had the \\\"AC Telemetry\\\" icon in the taskbar but never clicked it during either session\\\n\\\n**This is why 0 bytes were received on port 5005 across two sessions.**\\\n\\\n### Why `LAZY = FULL` was set\\\n\\\nThe manifest was configured with `LAZY = FULL` because the earlier conversion from `[SCRIPT]` to `[WINDOW_...]` mode copied this setting from the AC Tracer app (which also uses `LAZY = FULL`). For a GUI-only app like AC Tracer, lazy loading makes sense — no point running the script until the user wants to see the window. But for a **background telemetry sender**, lazy loading defeats the entire purpose — the app needs to run from session start.\\\n\\\n### The Fix\\\n\\\n**Change `manifest.ini` line 13:**\\\n```diff\\\n- LAZY = FULL\\\n+ LAZY = NONE\\\n```\\\n\\\nOr simply remove the `[CORE]` section's `LAZY` line entirely (NONE is the default).\\\n\\\nWith `LAZY = NONE`:\\\n- CSP loads and executes `main.lua` immediately when AC starts loading the session\\\n- `require(\\\"src.telemetry\\\")` runs → `require(\\\"config\\\")` + `require(\\\"src.json\\\")` + `require(\\\"socket\\\")` execute\\\n- `script.update(dt)` runs every frame from session start\\\n- UDP socket is created at load time\\\n- Telemetry JSON datagrams start flowing to port 5005 immediately\\\n\\\n### Secondary Concern: LuaSocket Availability\\\n\\\nAfter fixing LAZY, `require(\\\"socket\\\")` may still fail if LuaSocket is not available in CSP's sandboxed Lua environment. The three diagnostic `ac.log()` checkpoints will confirm this on the next AC run:\\\n- If \\\"Before require('socket')\\\" appears but \\\"require('socket') succeeded\\\" doesn't → LuaSocket is unavailable\\\n- If \\\"require('socket') succeeded\\\" appears but \\\"socket.udp() succeeded\\\" doesn't → `socket.udp()` function is missing\\\n- If all three appear → the plugin works end-to-end\\\n\\\nIf LuaSocket is unavailable, alternatives to investigate:\\\n- CSP's native networking: `ac.connect()`, `ac.connectUDP()`, `web.request()`\\\n- CSP's `ac.store()` / `ac.storage()` for file-based data exchange\\\n- Named pipe approach via `io.open()` on a FIFO\\\n\\\n### Tertiary Concern: Window Visibility\\\n\\\nWith `LAZY = NONE`, the \\\"AC Telemetry ●\\\" floating title bar will appear on screen at session start (because `VISIBLE = 1`). For a background telemetry sender, this is unnecessary. Consider either:\\\n- Setting `VISIBLE = 0` to hide the window by default (script still runs)\\\n- Keeping `VISIBLE = 1` as a visual indicator that the plugin is active\\\n- Using a minimal window that shows connection status\\\n\\\n### Comparison with Other Apps\\\n\\\n| App | LAZY Mode | impl.: in logs | Behavior |\\\n|---|---|---|---|\\\n| AppShelf | FULL | `0000000000000000` | Loads on click, unloads on close |\\\n| CspDebug | FULL | `0000000000000000` | Loads on click, unloads on close |\\\n| Mumble | (not loaded) | N/A | \\\"App is not available\\\" (online only) |\\\n| AC Tracer | FULL | `0000000000000000` | Loads on click, unloads on close |\\\n| **AC Telemetry** | **FULL** | `0000000000000000` | **Never clicked → never loaded** |\\\n\\\nAll Lua apps show `impl.: 0000000000000000` until activated. This is normal — it's not an error indicator.\\\n\\\n---\\\n\\\n## 5. Lua Plugin vs 10101 — Honest Assessment\\\n\\\n**Overlap: ~80% of Lua fields already exist in 10101.** The core telemetry (speed, RPM, gear, inputs, G-forces, wheel slip, lap times) is already being captured at 60 Hz by the Telemetry Tool.\\\n\\\n**What Lua adds that 10101 doesn't have:**\\\n\\\n| Field | CSP API | Value |\\\n|---|---|---|\\\n| **Per-wheel suspension travel** | `car.wheels[i].suspensionTravel` | Detailed damper analysis, setup validation |\\\n| **5-zone damage model** | `car.damage.*` | Body/aero damage monitoring |\\\n| **CSP extensions** | Various `ac.*` calls | Weather, track temp, fuel (can be added trivially) |\\\n| **World position** | `car.position` (if added) | Currently missing from Lua schema, trivial to add |\\\n| **Fuel level** | `car.fuel` | Strategy coaching (not in 10101) |\\\n| **Tyre wear** | CSP tyre API | Long-run strategy |\\\n\\\n**What 10101 has that Lua doesn't:**\\\n\\\n| Field | Value |\\\n|---|---|\\\n| **Multi-car data** | All drivers, not just player car |\\\n| **Tyre core temperatures** | Per-wheel thermal state |\\\n| **Slip ratios AND slip angles** | Both metrics per wheel |\\\n| **Normalized slip** | Combined grip metric |\\\n| **Tyre dirty level** | Marble buildup |\\\n| **World/local velocity vectors** | Full 3D velocity |\\\n| **ERS/DRS/P2P** | Hybrid/electronic systems |\\\n| **Ride height F/R** | Setup validation |\\\n| **Turbo boost** | Forced induction monitoring |\\\n\\\n### Would the Lua feed be \\\"better\\\" than 10101?\\\n\\\n**No — but it would be complementary.** Here's the nuanced answer:\\\n\\\n1. **For pure telemetry coverage, 10101 is already superior.** It has more fields, multi-car data, validation markers, and proven reliability.\\\n\\\n2. **The Lua plugin's value is in CSP-specific extensions** — damage, fuel, tyre wear, weather — that the Telemetry Tool Python plugin doesn't expose because it reads from AC's shared memory, not CSP's extended API.\\\n\\\n3. **The Lua plugin's real advantage is control.** We own the code. We can add any field from the CSP Lua API at any time. The Telemetry Tool is a third-party binary we can't modify.\\\n\\\n4. **Format advantage**: JSON from Lua vs binary from 10101. JSON is far easier to debug, inspect, and extend. Binary is more compact but opaque.\\\n\\\n---\\\n\\\n## 6. Updated Recommendations\\\n\\\n### Priority 1: Fix the Lua plugin (one-line change)\\\nChange `LAZY = FULL` to `LAZY = NONE` in `manifest.ini`. Redeploy. Restart AC. This should immediately fix the \\\"script never loads\\\" issue.\\\n\\\n### Priority 2: Verify LuaSocket after fix\\\nCheck CSP logs for the three `ac.log()` diagnostic messages. If LuaSocket is unavailable, investigate CSP native networking alternatives.\\\n\\\n### Priority 3: Keep 10101 as the primary data source\\\nIt's working, reliable, data-rich, and provides everything needed for Phase 2–4. Start building parsers and analysis on this foundation.\\\n\\\n### Priority 4: Start parsing 10101 binary data\\\nWe have 10.6 MB of validated binary telemetry across two sessions. The packet structure is fully documented (359 bytes, packet type 22). Build the Rust parser.\\\n\\\n### Priority 5: Fix KSUDP handshake (or abandon it)\\\nLow ROI. Only invest here if both other feeds fail.\\\n\\\n---\\\n\\\n## 7. Data Comparison Matrix\\\n\\\n| Capability | 9996 KSUDP | 10101 Telemetry Tool | 5005 Lua Plugin |\\\n|---|---|---|---|\\\n| **Status** | ❌ Sparse (13 pkts) | ✅ Working (17K pkts) | ❌ Not working (LAZY=FULL) |\\\n| **Rate** | ~0.04 Hz (broken) | ~60 Hz ✅ | Configurable (target 60 Hz) |\\\n| **Format** | Binary | Binary | JSON ✅ |\\\n| **Basic inputs** | ✅ | ✅ | ✅ |\\\n| **G-forces** | ⚠️ Basic | ✅ 3-axis | ✅ 3-axis |\\\n| **Wheel slip** | ❌ | ✅ Ratios + angles | ✅ Per-wheel |\\\n| **Tyre temps** | ❌ | ✅ Core temps | ⚠️ Can add via CSP |\\\n| **Tyre wear** | ❌ | ❌ | ✅ CSP API |\\\n| **Suspension** | ⚠️ (200Hz claim) | ✅ Ride height F/R | ✅ Per-wheel travel |\\\n| **Damage** | ❌ | ❌ | ✅ 5-zone CSP |\\\n| **Fuel** | ✅ | ❌ | ✅ CSP API |\\\n| **World position** | ✅ | ✅ | ⚠️ Trivial to add |\\\n| **Multi-car** | ❌ | ✅ All drivers | ❌ Player only |\\\n| **Velocity vectors** | ❌ | ✅ 3D world + local | ❌ |\\\n| **Weather** | ❌ | ❌ | ✅ CSP API |\\\n| **Coaching quality** | Low (~40%) | High (~95%) | High (~90%) + CSP unique |\\\n\\\n---\\\n\\\n## 8. Bottom Line\\\n\\\n> **The Telemetry Tool (10101) is our workhorse.** It delivers 60 Hz of rich, validated, multi-car telemetry with wheel dynamics and tyre thermal data. The Lua plugin (5005) was never broken — it was never *activated*. Change `LAZY = FULL` to `LAZY = NONE` and it should start working immediately. The Lua plugin will add CSP-specific extensions (damage, fuel, tyre wear, weather) that make the combined data set uniquely powerful for sim racing coaching on Linux. KSUDP (9996) is a low-priority fallback.\\\n\\\n---\\\n\\\n## 9. Log File Reference\\\n\\\n| Log | Path | Key findings |\\\n|---|---|---|\\\n| `log.txt` | `<Proton Docs>/Documents/Assetto Corsa/logs/` | AC main log. Shows KSUDP bound OK (line 474). No Lua errors. No ac.log() messages. |\\\n| `custom_shaders_patch.log` | Same dir | CSP debug log. Shows app loading sequence. `impl.: 0000000000000000` for all Lua apps (normal). No Lua errors. No ac.log() messages. |\\\n| `py_log.txt` | Same dir | \\\"Telemetry Tool plugin 1.3 — Sending data to 127.0.0.1:10101\\\" — confirmed working. |\\\n| `errors.txt` | Same dir | Only camera_manager.ini missing keys. No Lua errors. |\\\n| imgui_settings.ini | `cfg/extension/state/` | `IMGUI_LUA_actelemetryplugin_main=60,60,366,164` and `TASKBAR_APPS_0='AC Telemetry'` — app was in taskbar but window never rendered. |\\\n| AppShelf manifest | `extension/internal/lua-apps/AppShelf/manifest.ini` | **Contains CSP's LAZY documentation** — confirms FULL = \\\"load when opened, unload when closed\\\". |\\\n\\\n---\\\n\\\n*Analysis date: 2026-06-03*\\\n*Data source: Two AC sessions at Vallelunga, Abarth 500, Soft tyres*\\\n*Root cause: LAZY=FULL prevents Lua script execution until user activates app in-game*\\\n*Fix: Change LAZY=FULL to LAZY=NONE in manifest.ini*\\\n*Author: Kilo (automated analysis)*\"]],\"start1\":0,\"start2\":0,\"length1\":0,\"length2\":16779}]"
metadata_diff: {"new":{"id":"395bc805650d44b6bfec423ca095ed64","parent_id":"0e8e00b432a840628faa4df5bc2068bc","latitude":"0.00000000","longitude":"0.00000000","altitude":"0.0000","author":"","source_url":"","is_todo":0,"todo_due":0,"todo_completed":0,"source":"joplin-desktop","source_application":"net.cozic.joplin-desktop","application_data":"","order":1780501069270,"markup_language":1,"is_shared":0,"share_id":"","conflict_original_id":"","master_key_id":"","user_data":"","deleted_time":0},"deleted":[]}
encryption_cipher_text: 
encryption_applied: 0
updated_time: 2026-06-03T15:57:54.808Z
created_time: 2026-06-03T15:57:54.808Z
type_: 13