forge-openclaw-plugin 0.2.92 → 0.2.94

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.
Files changed (28) hide show
  1. package/dist/assets/{board-DKxKOwax.js → board-D1HbyD4u.js} +1 -1
  2. package/dist/assets/{index-BNvUaA6y.js → index-DWZd3qT-.js} +44 -44
  3. package/dist/assets/index-PA_Ih223.css +1 -0
  4. package/dist/assets/{motion-CM4AfIqo.js → motion-D2OqILg_.js} +1 -1
  5. package/dist/assets/{table-BUeQ9wzR.js → table-YWWjPjC_.js} +1 -1
  6. package/dist/assets/{ui-3Wd4pVaA.js → ui-DikPZj8S.js} +1 -1
  7. package/dist/assets/vendor-BS9OPVNh.js +2181 -0
  8. package/dist/companion-iroh/darwin-arm64/forge-companion-iroh +0 -0
  9. package/dist/companion-iroh/darwin-x64/forge-companion-iroh +0 -0
  10. package/dist/companion-iroh/linux-x64/forge-companion-iroh +0 -0
  11. package/dist/index.html +7 -7
  12. package/dist/openclaw/parity.js +1 -0
  13. package/dist/openclaw/routes.js +5 -0
  14. package/dist/openclaw/tools.js +7 -0
  15. package/dist/server/server/migrations/064_health_workout_time_series_identity.sql +161 -0
  16. package/dist/server/server/src/app.js +72 -2
  17. package/dist/server/server/src/health-workout-analytics.js +8 -2
  18. package/dist/server/server/src/health.js +337 -2
  19. package/dist/server/server/src/openapi.js +59 -0
  20. package/dist/server/src/lib/api.js +6 -0
  21. package/openclaw.plugin.json +2 -1
  22. package/package.json +1 -1
  23. package/server/migrations/064_health_workout_time_series_identity.sql +161 -0
  24. package/skills/forge-openclaw/SKILL.md +25 -7
  25. package/skills/forge-openclaw/entity_conversation_playbooks.md +88 -12
  26. package/skills/forge-openclaw/psyche_entity_playbooks.md +35 -0
  27. package/dist/assets/index-NqIbz_lv.css +0 -1
  28. package/dist/assets/vendor-BVU0cZC9.js +0 -2171
@@ -0,0 +1,161 @@
1
+ CREATE TEMP TABLE health_workout_time_series_dedupe AS
2
+ SELECT
3
+ workout_id,
4
+ metric_key,
5
+ source_sample_uid,
6
+ MIN(rowid) AS survivor_rowid,
7
+ (
8
+ SELECT latest.rowid
9
+ FROM health_workout_time_series AS latest
10
+ WHERE latest.workout_id = grouped.workout_id
11
+ AND latest.metric_key = grouped.metric_key
12
+ AND latest.source_sample_uid = grouped.source_sample_uid
13
+ ORDER BY latest.updated_at DESC, latest.created_at DESC, latest.rowid DESC
14
+ LIMIT 1
15
+ ) AS latest_rowid,
16
+ (
17
+ SELECT latest.series_index
18
+ FROM health_workout_time_series AS latest
19
+ WHERE latest.workout_id = grouped.workout_id
20
+ AND latest.metric_key = grouped.metric_key
21
+ AND latest.source_sample_uid = grouped.source_sample_uid
22
+ ORDER BY latest.updated_at DESC, latest.created_at DESC, latest.rowid DESC
23
+ LIMIT 1
24
+ ) AS latest_series_index
25
+ FROM health_workout_time_series AS grouped
26
+ WHERE source_sample_uid IS NOT NULL
27
+ AND source_sample_uid != ''
28
+ GROUP BY workout_id, metric_key, source_sample_uid
29
+ HAVING COUNT(*) > 1;
30
+
31
+ UPDATE health_workout_time_series
32
+ SET
33
+ label = (
34
+ SELECT latest.label
35
+ FROM health_workout_time_series AS latest
36
+ JOIN health_workout_time_series_dedupe AS dedupe
37
+ ON dedupe.latest_rowid = latest.rowid
38
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
39
+ ),
40
+ category = (
41
+ SELECT latest.category
42
+ FROM health_workout_time_series AS latest
43
+ JOIN health_workout_time_series_dedupe AS dedupe
44
+ ON dedupe.latest_rowid = latest.rowid
45
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
46
+ ),
47
+ unit = (
48
+ SELECT latest.unit
49
+ FROM health_workout_time_series AS latest
50
+ JOIN health_workout_time_series_dedupe AS dedupe
51
+ ON dedupe.latest_rowid = latest.rowid
52
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
53
+ ),
54
+ value = (
55
+ SELECT latest.value
56
+ FROM health_workout_time_series AS latest
57
+ JOIN health_workout_time_series_dedupe AS dedupe
58
+ ON dedupe.latest_rowid = latest.rowid
59
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
60
+ ),
61
+ started_at = (
62
+ SELECT latest.started_at
63
+ FROM health_workout_time_series AS latest
64
+ JOIN health_workout_time_series_dedupe AS dedupe
65
+ ON dedupe.latest_rowid = latest.rowid
66
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
67
+ ),
68
+ ended_at = (
69
+ SELECT latest.ended_at
70
+ FROM health_workout_time_series AS latest
71
+ JOIN health_workout_time_series_dedupe AS dedupe
72
+ ON dedupe.latest_rowid = latest.rowid
73
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
74
+ ),
75
+ source_device = (
76
+ SELECT latest.source_device
77
+ FROM health_workout_time_series AS latest
78
+ JOIN health_workout_time_series_dedupe AS dedupe
79
+ ON dedupe.latest_rowid = latest.rowid
80
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
81
+ ),
82
+ source_bundle_identifier = (
83
+ SELECT latest.source_bundle_identifier
84
+ FROM health_workout_time_series AS latest
85
+ JOIN health_workout_time_series_dedupe AS dedupe
86
+ ON dedupe.latest_rowid = latest.rowid
87
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
88
+ ),
89
+ source_product_type = (
90
+ SELECT latest.source_product_type
91
+ FROM health_workout_time_series AS latest
92
+ JOIN health_workout_time_series_dedupe AS dedupe
93
+ ON dedupe.latest_rowid = latest.rowid
94
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
95
+ ),
96
+ capture_method = (
97
+ SELECT latest.capture_method
98
+ FROM health_workout_time_series AS latest
99
+ JOIN health_workout_time_series_dedupe AS dedupe
100
+ ON dedupe.latest_rowid = latest.rowid
101
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
102
+ ),
103
+ quality_flags_json = (
104
+ SELECT latest.quality_flags_json
105
+ FROM health_workout_time_series AS latest
106
+ JOIN health_workout_time_series_dedupe AS dedupe
107
+ ON dedupe.latest_rowid = latest.rowid
108
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
109
+ ),
110
+ metadata_json = (
111
+ SELECT latest.metadata_json
112
+ FROM health_workout_time_series AS latest
113
+ JOIN health_workout_time_series_dedupe AS dedupe
114
+ ON dedupe.latest_rowid = latest.rowid
115
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
116
+ ),
117
+ provenance_json = (
118
+ SELECT latest.provenance_json
119
+ FROM health_workout_time_series AS latest
120
+ JOIN health_workout_time_series_dedupe AS dedupe
121
+ ON dedupe.latest_rowid = latest.rowid
122
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
123
+ ),
124
+ updated_at = (
125
+ SELECT latest.updated_at
126
+ FROM health_workout_time_series AS latest
127
+ JOIN health_workout_time_series_dedupe AS dedupe
128
+ ON dedupe.latest_rowid = latest.rowid
129
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
130
+ )
131
+ WHERE rowid IN (
132
+ SELECT survivor_rowid
133
+ FROM health_workout_time_series_dedupe
134
+ );
135
+
136
+ DELETE FROM health_workout_time_series
137
+ WHERE rowid IN (
138
+ SELECT duplicate.rowid
139
+ FROM health_workout_time_series AS duplicate
140
+ JOIN health_workout_time_series_dedupe AS dedupe
141
+ ON dedupe.workout_id = duplicate.workout_id
142
+ AND dedupe.metric_key = duplicate.metric_key
143
+ AND dedupe.source_sample_uid = duplicate.source_sample_uid
144
+ WHERE duplicate.rowid != dedupe.survivor_rowid
145
+ );
146
+
147
+ UPDATE health_workout_time_series
148
+ SET series_index = (
149
+ SELECT dedupe.latest_series_index
150
+ FROM health_workout_time_series_dedupe AS dedupe
151
+ WHERE dedupe.survivor_rowid = health_workout_time_series.rowid
152
+ )
153
+ WHERE rowid IN (
154
+ SELECT survivor_rowid
155
+ FROM health_workout_time_series_dedupe
156
+ );
157
+
158
+ DROP TABLE health_workout_time_series_dedupe;
159
+
160
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_health_workout_time_series_sample_identity
161
+ ON health_workout_time_series(workout_id, metric_key, source_sample_uid);
@@ -116,9 +116,17 @@ Concrete route-key examples for internal use:
116
116
  `{"routeKey":"settings","query":{"userIds":["user_operator"]}}`
117
117
  - Movement settings update:
118
118
  `{"routeKey":"settingsUpdate","body":{"trackingEnabled":true,"publishMode":"draft_review","retentionMode":"aggregates_only"}}`
119
+ - Movement known-place creation:
120
+ `{"routeKey":"placeCreate","body":{"label":"Home","centerLat":46.2044,"centerLon":6.1432,"radiusMeters":120,"userId":"user_operator","note":"Primary home boundary for future time-in-place reads."}}`
121
+ - Movement known-place update:
122
+ `{"routeKey":"placeUpdate","pathParams":{"id":"place_home"},"body":{"label":"Home office","radiusMeters":90,"note":"Tighten the boundary so clinic visits do not count as home."}}`
119
123
  - Movement missing-stay correction:
120
124
  first `{"routeKey":"userBoxPreflight","body":{"kind":"stay","startedAt":"2026-05-06T13:00:00.000Z","endedAt":"2026-05-06T15:00:00.000Z","placeLabel":"Home","userId":"user_operator"}}`,
121
125
  then `{"routeKey":"userBoxCreate","body":{"kind":"stay","startedAt":"2026-05-06T13:00:00.000Z","endedAt":"2026-05-06T15:00:00.000Z","placeLabel":"Home","userId":"user_operator","note":"Manual correction after reviewing the timeline."}}`
126
+ - Movement saved-overlay update:
127
+ `{"routeKey":"userBoxUpdate","pathParams":{"id":"box_manual_123"},"body":{"endedAt":"2026-05-06T15:30:00.000Z","note":"Extended after checking the timeline detail."}}`
128
+ - Movement saved-overlay delete:
129
+ `{"routeKey":"userBoxDelete","pathParams":{"id":"box_manual_123"}}`
122
130
  - Life Force overview:
123
131
  `{"routeKey":"overview"}`
124
132
  - Life Force profile edit:
@@ -139,6 +147,10 @@ Concrete route-key examples for internal use:
139
147
  `{"routeKey":"deleteFlow","pathParams":{"id":"flow_research_digest"}}`
140
148
  - Workbench run detail:
141
149
  `{"routeKey":"runDetail","pathParams":{"id":"flow_research_digest","runId":"run_123"}}`
150
+ - Workbench run nodes:
151
+ `{"routeKey":"runNodes","pathParams":{"id":"flow_research_digest","runId":"run_123"}}`
152
+ - Workbench node result:
153
+ `{"routeKey":"nodeResult","pathParams":{"id":"flow_research_digest","runId":"run_123","nodeId":"node_summary"}}`
142
154
  - Workbench published output:
143
155
  `{"routeKey":"publishedOutput","pathParams":{"id":"flow_research_digest"}}`
144
156
  - Workbench latest node output:
@@ -187,14 +199,16 @@ Wiki navigation and search rule:
187
199
  Health rule:
188
200
 
189
201
  - Sleep and sports records are first-class health surfaces, not generic notes or tasks.
190
- - Use `forge_get_sleep_overview` and `forge_get_sports_overview` for review and trend reading.
202
+ - Use `forge_get_sleep_overview`, `forge_get_sports_overview`, and
203
+ `forge_get_training_load_overview` for health review and trend reading.
191
204
  - In `forge_get_agent_onboarding.entityRouteModel.readModelOnlySurfaces`, operator,
192
- calendar, self-observation, sleep, and sports read models are published with
205
+ calendar, self-observation, sleep, sports, and training-load read models are published with
193
206
  both camelCase names and entity-style aliases where useful, including
194
207
  `operatorOverview`, `operatorContext`, `calendarOverview`, `sleepOverview`,
195
- `sportsOverview`, `operator_overview`, `operator_context`,
196
- `calendar_overview`, `self_observation`, `sleep_overview`, and
197
- `sports_overview`. Treat those as read-only surfaces, not batch CRUD entities.
208
+ `sportsOverview`, `trainingLoad`, `operator_overview`, `operator_context`,
209
+ `calendar_overview`, `self_observation`, `sleep_overview`,
210
+ `sports_overview`, and `training_load`. Treat those as read-only surfaces,
211
+ not batch CRUD entities.
198
212
  - Use `forge_get_operator_overview` for a broad Forge status read, `forge_get_operator_context`
199
213
  for current work and risk, and `forge_get_calendar_overview` before calendar-aware
200
214
  planning or scheduling mutations.
@@ -224,6 +238,7 @@ Entity conversation rule:
224
238
  before you reopen create or update intake.
225
239
  - When updating an entity, start with what is changing, what should stay true, and what prompted the update now.
226
240
  - When enough is clear, briefly summarize what you heard in the user's own language before asking for the last missing structural detail.
241
+ - Treat `userId` and human/bot assignees as accountability and scope, not as opening form fields. Ask whose human or bot record it is only when ownership changes visibility, review scope, collaboration, automation behavior, or later filtering; for read requests, ask user scope only when the answer would differ across owners.
227
242
  - The quick intake prompts later in this file are fallback checkpoints, not a script to read aloud.
228
243
 
229
244
  Forge data location rule:
@@ -249,6 +264,7 @@ Psyche interview rule:
249
264
  - After the first real answer, choose one follow-up lane at a time: situation, sequence, meaning, protection, cost, longing/value, or tentative name.
250
265
  - Do not minimize functional analysis, trigger chains, behavior patterns, modes, beliefs, or schema themes. Once at least one concrete example is clear, offer one careful interpretive hypothesis when it would help the user understand the function, protection, cost, belief, mode, or schema theme.
251
266
  - Phrase interpretive hypotheses as collaborative and testable, not as verdicts. A good hypothesis says what the reaction may be protecting, predicting, relieving, or costing, then asks whether that lands or needs correction.
267
+ - If several Psyche containers are plausible, do not ask the user to choose from a taxonomy menu first. Reflect the lived difference, offer one careful hypothesis when a concrete example is visible, then distinguish the options in plain language: one episode as a `trigger_report`, a recurring loop as a `behavior_pattern`, one repeated move as `behavior`, one sentence as `belief_entry`, a part-state as `mode_profile` or `mode_guide_session`, or reusable future-labeling as `event_type` or `emotion_definition`.
252
268
  - For Psyche updates, start with what feels newly true, newly visible, or newly inaccurate, then ask what should stay true before changing the formulation.
253
269
  - If a fresh episode is what made a Psyche update visible, anchor in that episode before renaming the durable belief, pattern, mode, or value.
254
270
  - If the user says they want help understanding a Psyche issue before saving it, ask one orienting question first instead of jumping straight into a full interpretation, diagnosis-like label, save suggestion, replacement belief, or suggested title.
@@ -510,7 +526,7 @@ Use the wiki tools for SQLite-backed memory work:
510
526
  `forge_get_wiki_settings`, `forge_list_wiki_pages`, `forge_get_wiki_page`, `forge_search_wiki`, `forge_upsert_wiki_page`, `forge_get_wiki_health`, `forge_sync_wiki_vault`, `forge_reindex_wiki_embeddings`, `forge_ingest_wiki_source`
511
527
 
512
528
  Use the health tools for review and reflective enrichment, not as the default CRUD architecture:
