Files
GroundedHelper/frontend/CLAUDE.md
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

6.5 KiB
Raw Permalink Blame History

Grounded — Flutter Frontend

A to-do app that doesn't believe you.

Architecture ported from Documents/Autoreceptives/Frontend/Receptive. Same structure, conventions and infrastructure; the business logic is the debt and enforcement engine.


1. Stack

Flutter (Dart ^3.6.2), stacked MVVM, dio, flutter_secure_storage, flutter_dotenv, fl_chart, flutter_local_notifications. Package name and lib/ root are both Grounded, so imports read package:Grounded/Grounded/.... Org is nya (nya.grounded).

Codegen is via Mason — screens, endpoints and storage fields are generated, never hand-scaffolded.


2. Layout (lib/Grounded/)

about/external/data/        responses & domain models (+ pages/ for pagination)
about/external/initial/     request bodies
about/internal/application/ enums and app-internal models
about/internal/file/        FileStorage
comms/                      CommsDirections · ConnectComms · Comms
informatics/                DataManager · AppDataManager
memory/                     ConnectInternalMemory · InternalMemory
configs/                    Navigator · Env · NotificationServiceConfig
designs/                    Component · Shell · Responsive · buttons/ input/ text/
see/<feature>/              screens, 4 files each
utils/                      Colors · CommonUtils · engines · validators

3. The 4-file screen pattern (mandatory)

File Role
Foo.dart StatefulWidget shell — creates FooState only.
FooState.dart All UI + local state; implements ConnectFoo.
ViewFoo.dart extends ParentViewModel — business logic, calls DataManager, pushes results back through ConnectFoo.
ConnectFoo.dart Abstract callbacks so the ViewModel never touches widgets.

ViewModelBuilder<ViewFoo>.reactive wires them. onViewModelReady assigns _model and calls one named _initiate(). No logic in builder: before the return.

Generate with: mason make mvvc_template --project Grounded --screen Foo


4. ParentViewModel

Constructs the single AppDataManager and owns everything cross-cutting: showLoading / closeLoading, hasNetwork(retry), showError, showApplicationNotification, and handleError — whose decision tree routes 401 → sessionExpired() and error code 5000.901 → updateMe().

Guard every network call:

void loadThing(ThingRequest request) async {
  if (!await hasNetwork(() => loadThing(request))) return;
  showLoading('Loading…');
  try {
    final response = await getDataManager().getThing(request);
    closeLoading();
    connection.onThingLoaded(Thing.fromJson(response.data));
  } catch (e) {
    handleError(e, () => loadThing(request), () => dismissError(), 'Retry');
  }
}

5. Domain — the enforcement engine

Three primitives: Commitment (what you said you'd do), Debt (weighted, decaying score), Standing (Good → Warned → Grounded → Lockdown).

Goals contain commitments via Commitment.parentId — "Workout" holds "Monday shoulders". Goals never carry debt; the tasks inside them do.

Engines in utils/, each mapping 1:1 to the spec's formulas:

Engine Owns
DebtEngine w(class) × severity(d) × decay(t); abandonment 2×, no decay 30d; late complete retains 30%
StandingEngine tier derivation; what each tier permits
CapacityEngine blocks over-scheduling against p50 of historical completed minutes × 0.85
IntegrityEngine session integrity, weekly volume, plyo contact ceiling, recovery gate
ExcuseAnalyser on-device excuse clustering + the confrontation copy
GuardrailEngine distress detection, amnesty tokens
ToneEngine all enforcement copy — the one place the tone cap is enforced

Thresholds live in Thresholds.dart. Never inline a limit.

CommitmentEvent is append-only and is the source of truth — not the status field. That's what makes honest history and excuse analysis possible.


6. Design language

See design.md. In short: black chrome → white sheet with a 28 radius → oversized Light display title → tiny grey all-caps labels above values.

  • Every screen is built from Sheet (designs/Shell.dart).
  • Display titles are TextType.Light. Bold is for labels and metrics only.
  • Never raw Text/TextStyle — use text() from designs/text/Text.dart.
  • Never inline hex — use utils/Colors.dart.
  • Standing owns a colour used consistently everywhere (chrome, chip, meter).
  • One primary button per screen; everything else outlined or text.

Font: General Sans (Fontshare, FFL — see fonts/LICENSE-GeneralSans.txt), wrapped as TextType.{Bold,Medium,Regular,Light}.


7. Live task runner

see/live/ is the full-screen runner: a task being run takes over the screen. Elapsed time is derived from wall-clock, not counted by the ticker, so a screen-off period cannot lose time. Backgrounding pauses the clock and increments backgroundedCount — that's what makes Timer proof mean anything.

LocalNotificationEngine mirrors it into an ongoing notification and fires alarm-class full-screen intents for non-negotiables. Android manifest carries USE_FULL_SCREEN_INTENT, SCHEDULE_EXACT_ALARM, and the activity is showWhenLocked + turnScreenOn.


8. Hard conventions

  1. Named event handlers only — onPressed: _onSave, never () => _save().
  2. selectField loads on tap; never pre-load picker options.
  3. List parsing via utils/ObjectConvertors.dart — never inline .map(...fromJson).
  4. Pagination: HistoryRequest { PageAndSort }; responses are *Page; last == true stops loading.
  5. Reload-on-return: child Navigator.pop(context, true), parent refreshes on the result.
  6. New endpoint → mason make api_endpoint (injects into all four HTTP files).
  7. New secure field → mason make internal_memory.
  8. One class per file, named after the class.

9. Environment

.env is a bundled asset, loaded in main() before runApp:

GROUNDED_PRODUCTION_PATH · GROUNDED_LOCAL_PATH · LOCALISED_APP_VERSION

isProd in CommsDirections.dart flips local↔production. Requests carry the three identity headers: what, whom, version.


10. Commands

flutter pub get
flutter analyze lib/            # bricks/ are excluded — templates aren't valid Dart
flutter run

mason get
mason make mvvc_template --project Grounded --screen MyScreen

dart run flutter_launcher_icons
dart run flutter_native_splash:create