Skip to content

coach-mcp v1.1.0

Latest

Choose a tag to compare

@github-actions github-actions released this 27 Aug 06:48
· 4 commits to main since this release

A reliability and coaching-correctness release. The ACWR injury gate now runs
on the validated rolling 7d:28d model instead of the EWMA approximation, and a
class of date/anomaly bugs that made the coach misread what happened when is
fixed at the root (with the live failure that surfaced them captured as a
regression test). No new features and no breaking changes for MCP clients —
the tool surface, names, and config are identical to 1.0.0.

Fixed

  • Morning-audit crash loop: scripts/daily_loop.py no longer dies at
    import when daily_loop.log is held by another writer. The Task Scheduler
    action's cmd >> redirect into the same file the script's own
    logging.FileHandler opens held the log without write sharing (Windows),
    so every scheduled run since the task's 2026-06-10 registration crashed
    with PermissionError before doing any work. The file handler is now
    best-effort (console-only fallback) and the shipped task guidance redirects
    scheduler output to a separate daily_loop_task.log.
  • Planned-vs-actual matcher no longer crosswires types (live coaching
    failure, 2026-06-10): pairing now happens ONLY between a planned session
    and an actual whose types satisfy taxonomy.types_match, with a new
    name-hint fallback so plan "mobility" matches Garmin type other when the
    activity name contains mobility/stretch/yoga ("Cape Town Mobility"); when
    several actuals match by type the closest duration wins. Unmatched planned
    sessions are missing, unmatched actuals are unplanned (load included)
    — never paired just because both were left over. The skipped-padel day now
    reads mobility=completed, padel=MISSING, hard ride=UNPLANNED instead of
    two fabricated type_mismatches. type_mismatch survives only as a narrow
    substitute signal: one unmatched planned session whose type the taxonomy
    can't classify (e.g. race) plus exactly one leftover actual.
  • Today is pending, never missed: planned sessions dated today no longer
    produce missing anomalies or land in plan_adherence.skipped_dates — a
    06:27 snapshot was flagging the day's sessions as already skipped. The
    comparison cutoff is now date < today for missing; today belongs in
    pending_dates. Persistent-anomaly registration refuses missing-anomalies
    dated today, and cleanup drops previously mis-registered open
    missing-anomalies for the current date (they re-register tomorrow if the
    session genuinely never happened). Anomaly ids keep the
    <date>:<type>:<slug> format.
  • Snapshot payload is temporally self-anchoring (the coach combined
    week-old anomalies into "padel was today"): week_grid entries and all
    anomalies carry days_ago (0 = today), the snapshot carries
    week_grid_today, planned_vs_actual carries as_of, and every anomaly
    summary embeds its absolute date plus a relative phrase
    ("2026-06-10 (yesterday): ..."), recomputed against the threaded today on
    every snapshot. SERVER_INSTRUCTIONS now mandates trusting
    current_time_context over any date impression from earlier conversation
    and stating the current date/day at session start; the full date-discipline
    doctrine lives in coach://coaching/doctrine.

Changed

  • ACWR cutover to the classic rolling 7d:28d model (owner-approved after
    the 90-day shadow period — mean abs diff 0.264, 42% zone mismatch, and the
    May 11-13 post-stage-race danger window the EWMA model missed). The rolling
    coupled-window ratio (Hulin/Gabbett — the model the 0.8/1.3/1.5 thresholds
    were derived against) is now the PRIMARY acwr/acwr_status everywhere:
    snapshot fitness_metrics, load_hierarchy, acwr_warnings, the weekly
    prescription volume adjustment, the coaching score health component, and
    sport-specific ACWR (the load hierarchy never mixes models). The legacy
    EWMA ratio is demoted to fitness_metrics.acwr_ewma
    {value, zone, safe, note} — reference only. The shadow keys
    (acwr_rolling, acwr_rolling_status, acwr_shadow) are removed.
    CTL/ATL/TSB math, the 0.8/1.3/1.5 thresholds, and the [10, 15, 25] volume
    steps are unchanged.
  • Docs clarify that Cloudflare handling is a library dependency, not custom
    code in this repo
    — Garmin's SSO sits behind Cloudflare and the
    garminconnect library handles it natively via its curl_cffi dependency;
    this project's old garth + Playwright login fallback was deleted during the
    1.0 rebuild.
  • Docs aligned with MCP spec 2026-07-28 (the stateless-core release):
    COACH_TRANSPORT=sse is documented as legacy-only (the HTTP+SSE transport
    was formally deprecated upstream), and the deferred elicitation re-add is
    redesigned around the MRTR pattern instead of the removed server-initiated
    ctx.elicit() flow. No behavior changes — this stdio server needs no
    migration.

Added

  • scripts/recompute_acwr_history.py: supervised one-off migration that
    recomputes the acwr field of every stored fitness_history.json snapshot
    (total + per-sport) under the rolling model — --check dry-run by default,
    --apply writes after a one-time .pre-acwr-cutover.bak backup;
    ctl/atl/tsb are never touched.