Reading an AutoQ Pick
AutoQ · evidence reference
Every pick now writes down what it decided. This is what it records at each stage, where to find it, and what a wrong one looks like — so “that’s odd” becomes a verdict instead of a description.
One line, every pick
A single summary line lands in mbxhub.log for every pick, at the default level. Nothing to enable. It replaced eight lines that a fill used to emit, three of which reported the same number three times and none of which named where the pick aimed.
AutoQ pick 7a3f2c11 [fill/AutoQ · Station: Metal] trigger=queue-low run=station:Metal pool=7519->4188(cached) gates=maxLen:12,filter:3319 center=follow-np(0.52,0.61) reach=0.25->0.35+ pooled=612 quota-cut=12 queued=5 flow=Smooth 142ms
| Field | Reads as |
|---|---|
| 7a3f2c11 | The pick’s id. Find the full record by it. |
| [fill/…] | Which door this came in by, and who was driving. |
| pool=7519->4188 | Considered, then eligible. (cached) means the pool was reused, so no gate ran. |
| gates=… | Which eligibility rule removed how many. Absent means nothing was removed. |
| center=… | Where it aimed, and whether that came from a run or from the music. |
| reach=0.25->0.35+ | How far out it looked. The + means it had to widen. |
| quota-cut=12 | Dropped by a diversity cap — not by scoring low. |
| sent=1 | On a send: your tracks. Never folded into queued, which is AutoQ’s. |
Stage by stage, with its evidence
The left column is what the stage decides. The right is what it now writes down, and underneath — in rust — what a wrong one looks like.
Something asks for tracks
The queue ran low, a track changed, or you pressed something. Nothing runs on a timer.
path = which of eight doors A fill you did not ask for: trigger=queue-low with a queue that was not low.
Who is driving
AutoQ picks if it is enabled and Pick mode is not Off. Otherwise TrueShuffle, if that is on.
What is even eligible
Hard gates. Each removes tracks, and nothing downstream puts them back.
pool = initial → final, and whether it was reused An empty queue with one gate holding a number close to the whole library.
Where it aimed
A running station sets the aiming point and beats everything, including the album you just started. With no run, AutoQ follows the music.
reach, whether it widened, and the pool left after it A block that ignores what you were playing: center=run from a station you forgot was on, or center=none because nothing in play was analysed.
Which of those it prefers
Every surviving track is scored. Taste matching does nothing until you have reacted to something.
weights = the set in force Every component near identical across the ten: nothing is steering, and the order is a coin toss.
Spread it out
Caps on how many one artist or genre may contribute. Over quota is dropped, not demoted.
The running order
The flow shapes the set. Continuity keeps neighbours in compatible key, tempo and texture.
Into the queue
Tracks are appended, each stamped with who queued it and why.
sentUrls / sentQueued = yours, kept separate
sendMode = the steer variant a send applied (refresh / reuse / restart) — the same value the send’s response reports as mode queued=0 on a send: your tracks went in and nothing filled around them.
Turning it on
The summary line is always there. The full record is not, because a record per pick is a lot of detail to write when nobody is reading it.
| What | Needs | Where |
|---|---|---|
| The summary line | nothing | mbxhub.log |
| Last 20 records, in memory | diagEndpointEnabled + pickJournalEnabled | GET /diag/autoq/picks |
| Every record, on disk | pickJournalEnabled | autoq-picks.log |
Why the ring is always filling
The last twenty picks are held in memory whether or not the journal is on. So when something odd happens, switching diagnostics on answers straight away — you are not waiting for the problem to happen a second time while the recorder runs.
The file and the endpoint use the same formatter, so a record on the wire is byte-identical to the same record in the log. A bug report and a live probe describe the same thing.
Two shapes that will surprise a reader
A normally-numeric field is the string "NaN" when the value is not finite — that is deliberate, because null would read as “absent” and hide a real defect on the exact signal you were looking at.
And on a send, sentUrls is yours while queued is AutoQ’s. They are never one number. The steer variant rides on the same record (sendMode, shown as mode= on the summary line) — it is the very value the send’s response returned, so the toast a listener saw and the journal line a triager reads cannot tell two different stories.
Where to look first
| Question | Look at |
|---|---|
| Is AutoQ picking at all, and as what? | /status |
| How much of my library carries the data? | /status — Coverage row |
| What weights are actually in force? | /status — Continuity weight row |
| Why did it pick that? | /diag/autoq/picks |
| Why did it pick that an hour ago? | autoq-picks.log |