chore: add dropped question to reports

This commit is contained in:
2026-09-19 23:15:31 -04:00
parent 92c8a8fc75
commit ba84c4d82a
4 changed files with 110 additions and 5 deletions
+24
View File
@@ -299,6 +299,7 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
value.insert_some("correct", question.correct.map(Value::Bool));
value.insert("credit", Value::Float(question.credit));
value.insert("bonus", Value::Bool(question.bonus));
value.insert("dropped", Value::Bool(question.dropped));
value.insert("blank", Value::Bool(question.blank));
value.insert_some("class-rate", question.class_rate.map(Value::Float));
value.insert(
@@ -348,6 +349,17 @@ pub fn student_value(diagnostic: &StudentDiagnostic, config: &RenderConfig) -> V
),
);
out.insert(
"dropped-questions",
Value::Array(
diagnostic
.dropped_questions
.iter()
.map(|n| Value::Int(*n as i64))
.collect(),
),
);
out.insert(
"review-lectures",
Value::Array(
@@ -612,6 +624,17 @@ pub fn cohort_value(diagnostic: &CohortDiagnostic, config: &RenderConfig) -> Val
),
);
out.insert(
"dropped-questions",
Value::Array(
diagnostic
.dropped_questions
.iter()
.map(|n| Value::Int(*n as i64))
.collect(),
),
);
let triage_rows = |rows: &[crate::diagnostic::TriageRow]| -> Value {
Value::Array(rows.iter().map(|row| triage_value(row, content)).collect())
};
@@ -1128,6 +1151,7 @@ mod tests {
gaps: Vec::new(),
grades: Vec::new(),
lectures: Vec::new(),
dropped_questions: Vec::new(),
questions: Vec::new(),
triage: crate::diagnostic::Triage::default(),
predictions: crate::diagnostic::PredictionSummary::default(),
@@ -167,6 +167,7 @@
band-hit: 11,
biggest-surprise: (number: 14, expected: 0.45, observed: 0.86),
),
dropped-questions: (),
revise: (),
forms: (
(id: "A", students: 12, mean: 73.5, sd: 10.2),
@@ -989,6 +990,17 @@
One row per question, in the order they were numbered. Option letters are the
bank's, not any one form's. See the guide above for what p, r, and D mean; the
r column is colour-coded against the conventional cut points.
#{
let dropped = cb-data.at("dropped-questions", default: ())
if dropped.len() > 0 [
#plural(dropped.len(), "Question", "Questions")
#dropped.map(str).join(", ")
#plural(dropped.len(), "is", "are")
marked dropped in the assessment record, so
#plural(dropped.len(), "it is", "they are")
absent from this table and from every statistic above.
]
}
]
#table(
+33 -4
View File
@@ -121,6 +121,7 @@
correct: true,
credit: 1.0,
bonus: false,
dropped: false,
blank: false,
class-rate: 0.91,
taught-in: (),
@@ -451,6 +452,26 @@
},
)
#let dropped-questions = cb-data.at("dropped-questions", default: ())
#if dropped-questions.len() > 0 [
#block(above: entry-gap)[
#pad(right: prose-pad)[
#text(size: size-lead)[
#plural(dropped-questions.len(), "Question", "Questions")
#dropped-questions.map(str).join(", ")
#plural(dropped-questions.len(), "was", "were")
dropped after the exam and #plural(dropped-questions.len(), "is", "are")
not part of anyone's score. Your percentage above is out of the
#plural(dropped-questions.len(), "remaining question", "remaining questions").
Nothing you wrote on
#plural(dropped-questions.len(), "it", "them")
counted for or against you.
]
]
]
]
// ─────────────────────────────────────────────────────────────────────────────
// Levels
// ─────────────────────────────────────────────────────────────────────────────
@@ -750,7 +771,10 @@
#let questions = cb-data.at("questions", default: ())
#let question-box(q) = {
let color = if q.at("blank", default: false) { luma(160) } else if q.at("correct", default: false) == true {
let dropped = q.at("dropped", default: false)
let color = if dropped { luma(130) } else if q.at("blank", default: false) {
luma(160)
} else if q.at("correct", default: false) == true {
ok-color
} else if q.at("credit", default: 0.0) > 0.0 { mid-color } else { bad-color }
box(
@@ -763,10 +787,15 @@
#align(center)[
#text(size: size-small, weight: "bold", fill: color.darken(18%))[#q.number]
#{
let level = q.at("level", default: none)
if level != none {
if dropped {
linebreak()
text(size: size-tag, fill: luma(120))[L#level]
text(size: size-tag, fill: luma(110))[out]
} else {
let level = q.at("level", default: none)
if level != none {
linebreak()
text(size: size-tag, fill: luma(120))[L#level]
}
}
}
]