Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
7fda8d5
Adds tests for screens
Devasy Jul 23, 2026
a3d61b9
Adds tests
Devasy Jul 23, 2026
71659af
Adds comprehensive tests
Devasy Jul 23, 2026
9732b9a
Adds new tests
Devasy Jul 23, 2026
87ce588
Updates test.yml to run on release branches
Devasy Jul 23, 2026
bb98883
Adds test and resolved the warnings and issues
Devasy Jul 23, 2026
8e745cc
Updates tests and minor bug fixes
Devasy Jul 23, 2026
f0fc3c2
Adds fixes for failing testsm and adds connection timeout safety for …
Devasy Jul 24, 2026
43e4dd3
Adds missing lines patch
Devasy Jul 24, 2026
3abd451
Updates the tests with analyse failures
Devasy Jul 24, 2026
9a55007
Updates tests and routine creator to use the common component
Devasy Jul 24, 2026
3b787a0
Updates flutter version and adds tests
Devasy Jul 24, 2026
4b85588
Adds major genui Feature and renderer
Devasy Jul 27, 2026
2a17656
chore: remove patch_so script
Devasy Jul 28, 2026
a790d6e
build: add --build-id=none for jni package in F-Droid metadata
Devasy Jul 28, 2026
e89e2ca
ci: add jni build-id sed step for future reproducible releases
Devasy Jul 28, 2026
85a48fd
feat: assisted pullups, deload-aware ML, handle-scoped PRs, sleeping …
Devasy Aug 5, 2026
62beb92
feat(genui): add A2UiProps alias-aware coercing property reader
Devasy Aug 5, 2026
36253fb
feat(genui): add A2UiSpec contract, A2UiNode and A2UiRegistry
Devasy Aug 5, 2026
85b472d
fix(genui): make A2UiRegistry throw on name/alias collisions
Devasy Aug 5, 2026
6a67623
feat(genui): add A2UiParser with fence, envelope and alias repair
Devasy Aug 5, 2026
116ef77
fix(genui): balanced-bracket JSON extraction and envelope singleton fix
Devasy Aug 5, 2026
c846369
feat(genui): inject A2UiTheme and extract shared panel chrome
Devasy Aug 6, 2026
ffa451e
test(genui): strengthen theme-injection and add A2UiPanel coverage
Devasy Aug 6, 2026
cb60d5f
feat(genui): add A2UiSeries as the shared categorical data shape
Devasy Aug 6, 2026
a426fa2
fix(genui): cover fallback path in A2UiSeries.extract, fix negative-m…
Devasy Aug 6, 2026
a0c3ffc
feat(genui): add StatCardSpec with typed props and trend synonyms
Devasy Aug 6, 2026
1ce4ae1
feat(genui): add MetricGaugeSpec with safe progress and null value
Devasy Aug 6, 2026
58a77f2
feat(genui): add DynamicChartSpec for line, bar and pie
Devasy Aug 6, 2026
243d907
feat(genui): add ScatterPlotSpec with point repair and safe bounds
Devasy Aug 6, 2026
43cae7f
feat(genui): add RadarChartSpec sharing the labels/series shape
Devasy Aug 6, 2026
d3c18b3
feat(genui): add DataListGroupSpec with row repair and optional title
Devasy Aug 6, 2026
5e2e2f1
feat(genui): add FilterChipsSpec with nullable active option
Devasy Aug 6, 2026
359ffd3
feat(genui): add GridContainerSpec, default registry and renderer
Devasy Aug 6, 2026
8d32d0d
feat(genui): generate the A2UI prompt section from the registry
Devasy Aug 6, 2026
fc7e843
refactor(genui): wire coach screen to the A2UI package, drop legacy r…
Devasy Aug 7, 2026
1b0b8cc
fix(genui): bracket negative-value ranges in DynamicChart line/bar axes
Devasy Aug 7, 2026
2287ff0
test(genui): cover all-negative bounds and malformed point entries
Devasy Aug 7, 2026
939349a
fix(genui): widen per-node children lookup back to components/element…
Devasy Aug 7, 2026
298126e
fix(genui): widen looksLikeUi to catch prose-prefixed fences, fix vac…
Devasy Aug 7, 2026
6561e95
refactor(genui): drop presentation payload from tools, add purity and…
Devasy Aug 7, 2026
5735d98
fix(genui): depth-agnostic purity regex, pin two silent-visual regres…
Devasy Aug 7, 2026
c0913bb
fix(genui): propagate registry through recursion, pin prompt drift, c…
Devasy Aug 7, 2026
8024efa
Merge branch 'r2.1.0' of https://github.com/Devasy/RepForge into feat…
Devasy Aug 7, 2026
1f327a5
docs: add design spec for Hive->SQLite migration + coach SQL query tool
Devasy Aug 7, 2026
7a0c18c
fix: persist assisted-load volume correctly, tighten exercise-handle …
Devasy Aug 7, 2026
f363a21
fix: bound sleep-analytics window, drop fabricated data, resolve musc…
Devasy Aug 7, 2026
8862e9d
fix(genui): pie negative-value filtering, overflow guard, stat-card u…
Devasy Aug 7, 2026
0ff6c2d
test: close vacuous-test gaps and pin already-fixed regressions
Devasy Aug 7, 2026
b35df0a
docs: add implementation plan for Hive->SQLite migration + coach SQL …
Devasy Aug 8, 2026
f22e1eb
chore: add sqflite dependencies for SQLite storage migration
Devasy Aug 8, 2026
18bfb86
feat: add SqliteStorageService with schema and workout session CRUD
Devasy Aug 8, 2026
8105d9d
fix: persist bodyWeightAtLog in SqliteStorageService sets table
Devasy Aug 8, 2026
6908914
feat: implement routine and target CRUD in SqliteStorageService
Devasy Aug 8, 2026
bd95d23
feat: implement muscle group and custom exercise CRUD in SqliteStorag…
Devasy Aug 8, 2026
34c485c
feat: implement settings, PR, training program, and conversation CRUD…
Devasy Aug 8, 2026
bf771d0
feat: implement export/import in SqliteStorageService, completing ISt…
Devasy Aug 8, 2026
06281e0
feat: add settings enumeration helper to StorageService for migration
Devasy Aug 8, 2026
93f0713
feat: add StorageMigrationService for one-time Hive-to-SQLite migration
Devasy Aug 8, 2026
8c9efcf
feat: resolve Hive-vs-SQLite storage backend in main() before runApp
Devasy Aug 8, 2026
6c82b4f
feat: add SqlQueryService for read-only SQL execution
Devasy Aug 8, 2026
6265901
feat: wire run_sql_query tool into CoachToolService
Devasy Aug 8, 2026
e1854d4
fix: fall back to fresh StorageService when app is constructed withou…
Devasy Aug 8, 2026
616ee4e
fix: block run_sql_query from reading settings/sqlite_master (credent…
Devasy Aug 8, 2026
07ae559
fix: prevent trailing SQL comment from breaking LIMIT wrapper
Devasy Aug 8, 2026
2b94d45
docs: warn model against SELECT * across joins in run_sql_query
Devasy Aug 8, 2026
14d8ec8
refactor: extract testable storage backend resolution logic; guard sq…
Devasy Aug 8, 2026
e4cface
docs: add design spec for syncing sleep/HR data into SQLite for coach…
Devasy Aug 11, 2026
d009807
docs: add implementation plan for syncing sleep/HR data into SQLite
Devasy Aug 11, 2026
4b607be
feat: add health_samples/sleep_sessions tables + upsert methods to Sq…
Devasy Aug 11, 2026
35952cc
fix: prevent run_sql_query from closing the app's shared database con…
Devasy Aug 11, 2026
ca12d74
fix: address Task 1 review findings
Devasy Aug 11, 2026
5569113
fix: replace Finalizer with deterministic tearDown cleanup
Devasy Aug 11, 2026
fdb7d88
feat: add HealthDataSyncService to pull sleep/HR data into SQLite
Devasy Aug 11, 2026
a35eed7
feat: sync health data into SQLite once per app launch
Devasy Aug 11, 2026
7f7504e
feat: add manual 'Sync coach data now' action to Profile screen
Devasy Aug 11, 2026
f59f749
feat: teach run_sql_query about the new health_samples/sleep_sessions…
Devasy Aug 11, 2026
71de154
fix: remove overly broad auto-close from init, add explicit close to …
Devasy Aug 11, 2026
6e9014d
fix: address final review findings for health sync + coach SQL tool
Devasy Aug 11, 2026
cc45fcb
fix: address migration/SQL-tool review findings from PR #66
Devasy Aug 15, 2026
3019728
Merge branch 'r2.1.0' into migrate/sqflite-db
Devasy Aug 15, 2026
a04517f
fix: address second round of CodeRabbit findings on PR #66
Devasy Aug 15, 2026
727b1b1
feat: make coach tool-call round limit configurable, surface invoked …
Devasy Aug 15, 2026
b664f20
Merge branch 'main' of https://github.com/Devasy/RepForge into migrat…
Devasy Aug 15, 2026
715ef8c
Merge branch 'r2.1.0' into migrate/sqflite-db
Devasy Aug 15, 2026
1719801
Merge branch 'r2.1.0' of https://github.com/Devasy/RepForge into migr…
Devasy Aug 18, 2026
f421f03
feat: overhaul workout recommendation engine with recovery, readiness…
Devasy Aug 19, 2026
623e8eb
Merge remote-tracking branch 'origin/main' into feat/model-recommenda…
Devasy Aug 27, 2026
0c22ddd
test: drop coverage for ApiService/SettingsScreen removed by main merge
Devasy Aug 27, 2026
113dd76
feat: add per-model Gemini thinking level control
Devasy Aug 28, 2026
012293f
test: cover the Gemini model picker's ids, default and fallback chain
Devasy Aug 28, 2026
bfb4698
fix: address CodeRabbit review findings on PR #66
Devasy Aug 28, 2026
dcc7cb2
Merge branch 'migrate/sqflite-db' into feat/model-recommendations
Devasy Aug 28, 2026
6058ddc
Merge branch 'r2.1.0' into migrate/sqflite-db
Devasy Aug 28, 2026
56a5b3e
Merge branch 'migrate/sqflite-db' into feat/model-recommendations
Devasy Aug 28, 2026
4cb2327
fix: address CodeRabbit review findings on PR #76
Devasy Aug 28, 2026
d789b76
fix: address CodeRabbit review findings on PR #76
Devasy Aug 29, 2026
57e3ce5
feat: confirm AI settings saves with a toast
Devasy Aug 29, 2026
e7187cf
Merge branch 'r2.1.0' into feat/model-recommendations
Devasy Aug 31, 2026
1d4cb24
fix: address CodeRabbit review findings on PR #76
Devasy Aug 31, 2026
282f002
refactor(ui): extract shared screen chrome into rf_shell, refine work…
Devasy Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions docs/superpowers/plans/2026-08-18-recommendation-engine-upgrade.md

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions workout-logger/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import 'genui/a2ui.dart';
import 'theme/a2ui_app_theme.dart';
import 'screens/home_screen.dart';
import 'screens/onboarding_screen.dart';
import 'screens/widgets/rf_widgets.dart';

/// Resolved once in main() before runApp(). Read lazily by
/// WorkoutLoggerApp._storageService's static initializer, which only runs
Expand All @@ -46,9 +47,8 @@ IStorageService? _resolvedStorageService;
/// One-time, flag-gated, reversible Hive -> SQLite cutover. See
/// docs/superpowers/specs/2026-08-08-sqlite-migration-and-coach-sql-tool-design.md §6.
Future<void> _resolveStorageBackend() async {
// Hive stays initialized unconditionally: the cutover flag itself lives in
// this settings box, so it has to be readable before we know which backend
// to build — and the pre-migration path still runs on Hive outright.
// Hive must be initialized before the cutover check itself, since the
// migration flag below is read directly from the Hive 'settings' box.
await Hive.initFlutter();
final settingsBox = await Hive.openBox<String>('settings');
final alreadyMigrated = settingsBox.get(storageMigratedFlagKey) == 'true';
Expand Down Expand Up @@ -220,6 +220,9 @@ class WorkoutLoggerApp extends StatelessWidget {
title: 'Workout Logger',
debugShowCheckedModeBanner: false,
theme: AppTheme.darkTheme,
// Above the Navigator, so every route feeds the ambient glow.
builder: (context, child) =>
AmbientMotionScope(child: child ?? const SizedBox.shrink()),
home: const AppInitializer(),
),
),
Expand Down Expand Up @@ -262,6 +265,7 @@ class _AppInitializerState extends State<AppInitializer> {
settings.geminiApiKey,
model: settings.geminiModel,
maxToolRounds: settings.geminiMaxToolRounds,
thinkingLevel: settings.geminiThinkingLevel,
);
try {
await gemini.loadUsage();
Expand Down
39 changes: 39 additions & 0 deletions workout-logger/lib/models/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ class WorkoutSession {
final String? notes;
/// Non-null when this session was successfully synced to Health Connect.
final DateTime? hcSyncedAt;
/// Optional once-per-workout subjective effort (1 = Easy, 2 = Solid,
/// 3 = Brutal), captured on the post-workout summary screen. Used only to
/// calibrate [EffortEstimator]'s per-set RPE anchor — never required.
final int? sessionEffort;

WorkoutSession({
required this.id,
Expand All @@ -324,6 +328,7 @@ class WorkoutSession {
required this.duration,
this.notes,
this.hcSyncedAt,
this.sessionEffort,
});

double get totalVolume =>
Expand All @@ -337,6 +342,7 @@ class WorkoutSession {
'duration': duration,
'notes': notes,
'hcSyncedAt': hcSyncedAt?.toIso8601String(),
'sessionEffort': sessionEffort,
};

factory WorkoutSession.fromJson(Map<String, dynamic> json) => WorkoutSession(
Expand All @@ -351,6 +357,7 @@ class WorkoutSession {
hcSyncedAt: json['hcSyncedAt'] != null
? DateTime.parse(json['hcSyncedAt'] as String)
: null,
sessionEffort: json['sessionEffort'] as int?,
);

WorkoutSession copyWith({
Expand All @@ -361,6 +368,7 @@ class WorkoutSession {
Object? duration = _sentinel,
Object? notes = _sentinel,
Object? hcSyncedAt = _sentinel,
Object? sessionEffort = _sentinel,
}) => WorkoutSession(
id: id == _sentinel ? this.id : id as String,
date: date == _sentinel ? this.date : date as DateTime,
Expand All @@ -373,6 +381,9 @@ class WorkoutSession {
hcSyncedAt: hcSyncedAt == _sentinel
? this.hcSyncedAt
: hcSyncedAt as DateTime?,
sessionEffort: sessionEffort == _sentinel
? this.sessionEffort
: sessionEffort as int?,
);
}

Expand Down Expand Up @@ -480,6 +491,34 @@ class SetRecommendation {
});
}

// ==================== Effort Estimate ====================

/// Where an [EffortEstimate]'s RPE value came from.
///
/// No per-set RPE picker exists in this app — [userReported] is reserved
/// for if one is ever added, so estimated values can never be confused with
/// a real logged one.
enum EffortSource { userReported, estimatedWithHr, estimatedHrless }

/// A 0–10 RPE (rate of perceived exertion) estimate for one set, inferred
/// from data already logged rather than asked of the user. See
/// [EffortEstimator] for how it's computed.
class EffortEstimate {
final double rpe;
final EffortSource source;

/// 0–1. Capped below 1.0 (see [EffortEstimator.maxEstimatedConfidence]) —
/// an estimate can never claim the certainty a real user-reported value
/// would have.
final double confidence;

const EffortEstimate({
required this.rpe,
required this.source,
required this.confidence,
});
}

// ==================== Growth Model ====================

/// Functional form of a fitted growth curve.
Expand Down
Loading
Loading