Compare commits
2 Commits
1907e266c1
...
8b88402ecd
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b88402ecd | |||
| 578c87d59d |
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 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
|
## v1.2.0 — 2026-03-27
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|||||||
@@ -109,6 +109,37 @@ describe('determineStatuses', () => {
|
|||||||
// Most specs only have 1 qualifying course in spr1 (2.5 credits < 9)
|
// Most specs only have 1 qualifying course in spr1 (2.5 credits < 9)
|
||||||
expect(statuses['FIN']).toBe('unreachable');
|
expect(statuses['FIN']).toBe('unreachable');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('marks spec as unreachable when infeasible alongside achieved specs due to credit sharing', () => {
|
||||||
|
// Bug scenario: CRF+STR achieved, LCM has 10 credit upper bound but
|
||||||
|
// shared courses (spr3, fall3) are consumed by CRF/STR
|
||||||
|
const selectedCourses = [
|
||||||
|
'spr1-collaboration', // LCM, MGT
|
||||||
|
'spr2-financial-services', // BNK, CRF, FIN, FIM
|
||||||
|
'spr3-mergers-acquisitions', // CRF, FIN, LCM, STR(S1)
|
||||||
|
'spr4-foundations-entrepreneurship', // ENT, MGT, STR(S1)
|
||||||
|
'spr5-corporate-finance', // CRF, FIN
|
||||||
|
'sum1-global-immersion', // GLB
|
||||||
|
'sum2-business-drivers', // STR(S1)
|
||||||
|
'sum3-valuation', // BNK, CRF, FIN, FIM
|
||||||
|
'fall1-managing-change', // LCM, MGT, STR(S2)
|
||||||
|
'fall2-decision-models', // MGT, MTO
|
||||||
|
'fall3-corporate-governance', // LCM, MGT, SBI, STR(S1)
|
||||||
|
'fall4-game-theory', // MGT, STR(S1)
|
||||||
|
];
|
||||||
|
|
||||||
|
// Baseline: LCM is achievable when no specs are achieved (upper bound alone)
|
||||||
|
const statusesBaseline = determineStatuses(selectedCourses, [], []);
|
||||||
|
expect(statusesBaseline['LCM']).toBe('achievable');
|
||||||
|
|
||||||
|
// Core bug scenario: CRF+STR achieved (without MGT), LCM should still be unreachable
|
||||||
|
const statusesWithoutMgt = determineStatuses(selectedCourses, [], ['CRF', 'STR']);
|
||||||
|
expect(statusesWithoutMgt['LCM']).toBe('unreachable');
|
||||||
|
|
||||||
|
// LCM upper bound is 10 (>= 9) but infeasible alongside CRF+STR+MGT
|
||||||
|
const statusesWithMgt = determineStatuses(selectedCourses, [], ['CRF', 'STR', 'MGT']);
|
||||||
|
expect(statusesWithMgt['LCM']).toBe('unreachable');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('optimize (integration)', () => {
|
describe('optimize (integration)', () => {
|
||||||
|
|||||||
@@ -178,7 +178,20 @@ export function determineStatuses(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses[spec.id] = 'achievable';
|
// Verify spec is actually feasible alongside already-achieved specs,
|
||||||
|
// but only when all course slots are committed (no open sets remain).
|
||||||
|
// With open sets, the user can still pick different courses, so LP
|
||||||
|
// feasibility over selected courses alone would give false negatives.
|
||||||
|
if (openSetSet.size === 0) {
|
||||||
|
const testSet = [...achieved, spec.id];
|
||||||
|
const filteredCourseIds = excludedCourseIds
|
||||||
|
? selectedCourseIds.filter((id) => !excludedCourseIds.has(id))
|
||||||
|
: selectedCourseIds;
|
||||||
|
const feasResult = checkWithS2(filteredCourseIds, testSet);
|
||||||
|
statuses[spec.id] = feasResult.feasible ? 'achievable' : 'unreachable';
|
||||||
|
} else {
|
||||||
|
statuses[spec.id] = 'achievable';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return statuses;
|
return statuses;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import react from '@vitejs/plugin-react'
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
define: {
|
define: {
|
||||||
__APP_VERSION__: JSON.stringify('1.2.0'),
|
__APP_VERSION__: JSON.stringify('1.2.1'),
|
||||||
__APP_VERSION_DATE__: JSON.stringify('2026-03-27'),
|
__APP_VERSION_DATE__: JSON.stringify('2026-03-27'),
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
|
|||||||
Reference in New Issue
Block a user