Skip to content

fix(display): count completions per track + decouple hero total - #2935

Merged
jung-thomas merged 2 commits into
DEVfrom
worktree-display-path-buckets
Oct 26, 2026
Merged

jung-thomas merged 2 commits into
DEVfrom
worktree-display-path-buckets

Conversation

@jung-thomas

Copy link
Copy Markdown
Contributor

Summary

Two regressions from the initial track-grouping fix (#2933), both reported on the live PROD display:

  1. Per-track bars counted distinct users, not completions. computePathBuckets deduped by (user, track), so 5 completions by one attendee read as 1. → now counts every TUTORIAL completion in a track (no user dedup).
  2. Hero "total activity" counter collapsed. It summed bucket counts; once buckets became track-scoped, the hero dropped from all window completions (~62) to only track-member completions (3), and double-counted tutorials shared across tracks. → computePathBuckets now returns { buckets, totalCompletions }; totalCompletions = all window TUTORIAL completions, track-independent.

Changes

  • srv/lib/event-path-buckets.js — count completions (not users); return { buckets, totalCompletions }.
  • srv/event-stream-service.{js,cds} — expose totalCompletions; declare new completionTick event.
  • srv/display-service.{js,cds} — unpack .buckets (admin array contract unchanged); declare completionTick.
  • srv/developer-service.js — socket now fires completionTick once per active event for every completion (drives hero), plus tutorialCompleted per matching track (drives bars).
  • app/display-app/src/event-stream.ts — totalCount seeded from totalCompletions (falls back to bucket sum for old servers), bumped by completionTick; no longer summed from buckets.

Deferred (data issue, not display)

Checkpoints: probe of event 10000002 shows 0 window checkpoint completions and all 7 checkpoint path items have null taskLegacyId (no join key) — counting them would be inert. The two prize-only Joule tracks reading 0 is dead-slot path data (11 null-legacyId tutorial items in the mission), tracked separately.

Verification

  • 45 unit tests pass (new: completions-not-users, totalCompletions incl. no-track + no-window cases).
  • PROD probe event 10000002: totalCompletions=62, ABAP=3 (was 2 under user-dedup), Joule Studio=1.

Test plan

  • Deploy to DEV, load display-app on event 10000002 — hero shows total activity (~62), track bars show completion counts, live completions bump both correctly

Two regressions from the initial track-grouping change, both reported live:

1. Per-track bars counted DISTINCT USERS, not completions. computePathBuckets
   deduped by (user, track), so 5 completions by one attendee read as 1.
   → count every TUTORIAL completion in a track (no user dedup).

2. The hero "total activity" counter summed bucket counts. Once buckets became
   track-scoped, the hero collapsed from all window completions (~62) to only
   track-member completions (3) — and double-counted tutorials shared across
   tracks. → computePathBuckets now returns { buckets, totalCompletions };
   totalCompletions = ALL window TUTORIAL completions, track-independent.

Frontend (event-stream.ts): totalCount is seeded from totalCompletions on fetch
(falls back to bucket sum for older servers) and bumped by a new per-completion
`completionTick` socket event — NOT by summing buckets. Track bars still driven
by `tutorialCompleted` (one per track). A completion outside every track ticks
the hero but adds no bar; a multi-track tutorial ticks the hero once (one tick
per active event) while lighting each of its track bars.

Backend socket emit (developer-service.js) now fires `completionTick` once per
active event for every completion, plus `tutorialCompleted` per matching track.
New `completionTick` event declared on both EventStreamService + DisplayService.

Checkpoints DEFERRED: probe of event 10000002 shows 0 window checkpoint
completions and all 7 checkpoint path items carry null taskLegacyId (no join
key) — counting them would be inert. The two prize-only Joule tracks reading 0
is dead-slot path data (11 null-legacyId tutorial items in the mission), a
content issue tracked separately, not a display bug.

Verified against PROD event 10000002: totalCompletions=62, ABAP=3 (was 2 under
user-dedup), Joule Studio=1.
…skLegacyId

buildTrackMap matched completions to tracks using only CompletionPathItems.
taskLegacyId. But manually-authored event content (#1866) populates the item's
tutorial_ID FK (UUID) and leaves taskLegacyId NULL — the normal shape for the
TechEd/DSAG event missions, not a data defect. Those FK-only items fell through
entirely, so whole tracks with real tutorials AND real completions ("Joule
Studio with N8N", "Keynote Demo", "Agent Extension", "Command Line", "Frontend")
counted 0.

Resolve FK-first, mirroring path-item-task-resolver.buildTaskMap:
- direct TUTORIAL items: prefer tutorial_ID → Tutorials.legacyId, else taskLegacyId
- GROUP children (GroupPathItems): resolve tutorial_ID → legacyId too
- CHECKPOINT/PETOBERFEST unchanged (no FK column)
All collected tutorial_ID UUIDs resolved to legacyId in one batch, then the map
is keyed by legacyId (what TaskRecords.taskLegacyId carries).

Verified against PROD event 10000002: previously-zero tracks now count —
"Joule Studio with N8N"=1, "Joule Studio Keynote Demo"=1 (the two tracks the
reporter completed), alongside "Joule Studio"=1, "ABAP"=3; totalCompletions=66.

New unit test: Track Gamma fed by an FK-only path item (tutorial_ID set,
taskLegacyId NULL) + a completion carrying the resolved legacyId → counts 1.
@jung-thomas

Copy link
Copy Markdown
Contributor Author

Added a third fix (commit 3b2ab68): resolve track path items by tutorial_ID FK, not just taskLegacyId.

The reporter flagged that tracks they'd completed ("Joule Studio with N8N", "Keynote Demo") still showed 0. Root cause: buildTrackMap matched completions to tracks using only CompletionPathItems.taskLegacyId, but manually-authored event content (#1866) sets the item's tutorial_ID FK and leaves taskLegacyId NULL — the normal shape for the TechEd/DSAG event missions. Those FK-only items fell through, so whole tracks with real tutorials and real activity counted 0.

Now FK-first (mirrors path-item-task-resolver.buildTaskMap): direct TUTORIAL items and GROUP children resolve tutorial_ID → Tutorials.legacyId, then the map is keyed by legacyId. CHECKPOINT/PETOBERFEST unchanged.

PROD probe event 10000002 after fix: "Joule Studio with N8N"=1, "Joule Studio Keynote Demo"=1 (both now appear), "Joule Studio"=1, "ABAP"=3, totalCompletions=66. New unit test covers an FK-only path item.

@jung-thomas
jung-thomas merged commit 816516e into DEV Oct 26, 2026
5 of 6 checks passed
@jung-thomas
jung-thomas deleted the worktree-display-path-buckets branch October 26, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant