RPE nomenclature for Hydrolyze intensity

Writing Search related

The principle (verbatim, per signal-detector contract)

User's exact direction (2026-06-16):

"for intensity lets work on the nomenclature. use RPE instead of

other terms for instensity (e.g. RPE6-7, could also use a range.

RPE6-7 generally corrosponds to zone 2—roughly the intensity at

which you would hold a conversation but it would be uncomfortable—

Peter Attia n.d.). Also keep this in mind for the parser, as when

a coach creates a workout in the parser they have user moderate or

another more ambigous term. when they use ambiguious terms prompt

the user to assign an RPE to that term. so we can collect and save

the swimming data accordingly. And then in future know that when

the coach writes moderate in the parser you know that corrolates

to RPE6-7."

Why RPE is the right abstraction

The current intensity column on swimmer_pbs and workout_sets is free-text: 'max', 'moderate', 'threshold', 'easy'. These are ambiguous — different coaches mean different things by "moderate" (zone 2 vs zone 3). The flywheel needs a SHARED scale to compare across coaches and across history.

RPE (Rate of Perceived Exertion) is the standard scale in modern swim coaching (CR10 / OMNI: 1-10, where 1 = easy, 10 = all-out). It supports ranges (RPE 6-7), which matches the reality that lap-to-lap effort varies within a single set.

RPE6-7 = zone 2 = "the intensity at which you would hold a conversation but it would be uncomfortable" (Peter Attia, n.d., citing the conversational-pace test as a practical zone 2 marker).

The vocabulary-mapping principle (the deep insight)

The parser shouldn't FORCE the coach to speak RPE. The coach naturally says "moderate" or "hard" or "easy recovery." The parser should:

  1. Detect ambiguous terms ("moderate", "hard", "easy", "fast",

"tempo", "cruise", "all-out", "tough") in the workout description

  1. Look up the coach's vocabulary — a per-coach table

coach_vocabulary(coach_id, user_term, rpe) that maps the coach's natural language to RPE

  1. If mapped: use the RPE silently (small RPE indicator in the

corner so the coach can override)

  1. If not mapped: prompt inline with an RPE picker

(4-5 / 6-7 / 8-9 / 10). The coach taps one. The mapping is saved.

  1. Future use: the same coach's "moderate" silently resolves to

RPE6-7. The parser learns the coach's vocabulary over time.

This is the data flywheel applied to the coach's language, not just their PBs. Each session, the parser either uses a known mapping (silent) or learns a new one (prompt). Over a season, the coach's vocabulary is fully mapped, and they can keep using their natural language without thinking about RPE.

The collected coach_vocabulary rows are also a per-coach "intensity training" dataset. Future analysis: "this coach's 'moderate' = RPE6-7, but the average across all coaches maps 'moderate' to RPE7-8" — useful for new-coach onboarding.

The proposed canonical mapping

User term (parser)RPE mappingReasoning
"easy", "recovery"RPE4-5Easy aerobic, can hold conversation
"moderate", "cruise"RPE6-7Zone 2, conversational but uncomfortable
"hard", "threshold", "tempo"RPE8-9Comfortably hard, lactate threshold
"max", "sprint", "all-out"RPE10All-out, no range

RPE 1-3 is unused in swim training (too easy to be relevant). RPE supports ranges ("RPE6-7" is two numbers; single values parse to a degenerate range [n, n]).

How the 5-way match adapts

The v1.13 5-way match key is (swimmer, stroke, distance, intensity, gear). With RPE-based intensity, the match algorithm changes:

TierLogicExample
1. Exactworkout RPE == PB RPE"RPE6-7" matches "RPE6-7"
1.5. Range overlapworkout RPE range ∩ PB RPE range ≠ ∅"RPE6-7" matches "RPE7" (the 7 overlaps)
2. Same RPE, any gearworkout RPE == PB RPE, gear differs"RPE6-7 @ paddles" matches "RPE6-7 @ no gear"
3. Any RPE, same stroke/distanceany intensity overlap"RPE6-7" matches "RPE4-5" (broader fallback)

The algorithm parses RPE strings ("RPE6-7") into numeric ranges (e.g., [6, 7]). Single values parse to [n, n]. Legacy terms ('max', 'moderate', 'threshold', 'easy') parse via a fallback table at query time, so v1.14 ships non-destructively.

Why this matters for the pairing engine

The pairing engine's accuracy depends on the predictor knowing the swimmer's pace for THE specific intensity the coach is asking for. Today, the predictor uses the PB at whatever intensity is closest to the workout's intensity (the 5-way match). With RPE:

swimmer's RPE6-7 PB → exact match → tight σ → high confidence

only the swimmer's RPE10 PB → tier 3 fallback → loose σ → low confidence (correctly: the predictor doesn't know the swimmer's moderate pace)

The RPE system makes the confidence calibration tighter and more honest about the actual training intensity, not the race intensity.

The v1.14 plan

StepWhatWhy
1Add coach_vocabulary table(coach_id, user_term, rpe, created_at). The parser's learning state.
2Update WorkoutSet.intensityLabel to store RPE syntax"RPE6-7" becomes the canonical format from this point forward
3Add RPE parser to SessionStartViewDetects ambiguous terms in the workout description, shows inline RPE picker, saves vocabulary
4Update PBService to parse RPE stringsTier 1.5 (range overlap) and updated tiered fallbacks
5Map legacy 'max'/'moderate'/etc. at query timeNon-destructive — v1.14 ships, v2 migrates
6CLI test scenario: "RPE range overlap"Verify Tier 1.5 works correctly

Open questions for the user

Related concepts

Cited

Published and managed by TARS, an AI co-author built on Nathan's gbrain.