Skip to content

Make load_and_authorize_remix deterministic.#696

Merged
fspeirs merged 2 commits intomainfrom
1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record
Mar 13, 2026
Merged

Make load_and_authorize_remix deterministic.#696
fspeirs merged 2 commits intomainfrom
1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record

Conversation

@fspeirs
Copy link
Contributor

@fspeirs fspeirs commented Feb 26, 2026

This commit changes RemixesController#load_and_authorize_remix to deterministically always return the oldest remix, matching the logic that currently exists in LessonsController#user_remix.

While, in principle, there should not be multiple records where (remixed_from_id:, user_id:) are the same, in practice there are and there is no database constraint to prevent there being.

The previous code would nondeterministically return one of possibly many records, causing downstream errors in Experience CS since each would have a different identifier, not matching the one stored in Experience CS.

Overarching epic:

https://github.com/RaspberryPiFoundation/experience-cs/issues/1826

Status

Points for consideration:

  • Security
  • Performance

What's changed?

I factored out the remix selection logic from LessonsController#user_remix into a new concern and reused that logic there and in RemixesController#load_and_authorize_project so now both endpoints should be consistent in which remix they select for which user and project.

Steps to perform after deploying to production

There are no additional steps required and this behaviour change should only affect users who have multiple remix records - these users will now only be able to access their oldest remix instead of getting a random one back.

@cla-bot cla-bot bot added the cla-signed label Feb 26, 2026
@fspeirs fspeirs marked this pull request as ready for review February 26, 2026 11:18
Copilot AI review requested due to automatic review settings February 26, 2026 11:18
Copy link
Contributor

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

This PR makes the load_and_authorize_remix method deterministic by explicitly ordering remix records when multiple records exist with the same (remixed_from_id, user_id) pair. The fix addresses a production issue where Experience CS was receiving inconsistent project identifiers due to nondeterministic query results. The change ensures that users always receive their most recently created remix instead of a random one.

Changes:

  • Modified RemixesController#load_and_authorize_remix to use .where().order().first! instead of find_by!, ordering by created_at: :desc, updated_at: :desc to deterministically return the most recent remix

@fspeirs fspeirs force-pushed the 1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record branch 2 times, most recently from 529bb80 to dac5345 Compare February 26, 2026 11:38
@github-actions
Copy link

github-actions bot commented Mar 13, 2026

Test coverage

89.74% line coverage reported by SimpleCov.
Run: https://github.com/RaspberryPiFoundation/editor-api/actions/runs/23056370146

@fspeirs fspeirs force-pushed the 1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record branch from 2e4a84f to 052c5fc Compare March 13, 2026 14:35
@fspeirs fspeirs requested a review from Copilot March 13, 2026 14:37
Copy link
Contributor

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

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.


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

You can also share your feedback on Copilot code review. Take the survey.

fspeirs added 2 commits March 13, 2026 14:50
This commit changes RemixesController#load_and_authorize_remix to
deterministically always return the most recent Project record based on
created_at and, secondarily, updated_at dates.

While, in principle, there should not be multiple records where
(remixed_from_id:, user_id:) are the same, in practice there are and
there is no database constraint to prevent there being.

The previous code would nondeterministically return one of possibly many
records, causing downstream errors in Experience CS since each would
have a different identifier, not matching the one stored in Experience
CS.

Overarching epic:

RaspberryPiFoundation/experience-cs#1826
This commit factors out the remix selection logic that was common
between LessonsController#user_remix and
RemixesController#load_and_authorize_remix into a new concern called
RemixSelection that is used in both controllers.

RemixSelection instantiates the rule that, for any user, the canonical
remix of a project is the remix which was created first. Any subsequent
remixes will not be accessible.
@fspeirs fspeirs force-pushed the 1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record branch from 052c5fc to 4cf245d Compare March 13, 2026 14:50
Copy link
Contributor

@zetter-rpf zetter-rpf left a comment

Choose a reason for hiding this comment

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

Nice one! thanks for spending the time with me to work it out.

@fspeirs fspeirs merged commit 3648cc6 into main Mar 13, 2026
6 checks passed
@fspeirs fspeirs deleted the 1186-editor-api-remix-lookup-should-deterministically-return-the-most-recently-created-record branch March 13, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants