""" Neontology node schemas for the cc.public.exams knowledge graph. cc.public.exams is a dedicated, shared, public Neo4j database — co-primary/authoritative for the exam knowledge graph (specs, spec-points, paper→question→part→region structure, ASSESSES links). Supabase remains source of truth for operational data (geometry, marks, submissions); the two layers join on shared UUIDs: exam_questions.id <-> Question|Part.uuid_string (container -> Question, leaf -> Part) exam_response_areas.id <-> Region.uuid_string eb_exams.exam_code <-> ExamPaper.exam_code eb_specifications.spec_code <-> Specification.spec_code Ownership: created by an infra-init step; read by all authenticated API calls; written by the API service role only (no direct client writes). """ from typing import ClassVar, Optional from ..base_nodes import CCBaseNode class ExamBaseNode(CCBaseNode): __primarylabel__: ClassVar[str] = '' class ExamBoardNode(ExamBaseNode): __primarylabel__: ClassVar[str] = 'ExamBoard' code: str # 'AQA' name: str class SpecificationNode(ExamBaseNode): __primarylabel__: ClassVar[str] = 'Specification' spec_code: str # 'AQA-PHYS-8463' (== Supabase eb_specifications.spec_code) exam_board_code: str subject_code: Optional[str] = None award_code: Optional[str] = None title: Optional[str] = None class SpecPointNode(ExamBaseNode): __primarylabel__: ClassVar[str] = 'SpecPoint' ref: str # '4.1', '4.2.1' description: str spec_code: str exam_board_code: str class ExamPaperNode(ExamBaseNode): __primarylabel__: ClassVar[str] = 'ExamPaper' exam_code: str # == Supabase eb_exams.exam_code spec_code: str paper_code: Optional[str] = None tier: Optional[str] = None session: Optional[str] = None title: Optional[str] = None page_count: Optional[int] = None class QuestionNode(ExamBaseNode): # roll-up container; uuid_string == exam_questions.id __primarylabel__: ClassVar[str] = 'Question' exam_code: str label: str # '01' order: int max_marks: float class PartNode(ExamBaseNode): # leaf; uuid_string == exam_questions.id __primarylabel__: ClassVar[str] = 'Part' exam_code: str label: str # '01.1' order: int max_marks: float answer_type: str mark_scheme_type: str class RegionNode(ExamBaseNode): # uuid_string == exam_response_areas.id __primarylabel__: ClassVar[str] = 'Region' page: int kind: str # 'response' | 'context' response_form: str # Relationship reference (written by the projection / linker, not modelled as classes here): # (:ExamBoard)-[:PUBLISHES]->(:Specification) # (:Specification)-[:HAS_SPEC_POINT]->(:SpecPoint) # (:Specification)-[:HAS_PAPER]->(:ExamPaper) # (:ExamPaper)-[:HAS_QUESTION]->(:Question) # (:Question)-[:HAS_PART]->(:Part) # nested questions allowed # (:Part)-[:HAS_REGION]->(:Region) # (:Part)-[:ASSESSES]->(:SpecPoint) # from exam_questions.spec_ref # (:SpecPoint)-[:TEACHES]->(:LearningStatement) # DEFERRED cross-db bridge