Fix decision-engine override behavior: sleep/pms return GENTLE per spec
The spec (decision-engine.md lines 93-94) clearly states: - sleep override -> GENTLE - pms override -> GENTLE But the implementation was returning REST for all overrides. This fix: - Updates decision-engine.ts to use OVERRIDE_DECISIONS with correct status/reason/icon per override type - Updates tests to expect GENTLE for sleep and pms overrides - Aligns implementation with specification Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -128,7 +128,7 @@ describe("getTrainingDecision (algorithmic rules)", () => {
|
||||
});
|
||||
|
||||
describe("getDecisionWithOverrides", () => {
|
||||
describe("override types force REST", () => {
|
||||
describe("override types force appropriate decisions", () => {
|
||||
it("flare override forces REST", () => {
|
||||
const data = createHealthyData();
|
||||
const overrides: OverrideType[] = ["flare"];
|
||||
@@ -145,20 +145,20 @@ describe("getDecisionWithOverrides", () => {
|
||||
expect(result.reason).toContain("stress");
|
||||
});
|
||||
|
||||
it("sleep override forces REST", () => {
|
||||
it("sleep override forces GENTLE (per spec)", () => {
|
||||
const data = createHealthyData();
|
||||
const overrides: OverrideType[] = ["sleep"];
|
||||
const result = getDecisionWithOverrides(data, overrides);
|
||||
expect(result.status).toBe("REST");
|
||||
expect(result.status).toBe("GENTLE");
|
||||
expect(result.reason).toContain("sleep");
|
||||
});
|
||||
|
||||
it("pms override forces REST", () => {
|
||||
it("pms override forces GENTLE (per spec)", () => {
|
||||
const data = createHealthyData();
|
||||
const overrides: OverrideType[] = ["pms"];
|
||||
const result = getDecisionWithOverrides(data, overrides);
|
||||
expect(result.status).toBe("REST");
|
||||
expect(result.reason).toContain("pms");
|
||||
expect(result.status).toBe("GENTLE");
|
||||
expect(result.reason).toContain("PMS");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,11 +6,31 @@ import type { DailyData, Decision, OverrideType } from "@/types";
|
||||
// Override priority order - checked before algorithmic rules
|
||||
const OVERRIDE_PRIORITY: OverrideType[] = ["flare", "stress", "sleep", "pms"];
|
||||
|
||||
const OVERRIDE_REASONS: Record<OverrideType, string> = {
|
||||
flare: "Hashimoto's flare - rest required",
|
||||
stress: "High stress override - rest required",
|
||||
sleep: "Poor sleep override - rest required",
|
||||
pms: "pms override - rest required",
|
||||
// Override decisions per spec: flare/stress -> REST, sleep/pms -> GENTLE
|
||||
const OVERRIDE_DECISIONS: Record<
|
||||
OverrideType,
|
||||
{ status: "REST" | "GENTLE"; reason: string; icon: string }
|
||||
> = {
|
||||
flare: {
|
||||
status: "REST",
|
||||
reason: "Hashimoto's flare - rest required",
|
||||
icon: "🛑",
|
||||
},
|
||||
stress: {
|
||||
status: "REST",
|
||||
reason: "High stress override - rest required",
|
||||
icon: "🛑",
|
||||
},
|
||||
sleep: {
|
||||
status: "GENTLE",
|
||||
reason: "Poor sleep override - gentle activity only",
|
||||
icon: "🟡",
|
||||
},
|
||||
pms: {
|
||||
status: "GENTLE",
|
||||
reason: "PMS override - gentle activity only",
|
||||
icon: "🟡",
|
||||
},
|
||||
};
|
||||
|
||||
export function getTrainingDecision(data: DailyData): Decision {
|
||||
@@ -81,10 +101,11 @@ export function getDecisionWithOverrides(
|
||||
// Check overrides first, in priority order: flare > stress > sleep > pms
|
||||
for (const override of OVERRIDE_PRIORITY) {
|
||||
if (overrides.includes(override)) {
|
||||
const overrideDecision = OVERRIDE_DECISIONS[override];
|
||||
const decision: Decision = {
|
||||
status: "REST",
|
||||
reason: OVERRIDE_REASONS[override],
|
||||
icon: "🛑",
|
||||
status: overrideDecision.status,
|
||||
reason: overrideDecision.reason,
|
||||
icon: overrideDecision.icon,
|
||||
};
|
||||
decisionEngineCallsTotal.inc({ decision: decision.status });
|
||||
return decision;
|
||||
|
||||
Reference in New Issue
Block a user