Files
GroundedHelper/frontend/lib/Grounded/utils/GuardrailEngine.dart
alvocool 16bff634b5 Initial commit: Grounded Flutter frontend
A to-do app that doesn't believe you — an enforcement layer rather than a
neutral ledger.

Architecture ported from Autoreceptives/Frontend/Receptive: stacked MVVM with
the mandatory 4-file screen pattern, one ParentViewModel owning the loading /
network / error overlays and the handleError decision tree, one AppDataManager
gateway, dio comms carrying the three identity headers, secure storage with
random-suffixed keys, and a single-chokepoint Navigator. Package root and Dart
package name are both Grounded; org is nya.

The enforcement engine, one unit per formula in utils/:

- DebtEngine      w(class) x severity(d) x decay(t), sublinear severity so old
                  misses cannot swamp the score; abandonment 2x with 30-day
                  decay immunity; late complete retains 30%
- StandingEngine  Good -> Warned -> Grounded -> Lockdown, derived not set;
                  Grounded replaces home with the overdue queue
- CapacityEngine  blocks over-scheduling against p50 of historically completed
                  minutes, with a learned per-category estimation multiplier
- IntegrityEngine session integrity, weekly volume, plyometric contact ceiling
                  and enforced recovery gaps
- ExcuseAnalyser  on-device excuse clustering plus the confrontation copy
- GuardrailEngine distress detection and rationed amnesty
- ToneEngine      all enforcement copy, so the tone cap lives in one place

CommitmentEvent is append-only and is the source of truth rather than the
status field, which is what makes honest history and excuse analysis possible.

Goals contain commitments via parentId, and a task can be run from a
full-screen runner that derives elapsed time from wall-clock so screen-off
cannot lose time. Backgrounding pauses the clock and is counted. The runner is
mirrored into an ongoing notification, with alarm-class full-screen intents
reserved for non-negotiables.

Design language, fonts, icon and native splash are in place; Mason bricks are
retargeted to this project and verified end-to-end.

flutter analyze lib/ reports no errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mfu2gQLSFN21YRBcU2NrTt
2026-07-27 09:11:17 +03:00

45 lines
1.7 KiB
Dart

/// 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;
}