Files
emba-course-solver/CHANGELOG.md
T
Bill 2ebfb9d2ec v1.4.0: Desktop layout redesign + mobile tabs
Specializations move from a 340px left rail to a horizontal 2-row chip
grid at the top (drag L→R to rank). Each chip shows rank, spec-colored
abbreviation tag matching the tags used in plans/schedule, full name on
its own row, status glyph, and a micro credit bar. Hover/tap a chip to
see full status, allocated/threshold credits, and contributing-courses
breakdown in a popover.

The right pane splits into two side-by-side columns on desktop: Top
Plans (left) and Schedule (right), each scrolling independently. The
search progress bar hoists into a global strip below the spec grid so
it stays visible regardless of which column is scrolled.

Schedule blocks render their course choices as a horizontal row of
equal-width buttons (3-5 per set) instead of stacked rows. Pinned sets
collapse to a single line with the course name inline next to the set
title. Term headers (Spring/Summer/Fall) remain as section dividers.

On mobile, the layout becomes a 3-tab segmented control
(Specializations / Plans / Courses) with the search progress strip
above the tabs. The previous floating MobileStatusBanner and
MobileCourseBanner are dropped — tabs replace their navigation
function.
2026-05-09 17:45:28 -04:00

14 KiB
Raw Blame History

Changelog

v1.4.0 — 2026-05-09

Changes

  • Desktop layout redesigned — specializations move from a 340px left rail into a horizontal drag-to-rank chip strip at the top of the page (left = highest priority). The previous right pane splits into two side-by-side columns: Top Plans on the left, Schedule on the right. Each column scrolls independently so the schedule no longer gets pushed below the fold when plans expand.
  • Search progress hoisted to a global strip — the animated progress bar moves out of Top Plans into a thin strip directly below the spec strip. It stays visible regardless of which column you're scrolling. The static "Search complete · N explored" / "Search incomplete · cap hit at N" text remains inline with the Top Plans header.
  • Specialization chips with hover popover — each chip shows rank, full specialization name (line-clamped to 2 lines), status indicator, and a micro credit bar; status is encoded by background color. Hovering (or tapping on touch) opens a popover with the full name, status word, allocated/threshold credits, and — for achieved specializations — the contributing-courses breakdown. The strip scrolls horizontally when the 15 chips don't fit in the available width.
  • Horizontal drag-to-reorder on desktop — switched the spec sort strategy from verticalListSortingStrategy to horizontalListSortingStrategy. Mobile keeps vertical drag.
  • Schedule blocks render horizontal course buttons on desktop — each non-pinned elective set lays its course choices out as a flex row of equal-width buttons (35 per set) instead of stacked rows. Each button shows the info icon (top-left), the recommended star (top-right when applicable), the course name with line-clamp, and a row of spec ceiling tags at the bottom. Cancelled / already-selected / per-course searching states preserve their semantics in the new layout.
  • Compact pinned-set rendering — when a course is pinned, the elective-set card collapses to a single line: Set Name: Course Name [Clear]. The previous separate-row pinned-view block is gone, freeing vertical space.
  • Mobile (≤640px) layout unchanged — vertical specialization list, stacked Top Plans + Schedule sections, in-line progress bar, MobileStatusBanner and MobileCourseBanner all behave as before.

v1.3.3 — 2026-05-09

Changes

  • Lexicographic priority comparison — fixes a scoring bug where combinations of lower-priority specializations could outrank a single higher-priority specialization in priority-order mode. The comparator now uses lex-by-rank: a plan containing a higher-ranked specialization always beats a plan that doesn't, regardless of how many lower-ranked specializations the latter contains. Lower-ranked specializations only act as tiebreakers among plans that all contain the same higher-ranked specs. Same logic also tiebreaks within maximize-count mode.
  • Score display matches the comparator — the per-plan score now shows the lexicographic rank weight in compact form (e.g. score 24.6k) instead of the legacy sum-of-weights. Hover the score for the full integer.
  • Cache cap retains warm entries — when the leaf cache hits the 500k cap, new entries are now dropped instead of clearing the cache; the existing 500k stay as a starting point for subsequent pin/unpin operations.
  • Cache stays valid across the comparator change — leaves cached under v1.3.2 still produce correct rankings under the new comparator since achievedSpecs (the input to lex compare) is unchanged.

v1.3.2 — 2026-05-09

Changes

  • Leaf cache for instant pin/unpin — decision-tree leaf outcomes are now cached on the main thread keyed by their full 12-course assignment. Pin operations filter the cache and re-derive the top-K + per-set ceilings instantly with no worker spawn. Unpin operations show the cached subset immediately and stream improvements as a background worker fills in the missing leaves. The cache persists across pin, unpin, and adopt-plan operations.
  • Cache invalidation — the cache is cleared only when the active mode or the specialization ranking changes. Pin/unpin alone never invalidates.
  • skipKeys worker contract — workers now accept a list of cached assignment keys and skip the optimizer call for any leaf already in the cache, while still counting iterations toward the global progress percentage.
  • leafEvaluated worker event — workers stream individual leaf outcomes to the main thread for cache population as the search progresses.
  • deriveFromLeaves shared helper — pure function that produces the top-K and per-set ceilings from a leaf collection; used by both the main-thread cache filter and the worker's final emission for parity.
  • 500,000-leaf soft cap — the cache is cleared if it grows beyond 500k entries, bounding worst-case memory at ~150 MB. Typical sessions stay well below.

v1.3.1 — 2026-05-09

Changes

  • Exhaustive decision-tree search — replaced the saturation early-termination with full enumeration of the open-set cartesian product. Per-set ceiling cells now reflect the true best outcome for every (set, course) pair instead of leaving most cells stuck at "0 specs". Top Plans surfaces all genuinely-feasible plans, including 3-spec maximize-count plans that the v1.3.0 search missed. The previous iteration cap has been removed; search runs to full completion.
  • Mode-dependent enumeration ordering — priority-order mode keeps the priority-target-first heuristic; maximize-count mode now orders DFS children by descending count of qualifications for reachable specializations, surfacing generalist courses (e.g., Climate Finance with 6 qualifications) before specialists.
  • Mode-aware comparator — top-K and per-cell ceiling rankings now match the active mode: priority-order ranks by (priorityScore, count) so the top-priority spec surfaces; maximize-count ranks by (count, priorityScore) so the highest count wins. Recommended badges follow the same rule.
  • "Recommended" badge per set — each elective set now highlights the choice with the best ceiling outcome under the current mode. Rendered inline next to the course name to keep button height stable.
  • Color-coded spec tags — the per-cell outcome list and the Top Plans badges now use a fixed per-spec color palette so each specialization is visually identifiable at a glance.
  • "Top outcome if picked ↓" caption — added a small column header on each open elective set so the spec tags are clearly identified as decision-tree outcomes (not the course's own qualifications).
  • Visual progress bar — Top Plans header now shows a progress bar with iterations / total · NN% while the search runs, replacing the earlier text-only count.
  • Per-cell streaming indicators — courses that haven't been evaluated yet show a "searching" pulse instead of misleading "0 specs"; cells transition to their final value as the search completes.
  • Per-set spinner — each elective set heading shows a spinner while at least one of its choices is still unevaluated.

v1.3.0 — 2026-05-09

Changes

  • Top Plans panel — new ranked list of up to 10 complete course plans, each showing the achieved specializations and the courses to pin. An "Adopt plan" button pins all of a plan's courses in one click. Updates progressively as the search finds better outcomes.
  • Priority-aware decision tree — fixes the bug where a specialization could show "Achievable" without any per-set ceiling cell surfacing it. The decision-tree search now compares enumerated combinations by (count desc, priority score desc) and reorders DFS children so courses qualifying for the user's first reachable ranked spec are tried first, surfacing high-priority outcomes early.
  • Bounded search with saturation termination — search stops when the top-K stabilizes (default 500 stable iterations) or when the iteration cap (10000) is hit; partial results are flagged in the UI.
  • Per-cell streaming — the worker now emits per-cell ceiling updates instead of per-set rollups, so the per-set table refines progressively rather than appearing in coarse chunks.

v1.2.2 — 2026-05-09

Changes

  • Healthcare specialization (HCR) — added 15th specialization, Healthcare; qualifies via The Business of Health & Medical Care (Spring Set 2), Analytics & Machine Learning for Managers (Spring Set 3), Digital Marketing Strategy in Practice (Summer Set 2), and Managing Change (Fall Set 1); 10 total credits available, no required course gate
  • Course rename — "Social Media and Mobile Technology" renamed to "Digital Marketing Strategy in Practice"; description replaced with new MSKCC-anchored content covering digital strategy and agentic AI; instructor cleared pending confirmation
  • Cancellations (Approach B) — switched from delete-and-replace to flagging cancelled courses with cancelled: true. "Customer Insights" (Spring Set 5) is now marked cancelled. "Managing Growing Companies" reappears in Summer Set 2 as a cancelled placeholder per the J27 sheet
  • Reachability testdata.test.ts now excludes cancelled courses when counting per-spec set reachability, so future cancellations are caught by an obvious assertion failure

v1.2.1 — 2026-03-27

Bug Fixes

  • Achievable status accuracy — specializations marked "Achievable" are now verified via LP feasibility check against already-achieved specs; previously, a specialization could show "Achievable" based on raw credit potential while actually being infeasible due to credit sharing with higher-priority achieved specializations

v1.2.0 — 2026-03-27

Changes

  • Course info popovers — each course now has an info icon that opens a popover showing the course description, instructor(s), and specialization tags, extracted from the J27 Electives PDF; opens on hover (desktop) or tap (mobile), with smart positioning that flips above when near the bottom of the viewport
  • Page title and favicon — updated browser tab from "app" with Vite icon to "EMBA Specialization Solver" with a graduation cap favicon in NYU Stern purple
  • Viewport-fitted layout — desktop layout now fits within the viewable area without page-level scrolling; each pane scrolls independently

v1.1.1 — 2026-03-27

Changes

  • Course replacement — replaced cancelled "Managing Growing Companies" with new course "Innovation and Design" in Summer Elective Set 2; qualifies for Brand Management, Entrepreneurship and Innovation, Marketing, and Strategy (S2)

v1.1.0 — 2026-03-13

Changes

  • Cancelled course support — "Managing Growing Companies" (Summer Elective Set 2) is marked as cancelled and rendered with strikethrough, greyed-out styling, and a "(Cancelled)" label; it is excluded from solver computations and decision tree enumeration
  • Duplicate course prevention — courses that appear in multiple elective sets (e.g., "Global Immersion Experience II" in Spring Set 1 and Summer Set 1, "The Financial Services Industry" in Spring Set 2 and Fall Set 4) are now linked; selecting one automatically disables and excludes its duplicate from selection and solver calculations, shown with an "(Already selected)" label
  • Credit bar tick marks — specialization progress bars now display light vertical tick marks at 2.5-credit intervals for visual scale reference, layered above bar fills with the 9.0 threshold marker remaining visually distinct

v1.0.0 — 2026-02-28

Initial release of the EMBA Specialization Solver.

Features

  • Optimization engine — LP-based credit allocation solver with two modes:
    • Maximize Count — finds the largest feasible set of specializations, using ranking as tiebreaker
    • Priority Order — greedily adds specializations in user-ranked order
  • Course selection UI — select one course per elective set across 12 sets (Spring, Summer, Fall terms)
  • Drag-and-drop specialization ranking — reorder the 14 specializations by priority with touch and keyboard support
  • Decision tree analysis — Web Worker enumerates remaining course combinations to compute ceiling outcomes per choice
  • Status tracking — each specialization classified as achieved, achievable, missing required course, or unreachable
  • Mode comparison — displays what the alternative optimization mode would produce
  • Credit bars and allocation breakdowns — visual progress toward the 9-credit threshold with expandable per-course detail
  • Credit legend — collapsible explainer for bars, badges, and limits
  • Required course labels — courses that are prerequisites for a specialization show "Required for ..." labels
  • Algorithm explanations — clear descriptions of how each optimization mode works
  • Skeleton loading — placeholder UI while decision tree analysis runs
  • Auto-expand achieved specializations — achieved specs show their credit breakdown by default
  • Responsive layout — two-panel grid on desktop/tablet, single-column on mobile
  • Mobile floating banners — top banner summarizes specialization statuses, bottom banner shows selection progress (N/12); both appear via IntersectionObserver and scroll to their sections on tap
  • CSS transitions and animations — cross-fade course pin/unpin, credit bar width changes, status badge color transitions, expand/collapse panels, mode toggle switching, flash on status changes; all respect prefers-reduced-motion
  • State persistence — rankings and selections saved to localStorage
  • Docker deployment — multi-stage Dockerfile (Node 22 build → Nginx Alpine serve) with Docker Compose, gzip compression, SPA fallback routing, immutable cache headers for hashed assets, configurable port (default 8080)
  • Full test suite — data integrity, feasibility solver, optimizer, and decision tree tests via Vitest

Constraints Modeled

  • Credit non-duplication (2.5 credits per course shared across specializations)
  • Maximum 3 specializations (30 total credits, 9 required each)
  • Required course prerequisites for 4 specializations
  • Strategy S1/S2 tier system (at most 1 S2 course contributes to Strategy)
  • Mutual exclusion from same-set conflicts