cb49123930
The v1.3.0 saturation termination silently capped the search after only
the heuristic-favored part of the tree, leaving most per-set ceiling cells
stuck at "0 specs" and hiding genuinely-feasible 3-spec plans in
maximize-count mode. Replace with full exhaustive enumeration plus a
batch of UX refinements that emerged during testing.
Algorithm:
- Drop the saturation early-termination entirely. Search now runs the
full open-set cartesian product to completion; the iteration cap is
also removed so no scenario exits partial.
- Add mode-dependent DFS child ordering: priority-order keeps the
priority-target-first heuristic; maximize-count orders children by
descending count of qualifications for reachable specs (generalist
courses tried first).
- Make the (count, priorityScore) comparator mode-aware: priority-order
ranks by (priorityScore, count) so the user's top spec surfaces;
maximize-count ranks by (count, priorityScore) so the highest count
wins. The same rule drives both top-K position and per-cell ceiling
selection (and the Recommended badge).
- Add an evaluated boolean to each ChoiceOutcome and set it on first
leaf evaluation. Distinguishes "still searching" from "evaluated, no
specs achieved" so the UI never shows misleading 0 specs for a cell
the search hasn't reached yet.
- Throttled progress events (~100ms) carrying iterations / total leaf
count, drive both the per-set spinner and the global progress bar.
UI:
- Top Plans header shows a horizontal progress bar with
"iterations / total · NN%" while the search runs; collapses to
"Search complete · N explored" on completion.
- Per-set spinner next to each elective set heading while any choice
in that set is unevaluated.
- Per-cell pulsing dot + "searching" text for unevaluated cells.
- Replace the "(HCR, BNK, ...)" text labels on each course with
color-coded SpecTag pills using a new fixed per-spec palette
(app/src/data/specColors.ts). Same palette applied to the Top Plans
achievement badges so the two views are visually consistent.
- "Top outcome if picked ↓" caption above the right side of each open
elective set so the spec tags are clearly identified as decision-tree
outcomes (not the course's own qualifications).
- Recommended badge moved inline next to the course name (instead of
on a separate row below) to keep button heights stable.
Tests:
- Replace the saturation early-termination test with an exhaustion test
asserting every cell ends with evaluated: true and partial: false.
- Add mode-dependent ordering test (max-count visits Climate Finance
before Corporate Governance in fall3).
- Add evaluated-flag transition test.
- Add throttled progress-event test (>= ~100ms between consecutive
emits).
- Performance smoke updated to a 60s budget for the exhaustive
user-scenario search; 8-open-set typical case completes in ~7s.
Files: solver/decisionTree.ts, solver/priority.ts (already shipped),
data/specColors.ts (new), components/{TopPlans,CourseSelection}.tsx,
state/appState.ts, workers/decisionTree.worker.ts,
__tests__/searchDecisionTree.test.ts, vite.config.ts, CHANGELOG.md,
openspec/changes/decision-tree-exhaustive-search/* (full change spec).
9.2 KiB
9.2 KiB
Changelog
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 test —
data.test.tsnow 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