From a0bf008a6f2454f70e59499246dc2af96b31ec85 Mon Sep 17 00:00:00 2001 From: PraveenTB <22687262+PraveenTB@users.noreply.github.com> Date: Tue, 1 Sep 2026 15:42:58 -0700 Subject: [PATCH] fix(zava-learning): replace placeholder quiz questions with a real curated bank The student portal rendered "Sample question 1 for PSY-100" with A/B/C/D options instead of a real quiz. Root cause: the curated quiz_questions seed in src/db/schema.sql only covered BIO-101, MATH-220 and ECON-201, and the static QUIZZES map in assessment-api covered the same three. HIST-180, CHEM-110 and PSY-100 had no entries at all, so both services fell through to their placeholder fallback, which is what students saw. Changes: - Author 5 curated questions for each of the 6 catalogue courses (30 total), replacing the 2-question stubs. Prompts are conceptual and proof-read; every question has 4 distinct options and one unambiguous correct answer, with the answer index varied across positions. - Keep the DB seed and the assessment-api bank byte-identical so the two quiz paths cannot drift. - Make the quiz_questions seed declarative (DELETE then INSERT) instead of seed-once-when-empty, so re-running the schema against an already provisioned lab converges on the current set rather than keeping stale rows. The file executes as a single implicit transaction, so the bank is never observably empty. - Render portal options as a labelled A./B./C./D. list; the previous non-breaking-space join ran the longer option text together. The placeholder fallbacks in assessment-api and quiz-service are left in place deliberately - they remain a useful signal that a course is missing curated content. Verified by running course-api, assessment-api and learner-portal locally: all 6 courses return questionCount=5 with zero placeholder prompts, and scoring returns 100% for the answer key and 20% for an all-A submission. schema.sql parses cleanly against the real PostgreSQL grammar (pglast), yielding 30 VALUES rows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/assessment-api/server.js | 76 +++++++++++++++-- labs/zava-learning/src/db/schema.sql | 84 ++++++++++++++++--- .../src/learner-portal/server.js | 9 +- 3 files changed, 151 insertions(+), 18 deletions(-) diff --git a/labs/zava-learning/src/assessment-api/server.js b/labs/zava-learning/src/assessment-api/server.js index 90f0a5732..34eda8134 100644 --- a/labs/zava-learning/src/assessment-api/server.js +++ b/labs/zava-learning/src/assessment-api/server.js @@ -37,19 +37,81 @@ const SERVICE = "assessment-api"; // Optional upstream dependency: validates the course exists before serving a quiz. const COURSE_API_URL = process.env.COURSE_API_URL || ""; -// Static quiz bank keyed by course id. +// Static quiz bank keyed by course id. Every course served by course-api must appear here: +// a course with no entry falls through to defaultQuiz() and renders as unusable placeholder +// questions in the student portal. const QUIZZES = { "BIO-101": [ - { q: "The basic unit of life is the?", options: ["Atom", "Cell", "Organ", "Tissue"], answer: 1 }, - { q: "DNA is found primarily in the?", options: ["Nucleus", "Membrane", "Cytoplasm", "Wall"], answer: 0 } + { q: "If every cell arises only from a pre-existing cell, what does that imply about the origin of a multicellular organism?", + options: ["It assembles from free-floating organic molecules", "It arises spontaneously from decaying matter", "It develops from a single fertilized cell", "It is copied whole from a parent organism"], answer: 2 }, + { q: "When an organism passes its traits to the next generation, which molecule carries the instructions that make that continuity possible?", + options: ["DNA", "ATP", "Cellulose", "Hemoglobin"], answer: 0 }, + { q: "If two unrelated species independently evolve similar wing structures, what does that similarity most likely reflect?", + options: ["A recent common ancestor", "Convergent evolution under similar selective pressures", "Genetic drift in an isolated population", "A shared developmental accident"], answer: 1 }, + { q: "Why does energy flow through an ecosystem in one direction while matter cycles through it repeatedly?", + options: ["Energy is lost as heat at every transfer, while atoms are reused", "Producers consume all available energy before it can return", "Decomposers destroy energy but preserve matter", "Energy cannot pass between trophic levels"], answer: 0 }, + { q: "If a cell's membrane were freely permeable to every solute, which fundamental capability would the cell lose?", + options: ["The ability to synthesize proteins", "The ability to store genetic information", "The ability to replicate its DNA", "The ability to hold an internal state different from its surroundings"], answer: 3 } ], "MATH-220": [ - { q: "The integral of 1/x dx is?", options: ["ln|x|+C", "x^2+C", "-1/x^2+C", "e^x+C"], answer: 0 }, - { q: "A series that approaches a limit is said to?", options: ["Diverge", "Oscillate", "Converge", "Repeat"], answer: 2 } + { q: "If a quantity's rate of change is proportional to the quantity itself, which kind of function describes its growth?", + options: ["Linear", "Exponential", "Quadratic", "Logarithmic"], answer: 1 }, + { q: "An infinite sum of ever-smaller terms can still fail to settle on a finite value. Which series demonstrates that?", + options: ["A geometric series with ratio 1/2", "A p-series with p = 2", "The harmonic series", "The alternating harmonic series"], answer: 2 }, + { q: "If velocity is integrated over an interval of time, what does the resulting definite integral represent?", + options: ["Total displacement over that interval", "Instantaneous acceleration", "Average speed at the endpoint", "The greatest velocity attained"], answer: 0 }, + { q: "Why can a smooth function be approximated arbitrarily well near a point by a Taylor polynomial?", + options: ["Because every smooth function is itself a polynomial", "Because its derivatives at that point encode its local behavior", "Because integration reverses differentiation", "Because continuity implies linearity"], answer: 1 }, + { q: "If the partial sums of a series of positive terms are increasing and bounded above, what follows about the series?", + options: ["It diverges", "It oscillates without settling", "Nothing can be concluded without further information", "It converges"], answer: 3 } + ], + "HIST-180": [ + { q: "If the Columbian Exchange carried crops, people and pathogens across the Atlantic, which consequence most reshaped indigenous American societies?", + options: ["The adoption of a shared written language", "Catastrophic population loss caused by introduced disease", "A shift from farming to nomadic herding", "The rapid growth of inland trading guilds"], answer: 1 }, + { q: "What underlying shift allowed European powers to project sustained influence across distant continents after 1500?", + options: ["Advances in navigation, finance and armed shipping", "A sudden collapse of Asian trade networks", "The abandonment of religious rivalry at home", "A uniform legal code imposed across Europe"], answer: 0 }, + { q: "When industrialization concentrated workers in cities, which new form of political organization emerged in response?", + options: ["Feudal manorial courts", "Guild apprenticeship systems", "Organized labor movements", "Absolute monarchy"], answer: 2 }, + { q: "Nationalism can both unite and fracture states. Which outcome illustrates its fracturing effect?", + options: ["The unification of the German states in 1871", "The founding of overseas trading companies", "The spread of a common European currency", "The dissolution of multi-ethnic empires after 1918"], answer: 3 }, + { q: "If decolonization transferred formal sovereignty to new states, why did economic dependence so often persist?", + options: ["Trade and capital structures built under colonial rule remained in place", "The new states rejected foreign trade entirely", "Former colonies possessed no natural resources", "Independence treaties forbade industrialization"], answer: 0 } + ], + "CHEM-110": [ + { q: "If matter is neither created nor destroyed in a reaction, what must be true of a balanced chemical equation?", + options: ["The same number of atoms of each element appears on both sides", "The number of molecules is identical on both sides", "The mass of the products exceeds that of the reactants", "Atoms are conserved only when energy is released"], answer: 0 }, + { q: "Graphite and diamond are built from the same element, yet their properties differ enormously. What accounts for that difference?", + options: ["They contain different isotopes", "Their atoms are bonded in different structural arrangements", "One is an element and the other a compound", "Their atoms hold different numbers of protons"], answer: 1 }, + { q: "When a reaction at equilibrium is disturbed by a change in concentration or temperature, how does the system respond?", + options: ["It stops until the disturbance is removed", "It reverses permanently", "It shifts so as to partially offset the change", "It proceeds to completion in the forward direction"], answer: 2 }, + { q: "What does it mean, thermodynamically, for a reaction to be spontaneous?", + options: ["It proceeds without continuous external input, however slowly", "It occurs instantaneously", "It releases heat in every case", "It requires a catalyst before it can begin"], answer: 0 }, + { q: "If electrons occupy discrete energy levels, what explains the distinct colors that an excited element emits?", + options: ["The nucleus emits visible light directly", "Heating an element alters its atomic number", "Electrons are destroyed as they lose energy", "Transitions between fixed energy levels release photons of specific energies"], answer: 3 } ], "ECON-201": [ - { q: "Demand curves typically slope?", options: ["Upward", "Downward", "Flat", "Vertical"], answer: 1 }, - { q: "Opportunity cost is the value of the?", options: ["Best alternative", "Total spend", "Sunk cost", "Tax"], answer: 0 } + { q: "If every choice forecloses an alternative, what is the true cost of a decision?", + options: ["The value of the best alternative forgone", "The amount of money actually paid", "The total resources available to the chooser", "The cost already sunk into the decision"], answer: 0 }, + { q: "If a price ceiling is set below the market-clearing price, what outcome should be expected?", + options: ["A persistent surplus", "A persistent shortage", "No change in the quantity traded", "An immediate increase in supply"], answer: 1 }, + { q: "Why does a firm in a competitive market choose the output at which marginal cost equals marginal revenue?", + options: ["It guarantees the lowest possible average cost", "It maximizes total revenue", "Any other level of output would forgo attainable profit", "It removes fixed costs from the calculation"], answer: 2 }, + { q: "If the benefits or harms of a transaction fall on people who are not party to it, what has the market failed to price?", + options: ["A sunk cost", "A fixed cost", "A transfer payment", "An externality"], answer: 3 }, + { q: "As a consumer eats one slice of pizza after another, why does the amount they will pay for each additional slice decline?", + options: ["Diminishing marginal utility", "Rising fixed costs", "An increase in market supply", "A shift in the production function"], answer: 0 } + ], + "PSY-100": [ + { q: "If the mind is an unwritten slate at birth, through which channel does all knowledge enter human consciousness?", + options: ["Innate intuition", "Sensory experience", "Divine revelation", "Unconscious memory"], answer: 1 }, + { q: "When a person is torn between immediate desire and moral duty, which structure of the mind does Freud describe as the mediator with reality?", + options: ["The id", "The superego", "The ego", "The shadow"], answer: 2 }, + { q: "Which position holds that every choice is the unavoidable consequence of prior conditioning rather than an act of free will?", + options: ["Existentialism", "Rationalism", "Dualism", "Determinism"], answer: 3 }, + { q: "When we perceive an object, we experience a unified whole rather than a collection of separate parts. Which principle explains that?", + options: ["Gestalt perception", "Empiricism", "Behavioral conditioning", "Reductionism"], answer: 0 }, + { q: "According to the existential perspective, what is the fundamental source of human suffering?", + options: ["Repressed traumatic memories", "The search for meaning in an indifferent universe", "An imbalance of brain chemistry", "A failure to adapt to environmental demands"], answer: 1 } ] }; diff --git a/labs/zava-learning/src/db/schema.sql b/labs/zava-learning/src/db/schema.sql index 50622721f..ba533abf8 100644 --- a/labs/zava-learning/src/db/schema.sql +++ b/labs/zava-learning/src/db/schema.sql @@ -63,16 +63,80 @@ CREATE TABLE IF NOT EXISTS quiz_questions ( answer_idx INT NOT NULL ); -INSERT INTO quiz_questions (course_id, prompt, options, answer_idx) -SELECT * FROM (VALUES - ('BIO-101', 'The basic unit of life is the?', '["Atom","Cell","Organ","Tissue"]'::jsonb, 1), - ('BIO-101', 'DNA is found primarily in the?', '["Nucleus","Membrane","Cytoplasm","Wall"]'::jsonb, 0), - ('MATH-220', 'The integral of 1/x dx is?', '["ln|x|+C","x^2+C","-1/x^2+C","e^x+C"]'::jsonb, 0), - ('MATH-220', 'A series that approaches a limit is said to?','["Diverge","Oscillate","Converge","Repeat"]'::jsonb, 2), - ('ECON-201', 'Demand curves typically slope?', '["Upward","Downward","Flat","Vertical"]'::jsonb, 1), - ('ECON-201', 'Opportunity cost is the value of the?', '["Best alternative","Total spend","Sunk cost","Tax"]'::jsonb, 0) -) AS v(course_id, prompt, options, answer_idx) -WHERE NOT EXISTS (SELECT 1 FROM quiz_questions); +-- Every course in `courses` must be represented here: quiz-service and assessment-api fall +-- back to a "Sample question N" placeholder for any course with no curated rows, which shows +-- up in the student portal as an unusable quiz. The seed is declarative rather than +-- seed-once-if-empty (`DELETE` then `INSERT`) so re-running the schema against an existing +-- lab converges the table on the current set instead of preserving stale rows. The whole file +-- executes as one implicit transaction, so students never observe an empty bank. +DELETE FROM quiz_questions; + +INSERT INTO quiz_questions (course_id, prompt, options, answer_idx) VALUES + ('BIO-101', 'If every cell arises only from a pre-existing cell, what does that imply about the origin of a multicellular organism?', + '["It assembles from free-floating organic molecules","It arises spontaneously from decaying matter","It develops from a single fertilized cell","It is copied whole from a parent organism"]'::jsonb, 2), + ('BIO-101', 'When an organism passes its traits to the next generation, which molecule carries the instructions that make that continuity possible?', + '["DNA","ATP","Cellulose","Hemoglobin"]'::jsonb, 0), + ('BIO-101', 'If two unrelated species independently evolve similar wing structures, what does that similarity most likely reflect?', + '["A recent common ancestor","Convergent evolution under similar selective pressures","Genetic drift in an isolated population","A shared developmental accident"]'::jsonb, 1), + ('BIO-101', 'Why does energy flow through an ecosystem in one direction while matter cycles through it repeatedly?', + '["Energy is lost as heat at every transfer, while atoms are reused","Producers consume all available energy before it can return","Decomposers destroy energy but preserve matter","Energy cannot pass between trophic levels"]'::jsonb, 0), + ('BIO-101', 'If a cell''s membrane were freely permeable to every solute, which fundamental capability would the cell lose?', + '["The ability to synthesize proteins","The ability to store genetic information","The ability to replicate its DNA","The ability to hold an internal state different from its surroundings"]'::jsonb, 3), + + ('MATH-220', 'If a quantity''s rate of change is proportional to the quantity itself, which kind of function describes its growth?', + '["Linear","Exponential","Quadratic","Logarithmic"]'::jsonb, 1), + ('MATH-220', 'An infinite sum of ever-smaller terms can still fail to settle on a finite value. Which series demonstrates that?', + '["A geometric series with ratio 1/2","A p-series with p = 2","The harmonic series","The alternating harmonic series"]'::jsonb, 2), + ('MATH-220', 'If velocity is integrated over an interval of time, what does the resulting definite integral represent?', + '["Total displacement over that interval","Instantaneous acceleration","Average speed at the endpoint","The greatest velocity attained"]'::jsonb, 0), + ('MATH-220', 'Why can a smooth function be approximated arbitrarily well near a point by a Taylor polynomial?', + '["Because every smooth function is itself a polynomial","Because its derivatives at that point encode its local behavior","Because integration reverses differentiation","Because continuity implies linearity"]'::jsonb, 1), + ('MATH-220', 'If the partial sums of a series of positive terms are increasing and bounded above, what follows about the series?', + '["It diverges","It oscillates without settling","Nothing can be concluded without further information","It converges"]'::jsonb, 3), + + ('HIST-180', 'If the Columbian Exchange carried crops, people and pathogens across the Atlantic, which consequence most reshaped indigenous American societies?', + '["The adoption of a shared written language","Catastrophic population loss caused by introduced disease","A shift from farming to nomadic herding","The rapid growth of inland trading guilds"]'::jsonb, 1), + ('HIST-180', 'What underlying shift allowed European powers to project sustained influence across distant continents after 1500?', + '["Advances in navigation, finance and armed shipping","A sudden collapse of Asian trade networks","The abandonment of religious rivalry at home","A uniform legal code imposed across Europe"]'::jsonb, 0), + ('HIST-180', 'When industrialization concentrated workers in cities, which new form of political organization emerged in response?', + '["Feudal manorial courts","Guild apprenticeship systems","Organized labor movements","Absolute monarchy"]'::jsonb, 2), + ('HIST-180', 'Nationalism can both unite and fracture states. Which outcome illustrates its fracturing effect?', + '["The unification of the German states in 1871","The founding of overseas trading companies","The spread of a common European currency","The dissolution of multi-ethnic empires after 1918"]'::jsonb, 3), + ('HIST-180', 'If decolonization transferred formal sovereignty to new states, why did economic dependence so often persist?', + '["Trade and capital structures built under colonial rule remained in place","The new states rejected foreign trade entirely","Former colonies possessed no natural resources","Independence treaties forbade industrialization"]'::jsonb, 0), + + ('CHEM-110', 'If matter is neither created nor destroyed in a reaction, what must be true of a balanced chemical equation?', + '["The same number of atoms of each element appears on both sides","The number of molecules is identical on both sides","The mass of the products exceeds that of the reactants","Atoms are conserved only when energy is released"]'::jsonb, 0), + ('CHEM-110', 'Graphite and diamond are built from the same element, yet their properties differ enormously. What accounts for that difference?', + '["They contain different isotopes","Their atoms are bonded in different structural arrangements","One is an element and the other a compound","Their atoms hold different numbers of protons"]'::jsonb, 1), + ('CHEM-110', 'When a reaction at equilibrium is disturbed by a change in concentration or temperature, how does the system respond?', + '["It stops until the disturbance is removed","It reverses permanently","It shifts so as to partially offset the change","It proceeds to completion in the forward direction"]'::jsonb, 2), + ('CHEM-110', 'What does it mean, thermodynamically, for a reaction to be spontaneous?', + '["It proceeds without continuous external input, however slowly","It occurs instantaneously","It releases heat in every case","It requires a catalyst before it can begin"]'::jsonb, 0), + ('CHEM-110', 'If electrons occupy discrete energy levels, what explains the distinct colors that an excited element emits?', + '["The nucleus emits visible light directly","Heating an element alters its atomic number","Electrons are destroyed as they lose energy","Transitions between fixed energy levels release photons of specific energies"]'::jsonb, 3), + + ('ECON-201', 'If every choice forecloses an alternative, what is the true cost of a decision?', + '["The value of the best alternative forgone","The amount of money actually paid","The total resources available to the chooser","The cost already sunk into the decision"]'::jsonb, 0), + ('ECON-201', 'If a price ceiling is set below the market-clearing price, what outcome should be expected?', + '["A persistent surplus","A persistent shortage","No change in the quantity traded","An immediate increase in supply"]'::jsonb, 1), + ('ECON-201', 'Why does a firm in a competitive market choose the output at which marginal cost equals marginal revenue?', + '["It guarantees the lowest possible average cost","It maximizes total revenue","Any other level of output would forgo attainable profit","It removes fixed costs from the calculation"]'::jsonb, 2), + ('ECON-201', 'If the benefits or harms of a transaction fall on people who are not party to it, what has the market failed to price?', + '["A sunk cost","A fixed cost","A transfer payment","An externality"]'::jsonb, 3), + ('ECON-201', 'As a consumer eats one slice of pizza after another, why does the amount they will pay for each additional slice decline?', + '["Diminishing marginal utility","Rising fixed costs","An increase in market supply","A shift in the production function"]'::jsonb, 0), + + ('PSY-100', 'If the mind is an unwritten slate at birth, through which channel does all knowledge enter human consciousness?', + '["Innate intuition","Sensory experience","Divine revelation","Unconscious memory"]'::jsonb, 1), + ('PSY-100', 'When a person is torn between immediate desire and moral duty, which structure of the mind does Freud describe as the mediator with reality?', + '["The id","The superego","The ego","The shadow"]'::jsonb, 2), + ('PSY-100', 'Which position holds that every choice is the unavoidable consequence of prior conditioning rather than an act of free will?', + '["Existentialism","Rationalism","Dualism","Determinism"]'::jsonb, 3), + ('PSY-100', 'When we perceive an object, we experience a unified whole rather than a collection of separate parts. Which principle explains that?', + '["Gestalt perception","Empiricism","Behavioral conditioning","Reductionism"]'::jsonb, 0), + ('PSY-100', 'According to the existential perspective, what is the fundamental source of human suffering?', + '["Repressed traumatic memories","The search for meaning in an indifferent universe","An imbalance of brain chemistry","A failure to adapt to environmental demands"]'::jsonb, 1); -- Gradebook: quiz submissions / scores. CREATE TABLE IF NOT EXISTS submissions ( diff --git a/labs/zava-learning/src/learner-portal/server.js b/labs/zava-learning/src/learner-portal/server.js index 1283f9b29..3d917f0cb 100644 --- a/labs/zava-learning/src/learner-portal/server.js +++ b/labs/zava-learning/src/learner-portal/server.js @@ -81,6 +81,11 @@ app.get("/", (_req, res) => { .meta{color:#5b6b7b;font-size:13px;margin-bottom:12px} button{background:#0b6bcb;color:#fff;border:0;border-radius:6px;padding:8px 12px;cursor:pointer} #quiz{margin-top:20px;padding:16px;background:#fff;border-radius:10px;border:1px solid #e1e8ef;display:none} + #quiz .q{margin:0 0 18px} + #quiz .prompt{font-weight:600;margin:0 0 8px} + #quiz .opts{list-style:none;margin:0;padding:0} + #quiz .opts li{padding:3px 0;color:#33475b} + #quiz .lbl{display:inline-block;width:22px;font-weight:600;color:#0b6bcb} .err{color:#b00020;font-weight:600} @@ -108,7 +113,9 @@ async function launchQuiz(id){ const r=await fetch('/api/quiz/'+id); if(!r.ok) throw new Error(r.status); const data=await r.json(); q.innerHTML='

Quiz: '+data.courseId+'

'+data.questions.map((x,i)=> - '

'+(i+1)+'. '+x.q+'
'+x.options.join('   ')+'

').join(''); + '

'+(i+1)+'. '+x.q+'

').join(''); }catch(e){ q.innerHTML='

We could not launch this quiz. Please try again shortly.

'; } } loadCourses();