diff --git a/.claude/skills/ipx-prod-check/SKILL.md b/.claude/skills/ipx-prod-check/SKILL.md index 6b69c08..d37386e 100644 --- a/.claude/skills/ipx-prod-check/SKILL.md +++ b/.claude/skills/ipx-prod-check/SKILL.md @@ -72,7 +72,7 @@ Count those from the metrics, not the log. | `ipx::scan` | `ev` and the event's own: `feed`, `new`, `downloaded`, `failed`, `bytes`, `msg`, `url`, `feeds`, `reason`, `from`, `to`; on a failure `error.type` and, from an HTTP error, `http.response.status_code` | the daemon's events, one line each, in words; warnings are feed and download failures | | `ipx::io` | `ev`, `feeds`, `pending`, `downloaded` on the `status` reply | commands arriving on the socket (`-> {...}`) and the answer to `ipx status` | | `ipx::daemon`, `ipx::cli`, `ipx::catalogue`, `ipx::scan`, ... | message, sometimes fields | start-up, shutdown, account and config messages, under the module that logs them; plain `ipx` before 2026-10-24, when main.rs was split (#356) | -| `ipx::client` | `ev`, `user`, `feed`, `enclosure`, `deadair`; `msg`, `src`, `line` on an error; `ms` on a timing | what the page reports from the browser (#190): `page_error`, `rejection` and `player_error` as warnings; `play_start` (ms from play to sound), `stall` (ms waiting mid-play) and `list_shown` (ms from a click to its list drawn, with `feed` the view and `filter`, #246) as info. Lines carry the trace of the action in the page: its API requests send `traceparent`, one trace id per tap or key | +| `ipx::client` | `ev`, `user`, `feed`, `enclosure`, `deadair`; `msg`, `src`, `line` on an error; `ms` on a timing | what the page reports from the browser (#190): `page_error`, `rejection`, `player_error` and `scroll_stuck` (a drag that should have scrolled the reader and did not, its snapshot in `state`, #384) as warnings; `swipe` (a swipe in the reader: `msg` next, prev, list, end or short, `state` its position, `5/50 of 312, more to load`, #384), `play_start` (ms from play to sound), `stall` (ms waiting mid-play) and `list_shown` (ms from a click to its list drawn, with `feed` the view and `filter`, #246) as info. Lines carry the trace of the action in the page: its API requests send `traceparent`, one trace id per tap or key | Events (`ev`): `feed_start` (debug), `feed_done` (new, downloaded, failed, torrents), `feed_skip` (not due, debug), `feed_error` (msg), `feed_moved` (from, to: a permanent redirect followed, the address @@ -272,6 +272,9 @@ a count says something happened, the lines and traces say why. $Q metric 'sum by (ev, msg) (count_over_time({container="iPX"} |= "\"target\":\"ipx::client\"" | json | __error__="" | level="WARN" [$range]))' 7d $Q logs '{container="iPX"} |= "\"target\":\"ipx::client\"" | json | ev=~"play_start|stall" | line_format "{{.timestamp}} {{.user}} {{.ev}} {{.ms}}ms deadair={{.deadair}} {{.feed}}"' 24h $Q metric 'quantile_over_time(0.95, {container="iPX"} |= "\"ev\":\"list_shown\"" | json | __error__="" | unwrap ms [$range]) by (feed, filter)' 24h + $Q metric 'sum by (msg) (count_over_time({container="iPX"} |= "\"ev\":\"swipe\"" | json | __error__="" [$range]))' 7d + $Q logs '{container="iPX"} |= "\"ev\":\"swipe\"" |= "\"msg\":\"end\"" | json | line_format "{{.timestamp}} {{.user}} {{.feed}} {{.filter}} {{.state}}"' 7d + $Q logs '{container="iPX"} |= "\"ev\":\"scroll_stuck\"" | json | line_format "{{.timestamp}} {{.user}} {{.feed}} {{.state}}"' 7d ``` A `player_error` is playback that failed in front of someone: `hls.js: ...` is DeadAir's playlist (its trace has the playlist and audio requests), `media error 4` a file the browser @@ -279,6 +282,19 @@ a count says something happened, the lines and traces say why. the minified `app.js`, so match the message to `web/src`. A `list_shown` over 1000 ms is a list someone waited for: its trace says whether the API or the network held it. `play_start` over 2000 ms, or a `stall`, is worth a trace: was it the server, Cloudflare, or the network. + Swipes and a reader that will not scroll (#383, #384). An `end` swipe is the reader bouncing + off the last item loaded: one whose `state` says `more to load` is the page failing to fetch + the next page in time, and several in a row from one person at the same position is #383 back. + An `end` without `more to load` is someone at the real end of the list, and fine. Many `short` + against few `next` is swipes not being taken, worth a look at `swipeMin` in `gestures.ts`. + Any `scroll_stuck` is a reader someone could not scroll, the bug #383 reported and never + found: read its `state` before anything else. `under the finger` other than `#detail` or + something inside it names a layer lying over the reader; `inert` other than `#dpeek`, `dialog + open`, a `transform` other than `none`, or `peek left behind` name what the page left in a wrong + state; `shown Ns ago` small says it followed a return from the background. File it with the + `state` line and that person's swipes just before it (`$Q logs` on `ev=~"swipe|scroll_stuck"` and + the `user`), even when the cause is not clear yet: it is the one record of the bug. + `docker logs --since 10m iPX 2>&1 | tail -5` shows the newest lines when Loki is behind. ## ipx-web, the page