Skip to content

Filter tracks with access_authorities#688

Merged
dylanjeffers merged 8 commits intomainfrom
filter-track-access-authorities
Mar 5, 2026
Merged

Filter tracks with access_authorities#688
dylanjeffers merged 8 commits intomainfrom
filter-track-access-authorities

Conversation

@dylanjeffers
Copy link
Contributor

No description provided.

@dylanjeffers dylanjeffers changed the title Filter track access authorities Filter tracks with access_authorities Mar 5, 2026
@@ -0,0 +1,9 @@
BEGIN;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if an index on not null achieves the same thing here for us with storing less data (not sure, genuine Q)

FROM tracks
WHERE isrc = ANY(@isrcs::text[]); No newline at end of file
WHERE isrc = ANY(@isrcs::text[])
AND is_current = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need is_current?

SELECT tr.track_id
FROM track_routes tr
JOIN tracks t ON t.track_id = tr.track_id AND t.is_current = true
AND t.access_authorities IS NULL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😢 sad we have to join tracks here now... Maybe we could filter later... we don't seem to be handling deleted tracks here for instance?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh good eye, yeah this will slow down all track pages for sure. i guess deleted tracks we still render a skeleton. for these... hmm

// For tracks: delete requested IDs from the index first, then re-index only those
// that still pass the filter (e.g. no access_authorities). So when a track gets
// access_authorities set, the next listen cycle removes it from search.
if collection == "tracks" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oooh interesting edge case... haven't thought about changing things to/from programmable access

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per offline discussion we can actually cut the esindexer changes

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the API and notification audience selection to exclude “programmable distribution” tracks by filtering out rows where tracks.access_authorities is set, and adds regression tests plus a DB index intended to support the new filters.

Changes:

  • Add access_authorities to the tracks schema and exclude such tracks from chat blast remixer audience selection.
  • Filter several API queries (tracks fetch, resolve-by-permalink, ISRC lookup, genres metrics, events) to require access_authorities IS NULL.
  • Add tests ensuring gated tracks are excluded from /tracks, /resolve, /metrics/genres, and /events.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
sql/01_schema.sql Schema sync: adds tracks.access_authorities and updates embedded chat_blast_audience function logic.
ddl/migrations/0191_tracks_access_authorities_partial_index.sql Adds a partial index intended to support access_authorities IS NULL filtering.
ddl/functions/chat_blast_audience.sql Excludes tracks with access_authorities from remixer audience selection.
api/v1_tracks_test.go Adds test asserting /v1/full/tracks excludes gated tracks.
api/v1_resolve_test.go Adds test asserting /v1/resolve returns 404 for gated tracks.
api/v1_metrics_genres_test.go Adds test asserting genre metrics exclude gated tracks.
api/v1_events_test.go Adds test asserting events for gated tracks are excluded.
api/dbv1/queries/get_tracks.sql Filters GetTracks to require t.access_authorities IS NULL.
api/dbv1/queries/get_track_ids_by_permalink.sql Filters permalink resolution to exclude gated tracks.
api/dbv1/queries/get_track_ids_by_isrc.sql Filters ISRC lookup to current, ungated tracks.
api/dbv1/queries/get_genres.sql Filters genre counts to exclude gated tracks.
api/dbv1/queries/get_events.sql Filters track-typed events to exclude gated/deleted tracks via join conditions.
api/dbv1/models.go Extends generated TrackRow model with AccessAuthorities.
api/dbv1/get_tracks.sql.go Regenerated sqlc output reflecting GetTracks filter changes.
api/dbv1/get_track_ids_by_permalink.sql.go Regenerated sqlc output reflecting permalink filter changes.
api/dbv1/get_track_ids_by_isrc.sql.go Regenerated sqlc output reflecting ISRC filter changes.
api/dbv1/get_genres.sql.go Regenerated sqlc output reflecting genres filter changes.
api/dbv1/get_events.sql.go Regenerated sqlc output reflecting events filter changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +4 to +5
-- We index rows WHERE access_authorities IS NULL so our queries (which filter
-- access_authorities IS NULL) can use it. A partial index on IS NOT NULL would
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration comment says “All track queries filter with access_authorities IS NULL”, but there are multiple non-sqlc queries in api/ that read from tracks and don’t currently apply that filter. This comment is misleading and could cause future changes to assume coverage that isn’t real; consider narrowing the wording (e.g., “dbv1 track queries used by …”) or ensuring the broader codebase is actually updated.

