`Question.is_shared` defaulted to 1 and was only ever set by a route nothing
called, so in practice it divided the bank into "everything" and "everything,
plus your own private ones" — a distinction that cost every recommendation
denominator a join and never changed an answer. Who may reach the bank is the
site's own access rules; who may manage a question is the category grant tree.
So the two predicates the whole bank was built on are now the same thing, and
say what they actually mean: a question is out of reach if it has been deleted
or belongs to a course. Nothing else. The column is dropped, the route that set
it is gone, the bulk "share" action with it, and the Private tile and pill go
from the question manager.
The tests that turned on it have been rewritten rather than deleted, because
the rule they were really about survives: revoking a question still revokes
every session carrying it — by deleting it, which is the only revocation left.
Several others named a category holding exactly two reachable questions and
then answered two particular ids; that category holds four now, so they name
the pair instead. A session's own sharing flag is untouched — that is a
different thing, and it is still how a session is handed to somebody.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
Favorites and the question libraries in one place. Card and Table views
with the choice remembered, sort by last used / created / name / size
with a direction control, a count line, and a search over name and date.
Favorites leads as a fixed row: it is the one shelf nobody made and
everybody has, so it cannot be renamed or deleted.
Sorted by when each was last used, not when it was made — the order
things were created in is nobody's mental model of their own shelf. A
library nobody has opened falls back to its age, because it is newer to
the learner than it is to the database. That needed
`user_collections.last_used_at`: null on every existing row, since
backfilling from created_at would invent a use that never happened.
A shelf opens in place rather than linking away. The obvious link would
have been /questions?collection=N, and there is no page there that reads
it — the old bank browser was dismantled — so the card would have led
nowhere. Questions can be taken back out from the open shelf, and any
shelf can be sat as a session through the existing explicit_ids builder.
The ⋯ menu moved out of QuizPage into components/MoreMenu; the player
keeps its own look and its own children through className props. It no
longer closes on any click inside, which the player's feedback form and
share dialog were relying on by accident.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN