A question reached a system through a symptom keyword it happened to mention — question → keyword → parent system — and only 726 of 4,281 keywords had ever been given a parent. The Systems tab saw 1,492 of 2,924 questions while Disciplines saw all of them. The system now sits on the category: question_categories.system_id. Every question has a category, so every question reaches a system. 2,919 of 2,924, and all sixteen buckets have real content. It stays a third way of asking rather than the discipline tree relabelled because a topic's system is assigned separately from where it sits in the tree. scripts/assign_category_systems takes the discipline as a default and lets the topic's own name overrule it, which is exactly the case that makes the axis worth having: conjunctivitis is filed under Infectious Disease and is an eye, osteomyelitis is filed there and is a bone. 110 of 660 topics were decided that way. Two regex traps caught in the dry run and fixed before applying: "adRENAL" matched the kidney rule, and "Abnormal Uterine Bleeding" matched the bleeding rule. Both now have a specific rule above the general one. I first tried to fix this by parenting the orphan keywords to systems, deriving each keyword's system from the questions carrying it. The dry run showed why that was the wrong shape: it reached only 534 of 3,555 orphans, and inherited every coarse edge of the discipline map — conjunctivitis came out as Multisystem because conjunctivitis questions are filed under Infectious Disease. That script is left in place, unapplied, as the record of a measurement worth keeping. No ForeignKey on system_id in the model: question_tags is a raw-SQL table with no ORM class, and declaring one leaves every metadata build unable to resolve it. The constraint is real in Postgres. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TqXevQJhxFrM7jJg82cgZN
38 lines
1.9 KiB
Python
38 lines
1.9 KiB
Python
from datetime import datetime
|
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Text, UniqueConstraint
|
|
from sqlalchemy.orm import relationship
|
|
from app.database import Base
|
|
|
|
|
|
class QuestionCategory(Base):
|
|
__tablename__ = "question_categories"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
parent_id = Column(Integer, ForeignKey("question_categories.id", ondelete="RESTRICT", name="fk_question_categories_parent"), nullable=True)
|
|
name = Column(String, nullable=False)
|
|
description = Column(Text, nullable=True)
|
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
# The organ system this topic belongs to, said once here rather than
|
|
# inferred from a keyword on each question. A category's discipline is
|
|
# where it sits in the tree; its system is a separate fact about it —
|
|
# conjunctivitis is filed under Infectious Disease and is an eye.
|
|
#
|
|
# No ForeignKey in the model: `question_tags` is a raw-SQL table with no
|
|
# ORM class, so declaring one here leaves every metadata build unable to
|
|
# resolve it. The constraint is real in Postgres; the migration adds it.
|
|
system_id = Column(Integer, nullable=True)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
questions = relationship("Question", back_populates="question_category",
|
|
foreign_keys="Question.question_category_id")
|
|
|
|
|
|
class QuestionCategoryLink(Base):
|
|
"""Additional (non-primary) category assignments for a question."""
|
|
|
|
__tablename__ = "question_category_links"
|
|
__table_args__ = (UniqueConstraint("question_id", "category_id", name="uq_question_category_link"),)
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
question_id = Column(Integer, ForeignKey("questions.id", ondelete="CASCADE"), nullable=False)
|
|
category_id = Column(Integer, ForeignKey("question_categories.id", ondelete="CASCADE"), nullable=False)
|