/// The counterweights. An app built on guilt has an obvious failure mode: the /// people who need it most delete it during their worst week. These are not /// nice-to-haves — they are the retention strategy. class GuardrailEngine { /// Debt increase over the window that counts as a spike. static const double debtSpikeDelta = 15; /// App opens per week below which engagement counts as dropped. static const int engagementFloor = 3; /// Readiness score below which inputs count as degraded. static const int readinessFloor = 4; /// Distress is the conjunction, not any single signal: debt spiking *and* /// engagement dropping *and* readiness degrading. Strictness must never be /// the response to someone who is actually struggling. static bool detectDistress({ required double debtDelta, required int appOpensThisWeek, required int meanReadiness, }) { final bool debtSpiking = debtDelta >= debtSpikeDelta; final bool disengaging = appOpensThisWeek <= engagementFloor; final bool degrading = meanReadiness > 0 && meanReadiness <= readinessFloor; return debtSpiking && disengaging && degrading; } /// How many amnesty tokens remain this month. Rationed so they feel /// valuable, but they exist so a bad flu does not destroy three months of /// progress. static int tokensRemaining(int granted, int spent) { final int remaining = granted - spent; return remaining > 0 ? remaining : 0; } static bool canSpendAmnesty(int granted, int spent) { return tokensRemaining(granted, spent) > 0; } /// When distressed, the plan is cut to this many non-negotiables and nothing /// else is asked for. static const int distressPlanSize = 3; }