@isparling/engram-coach 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -18
- package/SETUP.md +559 -0
- package/SKILL_PACK.md +75 -0
- package/analyses/catalog.md +257 -0
- package/analysis-tools/hrv-trend.ts +592 -0
- package/analysis-tools/migrate-structured-capture.ts +234 -0
- package/analysis-tools/race-context.ts +96 -0
- package/analysis-tools/stream-analyze.ts +1008 -0
- package/analysis-tools/tsb-predict.ts +117 -0
- package/capture-handler.ts +301 -0
- package/config.json.example +21 -0
- package/engram-coach-ambient-capture.ts +336 -0
- package/engram-coach-capture-types.ts +185 -0
- package/engram-coach-config.ts +268 -0
- package/engram-coach-domain.ts +7 -2
- package/engram-coach-keys.ts +189 -0
- package/engram-coach-materialization.ts +638 -0
- package/engram-coach-migration.ts +1078 -0
- package/engram-coach-pack.ts +17 -12
- package/engram-coach-presentation.ts +10 -1
- package/engram-coach-reconciliation.ts +305 -2
- package/engram-coach-structured-capture.ts +622 -0
- package/package.json +39 -6
- package/personas/aggressive-monitoring.md +121 -0
- package/personas/aggressive.json +85 -0
- package/personas/conservative-monitoring.md +133 -0
- package/personas/conservative.json +93 -0
- package/personas/polarized-monitoring.md +112 -0
- package/personas/polarized.json +72 -0
- package/personas/volume-monitoring.md +85 -0
- package/personas/volume.json +108 -0
- package/shared/retrieval.md +71 -0
- package/shared/setup.md +207 -0
- package/skills/.gitkeep +0 -0
- package/skills/adapt-plan/SKILL.md +263 -0
- package/skills/block-review/SKILL.md +275 -0
- package/skills/consult/SKILL.md +176 -0
- package/skills/intake/SKILL.md +315 -0
- package/skills/lactate-analyze/SKILL.md +230 -0
- package/skills/lessons-rollup/SKILL.md +196 -0
- package/skills/monitoring-rollup/SKILL.md +208 -0
- package/skills/race-analysis/SKILL.md +219 -0
- package/skills/season-retrospective/SKILL.md +200 -0
- package/skills/set-goal/SKILL.md +297 -0
- package/templates/base.md +55 -0
- package/templates/build-1.md +57 -0
- package/templates/build-2.md +62 -0
- package/templates/race-report.md +51 -0
- package/templates/race-specificity.md +62 -0
- package/templates/season-review.md +40 -0
- package/engram-coach-extractor.ts +0 -295
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: race-analysis
|
|
3
|
+
description: Five-phase post-race synthesis. Computes stream-derived race metrics via stream-analyze and race-context CLI tools, gathers athlete narrative (fueling, intent vs execution, surprises), and writes RACE_REPORT.md. Auto-tails lessons-rollup. Requires Intervals.icu MCP and config.json.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Race Analysis
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Rigid five-phase workflow for analyzing a single race and producing `RACE_REPORT.md`. Combines computed stream analyses (fade, time-in-zone, decoupling, surge response, lap trends, sim comparison) with athlete narrative on fueling, intent, and qualitative experience. All time-series compute happens in CLI tools — no raw streams enter LLM context.
|
|
11
|
+
|
|
12
|
+
**This skill is RIGID — phases execute in exact order. Do not skip, reorder, or combine phases.**
|
|
13
|
+
|
|
14
|
+
## Workflow
|
|
15
|
+
|
|
16
|
+
```dot
|
|
17
|
+
digraph race_analysis {
|
|
18
|
+
"Pre-Phase: Setup" [shape=box];
|
|
19
|
+
"P1: Orient" [shape=box];
|
|
20
|
+
"P2: Compute" [shape=box];
|
|
21
|
+
"P3: Gather" [shape=box];
|
|
22
|
+
"P4: Draft" [shape=box];
|
|
23
|
+
"Athlete approves?" [shape=diamond];
|
|
24
|
+
"P5: Write" [shape=box];
|
|
25
|
+
|
|
26
|
+
"Pre-Phase: Setup" -> "P1: Orient" -> "P2: Compute" -> "P3: Gather" -> "P4: Draft" -> "Athlete approves?";
|
|
27
|
+
"Athlete approves?" -> "P5: Write" [label="yes"];
|
|
28
|
+
"Athlete approves?" -> "P4: Draft" [label="revise"];
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### Pre-Phase Setup _(no user input — run silently)_
|
|
35
|
+
|
|
36
|
+
Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
|
|
37
|
+
preamble (paths, config, profile, persona, athlete profile).
|
|
38
|
+
|
|
39
|
+
**Optional steps this skill declares:** SEASON, MCP
|
|
40
|
+
|
|
41
|
+
Do not proceed past a stop condition defined there.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Phase 1 — Orient _(no user input)_
|
|
45
|
+
|
|
46
|
+
Resolve target activity, fetch metadata, identify comparison sims. No streams yet.
|
|
47
|
+
|
|
48
|
+
1. **Resolve target activity:**
|
|
49
|
+
- If athlete provided an activity ID, use it.
|
|
50
|
+
- Otherwise, call `get_recent_activities(limit=10)`. Filter to race-typed or athlete-flagged-as-race entries. If exactly one candidate, confirm with athlete:
|
|
51
|
+
> "Analyzing {activity_name} ({date}, {distance}km, {duration}). Correct?"
|
|
52
|
+
- If multiple candidates, list them and ask the athlete to pick.
|
|
53
|
+
|
|
54
|
+
2. Call `get_activity_details(activity_id)` to extract: name, type, start time, distance, duration, FTP at time of activity.
|
|
55
|
+
|
|
56
|
+
3. Call `get_calendar_events` over a 14-day window centered on the race date. Identify the prescription targeting this race (look for matching event name, date, or `is_race: true` flag in YAML frontmatter). If found, read the prescription file and note the target zones, planned duration, planned fueling.
|
|
57
|
+
|
|
58
|
+
4. **Identify comparison sims:** call `get_recent_activities(days_back=42, limit=50)`, filter to:
|
|
59
|
+
- Saturday activities
|
|
60
|
+
- Within the date range of the immediately-preceding Race Specificity block (resolve from prescriptions_dir naming)
|
|
61
|
+
- Duration ≥ 60% of race duration
|
|
62
|
+
Take the 3 most recent matching activities. For each, call `get_activity_details` to extract `np`, `avg_hr`, `decoupling_pct` (set to 0 if not present — sim_compare handles missing decoupling), `duration_sec`, `start_date`. Build the `ActivitySummaryForCompare` array.
|
|
63
|
+
|
|
64
|
+
5. **Decide segmentation strategy:** if `duration_sec > 6 * 3600` → hourly (omit `--fade-segments` to use default), else `--fade-segments=4`.
|
|
65
|
+
|
|
66
|
+
6. **Announce findings:**
|
|
67
|
+
> "Race identified: {name}, {duration}, FTP {ftp}W.
|
|
68
|
+
> Prescription: {found / not found}.
|
|
69
|
+
> Comparison sims: {N} found ({list dates}).
|
|
70
|
+
> Segmentation: {hourly / quartiles}."
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
### Phase 2 — Compute _(no user input — shells out)_
|
|
75
|
+
|
|
76
|
+
Run two CLIs and capture their JSON output. NO raw stream data enters LLM context — only the parsed summaries.
|
|
77
|
+
|
|
78
|
+
1. **Build sim-compare target file (if sims found):**
|
|
79
|
+
|
|
80
|
+
Call `get_activity_streams(activity_id)` for the target activity to compute its NP and avg HR via the stream-analyze tool itself, OR fetch via `get_activity_details` if available. (Prefer details — avoids a stream fetch.)
|
|
81
|
+
|
|
82
|
+
Write `/tmp/sim-target-{race_id}.json`:
|
|
83
|
+
```json
|
|
84
|
+
{ "activity_id": "{race_id}", "date": "{race_date}", "np": {...}, "avg_hr": {...}, "decoupling_pct": 0, "duration_sec": {...} }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Write `/tmp/sim-sims-{race_id}.json` as the array built in Phase 1 step 4.
|
|
88
|
+
|
|
89
|
+
2. **Run stream-analyze:**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd ${CLAUDE_PLUGIN_ROOT}/analysis-tools && npx tsx stream-analyze.ts \
|
|
93
|
+
--activity-id={race_id} \
|
|
94
|
+
--analyses=fade,time_in_zone,np_distribution,decoupling,hr_recovery,interval_cv,sim_compare,lap_trends \
|
|
95
|
+
--ftp-override={ftp} \
|
|
96
|
+
{--fade-segments=4 if quartiles, else omit} \
|
|
97
|
+
{--sim-compare-target=/tmp/sim-target-{race_id}.json --sim-compare-sims=/tmp/sim-sims-{race_id}.json if sims found, else omit}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
3. **Run race-context:**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cd ${CLAUDE_PLUGIN_ROOT}/analysis-tools && npx tsx race-context.ts --activity-id={race_id}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
4. **Assemble bundle:** parse both JSON outputs. For any analysis present in `output.errors`, drop it from the bundle and note the error for the draft phase.
|
|
107
|
+
|
|
108
|
+
5. **Announce health check (one line):**
|
|
109
|
+
> "Compute complete. {N of 8} analyses succeeded, race-context loaded ({weather present / weather absent})."
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### Phase 3 — Gather _(one question at a time — wait for each answer before asking the next)_
|
|
114
|
+
|
|
115
|
+
1. **Fueling timeline:**
|
|
116
|
+
> "Walk me through what you ate and drank during the race — roughly when, what, and how much. Anything you missed or struggled with?"
|
|
117
|
+
|
|
118
|
+
2. **Race intent vs execution:**
|
|
119
|
+
> "What was your plan going in? Where did you stick to it, and where did you deviate — deliberately or otherwise?"
|
|
120
|
+
|
|
121
|
+
3. **Where it got hard:**
|
|
122
|
+
> "When did the race start to feel hard? What did 'hard' mean — legs, breathing, motivation, fueling, something else?"
|
|
123
|
+
|
|
124
|
+
4. **Surprises:**
|
|
125
|
+
> "What surprised you, positively or negatively?"
|
|
126
|
+
|
|
127
|
+
5. **Off-record context:**
|
|
128
|
+
> "Anything else from race day or the days leading in that the data wouldn't capture? Sleep, illness, weather acclimation, equipment, pre-race stress."
|
|
129
|
+
|
|
130
|
+
6. **Form explicit report conclusions:**
|
|
131
|
+
From the computed bundle and gathered narrative, distill a small set of
|
|
132
|
+
atomic, explicitly approved conclusions that bear on existing keyed
|
|
133
|
+
state (for example, whether race execution confirms or contradicts the
|
|
134
|
+
targeted prescription). Each conclusion is recorded as an entry of the
|
|
135
|
+
`report_claims` array in the structured change set (`StructuredReportClaim`)
|
|
136
|
+
with ALL of:
|
|
137
|
+
- `entity_type`: `race-conclusion`
|
|
138
|
+
- `key_components`: the exact canonical state entity it bears on
|
|
139
|
+
(`entity_type` plus its durable identity components, e.g.
|
|
140
|
+
`{ entity_type: prescription, arc_id, session_id }`)
|
|
141
|
+
- `effective_at`: the effective time of the conclusion
|
|
142
|
+
- `statement`: one-sentence human-readable claim
|
|
143
|
+
- `source_document`: the relative path of the `RACE_REPORT.md` this
|
|
144
|
+
conclusion comes from
|
|
145
|
+
- `details`: the structured value of the conclusion
|
|
146
|
+
|
|
147
|
+
Narrative sections of the report stay narrative — only these atomic
|
|
148
|
+
conclusions become records.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### Phase 4 — Draft _(shown to athlete)_
|
|
153
|
+
Render the full `RACE_REPORT.md` using `templates/race-report.md` as the
|
|
154
|
+
skeleton. Fill every section from the Phase 2 bundle and Phase 3 answers.
|
|
155
|
+
Annotate any sections that were dropped due to errors (e.g., "Decoupling not
|
|
156
|
+
computed — duration <45min").
|
|
157
|
+
|
|
158
|
+
**Record preview — one combined approval:** alongside the full report draft,
|
|
159
|
+
call `engram_capture_preview({ change_set })` with the structured change set
|
|
160
|
+
containing the Phase 3 `report_claims`. Show the complete report AND the
|
|
161
|
+
record preview (the exact plan hash, each record's role/classification) to
|
|
162
|
+
the athlete together. The athlete approves BOTH the report text and the
|
|
163
|
+
capture plan under ONE approval; the approved plan hash is bound to this
|
|
164
|
+
exact content. Iterate on both until explicitly approved.
|
|
165
|
+
|
|
166
|
+
If the preview returns blocked errors, fix the change set and re-preview —
|
|
167
|
+
Phase 4 cannot complete without a ready plan hash.
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Phase 5 — Write _(with approval)_
|
|
173
|
+
|
|
174
|
+
1. Build the event slug: lowercase, hyphenated, from the activity name. Example: "Example Gravel Event" → `example-gravel-event`.
|
|
175
|
+
|
|
176
|
+
2. Create the directory:
|
|
177
|
+
```bash
|
|
178
|
+
mkdir -p {coaching_docs_dir}/{season}/races/{YYYY-MM-DD}-{event-slug}/
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
3. Write the approved `RACE_REPORT.md` to that directory. **This document
|
|
183
|
+
write happens FIRST and is the authoritative canonical report — it is
|
|
184
|
+
never regenerated from records.** If this write fails for any reason,
|
|
185
|
+
STOP: do not apply any records; report the failure to the athlete.
|
|
186
|
+
|
|
187
|
+
4. **Apply the approved capture plan:** only after the report write
|
|
188
|
+
succeeded, call `engram_capture_apply({ plan_hash })` with the exact
|
|
189
|
+
plan hash approved in Phase 4.
|
|
190
|
+
- `status: "stale"` → the pending preview was discarded; return to
|
|
191
|
+
Phase 4, re-preview, and get fresh approval.
|
|
192
|
+
- Report any index or compatibility-view staleness from the result to
|
|
193
|
+
the athlete (records remain authoritative either way); a stale index
|
|
194
|
+
refresh is retried via the guarded mechanism, never by editing views.
|
|
195
|
+
|
|
196
|
+
5. **Auto-tail lessons-rollup:** invoke the `lessons-rollup` skill ONLY
|
|
197
|
+
after BOTH the report document write AND the report claims apply
|
|
198
|
+
succeeded:
|
|
199
|
+
- `--source=race:{event-slug}`
|
|
200
|
+
- The bullets from the report's "Calibration Points for Future Blocks"
|
|
201
|
+
section as the append list.
|
|
202
|
+
|
|
203
|
+
The rollup keeps its own harness-backed claim gate; the report is never
|
|
204
|
+
reconstructed from the captured claims.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Key Constraints
|
|
209
|
+
|
|
210
|
+
| Rule | Detail |
|
|
211
|
+
|------|--------|
|
|
212
|
+
| Rigid phases | Execute in order — no skipping, reordering, or combining |
|
|
213
|
+
| Approval gate | Nothing written until Phase 4 draft explicitly approved — report text and capture plan approved together under one approval |
|
|
214
|
+
| One question at a time | Phase 3 never batches questions |
|
|
215
|
+
| No raw streams in context | All time-series math runs in stream-analyze; skill consumes condensed JSON |
|
|
216
|
+
| Partial-data tolerance | Missing analyses (e.g., decoupling on short events, sim_compare with no sims) annotate and skip rather than failing the report |
|
|
217
|
+
| Canonical report first | Phase 5 writes `RACE_REPORT.md` FIRST; a failed document write stops before any record apply |
|
|
218
|
+
| Explicit conclusions only | Only the atomic `report_claims` from the approved change set become records; narrative stays in the document |
|
|
219
|
+
| Auto-tail rollup | Phase 5 invokes lessons-rollup only after BOTH the report write and claims apply succeed |
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: season-retrospective
|
|
3
|
+
description: Five-phase end-of-season synthesis. Reads all block summaries and race reports for a season, gathers athlete reflection on the arc, synthesizes persona-fit assessment and cross-block patterns, writes SEASON_REVIEW.md, and auto-tails lessons-rollup. Requires Intervals.icu MCP and config.json.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Season Retrospective
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Rigid five-phase workflow for end-of-season synthesis. Reads existing block summaries and race reports (no per-activity computation), gathers the athlete's reflection on the arc, then constructs the season-level narrative — including a persona-fit assessment that drives next-season recommendations.
|
|
11
|
+
|
|
12
|
+
**This skill is RIGID — phases execute in exact order. Do not skip, reorder, or combine phases.**
|
|
13
|
+
|
|
14
|
+
## Workflow
|
|
15
|
+
|
|
16
|
+
```dot
|
|
17
|
+
digraph season_retrospective {
|
|
18
|
+
"Pre-Phase: Setup" [shape=box];
|
|
19
|
+
"P1: Orient" [shape=box];
|
|
20
|
+
"P2: Gather" [shape=box];
|
|
21
|
+
"P3: Synthesize" [shape=box];
|
|
22
|
+
"P4: Draft" [shape=box];
|
|
23
|
+
"Athlete approves?" [shape=diamond];
|
|
24
|
+
"P5: Write + Rollup" [shape=box];
|
|
25
|
+
|
|
26
|
+
"Pre-Phase: Setup" -> "P1: Orient" -> "P2: Gather" -> "P3: Synthesize" -> "P4: Draft" -> "Athlete approves?";
|
|
27
|
+
"Athlete approves?" -> "P5: Write + Rollup" [label="yes"];
|
|
28
|
+
"Athlete approves?" -> "P4: Draft" [label="revise"];
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### Pre-Phase Setup _(no user input — run silently)_
|
|
35
|
+
|
|
36
|
+
Follow **`${CLAUDE_PLUGIN_ROOT}/shared/setup.md`** — the shared configuration
|
|
37
|
+
preamble (paths, config, profile, persona, athlete profile).
|
|
38
|
+
|
|
39
|
+
**Optional steps this skill declares:** SEASON, MCP
|
|
40
|
+
|
|
41
|
+
Do not proceed past a stop condition defined there.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Phase 1 — Orient _(no user input)_
|
|
45
|
+
|
|
46
|
+
Document reads and low-cost MCP calls only. No streams, no per-activity computation.
|
|
47
|
+
|
|
48
|
+
1. **Enumerate season contents:**
|
|
49
|
+
- List `{coaching_docs_dir}/{season}/` → identify block directories and the `races/` directory.
|
|
50
|
+
- For each block directory, check for `SUMMARY.md`. If absent, note as a gap.
|
|
51
|
+
- List `{coaching_docs_dir}/{season}/races/` → enumerate race report directories.
|
|
52
|
+
|
|
53
|
+
2. **Read all block summaries** that exist.
|
|
54
|
+
|
|
55
|
+
3. **Read all race reports** that exist.
|
|
56
|
+
|
|
57
|
+
4. **Read intake record:** look for `{coaching_docs_dir}/intake/` or `{coaching_docs_dir}/{season}/intake.md`. Extract original goal, persona at season start, target date.
|
|
58
|
+
|
|
59
|
+
5. **Season-wide wellness trajectory:**
|
|
60
|
+
- Compute `season_duration_days` from intake target date and earliest block start (or use the first block's `block_start`).
|
|
61
|
+
- Call `get_wellness_data(days_back={season_duration_days + 1})`.
|
|
62
|
+
- Extract MONTHLY summary points only: peak CTL per month, lowest TSB per month, end-of-month CTL. Do NOT load per-day data into reasoning.
|
|
63
|
+
|
|
64
|
+
6. **QMD context queries:**
|
|
65
|
+
```bash
|
|
66
|
+
qmd query "{season} pivots"
|
|
67
|
+
qmd query "{season} persona changes"
|
|
68
|
+
|
|
69
|
+
Follow `${CLAUDE_PLUGIN_ROOT}/shared/retrieval.md` when constructing these — parameterize with the specifics below, and add queries for whatever this particular season actually raises.
|
|
70
|
+
```
|
|
71
|
+
Surface major mid-season decisions (e.g., persona switched at week 12, planned A-race deferred).
|
|
72
|
+
|
|
73
|
+
7. **Block-coverage gap check:** if any block has no SUMMARY.md, ask:
|
|
74
|
+
> "Block {name} has no SUMMARY.md. Run block-review for it first, or proceed without it?"
|
|
75
|
+
|
|
76
|
+
8. **Announce:**
|
|
77
|
+
> "Season span: {start} → {end}. Blocks completed: {N} ({list}). Race reports: {N}.
|
|
78
|
+
> Persona at start: {start_persona}. Persona at end: {end_persona}.
|
|
79
|
+
> Original goal: {goal}. Outcome (per athlete intake or recent message): {one-line}.
|
|
80
|
+
> Mid-season pivots: {summary}."
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Phase 2 — Gather _(one question at a time)_
|
|
85
|
+
|
|
86
|
+
1. **Goal achievement:**
|
|
87
|
+
> "Looking back at what you set out to do at the start of this season — how did the actual outcome compare? Not just the result, but how it felt to get there."
|
|
88
|
+
|
|
89
|
+
2. **What worked:**
|
|
90
|
+
> "What about your training do you most want to repeat next season? A specific block structure, a recovery pattern, a fueling approach, a persona fit — anything."
|
|
91
|
+
|
|
92
|
+
3. **What didn't:**
|
|
93
|
+
> "What would you change — knowing what you know now, what would you do differently from week one?"
|
|
94
|
+
|
|
95
|
+
4. **Forward intent:**
|
|
96
|
+
> "What's the next goal, and is it the same kind of goal as this one or a different shape entirely?"
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
### Phase 3 — Synthesize _(no user input — internal reasoning, no writes yet)_
|
|
101
|
+
|
|
102
|
+
Construct, but do not yet render:
|
|
103
|
+
|
|
104
|
+
1. **Arc narrative:** how blocks connected, where the load came from, where it peaked, how the taper went into the target event.
|
|
105
|
+
|
|
106
|
+
2. **Persona-fit assessment:** based on calibration points across blocks and athlete answers, did the active persona match how the athlete actually responded?
|
|
107
|
+
- Yes → cite supporting evidence.
|
|
108
|
+
- No → which persona's philosophy would have produced equal-or-better outcomes? What evidence?
|
|
109
|
+
- This is the highest-value cross-block insight — be specific.
|
|
110
|
+
|
|
111
|
+
3. **Goal-vs-outcome diagnosis:**
|
|
112
|
+
- Missed goal → what was the limiter? Cite specific data (race report fade, block summary HRV trends, etc.).
|
|
113
|
+
- Met or exceeded → what overperformed and is it durable? Or anomalous (e.g., favorable conditions)?
|
|
114
|
+
|
|
115
|
+
4. **Cross-block patterns:** scan all block summaries' "Calibration Points for Future Blocks" sections. Items that appear in 2+ blocks (semantically — paraphrasing acceptable) are durable patterns. List them with sources.
|
|
116
|
+
|
|
117
|
+
5. **Race-report integration:** what did the races reveal that block summaries alone wouldn't?
|
|
118
|
+
|
|
119
|
+
6. **Form explicit report conclusions:** distill the atomic, explicitly
|
|
120
|
+
approved conclusions of the season review — facts that bear on existing
|
|
121
|
+
keyed state (persona fit verdicts, durable cross-block patterns tied to
|
|
122
|
+
thresholds or monitoring concerns). Each conclusion is recorded as an
|
|
123
|
+
entry of the `report_claims` array in the structured change set
|
|
124
|
+
(`StructuredReportClaim`) with ALL of:
|
|
125
|
+
- `entity_type`: `season-conclusion`
|
|
126
|
+
- `key_components`: the exact canonical state entity it bears on
|
|
127
|
+
(`entity_type` plus its durable identity components)
|
|
128
|
+
- `effective_at`: the effective time of the conclusion
|
|
129
|
+
- `statement`: one-sentence human-readable claim
|
|
130
|
+
- `source_document`: the relative path of the `SEASON_REVIEW.md` this
|
|
131
|
+
conclusion comes from
|
|
132
|
+
- `details`: the structured value of the conclusion
|
|
133
|
+
|
|
134
|
+
Narrative sections stay narrative — only these atomic conclusions
|
|
135
|
+
become records.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Phase 4 — Draft _(shown to athlete)_
|
|
140
|
+
|
|
141
|
+
Render the full `SEASON_REVIEW.md` using `templates/season-review.md` as the
|
|
142
|
+
skeleton. Fill every section.
|
|
143
|
+
|
|
144
|
+
The "Calibration Points to Promote" section at the bottom is the explicit
|
|
145
|
+
list of bullets that will be passed to `lessons-rollup`. Bar is higher than
|
|
146
|
+
block-level — only cross-block patterns confirmed by race execution OR
|
|
147
|
+
pattern repetition across 2+ blocks.
|
|
148
|
+
|
|
149
|
+
**Record preview — one combined approval:** alongside the full report draft,
|
|
150
|
+
call `engram_capture_preview({ change_set })` with the structured change set
|
|
151
|
+
containing the Phase 3 `report_claims`. Show the complete report AND the
|
|
152
|
+
record preview (the exact plan hash, each record's role/classification) to
|
|
153
|
+
the athlete together. The athlete approves BOTH the report text and the
|
|
154
|
+
capture plan under ONE approval; the approved plan hash is bound to this
|
|
155
|
+
exact content. Iterate on both until explicitly approved. If the preview is
|
|
156
|
+
blocked, fix the change set and re-preview — this phase cannot complete
|
|
157
|
+
without a ready plan hash.
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Phase 5 — Write + Rollup _(with approval)_
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
1. Write `{coaching_docs_dir}/{season}/SEASON_REVIEW.md`. **This document
|
|
166
|
+
write happens FIRST and is the authoritative canonical season review —
|
|
167
|
+
it is never regenerated from records.** If this write fails for any
|
|
168
|
+
reason, STOP: do not apply any records; report the failure to the athlete.
|
|
169
|
+
|
|
170
|
+
2. **Apply the approved capture plan:** only after the document write
|
|
171
|
+
succeeded, call `engram_capture_apply({ plan_hash })` with the exact
|
|
172
|
+
plan hash approved in Phase 4.
|
|
173
|
+
- `status: "stale"` → the pending preview was discarded; return to
|
|
174
|
+
Phase 4, re-preview, and get fresh approval.
|
|
175
|
+
- Report any index or compatibility-view staleness from the result to
|
|
176
|
+
the athlete (records remain authoritative either way); a stale index
|
|
177
|
+
refresh is retried via the guarded mechanism, never by editing views.
|
|
178
|
+
|
|
179
|
+
3. **Auto-tail lessons-rollup** ONLY after BOTH the document write AND the
|
|
180
|
+
report claims apply succeeded:
|
|
181
|
+
- `--source=season:{season}`
|
|
182
|
+
- The "Calibration Points to Promote" bullets as the append list.
|
|
183
|
+
Non-additive diffs gate on approval. The rollup keeps its own
|
|
184
|
+
harness-backed claim gate; the review is never reconstructed from the
|
|
185
|
+
captured claims.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Key Constraints
|
|
190
|
+
|
|
191
|
+
| Rule | Detail |
|
|
192
|
+
|------|--------|
|
|
193
|
+
| Rigid phases | Execute in order — no skipping, reordering, or combining |
|
|
194
|
+
| Approval gate | Nothing written until Phase 4 draft explicitly approved — report text and capture plan approved together under one approval |
|
|
195
|
+
| No per-activity compute | All stream-derived signals come from existing block summaries and race reports |
|
|
196
|
+
| Wellness data is monthly-summarized | Season wellness trajectory loads only monthly summary points, never per-day |
|
|
197
|
+
| Partial-coverage tolerance | Missing block summaries are flagged and the season retrospective continues with a gap annotation |
|
|
198
|
+
| Canonical report first | Phase 5 writes `SEASON_REVIEW.md` FIRST; a failed document write stops before any record apply |
|
|
199
|
+
| Explicit conclusions only | Only the atomic `report_claims` from the approved change set become records; narrative stays in the document |
|
|
200
|
+
| Auto-tail rollup | lessons-rollup runs only after BOTH the document write and claims apply succeed |
|