Suggested change
-- We index rows WHERE access_authorities IS NULL so our queries (which filter
-- access_authorities IS NULL) can use it. A partial index on IS NOT NULL would
-- We index rows WHERE access_authorities IS NULL so queries that filter
-- access_authorities IS NULL can use it. A partial index on IS NOT NULL would

Copilot uses AI. Check for mistakes.
-- access_authorities IS NULL) can use it. A partial index on IS NOT NULL would
-- store less but would never be used for those queries.
CREATE INDEX IF NOT EXISTS idx_tracks_access_authorities_null
ON tracks (track_id)
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This partial index is on (track_id) only, which largely overlaps existing track_id-leading indexes (e.g. idx_track_status in schema) but adds extra write overhead. If the goal is to speed up the new access_authorities IS NULL filters, consider verifying with EXPLAIN that this index is actually chosen, or adjust the index to match the most expensive filtered queries (e.g. include additional columns / different leading columns) before adding another track_id index.

Suggested change
ON tracks (track_id)
ON tracks (access_authorities, track_id)

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +58
var before struct {
Data []struct {
Name string `json:"name"`
Count int64 `json:"count"`
}
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test unmarshals name, but TestMetricsGenres in the same file unmarshals genre and can silently pass without asserting anything. Update the older test to use the same response shape (name) and add a real assertion (e.g., expect at least one known genre) so the baseline coverage is meaningful.

Copilot uses AI. Check for mistakes.
Comment on lines 31 to 35
@@ -35,6 +35,8 @@ BEGIN
AND chat_blast.audience = 'remixer_audience'
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The remixer_audience query filters on access_authorities IS NULL but doesn’t restrict t/og to is_current = true. Since tracks is versioned (has txhash+track_id PK and is_current), an older row with NULL access_authorities could match even when the current track is gated. Add t.is_current = true and og.is_current = true (preferably in the JOINs) so the exclusion applies to the current track state.

Copilot uses AI. Check for mistakes.
AND og.owner_id = chat_blast.from_user_id
AND t.owner_id != chat_blast.from_user_id
AND t.access_authorities IS NULL
AND og.access_authorities IS NULL
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as in ddl/functions/chat_blast_audience.sql: the remixer_audience audience selection filters on access_authorities IS NULL but does not restrict to is_current = true. If historical rows exist, a gated track could still pass via an older is_current=false row with NULL access_authorities. Add t.is_current = true and og.is_current = true so gated tracks can’t be included via stale rows.

Suggested change
AND og.access_authorities IS NULL
AND og.access_authorities IS NULL
AND t.is_current = true
AND og.is_current = true

Copilot uses AI. Check for mistakes.
@@ -209,5 +209,6 @@ LEFT JOIN aggregate_plays on play_item_id = t.track_id
LEFT JOIN track_routes on t.track_id = track_routes.track_id and track_routes.is_current = true
WHERE (is_unlisted = false OR t.owner_id = @my_id OR @include_unlisted::bool = TRUE)
AND t.track_id = ANY(@ids::int[])
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetTracks filters out gated tracks with t.access_authorities IS NULL, but it doesn’t filter t.is_current = true. Since tracks is versioned (PK includes txhash and has is_current), a track whose current row is gated could still be returned via an older is_current=false row where access_authorities is NULL. Add AND t.is_current = true (and ensure joins/selects are consistent) so the exclusion can’t be bypassed via historical rows.

Suggested change
AND t.track_id = ANY(@ids::int[])
AND t.track_id = ANY(@ids::int[])
AND t.is_current = true

Copilot uses AI. Check for mistakes.
@dylanjeffers dylanjeffers merged commit 7a90a4a into main Mar 5, 2026
4 checks passed
@dylanjeffers dylanjeffers deleted the filter-track-access-authorities branch March 5, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants