Repository navigation
frontmatter tag audit
Status: Landed (2026-09-27)
Date: 2026-09-27
Corpus: markdown/ — 888 files: collections/ 728, canvas/ 87, efforts/ 53, feeds/ 14, dashboards/ 6.
Related: docs/prototypes/seed-data-unification.md, apps/playground/src/lib/frontmatter.ts, apps/playground/src/services/seed/SeedImporter.ts
All workout classification across the codebase is unified under namespaced typed tags. The previous three competing classification mechanisms (flat frontmatter tags:, frontmatter category:, and body pseudo-frontmatter Type/Difficulty) have been consolidated directly in markdown frontmatter.
The markdown files are the single source of truth. Seed compilation (scripts/generate-seed.ts) bundles files byte-faithfully into JSON chunks, and runtime import (SeedImporter.ts) extracts typed tags using the native extractTypedFrontmatterTags parser.
Workout notes (markdown/collections/** and markdown/feeds/**) carry structured frontmatter with typed keys matching registered tag types:
---
domain: crossfit
format: for-time
equipment:
- barbell
- pullup-bar
quality:
- conditioning
intent: benchmark
date: 2012-09-29
original_url: "https://example.com/wod"
wayback_url: "https://web.archive.org/web/.../wod"
---| Key | Type / Value | Purpose | Indexed As |
|---|---|---|---|
domain |
String / List (crossfit, parkour, swimming, etc.) |
Sport or training discipline |
Tag (type: 'domain') |
format |
String / List (for-time, amrap, emom, intervals, etc.) |
Session execution shape & time domain |
Tag (type: 'format') |
equipment |
String / List (kettlebell, barbell, clubs, etc.) |
Gear required for the workout |
Tag (type: 'equipment') |
quality |
String / List (strength, endurance, conditioning, etc.) |
Target physical adaptation / stimulus |
Tag (type: 'quality') |
intent |
String / List (benchmark, competition, sport) |
Protocol role or testing status |
Tag (type: 'intent') |
tags |
String / List | Unclassified / general user tags |
Tag (type: undefined) |
date |
YYYY-MM-DD |
Calendar anchor |
Note.date (epoch ms at 12:00 UTC) |
original_url / wayback_url
|
String | Provenance links | Frontmatter metadata (verbatim) |
template, collection, feed, dashboard
|
Boolean / String | Document page-type discriminators | Page routing / UI hierarchy |
-
difficulty: Dropped. 488/495 ZombieFit files carried the boilerplate stringBeginner / Advanced / Expert, while other collections used 12 incompatible ad-hoc scales. Contains no normalized signal. -
category: Retired from workouts. The collection chunk (catalogonNote) already provides folder grouping; discipline semantics moved todomain. -
dashboard/template/collection/feed: Page discriminators; never tagged.
crossfitparkourswimmingtriathlonclimbinggirevoy-sport
Replaces 80 free-text Type and Format prose strings with normalized kebab-case slugs:
-
for-time(fromFor Time,For Time / Volume Training) -
amrap(fromAMRAP,AMRAP (As Many Rounds As Possible)) -
emom(fromEMOM,EMOM (Every Minute on the Minute)) -
intervals(fromIntervals,Distance Intervals) -
skill(fromSkill,Technique Focus,Skill Development) -
max-weight(fromMax Weight) -
max-reps(fromMax Reps,Max Reps Endurance Test) -
complex(fromStrength Complex,Progressive Strength Complex,Advanced Complex) -
circuit(fromDouble Kettlebell Circuit,High-Intensity Circuit) -
finisher(fromHigh-Intensity Finisher) -
individual-medley(fromIndividual Medley,Elite Individual Medley) -
program(from multi-day training block overviews)
Composable across multiple pieces of gear per workout:
kettlebellbarbelldumbbellpullup-barringsclubsmacebellsandbagunconventionalminimalistbodyweight
strengthendurance-
conditioning(cardiomerged intoconditioning) -
power(fromSpeed/Power,Maximum Velocity,Anaerobic Power) -
recovery(fromRecovery,Mobility and Recovery)
-
benchmark(e.g. CrossFit Girl WODs, standardized benchmarks) -
competition(e.g. Games events, Girevoy Sport competition sets) sport
-
tag_typesstore (TagTypeRecord): Pre-seeded byStorageService.DEFAULT_TAG_TYPESandSeedImportStorage:-
domain(#10b981) -
format(#8b5cf6) -
equipment(#3b82f6) -
quality(#f59e0b) -
intent(#ec4899) - Backwards compatibility:
category(#6366f1),type(#a855f7),discipline(#14b8a6)
-
-
tagsstore (Tag): Indexed byby-label(unique label) andby-type(type?: TagType). -
note_tagsstore (NoteTag): N:M junction table indexed byby-note(noteId) andby-tag(tagId).
Both user note saves (IndexedDBContentProvider.ts) and seed imports (SeedImporter.ts) share the same parser in apps/playground/src/lib/frontmatter.ts:
const KNOWN_TAG_TYPES = DEFAULT_TAG_TYPES.map((t) => t.name);
// Native extraction: matches frontmatter keys to known tag types
const tags = extractTypedFrontmatterTags(rawContent, KNOWN_TAG_TYPES);- Keys matching known types (
domain: crossfit) yield{ label: 'crossfit', type: 'domain' }. -
tags:values yield{ label: 'name' }(untyped general tag). - Duplicate labels resolve in favor of the typed record.
- Frontmatter lives in
Note.rawContent, stored byte-identically with no synthetic re-serialization.
-
Hoisting (2026-09-27): Lifted body-level pseudo-frontmatter (
Type,Difficulty,Category, URLs) into leading YAML frontmatter across 662 collection workout files. -
Taxonomy Migration (2026-09-27): Ran
scripts/migrate-corpus-tags.tsacross 888 markdown files (748 modified):- Parsed flat
tags:and normalizedtype:into canonical typed keys (domain,format,equipment,quality,intent). - Merged
cardiointoconditioning. - Dropped empty
category:anddifficulty:values.
- Parsed flat
-
Seed Importer Cutover (2026-09-27): Removed the legacy category-munging code in
SeedImporter.tsin favor of directextractTypedFrontmatterTags(). -
Seed Compilation (2026-09-27): Re-generated seed artifacts under
apps/playground/public/seed/viascripts/generate-seed.ts(78 chunks, 889 files, 9262 KB).