optional velo reads json "reads": { "enabled": true, "required": false, "type": "PITCH_VELO", "unit": "mph", "mode": "max_of_attempts", "attempts_expected": 5, "bind_goal_type": "ARM_VELO", "allow_skip_measurement": true } optional lift reads json "reads": { "enabled": true, "required": true, "type": "LIFT_TOP_SET", "unit": "kg", "mode": "best_of_session", "attempts_expected": 3, "bind_goal_type": "BENCH", "derive": ["LIFT_1RM_EST"], "allow_skip_measurement": true } Note: we added a feature on install during test to wipe user data and not back it up. will need to reverse that in production important for lifts { "type": "section", "title": "Pre-Activation", "block_tag": "pre_activation" }, { "id": "jband_1", "name": "J-Band Series", "category": "warmup", "prescription": "n/a" }, { "type": "section", "title": "Med Ball (Light)", "block_tag": "light_med_ball" }, { "id": "mb_rot_1", "name": "Rotational Scoop Toss", "category": "power", "prescription": "3x6/side" }, { "type": "section", "title": "Strength", "block_tag": "strength" }, { "id": "trap_dl", "name": "Trap Bar Deadlift", "category": "lift", "prescription": "4x5 @RPE7", "restSeconds": 120 }, { "type": "section", "title": "Bracing Core", "block_tag": "bracing_core" }, { "id": "deadbug", "name": "Dead Bug", "category": "core", "prescription": "3x8/side" }, { "type": "section", "title": "Mobility", "block_tag": "mobility" }, { "id": "hip_mob", "name": "Hip Mobility Flow", "category": "mobility", "prescription": "5 min" } How to use block_tag (exact pattern) Rule 👉 Put block_tag on section rows Drills inherit the current block until the next section appears. You do not need to tag every drill. Example: Refactor ONE day from your pack Before (current) { "type": "section", "title": "Throwing – Intent" }, { "id": "intent_throws", "category": "throwing", "prescription": "10–16 throws @ 85–95%" } After (with block_tag) { "type": "section", "title": "Throwing – Intent", "block_tag": "intent_throwing" }, { "id": "intent_throws", "category": "throwing", "prescription": "10–16 throws @ 85–95%" } Now the app knows: These throws are high intent They are not recovery throws They should be hidden on Red days Recommended block_tags for YOUR pack Use a small, opinionated set. Throwing intent_throwing → high intent days recovery_throwing → <60%, flush, easy touch_throwing → optional/light intent Strength primary_strength → squat / hinge / main lift support_strength → upper support, core Technique & Recovery technique mobility That’s it. Don’t overbuild. Update your readiness rules to use block_tag Red day (precise) Instead of: "categories": ["throwing", "recovery", "technique"] You get: "actions": [ { "type": "allow_only_blocks", "block_tags": [ "recovery_throwing", "touch_throwing", "technique", "mobility" ] } ] Now: ❌ Intent throwing disappears ❌ Strength disappears ✅ Recovery throws remain ✅ Technique remains That’s exactly what the Foundational Athlete document intends. How the app should interpret block_tag Parsing logic (simple) Walk the drills array top → bottom Track currentBlockTag whenever you hit a section Assign that block_tag to all drills until the next section Rendering logic Green: render all Yellow: apply actions only to matching block_tags Red: only render drills whose block_tag is in the allow list Do you need to change everything right now? No. Here’s the phased approach I recommend: Phase 1 (what you’ve already done) Use category for readiness Works immediately Phase 2 (incremental, safe) Add block_tag to section headers Update readiness rules to prefer block_tag if present Fall back to category if missing This avoids breaking older packs. Mental model to remember Category = taxonomy Block tag = session logic If readiness affects session logic, use block_tag.