513
- `forge_get_sleep_overview`, `forge_get_sports_overview`, `forge_update_sleep_session`, `forge_update_workout_session`
529
+ `forge_get_sleep_overview`, `forge_get_sports_overview`, `forge_get_training_load_overview`, `forge_update_sleep_session`, `forge_update_workout_session`
514
530
 
515
531
  Use the dedicated domain routes for specialized surfaces that are not simple batch entities:
516
532
 
@@ -665,9 +681,10 @@ Use the health tools when the request is about sleep or sports review:
665
681
 
666
682
  - `forge_get_sleep_overview` to inspect recent nights, averages, regularity, stage breakdown, and linked reflective context
667
683
  - `forge_get_sports_overview` to inspect training volume, workout types, effort trends, habit-generated sessions, and linked context
684
+ - `forge_get_training_load_overview` to inspect cardiovascular load, HR zone balance, acute/chronic stress, high-intensity pressure, VO2max context, and training target fit
668
685
  - `forge_update_sleep_session` to add sleep-quality notes, tags, or links back to Forge entities after review
669
686
  - `forge_update_workout_session` to add subjective effort, mood, meaning, tags, or links on one workout after review
670
- - remember that the UI route is `/sports` while the backend overview route is `/api/v1/health/fitness`
687
+ - remember that the UI route is `/sports` while the backend overview route is `/api/v1/health/fitness`; the dedicated training-load UI is `/training-load` and its backend route is `/api/v1/health/training-load`
671
688
 
672
689
  Use these exact health batch payload shapes when the user is creating or editing the stored records themselves:
673
690
 
@@ -762,6 +779,7 @@ When the user asks which Forge tools are available, list exactly these tools:
762
779
  `forge_get_current_work`
763
780
  `forge_get_sleep_overview`
764
781
  `forge_get_sports_overview`
782
+ `forge_get_training_load_overview`
765
783
  `forge_update_sleep_session`
766
784
  `forge_update_workout_session`
767
785
  `forge_get_preferences_workspace`
@@ -204,6 +204,25 @@ When placement matters, prefer one hierarchy-aware linking question that can
204
204
  select or create the right goal, project, issue, or parent work item from the
205
205
  same search-first flow.
206
206
 
207
+ ## Owner And User-Scope Checkpoint
208
+
209
+ Most normal stored Forge entities can carry `userId`, and many planning records can
210
+ also carry human or bot assignees. Treat ownership as accountability and useful
211
+ visibility, not as the first field in the form.
212
+
213
+ - Do not open with "who owns this?" unless the user is explicitly delegating,
214
+ comparing human and bot work, or creating a record for someone else.
215
+ - Ask whose human or bot record it is only when ownership changes accountability,
216
+ visibility, review scope, automation behavior, or later filtering.
217
+ - For collaborative planning records, ask about assignees only after the outcome,
218
+ hierarchy placement, and owner are clear enough.
219
+ - For reviews and overviews, ask which user or owner scope matters only when the
220
+ answer would change across humans or bots.
221
+ - If the user's wording already names the owner or bot actor, use that as the
222
+ `userId` direction internally and ask only for any ambiguity that remains.
223
+ - When owner scope is irrelevant, stay with the entity's meaning, timing, route, or
224
+ links instead of adding an administrative question.
225
+
207
226
  ## Operation lane checkpoint
208
227
 
209
228
  Use this before you choose an API path or ask for more structure.
@@ -238,10 +257,10 @@ Use this quick split before the conversation gets too detailed.
238
257
  the user is trying to do, then use the dedicated action tool or note-backed write
239
258
  model.
240
259
  - `operator_overview`, `operator_context`, `calendar_overview`, `sleep_overview`,
241
- and `sports_overview` are read-model-only surfaces. Use them when the user wants
242
- to understand current Forge state, work risk, calendar commitments, nights,
243
- workouts, training load, recovery context, or health patterns before deciding
244
- whether a stored entity needs creation or enrichment.
260
+ `sports_overview`, and `training_load` are read-model-only surfaces. Use them
261
+ when the user wants to understand current Forge state, work risk, calendar
262
+ commitments, nights, workouts, cardiovascular load, recovery context, or health
263
+ patterns before deciding whether a stored entity needs creation or enrichment.
245
264
  - Movement, Life Force, and Workbench are specialized domain areas. Use their
