The number beside a folder in Topic reading was a question count while the browser lists articles, so "Hyperinflammatory Sepsis 4" meant four questions and opened onto no reading at all. It counts what it opens now, rolled up over the subtree, and a branch with nothing to read in it is not offered — a folder with a number on it is a promise. The hover card could not be reached. Its body was pointer-events: none, on the idea that a hint should not sit between the reader and the link — but the card is offset below the link and never covered it, while the pointer travelling down to Split view crossed a body it could not enter, so no mouseenter fired and the hide timer closed it on the way. The card takes the pointer now, with a bridge across the gap. And clicking the words opens the card rather than the article. A cross-reference is read mid-sentence, and navigating away to find out whether it was worth following is the thing that breaks the thread; the card's two controls — beside what you are reading, or a tab for later — are how you go. That also gives touch a route, where hover has none. Modified and middle clicks are still the browser's. The listing sent content and sections for all 331 articles, 214KB of prose a list never renders. It sends what a list needs, which is 21KB. The footer sat wherever the content stopped, so a page still loading put it halfway up the screen with background below it. The shell is a column the height of the window. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
38 lines
1.5 KiB
Python
38 lines
1.5 KiB
Python
"""Deleting a quiz must not destroy the questions extracted for it.
|
|
|
|
`questions.quiz_id` was created ON DELETE CASCADE, while the model has long
|
|
declared SET NULL and its comment says the column is informational — "which
|
|
quiz this question was originally extracted for" — with real membership held
|
|
in `quiz_question_links`. The database was the one being obeyed, so removing a
|
|
quiz silently erased every question it had produced, along with their attempts,
|
|
exam membership, media and article links, and straight past the trash that was
|
|
built to make exactly that impossible.
|
|
|
|
The model's intent is the correct one and is what this applies.
|
|
|
|
`quizzes.user_id` is the opposite case: the database cascades and the model
|
|
said nothing, and here the database is right — deleting an account is
|
|
documented as removing what it made. The model is corrected to match rather
|
|
than the data.
|
|
|
|
Revision ID: b8c9d0e1f2a3
|
|
Revises: a7b8c9d0e1f2
|
|
"""
|
|
from alembic import op
|
|
|
|
revision = "b8c9d0e1f2a3"
|
|
down_revision = "a7b8c9d0e1f2"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.drop_constraint("questions_quiz_id_fkey", "questions", type_="foreignkey")
|
|
op.create_foreign_key("questions_quiz_id_fkey", "questions", "quizzes",
|
|
["quiz_id"], ["id"], ondelete="SET NULL")
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_constraint("questions_quiz_id_fkey", "questions", type_="foreignkey")
|
|
op.create_foreign_key("questions_quiz_id_fkey", "questions", "quizzes",
|
|
["quiz_id"], ["id"], ondelete="CASCADE")
|