v1.2.2: Add Healthcare specialization, mark cancelled courses, rename Digital Marketing

Apply the J27 (5/6/2026) Stern specialization sheet:

- Add Healthcare (HCR) as the 15th specialization, with HCR cross-listings on
  spr2-health-medical, spr3-analytics-ml, sum2-social-media (renamed), and
  fall1-managing-change. 10 credits available, no required-course gate.
- Rename sum2-social-media to "Digital Marketing Strategy in Practice";
  replace its description with new MSKCC-anchored content; clear instructor
  pending confirmation of new lead.
- Switch from delete-and-replace to the previously-unused cancelled flag
  (Approach B): mark spr5-customer-insights cancelled, add Managing Growing
  Companies back to Summer Set 2 as a cancelled placeholder per the printed
  sheet.
- Update data integrity tests: course count 46 -> 47, spec count 14 -> 15;
  per-spec "across sets" helper now filters cancelled courses so future
  cancellations trigger an obvious assertion failure (BRM 6 -> 5,
  MKT 7 -> 6, HCR 4 new).
- Replace hardcoded 14 in optimizer.test.ts with SPECIALIZATIONS.length.
This commit is contained in:
2026-05-09 14:50:26 -04:00
parent 0beafb58b5
commit 4d6f81d1e5
14 changed files with 325 additions and 20 deletions
+9
View File
@@ -1,5 +1,14 @@
# Changelog # Changelog
## 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.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 ## v1.2.1 — 2026-03-27
### Bug Fixes ### Bug Fixes
+12 -9
View File
@@ -5,16 +5,16 @@ import { SPECIALIZATIONS } from '../specializations';
import { coursesBySet, coursesBySpec } from '../lookups'; import { coursesBySet, coursesBySpec } from '../lookups';
describe('Data integrity', () => { describe('Data integrity', () => {
it('has exactly 46 courses', () => { it('has exactly 47 courses', () => {
expect(COURSES.length).toBe(46); expect(COURSES.length).toBe(47);
}); });
it('has exactly 12 elective sets', () => { it('has exactly 12 elective sets', () => {
expect(ELECTIVE_SETS.length).toBe(12); expect(ELECTIVE_SETS.length).toBe(12);
}); });
it('has exactly 14 specializations', () => { it('has exactly 15 specializations', () => {
expect(SPECIALIZATIONS.length).toBe(14); expect(SPECIALIZATIONS.length).toBe(15);
}); });
it('every course belongs to a valid set and that set references the course', () => { it('every course belongs to a valid set and that set references the course', () => {
@@ -78,30 +78,33 @@ describe('Data integrity', () => {
}); });
describe('per-specialization "across sets" counts match reachability table', () => { describe('per-specialization "across sets" counts match reachability table', () => {
// Expected counts: number of distinct sets that have at least one qualifying course // Expected counts: number of distinct sets that have at least one non-cancelled qualifying course
const expectedAcrossSets: Record<string, number> = { const expectedAcrossSets: Record<string, number> = {
MGT: 11, MGT: 11,
STR: 9, STR: 9,
LCM: 9, LCM: 9,
FIN: 9, FIN: 9,
CRF: 8, CRF: 8,
MKT: 7, MKT: 6,
BNK: 6, BNK: 6,
BRM: 6,
FIM: 6, FIM: 6,
MTO: 6, MTO: 6,
BRM: 5,
GLB: 5, GLB: 5,
EMT: 4, EMT: 4,
ENT: 4, ENT: 4,
HCR: 4,
SBI: 4, SBI: 4,
}; };
for (const [specId, expected] of Object.entries(expectedAcrossSets)) { for (const [specId, expected] of Object.entries(expectedAcrossSets)) {
it(`${specId} qualifies across ${expected} sets`, () => { it(`${specId} qualifies across ${expected} sets`, () => {
const entries = coursesBySpec[specId] || []; const entries = coursesBySpec[specId] || [];
const courseIds = entries.map((e) => e.courseId);
const setIds = new Set( const setIds = new Set(
courseIds.map((cid) => COURSES.find((c) => c.id === cid)!.setId) entries
.map((e) => COURSES.find((c) => c.id === e.courseId)!)
.filter((c) => !c.cancelled)
.map((c) => c.setId)
); );
expect(setIds.size).toBe(expected); expect(setIds.size).toBe(expected);
}); });
+2 -2
View File
@@ -114,8 +114,8 @@ export const COURSE_DESCRIPTIONS: Record<string, CourseInfo> = {
instructors: ['Luke Williams'], instructors: ['Luke Williams'],
}, },
'sum2-social-media': { 'sum2-social-media': {
description: 'This course is designed to provide business leaders with a framework for a company to evaluate social media and enhance their integrated marketing campaigns. You will be provided with the tools to understand the current mobile technology landscape. This course covers important issues that leaders must have a POV on, including: data privacy, marketing technology, mobile video, and top mobile advertising companies. This course strikes a balanced approach of covering the pressing issues of today and timeless foundational marketing principles.\n\nThis is a fast-paced course that is designed for you to learn the basic concepts, terms, and principles that apply to the social media industry. To become familiar with key strategic issues across the sector, you will analyze the activities of the leading social media companies and applications through articles, case studies, and lectures. By the conclusion of the course, as a senior executive you will have gained an understanding of the opportunities and challenges your organization must consider as it manages its social media and mobile technology platforms.', description: 'Digital strategy drives business performance. It shapes how companies capture demand and design customer experiences. At senior management levels today, digital fluency is expected. Business leaders know where to focus their teams, what to prioritize, and where customer understanding driven by agentic AI can create competitive advantage.\n\nThe course centers on live engagement with the senior digital strategy team at Memorial Sloan Kettering Cancer Center - one of the top two cancer centers in the country. Teams will develop and present a digital strategy that encourages patients under the age of 40 to seek their care at MSKCC.\n\nYou\'ll build a practical framework connecting segmentation, positioning, content, channels, platforms, AI, and performance measurement. Increasingly, this includes agentic AI - systems that don\'t just generate outputs, but act: orchestrating journeys, adapting content in real time. The challenge is not access to these capabilities but knowing where and how to deploy them for impact.\n\nTara Liggins, VP of Engagement at L\'Oréal, will join several sessions to show how digital strategy translates into digital tactical engagement. Dr. Nnamdi Ezeanochie, a thought leader at Google Gemini will lead a session on how all aspects of AI is reshaping strategy - from passive tools to systems that act, decide, and optimize.\n\nBy the end of this course, students will not just understand digital strategy. Importantly, they will leave with the confidence and judgment to LEAD cross-functional teams, influence executive stakeholders, and drive digital strategies that don\'t sit on slides - but get funded, implemented, and deliver results.',
instructors: ['Stewart Krentzman'], instructors: [],
}, },
'sum2-leading-ai': { 'sum2-leading-ai': {
description: 'We\'re at a new age, an age where artificial intelligence is becoming the most influential General Purpose Technology, a technology that once arrived, is poised to morph all aspects of our lives, irreversibly. Artificial Intelligence (AI) rapidly moves into the mainstream, supported by emerging capabilities in cloud and quantum computing, big data, open source software, and ML algorithms to name a few key forces. AI is already demonstrating capabilities that generate greater efficiencies, precision, and personalization, and at times, greater creative output than humans. And with this growing capacity, there grow questions regarding the business value of AI, the societal implications of deploying this technology, and of course, new and intriguing ethical considerations. This course will introduce you to some of the major disruptive Artificial Intelligence developments, concepts, and considerations, and will address the future of work questions as we lead and evolve/sustain AI-enabled businesses.', description: 'We\'re at a new age, an age where artificial intelligence is becoming the most influential General Purpose Technology, a technology that once arrived, is poised to morph all aspects of our lives, irreversibly. Artificial Intelligence (AI) rapidly moves into the mainstream, supported by emerging capabilities in cloud and quantum computing, big data, open source software, and ML algorithms to name a few key forces. AI is already demonstrating capabilities that generate greater efficiencies, precision, and personalization, and at times, greater creative output than humans. And with this growing capacity, there grow questions regarding the business value of AI, the societal implications of deploying this technology, and of course, new and intriguing ethical considerations. This course will introduce you to some of the major disruptive Artificial Intelligence developments, concepts, and considerations, and will address the future of work questions as we lead and evolve/sustain AI-enabled businesses.',
+11 -5
View File
@@ -22,7 +22,7 @@ export const COURSES: Course[] = [
}, },
{ {
id: 'spr2-health-medical', name: 'The Business of Health & Medical Care', setId: 'spr2', id: 'spr2-health-medical', name: 'The Business of Health & Medical Care', setId: 'spr2',
qualifications: [{ specId: 'STR', marker: 'S2' }], qualifications: [{ specId: 'HCR', marker: 'standard' }, { specId: 'STR', marker: 'S2' }],
}, },
{ {
id: 'spr2-human-rights', name: 'Human Rights and Business', setId: 'spr2', id: 'spr2-human-rights', name: 'Human Rights and Business', setId: 'spr2',
@@ -54,7 +54,7 @@ export const COURSES: Course[] = [
}, },
{ {
id: 'spr3-analytics-ml', name: 'Analytics & Machine Learning for Managers', setId: 'spr3', id: 'spr3-analytics-ml', name: 'Analytics & Machine Learning for Managers', setId: 'spr3',
qualifications: [{ specId: 'MTO', marker: 'standard' }], qualifications: [{ specId: 'HCR', marker: 'standard' }, { specId: 'MTO', marker: 'standard' }],
}, },
// === Spring Elective Set 4 === // === Spring Elective Set 4 ===
@@ -91,6 +91,7 @@ export const COURSES: Course[] = [
{ {
id: 'spr5-customer-insights', name: 'Customer Insights', setId: 'spr5', id: 'spr5-customer-insights', name: 'Customer Insights', setId: 'spr5',
qualifications: [{ specId: 'BRM', marker: 'standard' }, { specId: 'MKT', marker: 'standard' }], qualifications: [{ specId: 'BRM', marker: 'standard' }, { specId: 'MKT', marker: 'standard' }],
cancelled: true,
}, },
// === Summer Elective Set 1 === // === Summer Elective Set 1 ===
@@ -108,6 +109,11 @@ export const COURSES: Course[] = [
}, },
// === Summer Elective Set 2 === // === Summer Elective Set 2 ===
{
id: 'sum2-managing-growing-companies', name: 'Managing Growing Companies', setId: 'sum2',
qualifications: [],
cancelled: true,
},
{ {
id: 'sum2-innovation-design', name: 'Innovation and Design', setId: 'sum2', id: 'sum2-innovation-design', name: 'Innovation and Design', setId: 'sum2',
qualifications: [ qualifications: [
@@ -116,8 +122,8 @@ export const COURSES: Course[] = [
], ],
}, },
{ {
id: 'sum2-social-media', name: 'Social Media and Mobile Technology', setId: 'sum2', id: 'sum2-social-media', name: 'Digital Marketing Strategy in Practice', setId: 'sum2',
qualifications: [{ specId: 'BRM', marker: 'standard' }, { specId: 'EMT', marker: 'standard' }, { specId: 'MKT', marker: 'standard' }], qualifications: [{ specId: 'BRM', marker: 'standard' }, { specId: 'EMT', marker: 'standard' }, { specId: 'HCR', marker: 'standard' }, { specId: 'MKT', marker: 'standard' }],
}, },
{ {
id: 'sum2-leading-ai', name: 'Leading in the Age of AI', setId: 'sum2', id: 'sum2-leading-ai', name: 'Leading in the Age of AI', setId: 'sum2',
@@ -164,7 +170,7 @@ export const COURSES: Course[] = [
}, },
{ {
id: 'fall1-managing-change', name: 'Managing Change', setId: 'fall1', id: 'fall1-managing-change', name: 'Managing Change', setId: 'fall1',
qualifications: [{ specId: 'LCM', marker: 'standard' }, { specId: 'MGT', marker: 'standard' }, { specId: 'STR', marker: 'S2' }], qualifications: [{ specId: 'HCR', marker: 'standard' }, { specId: 'LCM', marker: 'standard' }, { specId: 'MGT', marker: 'standard' }, { specId: 'STR', marker: 'S2' }],
}, },
{ {
id: 'fall1-social-entrepreneurship', name: 'Social Entrepreneurship', setId: 'fall1', id: 'fall1-social-entrepreneurship', name: 'Social Entrepreneurship', setId: 'fall1',
+1 -1
View File
@@ -27,7 +27,7 @@ export const ELECTIVE_SETS: ElectiveSet[] = [
}, },
{ {
id: 'sum2', name: 'Summer Elective Set 2', term: 'Summer', id: 'sum2', name: 'Summer Elective Set 2', term: 'Summer',
courseIds: ['sum2-innovation-design', 'sum2-social-media', 'sum2-leading-ai', 'sum2-business-drivers'], courseIds: ['sum2-managing-growing-companies', 'sum2-innovation-design', 'sum2-social-media', 'sum2-leading-ai', 'sum2-business-drivers'],
}, },
{ {
id: 'sum3', name: 'Summer Elective Set 3', term: 'Summer', id: 'sum3', name: 'Summer Elective Set 3', term: 'Summer',
+1
View File
@@ -9,6 +9,7 @@ export const SPECIALIZATIONS: Specialization[] = [
{ id: 'FIN', name: 'Finance', abbreviation: 'FIN' }, { id: 'FIN', name: 'Finance', abbreviation: 'FIN' },
{ id: 'FIM', name: 'Financial Instruments and Markets', abbreviation: 'FIM' }, { id: 'FIM', name: 'Financial Instruments and Markets', abbreviation: 'FIM' },
{ id: 'GLB', name: 'Global Business', abbreviation: 'GLB' }, { id: 'GLB', name: 'Global Business', abbreviation: 'GLB' },
{ id: 'HCR', name: 'Healthcare', abbreviation: 'HCR' },
{ id: 'LCM', name: 'Leadership and Change Management', abbreviation: 'LCM' }, { id: 'LCM', name: 'Leadership and Change Management', abbreviation: 'LCM' },
{ id: 'MGT', name: 'Management', abbreviation: 'MGT' }, { id: 'MGT', name: 'Management', abbreviation: 'MGT' },
{ id: 'MKT', name: 'Marketing', abbreviation: 'MKT' }, { id: 'MKT', name: 'Marketing', abbreviation: 'MKT' },
+1 -1
View File
@@ -149,7 +149,7 @@ describe('optimize (integration)', () => {
expect(result.allocations).toBeDefined(); expect(result.allocations).toBeDefined();
expect(result.statuses).toBeDefined(); expect(result.statuses).toBeDefined();
expect(result.upperBounds).toBeDefined(); expect(result.upperBounds).toBeDefined();
expect(Object.keys(result.statuses).length).toBe(14); expect(Object.keys(result.statuses).length).toBe(SPECIALIZATIONS.length);
}); });
it('modes can produce different results', () => { it('modes can produce different results', () => {
+2 -2
View File
@@ -6,8 +6,8 @@ import react from '@vitejs/plugin-react'
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
define: { define: {
__APP_VERSION__: JSON.stringify('1.2.1'), __APP_VERSION__: JSON.stringify('1.2.2'),
__APP_VERSION_DATE__: JSON.stringify('2026-03-27'), __APP_VERSION_DATE__: JSON.stringify('2026-05-09'),
}, },
server: { server: {
allowedHosts: ['soos'], allowedHosts: ['soos'],
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-05-09
@@ -0,0 +1,3 @@
# j27-spec-update
Apply J27 specialization sheet (5/6/2026): add Healthcare specialization, mark Customer Insights cancelled, add cancelled Managing Growing Companies entry, rename and re-describe Social Media → Digital Marketing Strategy in Practice, add HCR qualifications to four existing courses.
@@ -0,0 +1,75 @@
## Context
The Stern J27 Specializations one-pager (5/6/2026) introduces structural changes that go beyond a simple data refresh:
- A new **Healthcare** specialization (HCR) — the first new specialization since the app's initial 14
- Two cancelled-course bookkeeping items (Customer Insights becomes cancelled; Managing Growing Companies reappears as a cancelled placeholder)
- A renamed elective (Social Media and Mobile Technology → Digital Marketing Strategy in Practice) with a substantively different syllabus, instructor lineup, and a new qualification (Healthcare)
The existing codebase already includes the full plumbing for `cancelled: true` (defined in `app/src/data/types.ts:22`, indexed in `app/src/data/lookups.ts:43-45`, excluded from solver via `app/src/state/appState.ts:94-95`, greyed-out in `app/src/components/CourseSelection.tsx:279`) but the prior change `replace-cancelled-course-with-innovation-design` chose hard-deletion over the flag. This change formalizes the flag as the standing pattern.
## Goals / Non-Goals
**Goals:**
- Bring data files into exact correspondence with the J27 sheet
- Establish `cancelled: true` as the canonical pattern for cancelled courses (Approach B)
- Make the data integrity test reflect *reachable* credits (excluding cancelled courses), so that a future cancellation triggers an obviously-failing reachability assertion
- Verify the published per-spec credit totals from the CSV match the computed reachability table
**Non-Goals:**
- No changes to the solver, lookups infrastructure, or React components — the cancelled flag is already honored end-to-end
- No new color/iconography work for HCR beyond what falls out of the existing rendering of unknown specializations (if a missing color is observed during browser testing, address with a follow-up; do not block on it)
- No data-migration support for older saved selections — the app does not persist user state across reloads
- No support for multiple simultaneous cohorts; this is an in-place J27 update
## Decisions
### Approach B (cancelled flag), not hard-delete
Use `cancelled: true` rather than removing entries. The flag exists, is fully wired, and matches the printed sheet 1:1 (which preserves the slot even when a course is cancelled). The prior delete-and-replace pattern was driven by lack of UI greying — that's no longer a constraint.
**Alternatives considered:** Hard-delete the cancelled entries, as in `replace-cancelled-course-with-innovation-design`. Rejected because the school's official sheet shows the cancelled slot, and preserving slot ordering helps students cross-reference printed materials.
### Add `sum2-managing-growing-companies` as a fresh cancelled entry
Even though a previous change removed this id, the J27 sheet reintroduces it as a cancelled placeholder. We add it back with `cancelled: true` and empty qualifications. The id is reusable because no persisted state references it.
**Alternative considered:** Skip it (Summer Set 2 stays at 4 entries). Rejected because the printed sheet shows 5 slots; hiding one would create a discrepancy the user might flag as a bug.
### Update reachability test to exclude cancelled courses
Modify `data.test.ts` so the per-spec "across sets" assertion filters out qualifications belonging to cancelled courses before counting distinct sets. This matches the CSV's published credit totals (BRM 12.5 = 5 sets × 2.5; MKT 15.0 = 6 sets × 2.5; HCR 10.0 = 4 sets × 2.5).
**Alternative considered:** Leave the test counting cancelled courses and accept that BRM/MKT reach-counts disagree with the published totals. Rejected — the test's stated purpose is to mirror the reachability table, and divergence makes regressions invisible.
### Do NOT change `coursesBySpec` to filter cancelled
The lookup map keeps cancelled qualifications. The solver already excludes them via `appState`'s `excluded` set, and other consumers (or future debug tooling) may want the full picture. Filter at the consumer (test), not at the source.
**Alternative considered:** Strip cancelled entries from `coursesBySpec` directly. Rejected because that hides data from any future caller that might legitimately want to inspect cancelled courses, and the test is the only consumer that currently cares.
### Clear instructor for Digital Marketing course
The new description (`digital-marketing.txt`) describes a substantively different course (MSKCC engagement, agentic AI) led by guest contributors from L'Oréal and Google Gemini, with no clear primary instructor named. Set `instructors: []` rather than carry forward Stewart Krentzman from the old syllabus, which would be misleading.
**Alternative considered:** Retain the prior instructor name. Rejected — the course content has changed materially, and showing a stale instructor is worse than showing none.
### Healthcare gets no required-course gate
The CSV asterisk convention (used for required courses) does not appear on any HCR-qualifying course. Healthcare therefore has no `requiredCourseId`.
## Risks / Trade-offs
- **Reachability test now depends on cancelled flag** → Mitigation: the test continues to assert all 14 (now 15) specs; if the cancelled flag is accidentally cleared, the test's set count for BRM/MKT will jump back up and fail
- **HCR may render with no themed color in legend** → Mitigation: verify in browser; if a default color is unacceptable, file a follow-up rather than blocking this change
- **Reusing the `sum2-managing-growing-companies` id** → Risk is low (no persistence); document the reuse in the changelog so a future bisecting developer is not surprised
- **CSV header dates the sheet 5/6/2026 (one day before today's date)** → No risk; just confirms the sheet is current
## Migration Plan
1. Land data changes in a single commit (or one commit per file, whichever fits the repo's PR style)
2. Run `pnpm test` (or `npm test`) and confirm all data integrity tests pass with updated expectations
3. Browser-verify: load the app, observe HCR appears in the specialization list, the two cancelled courses render greyed, the renamed Digital Marketing course shows the new description on info-popover hover
4. Bump `__APP_VERSION__` to `1.2.2` (patch bump consistent with prior data-only updates) and `__APP_VERSION_DATE__` in `app/vite.config.ts`
5. Add a `1.2.2` entry to `CHANGELOG.md`
Rollback: revert the data file changes; no schema or build changes to undo.
## Open Questions
- **Lead instructor for Digital Marketing Strategy in Practice** — the description names guest speakers but no primary instructor; clear for now and refresh if the school publishes one
- **HCR display color/order** — verify in browser; address with a follow-up if the default rendering looks wrong
@@ -0,0 +1,37 @@
## Why
The Stern School published an updated J27 Specializations one-pager (dated 5/6/2026) that introduces a new Healthcare specialization, cancels the Customer Insights elective, lists Managing Growing Companies as a cancelled placeholder in Summer Set 2, renames Social Media and Mobile Technology to Digital Marketing Strategy in Practice (with a substantively different course description and focus), and cross-lists four existing courses to the new Healthcare specialization. The solver's data files must match the official sheet so students rely on accurate availability information.
## What Changes
- Add **Healthcare (HCR)** specialization (10 credits, no required course)
- Add HCR qualification to four existing courses:
- `spr2-health-medical` (Business of Health & Medical Care)
- `spr3-analytics-ml` (Analytics & Machine Learning for Managers)
- `sum2-social-media` (formerly Social Media and Mobile Technology)
- `fall1-managing-change` (Managing Change)
- Rename `sum2-social-media` to **Digital Marketing Strategy in Practice** and replace its course description with the new MSKCC-anchored content (provided in `digital-marketing.txt`); clear instructor field pending confirmation of new lead instructor
- Mark **`spr5-customer-insights`** as `cancelled: true` (retain entry; do not delete) — switching from prior delete-and-replace pattern to the existing-but-unused `cancelled` flag pattern (Approach B)
- Add a new cancelled-only entry **`sum2-managing-growing-companies`** ("Managing Growing Companies") to Summer Set 2 with `cancelled: true` and no qualifications, restoring the printed sheet's 5-slot listing
- Update test assertions in `app/src/data/__tests__/data.test.ts` to reflect the 15th specialization, the 5-entry sum2 set, and revised per-spec set counts (BRM, MKT lose `spr5-customer-insights`)
## Capabilities
### New Capabilities
_None — this is a data refresh that uses existing capabilities (`course-data`, `specialization-ranking`)._
### Modified Capabilities
- `course-data`: Add Healthcare specialization, four HCR cross-listings, the renamed Digital Marketing course, and two cancelled-flag entries. Adopt `cancelled: true` (Approach B) as the standing pattern for cancelled courses, superseding the prior delete-and-replace approach.
## Impact
- `app/src/data/specializations.ts` — add HCR entry
- `app/src/data/courses.ts` — five qualification/name edits, one new cancelled entry, one cancelled-flag edit
- `app/src/data/electiveSets.ts` — append `sum2-managing-growing-companies` to `sum2.courseIds`
- `app/src/data/courseDescriptions.ts` — replace `sum2-social-media` description; clear instructors
- `app/src/data/__tests__/data.test.ts` — update specialization count (14→15), course count (46→47), and per-spec/STR-marker assertions
- `app/vite.config.ts` — bump `__APP_VERSION__` and `__APP_VERSION_DATE__`
- `CHANGELOG.md` — add release entry
- No code changes to solver, lookups, or UI: existing `cancelled` plumbing in `lookups.ts:43-50`, `appState.ts:94-95`, and `CourseSelection.tsx:279` already handles greying-out and solver exclusion
@@ -0,0 +1,117 @@
## ADDED Requirements
### Requirement: Healthcare specialization
The system SHALL include "Healthcare" (abbreviation `HCR`) as a defined specialization with no required course gate.
#### Scenario: Healthcare appears in specialization list
- **WHEN** the data module is loaded
- **THEN** a specialization with id `HCR`, name "Healthcare", and abbreviation `HCR` is present in `SPECIALIZATIONS`
#### Scenario: Healthcare has no required course
- **WHEN** inspecting the Healthcare specialization
- **THEN** its `requiredCourseId` is undefined
#### Scenario: Healthcare reaches four elective sets
- **WHEN** counting the distinct elective sets containing at least one non-cancelled HCR-qualifying course
- **THEN** the count is exactly 4 (`spr2`, `spr3`, `sum2`, `fall1`), yielding 10.0 credits available (4 × 2.5)
### Requirement: Healthcare cross-listings on existing courses
The system SHALL add Healthcare (`HCR`, standard marker) as an additional qualification on four existing courses without removing their prior qualifications.
#### Scenario: Business of Health & Medical Care qualifies for Healthcare
- **WHEN** inspecting `spr2-health-medical` qualifications
- **THEN** the list includes both `STR` (S2) and `HCR` (standard)
#### Scenario: Analytics & Machine Learning for Managers qualifies for Healthcare
- **WHEN** inspecting `spr3-analytics-ml` qualifications
- **THEN** the list includes both `MTO` (standard) and `HCR` (standard)
#### Scenario: Digital Marketing Strategy in Practice qualifies for Healthcare
- **WHEN** inspecting `sum2-social-media` qualifications
- **THEN** the list includes `BRM`, `EMT`, `MKT`, and `HCR` (all standard)
#### Scenario: Managing Change qualifies for Healthcare
- **WHEN** inspecting `fall1-managing-change` qualifications
- **THEN** the list includes `LCM`, `MGT`, `STR` (S2), and `HCR` (standard)
### Requirement: Cancelled courses preserved with cancelled flag
The system SHALL retain cancelled course entries in the course data with `cancelled: true` rather than deleting them. Cancelled courses SHALL NOT be considered selectable, SHALL be excluded from solver computations, and SHALL render in the UI as visibly disabled.
#### Scenario: Customer Insights is marked cancelled
- **WHEN** inspecting `spr5-customer-insights`
- **THEN** the course has `cancelled: true` and remains a member of `spr5`
#### Scenario: Managing Growing Companies present as cancelled placeholder in Summer Set 2
- **WHEN** inspecting Summer Elective Set 2 (`sum2`)
- **THEN** it contains exactly five course entries, one of which is `sum2-managing-growing-companies` with `cancelled: true` and an empty qualifications list
#### Scenario: Cancelled courses excluded from solver
- **WHEN** the solver computes specialization assignments
- **THEN** no cancelled course id contributes credits toward any specialization
## MODIFIED Requirements
### Requirement: Course definitions
The system SHALL define exactly 47 courses. Each course SHALL have an ID, display name, and the ID of the elective set it belongs to. Courses MAY carry a `cancelled: true` flag indicating the offering has been withdrawn.
#### Scenario: Course count
- **WHEN** the data module is loaded
- **THEN** exactly 47 courses are defined
#### Scenario: Each course belongs to one set
- **WHEN** iterating all courses
- **THEN** every course references a valid elective set ID, and the set's course list includes that course
#### Scenario: Cancelled courses are flagged, not deleted
- **WHEN** filtering courses by `cancelled === true`
- **THEN** the result includes both `spr5-customer-insights` and `sum2-managing-growing-companies`
### Requirement: Specialization definitions
The system SHALL define exactly 15 specializations. Each specialization SHALL have an ID, display name, and abbreviation. Specializations with a required course gate SHALL reference the required course ID.
#### Scenario: Specialization count
- **WHEN** the data module is loaded
- **THEN** exactly 15 specializations are defined
#### Scenario: Healthcare is included
- **WHEN** searching specializations for id `HCR`
- **THEN** a specialization named "Healthcare" is found
#### Scenario: Required course mappings unchanged
- **WHEN** inspecting specializations with required courses
- **THEN** exactly 4 specializations have required course gates: SBI → `spr4-sustainability`, ENT → `spr4-foundations-entrepreneurship`, EMT → `sum3-entertainment-media`, BRM → `fall4-brand-strategy`
### Requirement: Course-specialization qualification matrix
Each course SHALL declare which specializations it qualifies for, with a marker type of standard (■), S1, or S2. Courses with no qualifying specializations (including cancelled courses) SHALL have an empty qualification list. Reachability counts SHALL exclude qualifications belonging to courses flagged `cancelled`.
#### Scenario: Marker types
- **WHEN** inspecting course qualifications
- **THEN** every qualification entry uses one of three marker types: standard, S1, or S2
#### Scenario: Strategy markers
- **WHEN** counting Strategy-qualifying courses across all (non-cancelled) courses
- **THEN** exactly 9 courses have S1 markers and exactly 8 courses have S2 markers
#### Scenario: Reachable distinct-set counts per specialization
- **WHEN** counting distinct elective sets containing at least one non-cancelled course qualifying for each specialization
- **THEN** the counts are: MGT 11, STR 9, LCM 9, FIN 9, CRF 8, MKT 6, BNK 6, BRM 5, FIM 6, MTO 6, GLB 5, EMT 4, ENT 4, SBI 4, HCR 4
- **AND** these counts represent raw distinct-set reachability, not the CSV's published credit totals (which additionally apply S1/S2 and shared-course rules — out of scope for this assertion)
### Requirement: Renamed Digital Marketing course
The system SHALL display course `sum2-social-media` with the name "Digital Marketing Strategy in Practice" and the updated description anchored on the Memorial Sloan Kettering Cancer Center engagement. The course id SHALL remain `sum2-social-media` (unchanged) so existing lookup tables and tests continue to resolve.
#### Scenario: Display name updated
- **WHEN** inspecting the course with id `sum2-social-media`
- **THEN** its `name` is "Digital Marketing Strategy in Practice"
#### Scenario: Description reflects MSKCC engagement
- **WHEN** the user opens the course info popover for `sum2-social-media`
- **THEN** the description references Memorial Sloan Kettering Cancer Center, agentic AI, and digital strategy practice
#### Scenario: Instructor cleared pending confirmation
- **WHEN** inspecting the course's instructor list in `COURSE_DESCRIPTIONS`
- **THEN** the `instructors` array is empty
## REMOVED Requirements
_None. The "Managing Growing Companies" id, previously removed by `replace-cancelled-course-with-innovation-design`, is reintroduced as a cancelled placeholder per the J27 sheet — see ADDED Requirements above._
+52
View File
@@ -0,0 +1,52 @@
## 1. Specialization Data
- [x] 1.1 Add `{ id: 'HCR', name: 'Healthcare', abbreviation: 'HCR' }` to `SPECIALIZATIONS` in `app/src/data/specializations.ts` (no `requiredCourseId`)
## 2. Course Data
- [x] 2.1 Add `{ specId: 'HCR', marker: 'standard' }` to qualifications of `spr2-health-medical` in `app/src/data/courses.ts`
- [x] 2.2 Add `{ specId: 'HCR', marker: 'standard' }` to qualifications of `spr3-analytics-ml`
- [x] 2.3 Rename `sum2-social-media` `name` to `'Digital Marketing Strategy in Practice'` and add `{ specId: 'HCR', marker: 'standard' }` to its qualifications
- [x] 2.4 Add `{ specId: 'HCR', marker: 'standard' }` to qualifications of `fall1-managing-change`
- [x] 2.5 Add `cancelled: true` to `spr5-customer-insights`; leave its `qualifications` array unchanged
- [x] 2.6 Append a new course entry `{ id: 'sum2-managing-growing-companies', name: 'Managing Growing Companies', setId: 'sum2', qualifications: [], cancelled: true }` to `COURSES`
## 3. Elective Set Membership
- [x] 3.1 In `app/src/data/electiveSets.ts`, append `'sum2-managing-growing-companies'` to `sum2.courseIds` (placement: end of list, matching the order of the printed J27 sheet)
## 4. Course Description
- [x] 4.1 In `app/src/data/courseDescriptions.ts`, replace the value at key `'sum2-social-media'` with the description text from `digital-marketing.txt` (paragraphs joined with `\n\n`); set `instructors: []`
## 5. Lookup Behavior Verification
- [x] 5.1 Confirm `coursesBySpec` in `app/src/data/lookups.ts` continues to include cancelled-course qualifications (no code change required; the test asserts the consumer-side filter, not the lookup itself)
## 6. Test Updates
- [x] 6.1 Update `app/src/data/__tests__/data.test.ts`: change `expect(COURSES.length).toBe(46)` to `47`
- [x] 6.2 Change `expect(SPECIALIZATIONS.length).toBe(14)` to `15`
- [x] 6.3 In the "across sets" describe block, change the helper to filter out qualifications belonging to cancelled courses before counting distinct sets (read `cancelled` via `COURSES.find(...)`)
- [x] 6.4 Update `expectedAcrossSets` map to: MGT 11, STR 9, LCM 9, FIN 9, CRF 8, MKT **6** (was 7), BNK 6, BRM **5** (was 6), FIM 6, MTO 6, GLB 5, EMT 4, ENT 4, SBI 4, **HCR 4** (new). Only BRM and MKT decrement (cancelled `spr5-customer-insights` removes spr5 from both); HCR is added. All other values unchanged. Note: this test counts raw distinct sets, not CSV-published credit totals (which apply S1/S2 and shared-course rules); do not "correct" other values to match the CSV.
- [x] 6.5 Confirm STR S1=9 / S2=8 marker counts test still passes unchanged (no STR markers added or removed)
- [x] 6.6 Run `npm test --prefix app` (or the project's preferred command) and confirm all data tests pass
## 7. Browser Verification
- [x] 7.1 Start dev server (`npm run dev --prefix app`) and load the app
- [x] 7.2 Confirm "Healthcare" appears in the specialization list/legend
- [x] 7.3 Confirm `spr5-customer-insights` ("Customer Insights") renders greyed/disabled in Spring Set 5
- [x] 7.4 Confirm `sum2-managing-growing-companies` ("Managing Growing Companies") renders greyed/disabled as the 5th entry in Summer Set 2
- [x] 7.5 Confirm `sum2-social-media` displays as "Digital Marketing Strategy in Practice"; open its info popover and verify the new MSKCC-anchored description appears with no instructor listed
- [x] 7.6 Pick a Healthcare-qualifying course (e.g., Managing Change), pin it, and confirm Healthcare appears in the resulting specialization analysis
- [x] 7.7 Note any rendering issue with HCR (missing color/legend entry) and capture for follow-up if found
## 8. Version and Changelog
- [x] 8.1 Bump `__APP_VERSION__` to `1.2.2` and update `__APP_VERSION_DATE__` to today's date in `app/vite.config.ts`
- [x] 8.2 Add a `## [1.2.2]` entry to `CHANGELOG.md` describing: new Healthcare specialization, four HCR cross-listings, Digital Marketing Strategy in Practice rename + new description, two cancelled-course entries (Customer Insights, Managing Growing Companies), and adoption of the `cancelled` flag pattern
## 9. Cleanup
- [x] 9.1 Delete `J27 Specializations.csv` and `digital-marketing.txt` from the repo root (these were drop-in inputs; data has been migrated into source)