246
265
  dedicated route families for timelines and overlays, energy profile/templates and
247
266
  fatigue signals, and Workbench flow execution or result artifacts. When available,
@@ -313,9 +332,17 @@ still knowing the exact write/read family before it acts.
313
332
  score, stages, or recovery patterns before deciding whether a specific
314
333
  `sleep_session` needs reflective enrichment.
315
334
  - `sports_overview`: read-model-only health surface. Use the sports overview route or
316
- `forge_get_sports_overview` when the user wants to review workouts, training load,
317
- effort, type distribution, or recovery context before deciding whether a specific
318
- `workout_session` needs reflective enrichment.
335
+ `forge_get_sports_overview` when the user wants to review workouts, effort, type
336
+ distribution, or recovery context before deciding whether a specific
337
+ `workout_session` needs reflective enrichment. Use
338
+ `forge_get_training_load_overview` or `/api/v1/health/training-load` for
339
+ cardiovascular load, HR zone balance, acute/chronic stress, VO2max context, or
340
+ training target questions.
341
+ - `training_load`: read-model-only health surface. Use
342
+ `forge_get_training_load_overview` or `/api/v1/health/training-load` when the
343
+ user wants training-load trends, acute/chronic ratio, HR zone distribution,
344
+ threshold exposure, VO2max/resting-HR context, or optimization targets before
345
+ deciding whether a specific `workout_session` needs notes or links.
319
346
  - `movement`: specialized domain surface. Use the dedicated movement routes for day,
320
347
  month, all-time, timeline, places, trip detail, selection aggregates, manual
321
348
  overlays, and repair actions.
@@ -1341,14 +1368,15 @@ Preferred opening question:
1341
1368
 
1342
1369
  ## Sports Overview
1343
1370
 
1344
- Aim: review workout and training-load context before deciding whether one workout
1345
- needs a reflective update or recovery follow-up.
1371
+ Aim: review workout context before deciding whether one workout needs a
1372
+ reflective update, and route deeper cardiovascular load questions to the
1373
+ training-load read model.
1346
1374
 
1347
1375
  Arc:
1348
1376
 
1349
1377
  1. Ask what the user wants to understand from the sports picture: one workout, a
1350
- recent training trend, effort, volume, type mix, recovery, or links to mood and
1351
- goals.
1378
+ recent training trend, effort, volume, type mix, recovery, zone balance, or
1379
+ links to mood and goals.
1352
1380
  2. Read the sports overview before asking the user to reconstruct metrics from memory.
1353
1381
  3. Reflect the practical decision the review should support.
1354
1382
  4. Move to `workout_session` enrichment only when one specific workout needs context,
@@ -1363,8 +1391,12 @@ Helpful follow-up lanes:
1363
1391
  Route note:
1364
1392
 
1365
1393
  - `sports_overview` is a read-model-only surface. Use `forge_get_sports_overview` or
1366
- `/api/v1/health/fitness` for review. Do not create, update, or delete
1394
+ `/api/v1/health/fitness` for session review. Do not create, update, or delete
1367
1395
  `sports_overview` through batch CRUD.
1396
+ - For cardiovascular load, HR zone distribution, acute/chronic load, VO2max
1397
+ context, or training target questions, use `forge_get_training_load_overview`
1398
+ or `/api/v1/health/training-load`. Treat `training_load` as read-model-only,
1399
+ not a batch CRUD entity.
1368
1400
  - If the review reveals that one workout needs reflective context, switch to the
1369
1401
  stored `workout_session` batch route or reflective update helper for that known
1370
1402
  session.
@@ -1378,6 +1410,50 @@ Preferred opening question:
1378
1410
 
1379
1411
  - "What are you trying to understand from your workout picture right now?"
1380
1412
 
