aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-10-18 14:32:57 +0200
committerAgando <roduccomm@gmail.com>2026-10-18 14:32:57 +0200
commit4d3fa20151e101d6486d5b57935370d93e0fcffe (patch)
tree1b7f6b77bde45b1c5f6172a53308d81f49b14866
parentee8a03a63adfb8db1edf38de72645d685cffff2e (diff)
course: exclude auto-open from lesson_open telemetry, add session counts, filter synthetic sids
-rw-r--r--course.html6
-rw-r--r--scripts/course-insights.py10
2 files changed, 9 insertions, 7 deletions
diff --git a/course.html b/course.html
index c61a901..c14979c 100644
--- a/course.html
+++ b/course.html
@@ -132,9 +132,9 @@ async function renderChapters(){
}
const p2 = prog(); const all = (MANIFEST.chapters||[]).flatMap(c=>(c.lessons||[]).map(l=>({c,l})));
const first = all.find(x=>!p2.completed[x.l.id]) || all[0];
- if(first) openLesson(first.c.id, first.l.id);
+ if(first) openLesson(first.c.id, first.l.id, false);
}
-async function openLesson(chId, lessonId){
+async function openLesson(chId, lessonId, doTrack = true){
$('reader').innerHTML = '<p class="small">Loading lesson…</p>';
try{
const ch = await fetch(BASE+'chapters/'+chId+'.json?v='+V).then(r=>r.json());
@@ -171,7 +171,7 @@ async function openLesson(chId, lessonId){
$('quiz-msg').style.color = ok ? 'var(--green)' : 'var(--rose)';
if(ok) completeLesson(l.id, 5);
});
- track('lesson_open', {lesson:l.id});
+ if (doTrack) track('lesson_open', {lesson:l.id});
}catch(e){ $('reader').innerHTML = '<p style="color:var(--rose)">Failed: '+esc(e.message)+'</p>'; }
}
function completeLesson(id, xp){
diff --git a/scripts/course-insights.py b/scripts/course-insights.py
index 0ee891e..299b264 100644
--- a/scripts/course-insights.py
+++ b/scripts/course-insights.py
@@ -14,21 +14,23 @@ def norm_q(q):
def main():
opens, completes, fails, cmds, questions = Counter(), Counter(), Counter(), Counter(), Counter()
- projects = Counter()
+ projects = Counter(); sids = set()
files = sorted(glob.glob(os.path.join(DATA, 'events-*.jsonl')))[-2:]
for path in files:
with open(path, encoding='utf-8', errors='ignore') as f:
for line in f:
try: e = json.loads(line)
except Exception: continue
+ if (e.get('sid') or '').startswith('test'): continue
t, d = e.get('type'), e.get('detail') or {}
lesson = (d.get('lesson') or '')[:40]
- if t == 'lesson_open' and lesson: opens[lesson] += 1
- elif t == 'lesson_complete' and lesson: completes[lesson] += 1
+ if t == 'lesson_open' and lesson: opens[lesson] += 1; sids.add(e.get('sid') or '')
+ elif t == 'lesson_complete' and lesson: completes[lesson] += 1; sids.add(e.get('sid') or '')
elif t == 'exercise_fail':
if lesson: fails[lesson] += 1
c = (d.get('command') or '').strip().split(' ')[0][:40]
if c: cmds[c] += 1
+ sids.add(e.get('sid') or '')
elif t == 'question':
q = norm_q(d.get('q'))
if len(q) >= 8: questions[q] += 1
@@ -46,7 +48,7 @@ def main():
'top_failed_commands': [{'cmd': c, 'n': n} for c, n in cmds.most_common(20)],
'top_questions': [{'q': q, 'n': n} for q, n in questions.most_common(20) if n >= 2],
'projects': dict(projects),
- 'totals': {'opens': sum(opens.values()), 'completes': sum(completes.values()), 'failures': sum(fails.values())}}
+ 'totals': {'sessions': len(sids), 'opens': sum(opens.values()), 'completes': sum(completes.values()), 'failures': sum(fails.values())}}
os.makedirs(os.path.dirname(OUT), exist_ok=True)
tmp = OUT + '.tmp'
with open(tmp, 'w', encoding='utf-8') as f: json.dump(payload, f, ensure_ascii=False, indent=1)