MBXHub

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
FieldReads as
7a3f2c11The pick’s id. Find the full record by it.
[fill/…]Which door this came in by, and who was driving.
pool=7519->4188Considered, 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=12Dropped by a diversity cap — not by scoring low.
sent=1On 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.

1

Something asks for tracks

The queue ran low, a track changed, or you pressed something. Nothing runs on a timer.

queue thresholdbatch size
trigger = queue-low | manual | send
path = which of eight doors A fill you did not ask for: trigger=queue-low with a queue that was not low.
2

Who is driving

AutoQ picks if it is enabled and Pick mode is not Off. Otherwise TrueShuffle, if that is on.

Pick mode
driver = AutoQ · Station: Metal The handover you did not make: two consecutive records going AutoQ then TrueShuffle with nothing between them.
3

What is even eligible

Hard gates. Each removes tracks, and nothing downstream puts them back.

your filterlength capfreshness
gates = ban, maxLen, speech, freshness, filter — each with what it dropped and what survived
pool = initial → final, and whether it was reused An empty queue with one gate holding a number close to the whole library.
4

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.

Tightnessflow
center = run | follow-np | follow-queue | none | radio-off
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.
5

Which of those it prefers

Every surviving track is scored. Taste matching does nothing until you have reacted to something.

reactions
scored = top ten, each with feat / track / artist / recency / div / explore / inf / mood / unheard
weights = the set in force Every component near identical across the ten: nothing is steering, and the order is a coin toss.
6

Spread it out

Caps on how many one artist or genre may contribute. Over quota is dropped, not demoted.

artist quotagenre quota
quotaDrops = each cut track, which cap cut it, and the count against the quota A track you expected, missing from the queue and present here — capped, not outranked.
7

The running order

The flow shapes the set. Continuity keeps neighbours in compatible key, tempo and texture.

flowkey weight
order = flow, key weight, and the sequence produced Sequence order differing from what actually played — something re-ordered the queue after AutoQ set it.
8

Into the queue

Tracks are appended, each stamped with who queued it and why.

queued = AutoQ’s own picks, with score and stamp
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.

WhatNeedsWhere
The summary linenothingmbxhub.log
Last 20 records, in memorydiagEndpointEnabled
+ pickJournalEnabled
GET /diag/autoq/picks
Every record, on diskpickJournalEnabledautoq-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

QuestionLook 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