Skip to content

Add Foundation Milestones and Movement Progressions for pre-Beginner …#1

Merged
OneMuppet merged 5 commits intoOpenProgression:mainfrom
SnowOak-Ventures:feature/foundation-progressions
Feb 25, 2026
Merged

Add Foundation Milestones and Movement Progressions for pre-Beginner …#1
OneMuppet merged 5 commits intoOpenProgression:mainfrom
SnowOak-Ventures:feature/foundation-progressions

Conversation

@andreas-eg
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown
Contributor

@OneMuppet OneMuppet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: Foundation Milestones & Movement Progressions

Thanks for putting this together. The research is thorough, the spec is well-written, and this addresses a real gap in the standard. People at the bottom of Beginner (never trained, returning from injury) currently get zero feedback for months -- this fixes that.

Below is a full review with specific issues and solutions. Addressing these will get the PR to merge.


1. Backwards Compatibility (the big-picture concern)

OpenProgression is a standard, not just a codebase. Apps, gym software, and coaching platforms are already consuming our data. Every change needs to be non-breaking by default. This PR is already designed to be additive (new files, no changes to existing schemas), which is the right approach. But there are a few things to tighten up:

The "7 levels, 8 categories" contract

Our tagline, README, website, and marketing all say "7 levels, 8 categories." Foundation Milestones introduce what looks like 3 new levels (F1, F2, F3) below Beginner. Even though the spec correctly states "milestones are NOT levels," consumers and users will inevitably ask: "Is this 10 levels now?"

Solution: The spec and README text should be very explicit that:

  • The 7-level system is unchanged. F1/F2/F3 are not levels.
  • data/levels.json is unchanged. No new level IDs, no new percentile ranges.
  • Milestones live in a completely separate data file (milestones.json) with a different schema.
  • Apps that don't implement milestones continue to work with zero changes.

Suggested wording for the README section:

Foundation Milestones are not levels -- they do not change the 7-level system. They are optional pre-level progress markers in a separate data file (data/milestones.json). Existing implementations that only read data/levels.json and data/benchmarks/*.json are unaffected.

Versioning strategy for the standard

This PR is a good moment to establish how OP handles additive extensions. We should document (maybe in CONTRIBUTING.md or a new spec/versioning.md) something like:

  • Patch (1.0.x): Bug fixes, typo corrections, source citation updates
  • Minor (1.x.0): Additive extensions (new data files, new optional fields). Existing consumers unaffected.
  • Major (x.0.0): Breaking changes to existing schemas, level definitions, or benchmark values

This PR would be a minor version bump (1.0.0 -> 1.1.0) since it adds new files but doesn't modify existing ones. The version fields in milestones.json and progressions.json are currently "1.0.0" -- consider whether these should match the standard's version or have their own versioning. I'd suggest they track the standard version (so "1.1.0" when this ships).

Action: Add a note in the PR about which version this targets. We can handle the versioning spec separately, but the PR should at minimum bump version fields appropriately.


2. README Merge Conflict (will break merge)

The PR's README changes are based on an older version of main. Since the PR was opened, we've added deep links to section headers, reformatted the roadmap with checkboxes, and added links throughout.

What will conflict

The roadmap section has diverged significantly:

PR expects:

## Roadmap

+- **Movement progressions & foundation milestones** -- ...
 - **Age-adjusted benchmarks** -- Current standards target ~18-40...

Main currently has:

## Roadmap

- [x] **[Level Calculator](https://openprogression.org/calculator)** -- ...
- [x] **[Scaled Programming](https://openprogression.org/programming)** -- ...
- [ ] **Age-adjusted benchmarks** -- Current standards target ~18-40...

The repository structure tree has also changed slightly.

Solution

Rebase the branch onto current main:

git fetch origin
git rebase origin/main

Then resolve the README conflicts:

  • Keep the current main's deep-linked headers and checkbox roadmap format
  • Add the Foundation Milestones section and progression files to the existing structure
  • The new roadmap item should follow the checkbox pattern: - [ ] **Movement progressions & foundation milestones** -- ...

Actually -- since this PR adds milestones and progressions, the roadmap item should be - [x] (checked) once merged.


3. Em Dashes -- Replace Throughout

We don't use em dashes (—) in this project. Use -- or rephrase instead.

Affected files:

  • README.md: F1 description ("no gym needed"), milestone explanation, roadmap item
  • data/milestones.json: the description field at the top level
  • spec/levels.md: multiple lines in the Foundation Milestones section
  • spec/progressions.md: throughout (many instances)

Solution

Run a find-and-replace across the PR's changed files:

# Replace all em dashes with --
sed -i '' 's/—/--/g' README.md spec/levels.md spec/progressions.md data/milestones.json

Verify the replacements read naturally. Some may benefit from rephrasing instead of a straight swap.


4. Equipment Tag Inconsistency

Two dumbbell exercises are tagged "equipment": "kettlebell":

  • db_press (Dumbbell Shoulder Press) in progressions.json, strict_press chain step 5
  • db_bench_press (Dumbbell Bench Press) in progressions.json, bench_press chain step 5

The spec's equipment tag table defines kettlebell as "Kettlebell or dumbbell," but for a machine-readable standard, having "equipment": "kettlebell" on a movement named "Dumbbell Bench Press" will confuse API consumers and break any filtering logic that takes the tags literally.

Solution (pick one)

Option A (recommended): Add a "dumbbell" equipment tag alongside "kettlebell":

| kettlebell | Kettlebell | Maybe |
| dumbbell   | Dumbbell   | Maybe |

Then tag the two dumbbell exercises with "equipment": "dumbbell".

Option B: Rename the tag to "free_weight" to cover both kettlebells and dumbbells. Less precise but avoids the proliferation of similar tags.

Option C: Keep as-is but rename the tag definition in the spec from "Kettlebell" to "Kettlebell / Dumbbell" and add a note. Least disruptive but still semantically confusing in the data.


5. Category Mapping: Farmer's Carry as "Gymnastics"

In milestones.json, the Farmer's Carry is categorized under "gymnastics". In the existing OP standard, gymnastics = pull-ups, HSPU, muscle-ups, toes-to-bar. Farmer's carry is a loaded carry / grip exercise.

I understand the reasoning -- it's in the pull-up progression chain (gymnastics target) and serves as an equipment-free grip strength proxy. But a consumer filtering milestones by category would see "gymnastics: carry heavy bags for 30 seconds" and be confused.

Solution

Either:

  • Move it to "bodyweight" -- it's a body-in-space loaded movement, closer to bodyweight than gymnastics
  • Add an explicit note in the milestone data or spec explaining why it's mapped to gymnastics (grip strength prerequisite for pull-up chain)
  • Use a "progressionCategory" field separate from "category" to distinguish "which OP category this feeds into" from "what type of exercise this is"

The simplest fix is moving it to "bodyweight" and adding a comment in the spec about the relationship to the pull-up chain.


6. Missing Categories in Milestones -- Needs Explicit Documentation

Foundation milestones cover 5-6 of the 8 categories (Squatting, Pressing, Pulling, Bodyweight, Monostructural, and arguably Gymnastics via grip). Olympic Lifting and Endurance are absent entirely.

This is almost certainly intentional (you can't clean without a barbell; metcon benchmarks like Fran require multiple prerequisite skills). But the spec doesn't say this, which means every reader will wonder "is this incomplete?"

Solution

Add a short section to spec/progressions.md under the milestone definitions:

Categories not covered by Foundation Milestones

Olympic Lifting and Endurance are intentionally excluded. Olympic lifts require barbell proficiency (which starts developing at F3 / post-F3). Endurance benchmarks (Fran, Grace, Murph) are multi-skill metcons that require competency in several movement patterns first. Athletes at the Foundation level should focus on building the movement patterns that these categories eventually require.

This turns a "gap" into a documented design decision.


7. The "either" Criteria Type -- New Schema Pattern

F3's "Dead Hang OR Farmer's Carry" requirement introduces a new criteria type ("type": "either") that doesn't exist anywhere else in the OP data model:

"criteria": {
  "type": "either",
  "options": [
    { "movement": "dead_hang_30s", "type": "time", "target": 30, "unit": "seconds" },
    { "movement": "farmers_carry_60s", "type": "time", "target": 60, "unit": "seconds" }
  ]
}

This is a nice pattern for accessibility (home vs. gym), but it's a schema extension that consumers need to handle. Any app parsing milestone requirements will encounter a criteria type it hasn't seen before.

Solution

  • Document the "either" type in the spec's data format section -- what it means, how to evaluate it (pass if ANY option passes), and the schema shape
  • Add validation for the "either" type in validate-data.mjs -- currently the validator checks typeof req.criteria === "object" but doesn't validate the "either" shape specifically
  • Consider whether this pattern might appear in future benchmark data too, and design the schema accordingly

8. Missing Source Citation

The spec text references Murphy et al. (2023) regarding Couch to 5K dropout rates ("73% non-completion rate with 19% injury incidence") in spec/progressions.md, but this source is not in data/sources.json.

Solution

Add the Murphy reference to sources.json:

{
  "id": "murphy_2023",
  "citation": "Murphy, M.H., et al. (2023). [full citation for the C25K dropout study]",
  "type": "peer_reviewed",
  "notes": "Couch to 5K completion and injury rates"
}

Or if this was a secondary reference not critical to OP's data, remove the specific stats from the spec text.


9. Duplicated Progression Steps

Steps 1-4 (wall push-up -> incline push-up -> knee push-up -> full push-up) are fully duplicated across three chains: push_up, strict_press, and bench_press. The sharedSteps and sharedUpTo fields document the relationship, which is good.

This isn't a blocker, but be aware that any future update to (say) the wall push-up criteria would need to be applied to 3 places. The duplication is fine for v1 simplicity -- just flag it for future consideration.

No action needed now, but a future improvement could normalize this by having shared chains reference step data from a single source.


Summary: What's needed to merge

# Issue Severity Action
1 Backwards compatibility language Medium Strengthen "not levels" messaging, add versioning note
2 README merge conflict Blocker Rebase onto current main, resolve conflicts
3 Em dashes Medium Find-and-replace with -- across all PR files
4 Equipment tags Low Add "dumbbell" tag or rename to "free_weight"
5 Farmer's carry category Low Move to "bodyweight" or document the gymnastics mapping
6 Missing category documentation Low Add explicit note about Olympic Lifting / Endurance exclusion
7 "either" criteria type Medium Document in spec, add validation
8 Missing Murphy source Low Add to sources.json or remove stats
9 Duplicated steps Info No action needed now

Items 2 and 3 are the hard requirements. The rest are recommendations that would strengthen the PR but aren't merge blockers.

Great work on this -- the research depth and spec quality are exactly what the standard needs. Looking forward to the next revision.

@OneMuppet
Copy link
Copy Markdown
Contributor

One more thing -- we just added spec/versioning.md to main which defines the stability contract for the standard (what counts as breaking, how version bumps work, core vs extension data files).

Worth reading before the next revision, especially:

  • "Extensions vs. Core" -- your new files (milestones.json, progressions.json) are correctly positioned as extensions. The spec now formalizes this distinction.
  • "New levels" section -- explicitly documents that Foundation Milestones are the right pattern for adding sub-Beginner granularity without touching the 7-level system.
  • "Adding New Content" -- covers what's minor vs major, so you can see where this PR fits (minor bump, 1.0.0 -> 1.1.0).

File: spec/versioning.md

…athletes

Extend the standard downward to serve untrained and deconditioned populations.
Adds three milestones (F1 Foundation, F2 Moving, F3 Ready) as optional pre-level
markers, and formalized movement regression chains for each benchmark movement.

New files: spec/progressions.md, data/progressions.json, data/milestones.json
Updated: README, levels spec, sources, and validation script.
…ibility

Replace dead hang with farmer's carry in F1 (no pull-up bar needed),
add box squat step, McGill Big 3 core exercises, band rows for home
pulling, walk 10min as running entry point, and 4 new research sources.
- Replace em dashes with -- across spec and data files
- Fix equipment tags: kettlebell -> free_weight for dumbbell exercises
- Fix Farmer's Carry category: gymnastics -> monostructural
- Remove Murphy et al. citation, soften C25K dropout claims
- Document "either" criteria type in spec and validate in script
- Strengthen "not levels" messaging with explicit compatibility note
- Add rationale for excluding Olympic Lifting and Endurance from milestones
@andreas-eg andreas-eg force-pushed the feature/foundation-progressions branch from 77f8332 to e12a884 Compare February 25, 2026 10:06
Per spec/versioning.md, milestones.json and progressions.json are
extensions introduced in 1.1.0. Update version fields and validator
to reflect this.
@andreas-eg
Copy link
Copy Markdown
Contributor Author

Addressed all review feedback in e12a884 + bumped extension versions in
a4efcaf. Item by item:

  1. Rebase onto main -- Done. Branch is cleanly rebased onto current main
    (including the versioning spec).

  2. Em dashes → -- -- Replaced all occurrences in README.md, spec/levels.md,
    spec/progressions.md, and data/milestones.json.

  3. "Not levels" messaging -- Added explicit data/levels.json row to the
    compatibility table and a bold callout: "Foundation Milestones are not
    levels. They do not alter data/levels.json in any way."

  4. "either" criteria type -- Documented in spec/progressions.md with a
    Criteria Types table and JSON example. Updated the validator to check that
    options is an array with at least 2 entries, each having movement, type, and
    target.

  5. Equipment tags -- "kettlebell" → "free_weight" for Goblet Squat, KB
    Deadlift, DB Shoulder Press, DB Bench Press. Updated spec table.

  6. Farmer's Carry category -- "gymnastics" → "monostructural" for both
    entries in milestones.json.

  7. Murphy citation -- Removed "73% dropout" stat and "Murphy et al., 2023"
    from spec and data. Softened to "high dropout rates partly due to large
    progression jumps".

  8. Excluded categories rationale -- Added section explaining why Olympic
    Lifting (requires coaching) and Endurance (requires component proficiency)
    aren't covered by Foundation Milestones.

  9. Push-up duplication -- No action needed per review.

Version bump -- Noticed the new spec/versioning.md on main, which lists
milestones.json and progressions.json as 1.1.0 extensions. Bumped version
fields in both data files, spec/progressions.md, and the validator to 1.1.0.

Validator passes all 1232 checks.

@OneMuppet
Copy link
Copy Markdown
Contributor

Follow-up Review (after commits b4bb428, e12a884, a4efcaf)

Great work addressing the feedback. Almost everything from the first review is resolved. Here's the status and one remaining issue.

Resolved

# Issue Resolution
1 Backwards compatibility Strong "not levels" messaging throughout. Compatibility table in spec explicitly notes data/levels.json is untouched.
2 README merge conflict Rebased cleanly onto current main. Roadmap uses checkbox format, deep links preserved.
3 Em dashes All replaced with -- across every file.
4 Equipment tags "free_weight" tag adopted. Spec table updated. DB press and DB bench press correctly tagged.
5 Missing category docs "Categories Not Covered by Foundation Milestones" section added for Olympic Lifting and Endurance. Clear reasoning.
6 "either" criteria type Documented in spec with schema example and criteria type table. Validator now checks either options array, minimum 2 options, and required fields per option.
7 Murphy source Specific stats removed, softened to "high dropout rates partly due to large progression jumps." Clean approach.
8 Version bump milestones.json and progressions.json both at "1.1.0". Spec header updated. Validator checks the new version.

Remaining: Spec vs Data Category Mismatch for Farmer's Carry

The data in milestones.json was changed from "gymnastics" to "monostructural" for the farmer's carry, but the spec tables in spec/progressions.md were not updated to match. The spec and data must agree -- this is a core principle of the standard.

F1 -- spec says one thing, data says another:

spec/progressions.md F1 table:

| Farmer's Carry | Gymnastics | 30 seconds with ~5kg per hand |

data/milestones.json F1:

{
  "movement": "farmers_carry_30s",
  "category": "monostructural",
  ...
}

F3 -- same mismatch:

spec/progressions.md F3 table:

| Dead Hang OR Farmer's Carry | Gymnastics | 30 seconds hang, OR 60 seconds carry (~8kg/hand) |

data/milestones.json F3:

{
  "movement": "dead_hang_or_carry",
  "category": "monostructural",
  ...
}

Which category should it be?

Beyond just syncing spec and data, there's a design question here. With farmer's carry as "monostructural", the milestone category coverage looks like this:

F1:

  • Squatting: Chair Sit-to-Stand
  • Pressing: Wall Push-up
  • Pulling: Glute Bridge
  • Monostructural: Farmer's Carry + Walk 1km (two items, same category)
  • Gymnastics: nothing
  • Bodyweight: nothing

F3:

  • Squatting: Air Squat
  • Pressing: Full Push-up
  • Pulling: RDL
  • Bodyweight: Plank Hold
  • Monostructural: Dead Hang OR Farmer's Carry + Run 1 Mile (two items, same category)
  • Gymnastics: nothing

The milestones are supposed to follow the weakest-link principle and test across multiple categories. Having 2 monostructural items and 0 gymnastics in both F1 and F3 weakens that cross-category coverage.

Recommended fix

Option A (recommended): Revert to "gymnastics" in the data, update nothing in the spec.

The original "gymnastics" mapping actually made more sense. Farmer's carry is grip work -- it's in the pull-up progression chain (which targets gymnastics). Dead hang is explicitly a gymnastics prerequisite. Categorizing these as gymnastics gives the milestones proper cross-category coverage and connects them to the progression chain they feed into. The spec already has it right.

Changes needed:

  • data/milestones.json F1: change farmer's carry category back to "gymnastics"
  • data/milestones.json F3: change dead_hang_or_carry category back to "gymnastics"
  • No spec changes needed (already says Gymnastics)

Option B: Move to "bodyweight" in both spec and data.

Farmer's carry as bodyweight is defensible (loaded carry, body moving through space). This keeps gymnastics empty but at least doesn't double up on monostructural. Dead hang is a stretch for bodyweight though.

Changes needed:

  • data/milestones.json: change both to "bodyweight"
  • spec/progressions.md: update both F1 and F3 tables to say Bodyweight

Option C: Keep as "monostructural" but update the spec to match.

Least recommended. Fixes the mismatch but weakens cross-category coverage.

Changes needed:

  • spec/progressions.md: update F1 and F3 tables to say Monostructural

Whichever option you pick, the rule is: spec and data must say the same thing. The validator checks categories against data/categories.json, but it can't catch when the human-readable spec diverges from the machine-readable data. That's on us to keep in sync.

Once this is resolved, the PR is ready to merge.

Farmer's carry and dead hang feed the pull-up progression chain
(gymnastics). Keeping them as gymnastics preserves cross-category
coverage in milestones and matches the spec tables.
Copy link
Copy Markdown
Contributor

@OneMuppet OneMuppet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All review items resolved. Spec and data are in sync, category coverage is solid, versioning is correct at 1.1.0, and the extension is cleanly additive with no impact on core data files.

Good to merge.

@OneMuppet OneMuppet merged commit 0c53015 into OpenProgression:main Feb 25, 2026
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.

2 participants