Skip to content

Commit a3843d1

Browse files
sidprasadclaude
andauthored
Render the trace diagrams in misconception explainers (#177)
The "recommended review" card on the home page embeds a misconception explainer fragment, and two of the eight (implicitf, exclusiveu) build their argument around trace diagrams. index.html was the only page emitting .trace-diagram markup without loading tracerenderer.js, so those diagrams stayed empty divs: the Finally explainer ended on "Thus both these traces satisfy F p:" followed by nothing. It read as intermittent because the card picks one explainer at random from the student's top two misconceptions, and most explainers have no traces to lose. Load the renderer on the home page and run a render pass there. The three copies of that pass (home page, exercise questions, answer feedback) collapse into one TraceRenderer.renderAll(root), so the next page to emit trace markup only has to call it. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 75fe12f commit a3843d1

6 files changed

Lines changed: 41 additions & 21 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
This document summarizes notable updates since February 2025, with commit dates from the repository history for context.【728428†L1-L48】
44

55
## 2026-07
6+
- **Bugfix (2.1.6):** The trace diagrams inside misconception explainers never rendered. Explainers are shown in the "recommended review" card on the home page, but `index.html` was the one page emitting `.trace-diagram` markup without loading `tracerenderer.js`, so the diagrams stayed empty `<div>`s — leaving the Finally explainer ending on "Thus both these traces satisfy `F p`:" followed by nothing, and the Until explainer missing the trace its closing sentence refers to. It looked intermittent because only two of the eight explainers (`implicitf`, `exclusiveu`) illustrate the operator with traces, and the card shows one explainer drawn at random from the student's top two misconceptions. The home page now loads the renderer and runs a render pass. The three copies of that pass (home page, exercise questions, answer feedback) are now one `TraceRenderer.renderAll(root)` helper, so a page that emits trace markup only has to call it.
67
- **UX (2.1.5):** The "unclear sentence" report control on english-to-LTL questions no longer reads as a heading for the answer options. It was a bold rust question ("Is this English sentence confusing or unclear?") sitting an equal distance from the stem above and the radio list below, so it grouped with neither; its `.row.ml-2` wrapper also pulled it left of the stem's text edge, since Bootstrap's `.row` sets `margin-left: -15px` and `ml-2` only partly cancels it. It is now a quiet caption-style link reading "Report unclear wording" (imperative, so it cannot be mistaken for the question to answer), tucked under the sentence with asymmetric spacing (about 4px above, 18px below) that groups it with the stem. Being quiet means losing the color signal, so it carries a permanent underline rather than color alone (WCAG 1.4.1), and uses `--ink-2` at 8:1 rather than the muted `--ink-3`, which is 4.17:1 on the card and under AA for small text; color returns on hover and focus. The control stays a sibling of `.actualQuestion`, so its label never leaks into the logged `question_text`. The modal, its route, and its payload are unchanged.
78
- **A11y (2.1.5):** The keyboard focus ring now actually appears on that control. The theme's global ring is a zero-specificity `:where(...):focus-visible` rule, which Bootstrap's `.btn:focus { outline: 0 }` outranks on any button, so the only focus signal would have been a color shift; `.btn.unclear-flag:focus-visible` restates it at (0,3,0). The letter key also uses `--ink-2` (8:1) rather than `text-muted` (`--ink-3`, 4.17:1 on the card, under AA at that size), since the key is the only place the letters in the options are defined. The rest of the page still pairs `text-muted` with `small` at that sub-AA ratio (card-header meta, question description); that is pre-existing and wants its own pass.
89
- **Bugfix (2.1.4):** Themed english-to-LTL questions now state what their letters mean. The sentence was in words ("the document is open") while every answer option was in letters (`d`, `c`), and nothing connected the two, so a student also had to guess that `d` names the document being *open*, not the document, which has more than one state. Each themed question now carries a key listing only the literals its formula uses (`d`: the document is open), rendered above the sentence. Themed responses logged before this fix measured LTL reading confounded with guessing the naming, and both themed arms are affected; per-arm analyses spanning the change should be segmented. The abstract control arm is untouched, since it quotes its literals in the prose already and there is nothing to look up.

src/static/js/checkanswers.js

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,7 @@ function show_feedback(parent_node, question_type) {
254254

255255
// Render any trace diagrams in the feedback (e.g. misconception explainers)
256256
if (typeof TraceRenderer !== 'undefined') {
257-
feedback_div.querySelectorAll('.trace-diagram').forEach(function (el) {
258-
if (el.dataset.trace && !el.dataset.rendered) {
259-
try {
260-
TraceRenderer.render(el, JSON.parse(el.dataset.trace));
261-
el.dataset.rendered = 'true';
262-
} catch (e) { /* ignore rendering errors in feedback diagrams */ }
263-
}
264-
});
257+
TraceRenderer.renderAll(feedback_div);
265258
}
266259

267260
// Increment the incorrect count

src/static/js/tracerenderer.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,5 +501,31 @@ var TraceRenderer = (function () {
501501
container.appendChild(svg);
502502
}
503503

504-
return { render: render };
504+
/**
505+
* Render every not-yet-rendered `.trace-diagram[data-trace]` under `root`.
506+
*
507+
* Any page that emits trace markup (question options, feedback, the
508+
* misconception explainer fragments) needs a pass like this; keeping one
509+
* copy here means a new page only has to load this script and call it.
510+
*
511+
* @param {HTMLElement|Document} [root] Defaults to the whole document.
512+
*/
513+
function renderAll(root) {
514+
var scope = root || document;
515+
var nodes = scope.querySelectorAll('.trace-diagram');
516+
for (var i = 0; i < nodes.length; i++) {
517+
var el = nodes[i];
518+
if (!el.dataset.trace || el.dataset.rendered) {
519+
continue;
520+
}
521+
try {
522+
render(el, JSON.parse(el.dataset.trace));
523+
el.dataset.rendered = 'true';
524+
} catch (e) {
525+
console.error('Error rendering trace diagram', e);
526+
}
527+
}
528+
}
529+
530+
return { render: render, renderAll: renderAll };
505531
})();

src/templates/exercise.html

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,8 @@ <h6 class="text-muted mb-3">What's next?</h6>
194194

195195
const ui_load_timeout_delay = 150;
196196
function renderTraceDiagrams(container) {
197-
$(container).find('.trace-diagram').each(function () {
198-
var el = this;
199-
if (el.dataset.trace && !el.dataset.rendered) {
200-
try {
201-
var data = JSON.parse(el.dataset.trace);
202-
TraceRenderer.render(el, data);
203-
el.dataset.rendered = 'true';
204-
} catch (e) {
205-
console.error('Error rendering trace diagram', e);
206-
}
207-
}
197+
$(container).each(function () {
198+
TraceRenderer.renderAll(this);
208199
});
209200
}
210201

src/templates/index.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
{% block head %}
44
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@1.1.0/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
55
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
6+
<!-- The recommended-review card embeds a misconception explainer, and some
7+
explainers illustrate the operator with trace diagrams. -->
8+
<script src="{{ url_for('static', filename='js/tracerenderer.js') }}"></script>
69
{% endblock %}
710

811
{% block content %}
@@ -155,5 +158,11 @@ <h6 class="text-muted mb-3">Have an exercise code?</h6>
155158
var exerciseId = document.getElementById('exerciseIdInput').value;
156159
window.location.href = '/exercise/load/' + exerciseId;
157160
}
161+
162+
document.addEventListener('DOMContentLoaded', function () {
163+
if (typeof TraceRenderer !== 'undefined') {
164+
TraceRenderer.renderAll();
165+
}
166+
});
158167
</script>
159168
{% endblock %}

src/templates/version.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.5
1+
2.1.6

0 commit comments

Comments
 (0)