1413
+ ## Training Load
1414
+
1415
+ Aim: review cardiovascular load and training targets before deciding whether one
1416
+ workout needs reflective enrichment or a recovery/target adjustment.
1417
+
1418
+ Arc:
1419
+
1420
+ 1. Ask what practical decision the user wants to support: build aerobic base,
1421
+ control overload risk, preserve hard-day quality, understand combat-sport
1422
+ intensity, or compare recent load against chronic base.
1423
+ 2. Read the training-load overview before asking the user to reconstruct zones,
1424
+ VO2max, or recent hard sessions from memory.
1425
+ 3. Reflect the load signal with explicit confidence: HR coverage, sensor limits,
1426
+ recent sample count, and whether kickboxing/wrist HR may be noisy.
1427
+ 4. Move to `workout_session` enrichment only when one specific workout needs
1428
+ notes, tags, context, or links.
1429
+
1430
+ Helpful follow-up lanes:
1431
+
1432
+ - whether the question is adaptation, overload risk, zone target, VO2max trend,
1433
+ sport contribution, or one recent session
1434
+ - which date range matters if the default 7-day and 28-day windows are not enough
1435
+ - whether the user is optimizing health, performance, recovery, or a specific
1436
+ upcoming training block
1437
+
1438
+ Route note:
1439
+
1440
+ - `training_load` is a read-model-only surface. Use
1441
+ `forge_get_training_load_overview` or `/api/v1/health/training-load` for
1442
+ cardiovascular load, HR zone distribution, acute/chronic load, VO2max context,
1443
+ and training target analysis. Do not create, update, or delete `training_load`
1444
+ through batch CRUD.
1445
+ - If one workout needs subjective effort, meaning, social context, or links,
1446
+ switch to the stored `workout_session` batch route or reflective update helper.
1447
+
1448
+ Ready to review when:
1449
+
1450
+ - the user's practical adaptation or recovery question is clear
1451
+ - the relevant time window or default 7-day/28-day comparison is acceptable
1452
+
1453
+ Preferred opening question:
1454
+
1455
+ - "What training-load decision are you trying to support right now?"
1456
+
1381
1457
  ## Calendar Overview
1382
1458
 
1383
1459
  Aim: review commitments, work blocks, provider state, and existing timeboxes before
@@ -251,6 +251,41 @@ short, tentative, and correctable.
251
251
  episode, or durable wiki explanation. Do not flatten schema work into a loose
252
252
  self-observation.
253
253
 
254
+ ## Entity Contrast Check
255
+
256
+ Use this when the user's material could fit several Psyche records. Do not ask the
257
+ user to choose from a taxonomy menu before you have reflected what the material is
258
+ doing.
259
+
260
+ - Choose `trigger_report` when the important thing is one charged episode and the
261
+ useful record is the sequence of situation, feeling, meaning, action, and
262
+ consequence.
263
+ - Choose `behavior_pattern` when the same cue -> body/emotion -> meaning ->
264
+ behavior/urge -> payoff -> cost loop repeats across situations and needs a
265
+ functional analysis.
266
+ - Choose `behavior` when one recurring move is the main object, even if the wider
267
+ loop is not mapped yet.
268
+ - Choose `belief_entry` when the live center is a sentence, rule, prediction, or
269
+ self/other/world assumption.
270
+ - Choose `mode_profile` when a recurring part-state has a stable voice, posture,
271
+ job, fear, or burden.
272
+ - Choose `mode_guide_session` when the user is inside the reaction and needs guided
273
+ present-moment exploration before a durable mode, belief, or pattern is clear.
274
+ - Choose `event_type` or `emotion_definition` when the reusable category or feeling
275
+ label will make future trigger reports more precise.
276
+
277
+ If two containers are genuinely plausible, say the distinction in plain language
278
+ after a reflection. For example: "We could save this as the episode if the meeting
279
+ itself is what matters, or as the recurring loop if this same freeze-and-overwork
280
+ sequence keeps happening. Which would help you more right now?" Ask that only after
281
+ the lived example is clear enough that the choice is meaningful.
282
+
283
+ After one concrete example is visible, it is often helpful to offer one careful
284
+ hypothesis before the contrast question: what the reaction may be protecting, what it
285
+ predicts, what short-term relief it creates, and what it costs. If the user corrects
286
+ the hypothesis, revise it once and then choose the record shape from the corrected
287
+ meaning.
288
+
254
289
  ## Therapeutic Direction Check
255
290
 
256
291
  Before each follow-up, quickly decide what therapeutic job the next question should do.