feat(metrics): provenance as standard — pick_kind for all system mixes
The #1249 mechanism (stamp WHY a track is in the snapshot at build time, freeze it onto the play at ingestion, break it down in metrics) generalizes from a For You one-off to the standard for every system mix (#1270): - Migration 0039 widens both pick_kind CHECKs (drop + re-add in the same change) to taste/fresh + Discover's dormant/cross_user/random + tier1-3 for the rule-#131 eligibility ladders. - GetForYouPickKindForTrack becomes GetSystemPickKindForTrack (user, variant, track); ingestion stamps any systemPlaylistSources play from its own variant's live snapshot, live + offline paths. - Discover stamps its candidate bucket on discoverTrack before the interleave, making the 40/30/30 allocation measurable; dedup keeps the taking bucket's stamp. - Metrics replace the for_you special-case with one pick-kind vocabulary — any family with attributed plays gets a breakdown, future stamping mixes need no metrics change. - Web: breakdown sub-rows are now toggled per surface (collapsed by default) so eight stamping mixes don't swamp the card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TsF3cNoKrqCYsU78cXC8U6
This commit is contained in:
@@ -198,7 +198,7 @@ describe('Settings page — Recommendation metrics card', () => {
|
||||
...over
|
||||
});
|
||||
|
||||
test('renders the For You taste/fresh breakdown rows (#1249)', async () => {
|
||||
test('breakdown rows are collapsed by default and expand on toggle (#1249/#1270)', async () => {
|
||||
setupPage();
|
||||
metricsMock.data = {
|
||||
window_days: 30,
|
||||
@@ -225,13 +225,23 @@ describe('Settings page — Recommendation metrics card', () => {
|
||||
]
|
||||
};
|
||||
render(SettingsPage);
|
||||
await waitFor(() => expect(screen.getByText('For You')).toBeInTheDocument());
|
||||
const toggle = await screen.findByRole('button', { name: /for you/i });
|
||||
// Collapsed by default: every stamping mix now carries a breakdown,
|
||||
// so always-open sub-rows would swamp the surface-level view.
|
||||
expect(toggle).toHaveAttribute('aria-expanded', 'false');
|
||||
expect(screen.queryByText(/Taste picks/)).not.toBeInTheDocument();
|
||||
|
||||
await fireEvent.click(toggle);
|
||||
expect(toggle).toHaveAttribute('aria-expanded', 'true');
|
||||
expect(screen.getByText(/Taste picks/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Fresh picks/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Earlier plays/)).toBeInTheDocument();
|
||||
|
||||
await fireEvent.click(toggle);
|
||||
expect(screen.queryByText(/Taste picks/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('surfaces without a breakdown render no sub-rows', async () => {
|
||||
test('surfaces without a breakdown render no toggle and no sub-rows', async () => {
|
||||
setupPage();
|
||||
metricsMock.data = {
|
||||
window_days: 30,
|
||||
@@ -246,6 +256,7 @@ describe('Settings page — Recommendation metrics card', () => {
|
||||
};
|
||||
render(SettingsPage);
|
||||
await waitFor(() => expect(screen.getByText('Radio')).toBeInTheDocument());
|
||||
expect(screen.queryByRole('button', { name: /radio/i })).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Taste picks/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user