added sync and backup
This commit is contained in:
109
.vscode/launch.json
vendored
Normal file
109
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// VS Code debug configurations for openrun.
|
||||
// Requires the "Python" + "Python Debugger" extensions from Microsoft.
|
||||
// Press F5 in any file to pick a configuration.
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Streamlit: openrun-web",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "streamlit",
|
||||
"args": [
|
||||
"run",
|
||||
"${workspaceFolder}/src/openrun/web/app.py",
|
||||
"--server.port=8501",
|
||||
"--browser.gatherUsageStats=false"
|
||||
],
|
||||
// justMyCode=false lets you step into openrun + Streamlit internals.
|
||||
// Set to true if you only ever want to break in your own code.
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Pytest: all tests",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "pytest",
|
||||
"args": ["tests", "-v"],
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Pytest: current file",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "pytest",
|
||||
"args": ["${file}", "-v"],
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Python: current file",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "CLI: openrun-init",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "openrun.setup",
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "CLI: openrun-ingest <path>",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "openrun.ingest.garmin_export",
|
||||
"args": ["${input:exportPath}"],
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "CLI: openrun-link-fit <path>",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "openrun.ingest.fit_linker",
|
||||
"args": ["${input:exportPath}"],
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "CLI: openrun-link-fit --relink <new-root>",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "openrun.ingest.fit_linker",
|
||||
"args": ["${input:exportPath}", "--relink"],
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "CLI: openrun-sync",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"module": "openrun.ingest.garmin_api",
|
||||
"justMyCode": false,
|
||||
"console": "integratedTerminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
"id": "exportPath",
|
||||
"type": "promptString",
|
||||
"description": "Path to a Garmin export folder or .zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
55
NEXT_SESSION.md
Normal file
55
NEXT_SESSION.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Session handoff — 2026-06-12
|
||||
|
||||
Working plan agreed with the user: step through P0→P4 below, in order.
|
||||
Read this file instead of re-exploring the repo; README.md + ROADMAP.md cover
|
||||
architecture and conventions. Delete this file when the list is done.
|
||||
|
||||
## State (verified 2026-06-12, P0 session)
|
||||
|
||||
- All 111 tests pass (`uv run pytest`).
|
||||
- **P0 DONE** (commit 6df25bcd, NOT yet pushed — push denied to agent, run
|
||||
`git push origin main`): .gitignore fixed and Takeout dump (23,673 files,
|
||||
personal health data) untracked; note it is still in remote history from
|
||||
earlier pushes — rewrite history if that ever matters. `.gitlab-ci.yml`
|
||||
added (assumes GitLab at g.o00.io; swap if Gitea/Forgejo). `gitlab` remote
|
||||
URL typo (ttps://) fixed. `scripts/backup_db.sh` snapshots the DB, keeps 14.
|
||||
- DB: `garmin/data/garmin.db` is canonical — 378 activities (→ 2026-05-10),
|
||||
349 FITs linked, wellness through 2026-05-17.
|
||||
- The stray `../data/garmin.db` (vault root) was a Takeout-ZIP ingest run from
|
||||
the wrong cwd on 2026-06-08 (7 extra activities May 17–Jun 2, epoch-ms
|
||||
timestamps, no FITs). Copied to
|
||||
`data/backups/vault-root-takeout-ingest-2026-06-08.db`; the original at
|
||||
`../data/` is redundant once live sync runs — user should delete it.
|
||||
- **Sync is blocked on auth**: `.secrets/` is empty. User runs
|
||||
`uv run openrun-auth` (password + MFA), then
|
||||
`uv run openrun-sync --days 35` (covers the wellness gap since May 17;
|
||||
activities + FITs are incremental automatically).
|
||||
- `race_plan` table is EMPTY and `manual_activities` empty, but openrun.toml
|
||||
has races: 30K 2026-06-13, 50K 2026-07-25, 50 MILE 2026-09-12.
|
||||
- Known bugs: 18 activities have epoch-ms floats in `start_time_local`
|
||||
(should be ISO strings) — normalize on ingest + one-time migration;
|
||||
`datetime.utcnow()` deprecation warnings in `src/openrun/ingest/garmin_api.py`.
|
||||
|
||||
## Plan
|
||||
|
||||
- **P0 — protect the work**: .gitignore, private remote, CI running pytest,
|
||||
pick canonical DB + backup story. (commit done)
|
||||
- **P1 — use it for the ultra build**: live sync (`openrun-auth` +
|
||||
`openrun-sync`, fall back to `../garmin-pgc/` python-garminconnect backend if
|
||||
garth hits Cloudflare 429), then populate `race_plan` through 2026-09-12
|
||||
using `banister_forecast` + `calibrate_tl_per_km`; log off-watch work.
|
||||
- **P2 — data quality**: fix the 18 mixed-format timestamps, utcnow warnings,
|
||||
add `schema_version` + tiny migration runner before any public release.
|
||||
- **P3 — merge sync fork**: fold `../garmin-pgc/` into openrun as
|
||||
`openrun-sync --backend=garminconnect` instead of a sibling project.
|
||||
- **P4 — roadmap items reordered for the ultra**: TrainingReadinessDTO +
|
||||
RunRacePredictions ingest (ROADMAP 1.2), route map (3.2). Defer DBSCAN,
|
||||
multi-athlete, distribution until after September.
|
||||
|
||||
## Gaps identified (not yet scheduled)
|
||||
|
||||
- Subjective data: RPE/soreness/injury notes (user hand-writes these in
|
||||
../RunningLogs.md; March right-leg injury) — tie into DB, plot vs ACWR/TSB.
|
||||
- Ultra metrics: weekly vert, time-on-feet, back-to-back long-run detection,
|
||||
grade-adjusted pace (`elevation_gain` already in schema, unused).
|
||||
- Sync automation (launchd/cron weekly `openrun-sync`).
|
||||
47
NatesNotes.md
Normal file
47
NatesNotes.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Nate Personal Notes
|
||||
|
||||
## Eisley
|
||||
|
||||
### Exercises
|
||||
|
||||
### Gait / posture
|
||||
- knee forward
|
||||
- stepping too far forward
|
||||
- lose momentum, hard strike, pulling
|
||||
- instead, run on ice
|
||||
- feet land underneath, push backward
|
||||
- this has revealed weakness and asymmetry in feet/ankles/legs
|
||||
- in particular, left foot is very difficult to load medial side during pushoff
|
||||
|
||||
- 170 bpm is ideal
|
||||
- This has made HR consistently maintainable < 145
|
||||
- I end up running slower to maintain HR
|
||||
- datafield on watch showing big HR/Cadence - only important fields for training
|
||||
|
||||
- feeling of winding/turning my feet sup on lateral, inf on medial
|
||||
- aligns with medial MTP avoidance, good queue
|
||||
|
||||
## Anatomy Observations
|
||||
- Natural cadence is 161. Body falls back to this if I don't think about it
|
||||
- Feeling of legs out of socket, or tailbone out of place, or sacrum twisted(?)
|
||||
- asymettery in motion of each leg
|
||||
- tightness and weakness where collarbones join
|
||||
- feel of trying to pull that area down seems right
|
||||
- likewise in shoulders, feel out of socket or twisted/tight
|
||||
|
||||
## Other PT Findings
|
||||
|
||||
### Connor Harris
|
||||
- Big toe ball exercise
|
||||
- side faces wall
|
||||
- forearm against wall, opposite leg slightly lateral
|
||||
- raise wall-side leg marcher
|
||||
- lift body w/far leg, focus on pressing into big toe ball
|
||||
- imagine trying to lift toes from ground
|
||||
|
||||
## Race Logistics
|
||||
- I have undernourished
|
||||
- 80g carb/hr goal
|
||||
- 3 strides in / 2 out breathing
|
||||
- noticed diaphragm very often in same place on same foot
|
||||
-
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 02 \u2014 Running\n",
|
||||
"# 02 — Running\n",
|
||||
"\n",
|
||||
"Volume, pace, HR efficiency, training load."
|
||||
]
|
||||
@@ -34,7 +34,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -71,7 +71,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -94,7 +94,7 @@
|
||||
" ax.scatter(g['avg_hr'], g['pace_min_per_km'], s=g['distance_km'] * 6, alpha=0.5, label=str(yr))\n",
|
||||
"ax.invert_yaxis() # faster pace = smaller number, want top\n",
|
||||
"ax.set_xlabel('Avg HR (bpm)')\n",
|
||||
"ax.set_ylabel('Pace (min/km, faster \u2191)')\n",
|
||||
"ax.set_ylabel('Pace (min/km, faster ↑)')\n",
|
||||
"ax.set_title('Pace vs. HR by run, sized by distance')\n",
|
||||
"ax.legend(title='Year')\n",
|
||||
"ax.grid(alpha=0.3)\n",
|
||||
@@ -111,7 +111,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -138,10 +138,10 @@
|
||||
"monthly_easy = easy.set_index('start_time_local')['pace_min_per_km'].resample('ME').median()\n",
|
||||
"\n",
|
||||
"fig, ax = plt.subplots(figsize=(13, 4))\n",
|
||||
"ax.scatter(easy['start_time_local'], easy['pace_min_per_km'], alpha=0.3, s=easy['distance_km']*5, label='runs (HR<150, \u22653km)')\n",
|
||||
"ax.scatter(easy['start_time_local'], easy['pace_min_per_km'], alpha=0.3, s=easy['distance_km']*5, label='runs (HR<150, ≥3km)')\n",
|
||||
"monthly_easy.plot(ax=ax, color='C3', lw=2, marker='o', label='Monthly median')\n",
|
||||
"ax.invert_yaxis()\n",
|
||||
"ax.set_ylabel('Pace (min/km, faster \u2191)')\n",
|
||||
"ax.set_ylabel('Pace (min/km, faster ↑)')\n",
|
||||
"ax.set_title('Easy-pace trend (proxy for aerobic fitness)')\n",
|
||||
"ax.legend()\n",
|
||||
"ax.grid(alpha=0.3)\n",
|
||||
@@ -151,7 +151,28 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": "## Training load \u2014 Banister CTL / ATL / TSB\n\nGarmin reports a per-activity training load. The standard endurance-training lens (TrainingPeaks \"Performance Management Chart\") tracks three derived numbers:\n\n- **CTL** *Chronic Training Load* \u2014 EWMA of daily load with \u03c4 = 42 days. **Fitness.**\n- **ATL** *Acute Training Load* \u2014 same EWMA with \u03c4 = 7 days. **Fatigue.**\n- **TSB** *Training Stress Balance* \u2014 yesterday's CTL minus yesterday's ATL. **Form.**\n\nTSB interpretation:\n\n| TSB | meaning |\n|---|---|\n| < \u221230 | severely fatigued (injury risk) |\n| \u221210 to \u221230 | productive overload \u2014 heart of a build |\n| \u221210 to 0 | balanced building |\n| 0 to +10 | sharpening |\n| **+10 to +25** | **fresh / peaked \u2014 race-day target** |\n| > +25 | detrained (taper too long) |\n\nThis replaces the older 7/28-day rolling ACWR plot \u2014 same data, EWMAs are smoother and TSB gives you race-day-readiness directly."
|
||||
"source": [
|
||||
"## Training load — Banister CTL / ATL / TSB\n",
|
||||
"\n",
|
||||
"Garmin reports a per-activity training load. The standard endurance-training lens (TrainingPeaks \"Performance Management Chart\") tracks three derived numbers:\n",
|
||||
"\n",
|
||||
"- **CTL** *Chronic Training Load* — EWMA of daily load with τ = 42 days. **Fitness.**\n",
|
||||
"- **ATL** *Acute Training Load* — same EWMA with τ = 7 days. **Fatigue.**\n",
|
||||
"- **TSB** *Training Stress Balance* — yesterday's CTL minus yesterday's ATL. **Form.**\n",
|
||||
"\n",
|
||||
"TSB interpretation:\n",
|
||||
"\n",
|
||||
"| TSB | meaning |\n",
|
||||
"|---|---|\n",
|
||||
"| < −30 | severely fatigued (injury risk) |\n",
|
||||
"| −10 to −30 | productive overload — heart of a build |\n",
|
||||
"| −10 to 0 | balanced building |\n",
|
||||
"| 0 to +10 | sharpening |\n",
|
||||
"| **+10 to +25** | **fresh / peaked — race-day target** |\n",
|
||||
"| > +25 | detrained (taper too long) |\n",
|
||||
"\n",
|
||||
"This replaces the older 7/28-day rolling ACWR plot — same data, EWMAs are smoother and TSB gives you race-day-readiness directly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -172,14 +193,14 @@
|
||||
"ax1.set_ylabel('training load')\n",
|
||||
"ax1.legend(loc='upper left')\n",
|
||||
"ax1.grid(alpha=0.3)\n",
|
||||
"ax1.set_title('Performance Management Chart \u2014 CTL / ATL / TSB')\n",
|
||||
"ax1.set_title('Performance Management Chart — CTL / ATL / TSB')\n",
|
||||
"\n",
|
||||
"# bottom panel: form\n",
|
||||
"ax2.plot(pmc.index, pmc['TSB'], color='#264653', lw=1.5)\n",
|
||||
"ax2.axhspan(10, 25, color='#2a9d8f', alpha=0.12, label='race-ready (+10 to +25)')\n",
|
||||
"ax2.axhspan(-30, -10, color='#e9c46a', alpha=0.12, label='productive overload (\u221230 to \u221210)')\n",
|
||||
"ax2.axhspan(-30, -10, color='#e9c46a', alpha=0.12, label='productive overload (−30 to −10)')\n",
|
||||
"ax2.axhline(0, color='gray', lw=0.6)\n",
|
||||
"ax2.axhline(-30, color='#e76f51', ls='--', lw=0.8, label='injury-risk floor (\u221230)')\n",
|
||||
"ax2.axhline(-30, color='#e76f51', ls='--', lw=0.8, label='injury-risk floor (−30)')\n",
|
||||
"ax2.set_ylabel('TSB (form)')\n",
|
||||
"ax2.legend(loc='lower left', fontsize=9)\n",
|
||||
"ax2.grid(alpha=0.3)\n",
|
||||
@@ -204,7 +225,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
@@ -347,4 +368,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user