Skip to content

feat(plan-tuner): Workout Plan Fine Tuner v1 - #60

Merged
silver-snoopy merged 5 commits into
masterfrom
feature/workout-plan-tuner
Apr 11, 2026
Merged

feat(plan-tuner): Workout Plan Fine Tuner v1#60
silver-snoopy merged 5 commits into
masterfrom
feature/workout-plan-tuner

Conversation

@silver-snoopy

@silver-snoopy silver-snoopy commented Apr 11, 2026

Copy link
Copy Markdown
Owner

Summary

First concrete slice of F2 (Workout Training Intelligence) from the 2026-03-22 actionable-intelligence research. Lets users persist a workout plan and, from each weekly report, generate an AI-tuned version for next week with per-change accept/reject.

  • Backend: new workout_plans / plan_versions / plan_adjustment_batches / plan_adjustments tables (migration 011), rule-first candidate-generation engine, LLM-as-selector tuner service with structural evidence validation, full CRUD + tune routes.
  • Frontend: new /plan page (create + view + version history), AdjustmentReviewModal with day-grouped diff + per-row accept/reject, OptimizePlanButton in expanded ReportCard.
  • Docs: docs/product-capabilities.md §7 (UC-PLAN-01..05), research update in the 2026-03-22 research doc.

Architecture highlights

  • Rule-first / LLM-selects. Backend deterministically computes the legal candidate set per exercise (hold / double progression / 2-for-2 / deload) with hard safety caps (±10% load, ≤1.3× weekly volume ACWR, max 40% of exercises changed per batch). The LLM only picks one and writes rationale. Eliminates hallucinated unsafe loads.
  • Structural evidence requirement. Every LLM selection must cite ≥1 evidence reference or the tuner retries once then errors. Defense-in-depth validation on top of the rule-based candidate filter.
  • Prompt-injection defense. PR feat: prompt injection defense & chat security hardening #58's flagSuspiciousInput applied to all user-pasted plan fields before prompting; matched fields are stripped with a marker rather than rejected.
  • Immutable versions. Every accept creates a new plan_versions row. Prior versions preserved for history/rollback. Transactional batch+adjustments insert.

v1 scope discipline

Shipped: paste-only plan source, single plan per user, CTA-only trigger, day count locked, one "balanced" progression personality, no F3 outcome coupling, no Hevy push-back. All per user-approved decisions at the intent gate.

Test plan

  • Backend: 410 unit + route tests pass (66 new)
  • Frontend: 74 component tests pass (22 new)
  • E2E: 7 Playwright tests covering full flow (create plan → optimize from report → review → accept → version bump)
  • Build clean across shared / backend / frontend
  • Lint clean, Prettier clean
  • Migration 011 reviewed — unique user_id constraint, proper FKs, CHECK constraints
  • Local manual smoke test: create plan → generate live report → tune → review → accept
  • Confirm Railway migration runs cleanly against production DB

Review artifacts

  • Intent, research, plan, verification, retro: .ade/tasks/workout-plan-tuner/
  • 3 parallel reviewers (logic / conventions / security) flagged 7 HIGH + 5 selected MEDIUM findings; all fixed in 2 review-fix cycles before this PR
  • Known v1 follow-ups documented in docs/product-capabilities.md §7

🤖 Generated with Claude Code

silver-snoopy and others added 5 commits April 11, 2026 22:35
Implements all Phase 4 frontend deliverables for the workout plan
fine tuner feature:

- useWorkoutPlan.ts: TanStack Query hooks (useCurrentPlan, useCreatePlan,
  useTunePlan, useDecideAdjustments) with toast feedback
- PlanPage: empty state with inline editor, populated state with day cards
  and version badge, collapsible version history
- PlanEditor: textarea + Parse & Save with loading/error states
- PlanDayCard: exercise table with sets × reps × load, fallback notes view
- PlanVersionHistory: collapsible version list with source badges
- AdjustmentReviewModal: day-grouped diff list, per-row accept/reject,
  accept all/reject all triage, confidence dots, evidence expand, commit
- OptimizePlanButton: enabled/disabled states, tune mutation, modal integration
- Unit tests: 22 new tests across 3 test files (all passing)
- E2E: 7-test spec covering full create→optimize→review→accept flow

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements the complete Workout Plan Fine-Tuner backend:
- DB query module (workout-plans.ts) with COLUMNS/mapRow pattern
- Plan schema validation (plan-schema.ts) and free-text parser (plan-parser.ts)
- Exercise metadata table ~50 exercises (exercise-metadata.ts)
- Rules engine: progression rules (2-for-2, double, deload, RPE guardrail),
  safety caps (±10% load, 1.3× volume, 40% change ratio, injury lock),
  and candidate generator orchestration
- AI tuner prompt builder and main tunePlan service (9-step orchestration)
- 7 REST endpoints under /api/plans with full error envelopes
- 62 new tests (406 total); build and lint clean

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
H1: applyMaxChangeRatio called post-LLM in tuner.ts step 8a;
    applyVolumeCap wired into candidate-generator.ts per-day loop.
H2: Add UNIQUE(user_id) to workout_plans migration; upsertPlan uses
    ON CONFLICT (user_id) DO UPDATE instead of DO NOTHING + separate UPDATE.
H3: validatePlanData accepts full 'conservative'|'balanced'|'aggressive'
    union; missing value defaults to 'balanced'.
H4: PATCH decide handler validates sourceVersion BEFORE committing status
    updates; bulkUpdateAdjustmentStatus now scoped to batchId.
H5: Export flagSuspiciousInput from conversation-service; tuner sanitizes
    day names, exercise names/notes, plan notes before building LLM prompt.
H6: Annotate aiProvider as AIProvider and batch as PlanAdjustmentBatch.
H7: useDecideAdjustments response type is DecideAdjustmentsResponse
    (versionNumber, data, message?); toast uses ?. fallback.
M1: Injury keyword matching uses word-boundary regex; 'back' narrowed to
    'lower back'/'lumbar' to avoid day-name false positives.
M2: insertAdjustmentBatchWithAdjustments wraps batch + adjustments in
    a single transaction (partial-batch protection).
M3: bulkUpdateAdjustmentStatus adds AND batch_id = $3 WHERE clause.
M4: POST /api/workout-plans rejects rawText > 50 000 chars with 413;
    buildFallback truncates stored notes to 10 000 chars.
M5: Tune endpoint error handler logs {planId, errMsg} instead of full err.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace non-atomic insertAdjustmentBatch + insertAdjustment loop in
tuner.ts with a single insertAdjustmentBatchWithAdjustments call that
wraps both the batch header and all adjustment rows in one transaction.
Update tuner.test.ts mocks and assertions accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add §7 Workout Plan Fine Tuner to product-capabilities.md with
UC-PLAN-01 through UC-PLAN-05, engine architecture, v1 limitations,
and future work. Renumber former §7-9 to §8-10.

Append implementation update block to actionable-intelligence-features
research doc recording F2 slice decisions and open items.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@vercel

vercel Bot commented Apr 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
vitals Ignored Ignored Apr 11, 2026 9:02pm

@silver-snoopy
silver-snoopy merged commit a749259 into master Apr 11, 2026
5 checks passed
@silver-snoopy
silver-snoopy deleted the feature/workout-plan-tuner branch April 11, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant